From 5fd85b7bb0c6971b28455c3ec23e91ca854c2f71 Mon Sep 17 00:00:00 2001 From: Amaury Chamayou Date: Thu, 9 Jan 2025 09:44:05 +0000 Subject: [PATCH 1/2] Remove vendored copy of nghttp2 (#6737) --- .azure-pipelines-release.yml | 6 +- .azure-pipelines-templates/deploy_aci.yml | 2 +- .azure_pipelines_snp.yml | 2 +- .github/workflows/bencher.yml | 2 +- .github/workflows/ci-verification.yml | 6 +- .github/workflows/ci.yml | 6 +- .github/workflows/codeql-analysis.yml | 2 +- .github/workflows/long-test.yml | 8 +- .github/workflows/long-verification.yml | 4 +- .github/workflows/release.yml | 2 +- 3rdparty/exported/nghttp2/CMakeLists.txt | 107 - 3rdparty/exported/nghttp2/Makefile.am | 81 - 3rdparty/exported/nghttp2/Makefile.in | 1053 -- 3rdparty/exported/nghttp2/Makefile.msvc | 254 - .../exported/nghttp2/includes/CMakeLists.txt | 4 - .../exported/nghttp2/includes/Makefile.am | 26 - .../exported/nghttp2/includes/Makefile.in | 664 -- .../nghttp2/includes/nghttp2/nghttp2.h | 7017 -------------- .../nghttp2/includes/nghttp2/nghttp2ver.h | 42 - .../nghttp2/includes/nghttp2/nghttp2ver.h.in | 42 - 3rdparty/exported/nghttp2/libnghttp2.pc.in | 33 - 3rdparty/exported/nghttp2/nghttp2_alpn.c | 70 - 3rdparty/exported/nghttp2/nghttp2_alpn.h | 34 - 3rdparty/exported/nghttp2/nghttp2_buf.c | 527 - 3rdparty/exported/nghttp2/nghttp2_buf.h | 412 - 3rdparty/exported/nghttp2/nghttp2_callbacks.c | 203 - 3rdparty/exported/nghttp2/nghttp2_callbacks.h | 156 - 3rdparty/exported/nghttp2/nghttp2_debug.c | 60 - 3rdparty/exported/nghttp2/nghttp2_debug.h | 43 - 3rdparty/exported/nghttp2/nghttp2_extpri.c | 41 - 3rdparty/exported/nghttp2/nghttp2_extpri.h | 65 - 3rdparty/exported/nghttp2/nghttp2_frame.c | 1214 --- 3rdparty/exported/nghttp2/nghttp2_frame.h | 637 -- 3rdparty/exported/nghttp2/nghttp2_hd.c | 2377 ----- 3rdparty/exported/nghttp2/nghttp2_hd.h | 442 - .../exported/nghttp2/nghttp2_hd_huffman.c | 146 - .../exported/nghttp2/nghttp2_hd_huffman.h | 72 - .../nghttp2/nghttp2_hd_huffman_data.c | 4980 ---------- 3rdparty/exported/nghttp2/nghttp2_helper.c | 805 -- 3rdparty/exported/nghttp2/nghttp2_helper.h | 145 - 3rdparty/exported/nghttp2/nghttp2_http.c | 709 -- 3rdparty/exported/nghttp2/nghttp2_http.h | 100 - 3rdparty/exported/nghttp2/nghttp2_int.h | 58 - 3rdparty/exported/nghttp2/nghttp2_map.c | 302 - 3rdparty/exported/nghttp2/nghttp2_map.h | 128 - 3rdparty/exported/nghttp2/nghttp2_mem.c | 74 - 3rdparty/exported/nghttp2/nghttp2_mem.h | 45 - 3rdparty/exported/nghttp2/nghttp2_net.h | 91 - 3rdparty/exported/nghttp2/nghttp2_option.c | 157 - 3rdparty/exported/nghttp2/nghttp2_option.h | 157 - .../exported/nghttp2/nghttp2_outbound_item.c | 156 - .../exported/nghttp2/nghttp2_outbound_item.h | 189 - 3rdparty/exported/nghttp2/nghttp2_pq.c | 183 - 3rdparty/exported/nghttp2/nghttp2_pq.h | 124 - .../exported/nghttp2/nghttp2_priority_spec.c | 52 - .../exported/nghttp2/nghttp2_priority_spec.h | 42 - 3rdparty/exported/nghttp2/nghttp2_queue.c | 85 - 3rdparty/exported/nghttp2/nghttp2_queue.h | 51 - 3rdparty/exported/nghttp2/nghttp2_ratelim.c | 75 - 3rdparty/exported/nghttp2/nghttp2_ratelim.h | 57 - 3rdparty/exported/nghttp2/nghttp2_rcbuf.c | 102 - 3rdparty/exported/nghttp2/nghttp2_rcbuf.h | 80 - 3rdparty/exported/nghttp2/nghttp2_session.c | 8459 ----------------- 3rdparty/exported/nghttp2/nghttp2_session.h | 984 -- 3rdparty/exported/nghttp2/nghttp2_stream.c | 1016 -- 3rdparty/exported/nghttp2/nghttp2_stream.h | 440 - 3rdparty/exported/nghttp2/nghttp2_submit.c | 970 -- 3rdparty/exported/nghttp2/nghttp2_submit.h | 40 - 3rdparty/exported/nghttp2/nghttp2_time.c | 63 - 3rdparty/exported/nghttp2/nghttp2_time.h | 38 - 3rdparty/exported/nghttp2/nghttp2_version.c | 38 - 3rdparty/exported/nghttp2/sfparse.c | 1145 --- 3rdparty/exported/nghttp2/sfparse.h | 409 - 3rdparty/exported/nghttp2/version.rc.in | 40 - CMakeLists.txt | 5 +- cgmanifest.json | 9 - cmake/cpack_settings.cmake | 4 +- cmake/nghttp2.cmake | 74 - docker/ccf_ci_built | 2 +- 79 files changed, 26 insertions(+), 38519 deletions(-) delete mode 100644 3rdparty/exported/nghttp2/CMakeLists.txt delete mode 100644 3rdparty/exported/nghttp2/Makefile.am delete mode 100644 3rdparty/exported/nghttp2/Makefile.in delete mode 100644 3rdparty/exported/nghttp2/Makefile.msvc delete mode 100644 3rdparty/exported/nghttp2/includes/CMakeLists.txt delete mode 100644 3rdparty/exported/nghttp2/includes/Makefile.am delete mode 100644 3rdparty/exported/nghttp2/includes/Makefile.in delete mode 100644 3rdparty/exported/nghttp2/includes/nghttp2/nghttp2.h delete mode 100644 3rdparty/exported/nghttp2/includes/nghttp2/nghttp2ver.h delete mode 100644 3rdparty/exported/nghttp2/includes/nghttp2/nghttp2ver.h.in delete mode 100644 3rdparty/exported/nghttp2/libnghttp2.pc.in delete mode 100644 3rdparty/exported/nghttp2/nghttp2_alpn.c delete mode 100644 3rdparty/exported/nghttp2/nghttp2_alpn.h delete mode 100644 3rdparty/exported/nghttp2/nghttp2_buf.c delete mode 100644 3rdparty/exported/nghttp2/nghttp2_buf.h delete mode 100644 3rdparty/exported/nghttp2/nghttp2_callbacks.c delete mode 100644 3rdparty/exported/nghttp2/nghttp2_callbacks.h delete mode 100644 3rdparty/exported/nghttp2/nghttp2_debug.c delete mode 100644 3rdparty/exported/nghttp2/nghttp2_debug.h delete mode 100644 3rdparty/exported/nghttp2/nghttp2_extpri.c delete mode 100644 3rdparty/exported/nghttp2/nghttp2_extpri.h delete mode 100644 3rdparty/exported/nghttp2/nghttp2_frame.c delete mode 100644 3rdparty/exported/nghttp2/nghttp2_frame.h delete mode 100644 3rdparty/exported/nghttp2/nghttp2_hd.c delete mode 100644 3rdparty/exported/nghttp2/nghttp2_hd.h delete mode 100644 3rdparty/exported/nghttp2/nghttp2_hd_huffman.c delete mode 100644 3rdparty/exported/nghttp2/nghttp2_hd_huffman.h delete mode 100644 3rdparty/exported/nghttp2/nghttp2_hd_huffman_data.c delete mode 100644 3rdparty/exported/nghttp2/nghttp2_helper.c delete mode 100644 3rdparty/exported/nghttp2/nghttp2_helper.h delete mode 100644 3rdparty/exported/nghttp2/nghttp2_http.c delete mode 100644 3rdparty/exported/nghttp2/nghttp2_http.h delete mode 100644 3rdparty/exported/nghttp2/nghttp2_int.h delete mode 100644 3rdparty/exported/nghttp2/nghttp2_map.c delete mode 100644 3rdparty/exported/nghttp2/nghttp2_map.h delete mode 100644 3rdparty/exported/nghttp2/nghttp2_mem.c delete mode 100644 3rdparty/exported/nghttp2/nghttp2_mem.h delete mode 100644 3rdparty/exported/nghttp2/nghttp2_net.h delete mode 100644 3rdparty/exported/nghttp2/nghttp2_option.c delete mode 100644 3rdparty/exported/nghttp2/nghttp2_option.h delete mode 100644 3rdparty/exported/nghttp2/nghttp2_outbound_item.c delete mode 100644 3rdparty/exported/nghttp2/nghttp2_outbound_item.h delete mode 100644 3rdparty/exported/nghttp2/nghttp2_pq.c delete mode 100644 3rdparty/exported/nghttp2/nghttp2_pq.h delete mode 100644 3rdparty/exported/nghttp2/nghttp2_priority_spec.c delete mode 100644 3rdparty/exported/nghttp2/nghttp2_priority_spec.h delete mode 100644 3rdparty/exported/nghttp2/nghttp2_queue.c delete mode 100644 3rdparty/exported/nghttp2/nghttp2_queue.h delete mode 100644 3rdparty/exported/nghttp2/nghttp2_ratelim.c delete mode 100644 3rdparty/exported/nghttp2/nghttp2_ratelim.h delete mode 100644 3rdparty/exported/nghttp2/nghttp2_rcbuf.c delete mode 100644 3rdparty/exported/nghttp2/nghttp2_rcbuf.h delete mode 100644 3rdparty/exported/nghttp2/nghttp2_session.c delete mode 100644 3rdparty/exported/nghttp2/nghttp2_session.h delete mode 100644 3rdparty/exported/nghttp2/nghttp2_stream.c delete mode 100644 3rdparty/exported/nghttp2/nghttp2_stream.h delete mode 100644 3rdparty/exported/nghttp2/nghttp2_submit.c delete mode 100644 3rdparty/exported/nghttp2/nghttp2_submit.h delete mode 100644 3rdparty/exported/nghttp2/nghttp2_time.c delete mode 100644 3rdparty/exported/nghttp2/nghttp2_time.h delete mode 100644 3rdparty/exported/nghttp2/nghttp2_version.c delete mode 100644 3rdparty/exported/nghttp2/sfparse.c delete mode 100644 3rdparty/exported/nghttp2/sfparse.h delete mode 100644 3rdparty/exported/nghttp2/version.rc.in delete mode 100644 cmake/nghttp2.cmake diff --git a/.azure-pipelines-release.yml b/.azure-pipelines-release.yml index 90e4218d41b7..12bb66fb48a1 100644 --- a/.azure-pipelines-release.yml +++ b/.azure-pipelines-release.yml @@ -8,15 +8,15 @@ pr: none resources: containers: - container: virtual - image: ghcr.io/microsoft/ccf/ci/default:build-08-01-2025-1 + image: ghcr.io/microsoft/ccf/ci/default:build-08-01-2025-2 options: --publish-all --cap-add NET_ADMIN --cap-add NET_RAW --cap-add SYS_PTRACE -v /lib/modules:/lib/modules:ro - container: snp - image: ghcr.io/microsoft/ccf/ci/default:build-08-01-2025-1 + image: ghcr.io/microsoft/ccf/ci/default:build-08-01-2025-2 options: --publish-all --cap-add NET_ADMIN --cap-add NET_RAW --cap-add SYS_PTRACE -v /lib/modules:/lib/modules:ro - container: sgx - image: ghcr.io/microsoft/ccf/ci/sgx:build-08-01-2025-1 + image: ghcr.io/microsoft/ccf/ci/sgx:build-08-01-2025-2 options: --publish-all --cap-add NET_ADMIN --cap-add NET_RAW --device /dev/sgx_enclave:/dev/sgx_enclave --device /dev/sgx_provision:/dev/sgx_provision -v /dev/sgx:/dev/sgx -v /lib/modules:/lib/modules:ro variables: diff --git a/.azure-pipelines-templates/deploy_aci.yml b/.azure-pipelines-templates/deploy_aci.yml index 4b6c3e844c97..5f22472b6150 100644 --- a/.azure-pipelines-templates/deploy_aci.yml +++ b/.azure-pipelines-templates/deploy_aci.yml @@ -50,7 +50,7 @@ jobs: env: ACR_REGISTRY_RESOURCE_NAME: ccfmsrc ACR_REGISTRY: ccfmsrc.azurecr.io - BASE_IMAGE: ghcr.io/microsoft/ccf/ci/default:build-08-01-2025-1 + BASE_IMAGE: ghcr.io/microsoft/ccf/ci/default:build-08-01-2025-2 - script: | set -ex diff --git a/.azure_pipelines_snp.yml b/.azure_pipelines_snp.yml index 5d3db5770004..2acc18cd345d 100644 --- a/.azure_pipelines_snp.yml +++ b/.azure_pipelines_snp.yml @@ -22,7 +22,7 @@ schedules: resources: containers: - container: virtual - image: ghcr.io/microsoft/ccf/ci/default:build-08-01-2025-1 + image: ghcr.io/microsoft/ccf/ci/default:build-08-01-2025-2 options: --publish-all --cap-add NET_ADMIN --cap-add NET_RAW --cap-add SYS_PTRACE -v /lib/modules:/lib/modules:ro jobs: diff --git a/.github/workflows/bencher.yml b/.github/workflows/bencher.yml index 3017074044a5..f9ebd24320ed 100644 --- a/.github/workflows/bencher.yml +++ b/.github/workflows/bencher.yml @@ -13,7 +13,7 @@ jobs: name: Continuous Benchmarking with Bencher runs-on: [self-hosted, 1ES.Pool=gha-virtual-ccf-sub] container: - image: ghcr.io/microsoft/ccf/ci/default:build-08-01-2025-1 + image: ghcr.io/microsoft/ccf/ci/default:build-08-01-2025-2 steps: - uses: actions/checkout@v4 with: diff --git a/.github/workflows/ci-verification.yml b/.github/workflows/ci-verification.yml index 61a55b8bc293..36d29a03815b 100644 --- a/.github/workflows/ci-verification.yml +++ b/.github/workflows/ci-verification.yml @@ -24,7 +24,7 @@ jobs: name: Model Checking - Consistency runs-on: [self-hosted, 1ES.Pool=gha-virtual-ccf-sub] container: - image: ghcr.io/microsoft/ccf/ci/default:build-08-01-2025-1 + image: ghcr.io/microsoft/ccf/ci/default:build-08-01-2025-2 defaults: run: working-directory: tla @@ -102,7 +102,7 @@ jobs: name: Model Checking - Consensus runs-on: [self-hosted, 1ES.Pool=gha-virtual-ccf-sub] container: - image: ghcr.io/microsoft/ccf/ci/default:build-08-01-2025-1 + image: ghcr.io/microsoft/ccf/ci/default:build-08-01-2025-2 defaults: run: working-directory: tla @@ -158,7 +158,7 @@ jobs: name: Trace Validation - Consensus runs-on: [self-hosted, 1ES.Pool=gha-virtual-ccf-sub] container: - image: ghcr.io/microsoft/ccf/ci/default:build-08-01-2025-1 + image: ghcr.io/microsoft/ccf/ci/default:build-08-01-2025-2 steps: - uses: actions/checkout@v4 diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 1afb379ddd8b..602dd842b818 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -20,7 +20,7 @@ jobs: checks: name: "Format and License Checks" runs-on: ubuntu-latest - container: ghcr.io/microsoft/ccf/ci/default:build-08-01-2025-1 + container: ghcr.io/microsoft/ccf/ci/default:build-08-01-2025-2 steps: - run: git config --global --add safe.directory "$GITHUB_WORKSPACE" @@ -44,7 +44,7 @@ jobs: options: --user root --publish-all --cap-add NET_ADMIN --cap-add NET_RAW --cap-add SYS_PTRACE -v /lib/modules:/lib/modules:ro runs-on: ${{ matrix.platform.nodes }} container: - image: ghcr.io/microsoft/ccf/ci/${{ matrix.platform.image }}:build-08-01-2025-1 + image: ghcr.io/microsoft/ccf/ci/${{ matrix.platform.image }}:build-08-01-2025-2 options: ${{ matrix.platform.options }} steps: - uses: actions/checkout@v4 @@ -114,7 +114,7 @@ jobs: # Build tools tdnf -y install build-essential clang cmake ninja-build which # Dependencies - tdnf -y install openssl-devel libuv-devel + tdnf -y install openssl-devel libuv-devel nghttp2-devel # Test dependencies tdnf -y install libarrow-devel parquet-libs-devel lldb npm jq expect # Install CDDL via rubygems diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index 6607e949ec51..1281fb3d74f9 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -25,7 +25,7 @@ jobs: # Insufficient space to run on public runner, so use custom pool runs-on: [self-hosted, 1ES.Pool=gha-virtual-ccf-sub] container: - image: ghcr.io/microsoft/ccf/ci/default:build-08-01-2025-1 + image: ghcr.io/microsoft/ccf/ci/default:build-08-01-2025-2 options: --user root permissions: diff --git a/.github/workflows/long-test.yml b/.github/workflows/long-test.yml index 657998b7baeb..d216aa08c507 100644 --- a/.github/workflows/long-test.yml +++ b/.github/workflows/long-test.yml @@ -17,7 +17,7 @@ jobs: if: ${{ contains(github.event.pull_request.labels.*.name, 'run-long-test') || github.event_name == 'workflow_dispatch' || github.event_name == 'schedule' }} runs-on: [self-hosted, 1ES.Pool=gha-virtual-ccf-sub] container: - image: ghcr.io/microsoft/ccf/ci/default:build-08-01-2025-1 + image: ghcr.io/microsoft/ccf/ci/default:build-08-01-2025-2 steps: - uses: actions/checkout@v4 @@ -35,7 +35,7 @@ jobs: if: ${{ contains(github.event.pull_request.labels.*.name, 'run-long-test') || github.event_name == 'workflow_dispatch' || github.event_name == 'schedule' }} runs-on: [self-hosted, 1ES.Pool=gha-virtual-ccf-sub] container: - image: ghcr.io/microsoft/ccf/ci/default:build-08-01-2025-1 + image: ghcr.io/microsoft/ccf/ci/default:build-08-01-2025-2 steps: - uses: actions/checkout@v4 @@ -79,7 +79,7 @@ jobs: name: TSAN runs-on: [self-hosted, 1ES.Pool=gha-virtual-ccf-sub] container: - image: ghcr.io/microsoft/ccf/ci/default:build-08-01-2025-1 + image: ghcr.io/microsoft/ccf/ci/default:build-08-01-2025-2 steps: - uses: actions/checkout@v4 @@ -117,7 +117,7 @@ jobs: name: LTS runs-on: [self-hosted, 1ES.Pool=gha-virtual-ccf-sub] container: - image: ghcr.io/microsoft/ccf/ci/default:build-08-01-2025-1 + image: ghcr.io/microsoft/ccf/ci/default:build-08-01-2025-2 steps: - uses: actions/checkout@v4 diff --git a/.github/workflows/long-verification.yml b/.github/workflows/long-verification.yml index 58ca8599199d..a43b767c7403 100644 --- a/.github/workflows/long-verification.yml +++ b/.github/workflows/long-verification.yml @@ -22,7 +22,7 @@ jobs: if: ${{ contains(github.event.pull_request.labels.*.name, 'run-long-verification') || github.event_name == 'workflow_dispatch' || github.event_name == 'schedule' }} runs-on: [self-hosted, 1ES.Pool=gha-virtual-ccf-sub] container: - image: ghcr.io/microsoft/ccf/ci/default:build-08-01-2025-1 + image: ghcr.io/microsoft/ccf/ci/default:build-08-01-2025-2 defaults: run: working-directory: tla @@ -50,7 +50,7 @@ jobs: if: ${{ contains(github.event.pull_request.labels.*.name, 'run-long-verification') || github.event_name == 'workflow_dispatch' || github.event_name == 'schedule' }} runs-on: [self-hosted, 1ES.Pool=gha-virtual-ccf-sub] container: - image: ghcr.io/microsoft/ccf/ci/default:build-08-01-2025-1 + image: ghcr.io/microsoft/ccf/ci/default:build-08-01-2025-2 defaults: run: working-directory: tla diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 2e9c3b778e30..1b3613cc52ea 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -75,7 +75,7 @@ jobs: nodes: [self-hosted, 1ES.Pool=gha-virtual-ccf-sub] runs-on: ${{ matrix.platform.nodes }} container: - image: ghcr.io/microsoft/ccf/ci/${{ matrix.platform.image }}:build-08-01-2025-1 + image: ghcr.io/microsoft/ccf/ci/${{ matrix.platform.image }}:build-08-01-2025-2 options: "--user root --publish-all --cap-add NET_ADMIN --cap-add NET_RAW --cap-add SYS_PTRACE -v /lib/modules:/lib/modules:ro ${{ matrix.platform.container_options }}" steps: - uses: actions/checkout@v4 diff --git a/3rdparty/exported/nghttp2/CMakeLists.txt b/3rdparty/exported/nghttp2/CMakeLists.txt deleted file mode 100644 index fda8dcb7fc7f..000000000000 --- a/3rdparty/exported/nghttp2/CMakeLists.txt +++ /dev/null @@ -1,107 +0,0 @@ -add_subdirectory(includes) - -include_directories( - "${CMAKE_CURRENT_SOURCE_DIR}/includes" - "${CMAKE_CURRENT_BINARY_DIR}/includes" -) - -add_definitions(-DBUILDING_NGHTTP2) - -set(NGHTTP2_SOURCES - nghttp2_pq.c nghttp2_map.c nghttp2_queue.c - nghttp2_frame.c - nghttp2_buf.c - nghttp2_stream.c nghttp2_outbound_item.c - nghttp2_session.c nghttp2_submit.c - nghttp2_helper.c - nghttp2_alpn.c - nghttp2_hd.c nghttp2_hd_huffman.c nghttp2_hd_huffman_data.c - nghttp2_version.c - nghttp2_priority_spec.c - nghttp2_option.c - nghttp2_callbacks.c - nghttp2_mem.c - nghttp2_http.c - nghttp2_rcbuf.c - nghttp2_extpri.c - nghttp2_ratelim.c - nghttp2_time.c - nghttp2_debug.c - sfparse.c -) - -set(NGHTTP2_RES "") -set(STATIC_LIB "nghttp2_static") -set(SHARED_LIB "nghttp2") - -if(BUILD_SHARED_LIBS AND BUILD_STATIC_LIBS AND MSVC AND NOT STATIC_LIB_SUFFIX) - set(STATIC_LIB_SUFFIX "_static") -endif() - -if(WIN32) - configure_file( - version.rc.in - ${CMAKE_CURRENT_BINARY_DIR}/version.rc - @ONLY) - - set(NGHTTP2_RES ${CMAKE_CURRENT_BINARY_DIR}/version.rc) -endif() - -set(EXPORT_SET "${PROJECT_NAME}-targets") - -# Public shared library -if(BUILD_SHARED_LIBS) - add_library(${SHARED_LIB} SHARED ${NGHTTP2_SOURCES} ${NGHTTP2_RES}) - - set_target_properties(${SHARED_LIB} PROPERTIES - COMPILE_FLAGS "${WARNCFLAGS}" - VERSION ${LT_VERSION} SOVERSION ${LT_SOVERSION} - C_VISIBILITY_PRESET hidden - ) - - target_include_directories(${SHARED_LIB} INTERFACE - $ - $ - $ - ) - - install(TARGETS ${SHARED_LIB} EXPORT ${EXPORT_SET}) - list(APPEND nghttp2_exports ${SHARED_LIB}) -endif() - -# Static library (for unittests because of symbol visibility) -if(BUILD_STATIC_LIBS) - add_library(${STATIC_LIB} STATIC ${NGHTTP2_SOURCES}) - - set_target_properties(${STATIC_LIB} PROPERTIES - COMPILE_FLAGS "${WARNCFLAGS}" - VERSION ${LT_VERSION} SOVERSION ${LT_SOVERSION} - ARCHIVE_OUTPUT_NAME nghttp2${STATIC_LIB_SUFFIX} - ) - - target_include_directories(${STATIC_LIB} INTERFACE - $ - $ - $ - ) - - target_compile_definitions(${STATIC_LIB} PUBLIC "-DNGHTTP2_STATICLIB") - - install(TARGETS ${STATIC_LIB} EXPORT ${EXPORT_SET}) - list(APPEND nghttp2_exports ${STATIC_LIB}) -endif() - -if(BUILD_SHARED_LIBS) - set(LIB_SELECTED ${SHARED_LIB}) -else() - set(LIB_SELECTED ${STATIC_LIB}) -endif() - -add_library(${PROJECT_NAME}::nghttp2 ALIAS ${LIB_SELECTED}) - -install(FILES "${CMAKE_CURRENT_BINARY_DIR}/libnghttp2.pc" - DESTINATION "${CMAKE_INSTALL_LIBDIR}/pkgconfig") - -install(EXPORT ${EXPORT_SET} - DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME} - NAMESPACE ${PROJECT_NAME}::) diff --git a/3rdparty/exported/nghttp2/Makefile.am b/3rdparty/exported/nghttp2/Makefile.am deleted file mode 100644 index 1168c1e61356..000000000000 --- a/3rdparty/exported/nghttp2/Makefile.am +++ /dev/null @@ -1,81 +0,0 @@ -# nghttp2 - HTTP/2 C Library - -# Copyright (c) 2012, 2013 Tatsuhiro Tsujikawa - -# Permission is hereby granted, free of charge, to any person obtaining -# a copy of this software and associated documentation files (the -# "Software"), to deal in the Software without restriction, including -# without limitation the rights to use, copy, modify, merge, publish, -# distribute, sublicense, and/or sell copies of the Software, and to -# permit persons to whom the Software is furnished to do so, subject to -# the following conditions: - -# The above copyright notice and this permission notice shall be -# included in all copies or substantial portions of the Software. - -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -SUBDIRS = includes - -EXTRA_DIST = Makefile.msvc CMakeLists.txt version.rc.in - -AM_CFLAGS = $(WARNCFLAGS) $(EXTRACFLAG) -AM_CPPFLAGS = -I$(srcdir)/includes -I$(builddir)/includes -DBUILDING_NGHTTP2 \ - @DEFS@ -AM_LDFLAGS = @LIBTOOL_LDFLAGS@ - -pkgconfigdir = $(libdir)/pkgconfig -pkgconfig_DATA = libnghttp2.pc -DISTCLEANFILES = $(pkgconfig_DATA) - -lib_LTLIBRARIES = libnghttp2.la - -OBJECTS = nghttp2_pq.c nghttp2_map.c nghttp2_queue.c \ - nghttp2_frame.c \ - nghttp2_buf.c \ - nghttp2_stream.c nghttp2_outbound_item.c \ - nghttp2_session.c nghttp2_submit.c \ - nghttp2_helper.c \ - nghttp2_alpn.c \ - nghttp2_hd.c nghttp2_hd_huffman.c nghttp2_hd_huffman_data.c \ - nghttp2_version.c \ - nghttp2_priority_spec.c \ - nghttp2_option.c \ - nghttp2_callbacks.c \ - nghttp2_mem.c \ - nghttp2_http.c \ - nghttp2_rcbuf.c \ - nghttp2_extpri.c \ - nghttp2_ratelim.c \ - nghttp2_time.c \ - nghttp2_debug.c \ - sfparse.c - -HFILES = nghttp2_pq.h nghttp2_int.h nghttp2_map.h nghttp2_queue.h \ - nghttp2_frame.h \ - nghttp2_buf.h \ - nghttp2_session.h nghttp2_helper.h nghttp2_stream.h nghttp2_int.h \ - nghttp2_alpn.h \ - nghttp2_submit.h nghttp2_outbound_item.h \ - nghttp2_net.h \ - nghttp2_hd.h nghttp2_hd_huffman.h \ - nghttp2_priority_spec.h \ - nghttp2_option.h \ - nghttp2_callbacks.h \ - nghttp2_mem.h \ - nghttp2_http.h \ - nghttp2_rcbuf.h \ - nghttp2_extpri.h \ - nghttp2_ratelim.h \ - nghttp2_time.h \ - nghttp2_debug.h \ - sfparse.h - -libnghttp2_la_SOURCES = $(HFILES) $(OBJECTS) -libnghttp2_la_LDFLAGS = $(AM_LDFLAGS) -no-undefined \ - -version-info $(LT_CURRENT):$(LT_REVISION):$(LT_AGE) diff --git a/3rdparty/exported/nghttp2/Makefile.in b/3rdparty/exported/nghttp2/Makefile.in deleted file mode 100644 index 14686ef14b1a..000000000000 --- a/3rdparty/exported/nghttp2/Makefile.in +++ /dev/null @@ -1,1053 +0,0 @@ -# Makefile.in generated by automake 1.16.5 from Makefile.am. -# @configure_input@ - -# Copyright (C) 1994-2021 Free Software Foundation, Inc. - -# This Makefile.in is free software; the Free Software Foundation -# gives unlimited permission to copy and/or distribute it, -# with or without modifications, as long as this notice is preserved. - -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY, to the extent permitted by law; without -# even the implied warranty of MERCHANTABILITY or FITNESS FOR A -# PARTICULAR PURPOSE. - -@SET_MAKE@ - -# nghttp2 - HTTP/2 C Library - -# Copyright (c) 2012, 2013 Tatsuhiro Tsujikawa - -# Permission is hereby granted, free of charge, to any person obtaining -# a copy of this software and associated documentation files (the -# "Software"), to deal in the Software without restriction, including -# without limitation the rights to use, copy, modify, merge, publish, -# distribute, sublicense, and/or sell copies of the Software, and to -# permit persons to whom the Software is furnished to do so, subject to -# the following conditions: - -# The above copyright notice and this permission notice shall be -# included in all copies or substantial portions of the Software. - - -VPATH = @srcdir@ -am__is_gnu_make = { \ - if test -z '$(MAKELEVEL)'; then \ - false; \ - elif test -n '$(MAKE_HOST)'; then \ - true; \ - elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ - true; \ - else \ - false; \ - fi; \ -} -am__make_running_with_option = \ - case $${target_option-} in \ - ?) ;; \ - *) echo "am__make_running_with_option: internal error: invalid" \ - "target option '$${target_option-}' specified" >&2; \ - exit 1;; \ - esac; \ - has_opt=no; \ - sane_makeflags=$$MAKEFLAGS; \ - if $(am__is_gnu_make); then \ - sane_makeflags=$$MFLAGS; \ - else \ - case $$MAKEFLAGS in \ - *\\[\ \ ]*) \ - bs=\\; \ - sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ - | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ - esac; \ - fi; \ - skip_next=no; \ - strip_trailopt () \ - { \ - flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ - }; \ - for flg in $$sane_makeflags; do \ - test $$skip_next = yes && { skip_next=no; continue; }; \ - case $$flg in \ - *=*|--*) continue;; \ - -*I) strip_trailopt 'I'; skip_next=yes;; \ - -*I?*) strip_trailopt 'I';; \ - -*O) strip_trailopt 'O'; skip_next=yes;; \ - -*O?*) strip_trailopt 'O';; \ - -*l) strip_trailopt 'l'; skip_next=yes;; \ - -*l?*) strip_trailopt 'l';; \ - -[dEDm]) skip_next=yes;; \ - -[JT]) skip_next=yes;; \ - esac; \ - case $$flg in \ - *$$target_option*) has_opt=yes; break;; \ - esac; \ - done; \ - test $$has_opt = yes -am__make_dryrun = (target_option=n; $(am__make_running_with_option)) -am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) -pkgdatadir = $(datadir)/@PACKAGE@ -pkgincludedir = $(includedir)/@PACKAGE@ -pkglibdir = $(libdir)/@PACKAGE@ -pkglibexecdir = $(libexecdir)/@PACKAGE@ -am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd -install_sh_DATA = $(install_sh) -c -m 644 -install_sh_PROGRAM = $(install_sh) -c -install_sh_SCRIPT = $(install_sh) -c -INSTALL_HEADER = $(INSTALL_DATA) -transform = $(program_transform_name) -NORMAL_INSTALL = : -PRE_INSTALL = : -POST_INSTALL = : -NORMAL_UNINSTALL = : -PRE_UNINSTALL = : -POST_UNINSTALL = : -build_triplet = @build@ -host_triplet = @host@ -target_triplet = @target@ -subdir = lib -ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 -am__aclocal_m4_deps = $(top_srcdir)/m4/ax_check_compile_flag.m4 \ - $(top_srcdir)/m4/ax_cxx_compile_stdcxx.m4 \ - $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \ - $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \ - $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/configure.ac -am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ - $(ACLOCAL_M4) -DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON) -mkinstalldirs = $(install_sh) -d -CONFIG_HEADER = $(top_builddir)/config.h -CONFIG_CLEAN_FILES = libnghttp2.pc -CONFIG_CLEAN_VPATH_FILES = -am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; -am__vpath_adj = case $$p in \ - $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ - *) f=$$p;; \ - esac; -am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; -am__install_max = 40 -am__nobase_strip_setup = \ - srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` -am__nobase_strip = \ - for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" -am__nobase_list = $(am__nobase_strip_setup); \ - for p in $$list; do echo "$$p $$p"; done | \ - sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ - $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ - if (++n[$$2] == $(am__install_max)) \ - { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ - END { for (dir in files) print dir, files[dir] }' -am__base_list = \ - sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ - sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' -am__uninstall_files_from_dir = { \ - test -z "$$files" \ - || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \ - || { echo " ( cd '$$dir' && rm -f" $$files ")"; \ - $(am__cd) "$$dir" && rm -f $$files; }; \ - } -am__installdirs = "$(DESTDIR)$(libdir)" "$(DESTDIR)$(pkgconfigdir)" -LTLIBRARIES = $(lib_LTLIBRARIES) -libnghttp2_la_LIBADD = -am__objects_1 = -am__objects_2 = nghttp2_pq.lo nghttp2_map.lo nghttp2_queue.lo \ - nghttp2_frame.lo nghttp2_buf.lo nghttp2_stream.lo \ - nghttp2_outbound_item.lo nghttp2_session.lo nghttp2_submit.lo \ - nghttp2_helper.lo nghttp2_alpn.lo nghttp2_hd.lo \ - nghttp2_hd_huffman.lo nghttp2_hd_huffman_data.lo \ - nghttp2_version.lo nghttp2_priority_spec.lo nghttp2_option.lo \ - nghttp2_callbacks.lo nghttp2_mem.lo nghttp2_http.lo \ - nghttp2_rcbuf.lo nghttp2_extpri.lo nghttp2_ratelim.lo \ - nghttp2_time.lo nghttp2_debug.lo sfparse.lo -am_libnghttp2_la_OBJECTS = $(am__objects_1) $(am__objects_2) -libnghttp2_la_OBJECTS = $(am_libnghttp2_la_OBJECTS) -AM_V_lt = $(am__v_lt_@AM_V@) -am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) -am__v_lt_0 = --silent -am__v_lt_1 = -libnghttp2_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ - $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ - $(libnghttp2_la_LDFLAGS) $(LDFLAGS) -o $@ -AM_V_P = $(am__v_P_@AM_V@) -am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) -am__v_P_0 = false -am__v_P_1 = : -AM_V_GEN = $(am__v_GEN_@AM_V@) -am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) -am__v_GEN_0 = @echo " GEN " $@; -am__v_GEN_1 = -AM_V_at = $(am__v_at_@AM_V@) -am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) -am__v_at_0 = @ -am__v_at_1 = -DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) -depcomp = $(SHELL) $(top_srcdir)/depcomp -am__maybe_remake_depfiles = depfiles -am__depfiles_remade = ./$(DEPDIR)/nghttp2_alpn.Plo \ - ./$(DEPDIR)/nghttp2_buf.Plo ./$(DEPDIR)/nghttp2_callbacks.Plo \ - ./$(DEPDIR)/nghttp2_debug.Plo ./$(DEPDIR)/nghttp2_extpri.Plo \ - ./$(DEPDIR)/nghttp2_frame.Plo ./$(DEPDIR)/nghttp2_hd.Plo \ - ./$(DEPDIR)/nghttp2_hd_huffman.Plo \ - ./$(DEPDIR)/nghttp2_hd_huffman_data.Plo \ - ./$(DEPDIR)/nghttp2_helper.Plo ./$(DEPDIR)/nghttp2_http.Plo \ - ./$(DEPDIR)/nghttp2_map.Plo ./$(DEPDIR)/nghttp2_mem.Plo \ - ./$(DEPDIR)/nghttp2_option.Plo \ - ./$(DEPDIR)/nghttp2_outbound_item.Plo \ - ./$(DEPDIR)/nghttp2_pq.Plo \ - ./$(DEPDIR)/nghttp2_priority_spec.Plo \ - ./$(DEPDIR)/nghttp2_queue.Plo ./$(DEPDIR)/nghttp2_ratelim.Plo \ - ./$(DEPDIR)/nghttp2_rcbuf.Plo ./$(DEPDIR)/nghttp2_session.Plo \ - ./$(DEPDIR)/nghttp2_stream.Plo ./$(DEPDIR)/nghttp2_submit.Plo \ - ./$(DEPDIR)/nghttp2_time.Plo ./$(DEPDIR)/nghttp2_version.Plo \ - ./$(DEPDIR)/sfparse.Plo -am__mv = mv -f -COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ - $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ - $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ - $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ - $(AM_CFLAGS) $(CFLAGS) -AM_V_CC = $(am__v_CC_@AM_V@) -am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@) -am__v_CC_0 = @echo " CC " $@; -am__v_CC_1 = -CCLD = $(CC) -LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ - $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ - $(AM_LDFLAGS) $(LDFLAGS) -o $@ -AM_V_CCLD = $(am__v_CCLD_@AM_V@) -am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@) -am__v_CCLD_0 = @echo " CCLD " $@; -am__v_CCLD_1 = -SOURCES = $(libnghttp2_la_SOURCES) -DIST_SOURCES = $(libnghttp2_la_SOURCES) -RECURSIVE_TARGETS = all-recursive check-recursive cscopelist-recursive \ - ctags-recursive dvi-recursive html-recursive info-recursive \ - install-data-recursive install-dvi-recursive \ - install-exec-recursive install-html-recursive \ - install-info-recursive install-pdf-recursive \ - install-ps-recursive install-recursive installcheck-recursive \ - installdirs-recursive pdf-recursive ps-recursive \ - tags-recursive uninstall-recursive -am__can_run_installinfo = \ - case $$AM_UPDATE_INFO_DIR in \ - n|no|NO) false;; \ - *) (install-info --version) >/dev/null 2>&1;; \ - esac -DATA = $(pkgconfig_DATA) -RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \ - distclean-recursive maintainer-clean-recursive -am__recursive_targets = \ - $(RECURSIVE_TARGETS) \ - $(RECURSIVE_CLEAN_TARGETS) \ - $(am__extra_recursive_targets) -AM_RECURSIVE_TARGETS = $(am__recursive_targets:-recursive=) TAGS CTAGS \ - distdir distdir-am -am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) -# Read a list of newline-separated strings from the standard input, -# and print each of them once, without duplicates. Input order is -# *not* preserved. -am__uniquify_input = $(AWK) '\ - BEGIN { nonempty = 0; } \ - { items[$$0] = 1; nonempty = 1; } \ - END { if (nonempty) { for (i in items) print i; }; } \ -' -# Make sure the list of sources is unique. This is necessary because, -# e.g., the same source file might be shared among _SOURCES variables -# for different programs/libraries. -am__define_uniq_tagged_files = \ - list='$(am__tagged_files)'; \ - unique=`for i in $$list; do \ - if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ - done | $(am__uniquify_input)` -DIST_SUBDIRS = $(SUBDIRS) -am__DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/libnghttp2.pc.in \ - $(top_srcdir)/depcomp -DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) -am__relativize = \ - dir0=`pwd`; \ - sed_first='s,^\([^/]*\)/.*$$,\1,'; \ - sed_rest='s,^[^/]*/*,,'; \ - sed_last='s,^.*/\([^/]*\)$$,\1,'; \ - sed_butlast='s,/*[^/]*$$,,'; \ - while test -n "$$dir1"; do \ - first=`echo "$$dir1" | sed -e "$$sed_first"`; \ - if test "$$first" != "."; then \ - if test "$$first" = ".."; then \ - dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \ - dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \ - else \ - first2=`echo "$$dir2" | sed -e "$$sed_first"`; \ - if test "$$first2" = "$$first"; then \ - dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \ - else \ - dir2="../$$dir2"; \ - fi; \ - dir0="$$dir0"/"$$first"; \ - fi; \ - fi; \ - dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \ - done; \ - reldir="$$dir2" -ACLOCAL = @ACLOCAL@ -AMTAR = @AMTAR@ -AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ -APPLDFLAGS = @APPLDFLAGS@ -AR = @AR@ -AUTOCONF = @AUTOCONF@ -AUTOHEADER = @AUTOHEADER@ -AUTOMAKE = @AUTOMAKE@ -AWK = @AWK@ -BPFCFLAGS = @BPFCFLAGS@ -CC = @CC@ -CCDEPMODE = @CCDEPMODE@ -CFLAGS = @CFLAGS@ -CPP = @CPP@ -CPPFLAGS = @CPPFLAGS@ -CSCOPE = @CSCOPE@ -CTAGS = @CTAGS@ -CXX = @CXX@ -CXX1XCXXFLAGS = @CXX1XCXXFLAGS@ -CXXCPP = @CXXCPP@ -CXXDEPMODE = @CXXDEPMODE@ -CXXFLAGS = @CXXFLAGS@ -CYGPATH_W = @CYGPATH_W@ -DEFS = @DEFS@ -DEPDIR = @DEPDIR@ -DLLTOOL = @DLLTOOL@ -DSYMUTIL = @DSYMUTIL@ -DUMPBIN = @DUMPBIN@ -ECHO_C = @ECHO_C@ -ECHO_N = @ECHO_N@ -ECHO_T = @ECHO_T@ -EGREP = @EGREP@ -ETAGS = @ETAGS@ -EXEEXT = @EXEEXT@ -EXTRABPFCFLAGS = @EXTRABPFCFLAGS@ -EXTRACFLAG = @EXTRACFLAG@ -EXTRA_DEFS = @EXTRA_DEFS@ -FGREP = @FGREP@ -FILECMD = @FILECMD@ -GREP = @GREP@ -HAVE_CXX20 = @HAVE_CXX20@ -INSTALL = @INSTALL@ -INSTALL_DATA = @INSTALL_DATA@ -INSTALL_PROGRAM = @INSTALL_PROGRAM@ -INSTALL_SCRIPT = @INSTALL_SCRIPT@ -INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ -JANSSON_CFLAGS = @JANSSON_CFLAGS@ -JANSSON_LIBS = @JANSSON_LIBS@ -JEMALLOC_CFLAGS = @JEMALLOC_CFLAGS@ -JEMALLOC_LIBS = @JEMALLOC_LIBS@ -LD = @LD@ -LDFLAGS = @LDFLAGS@ -LIBBPF_CFLAGS = @LIBBPF_CFLAGS@ -LIBBPF_LIBS = @LIBBPF_LIBS@ -LIBBROTLIDEC_CFLAGS = @LIBBROTLIDEC_CFLAGS@ -LIBBROTLIDEC_LIBS = @LIBBROTLIDEC_LIBS@ -LIBBROTLIENC_CFLAGS = @LIBBROTLIENC_CFLAGS@ -LIBBROTLIENC_LIBS = @LIBBROTLIENC_LIBS@ -LIBCARES_CFLAGS = @LIBCARES_CFLAGS@ -LIBCARES_LIBS = @LIBCARES_LIBS@ -LIBEVENT_OPENSSL_CFLAGS = @LIBEVENT_OPENSSL_CFLAGS@ -LIBEVENT_OPENSSL_LIBS = @LIBEVENT_OPENSSL_LIBS@ -LIBEV_CFLAGS = @LIBEV_CFLAGS@ -LIBEV_LIBS = @LIBEV_LIBS@ -LIBMRUBY_CFLAGS = @LIBMRUBY_CFLAGS@ -LIBMRUBY_LIBS = @LIBMRUBY_LIBS@ -LIBNGHTTP3_CFLAGS = @LIBNGHTTP3_CFLAGS@ -LIBNGHTTP3_LIBS = @LIBNGHTTP3_LIBS@ -LIBNGTCP2_CFLAGS = @LIBNGTCP2_CFLAGS@ -LIBNGTCP2_CRYPTO_BORINGSSL_CFLAGS = @LIBNGTCP2_CRYPTO_BORINGSSL_CFLAGS@ -LIBNGTCP2_CRYPTO_BORINGSSL_LIBS = @LIBNGTCP2_CRYPTO_BORINGSSL_LIBS@ -LIBNGTCP2_CRYPTO_QUICTLS_CFLAGS = @LIBNGTCP2_CRYPTO_QUICTLS_CFLAGS@ -LIBNGTCP2_CRYPTO_QUICTLS_LIBS = @LIBNGTCP2_CRYPTO_QUICTLS_LIBS@ -LIBNGTCP2_CRYPTO_WOLFSSL_CFLAGS = @LIBNGTCP2_CRYPTO_WOLFSSL_CFLAGS@ -LIBNGTCP2_CRYPTO_WOLFSSL_LIBS = @LIBNGTCP2_CRYPTO_WOLFSSL_LIBS@ -LIBNGTCP2_LIBS = @LIBNGTCP2_LIBS@ -LIBOBJS = @LIBOBJS@ -LIBS = @LIBS@ -LIBTOOL = @LIBTOOL@ -LIBTOOL_LDFLAGS = @LIBTOOL_LDFLAGS@ -LIBXML2_CFLAGS = @LIBXML2_CFLAGS@ -LIBXML2_LIBS = @LIBXML2_LIBS@ -LIPO = @LIPO@ -LN_S = @LN_S@ -LTLIBOBJS = @LTLIBOBJS@ -LT_AGE = @LT_AGE@ -LT_CURRENT = @LT_CURRENT@ -LT_REVISION = @LT_REVISION@ -LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@ -MAKEINFO = @MAKEINFO@ -MANIFEST_TOOL = @MANIFEST_TOOL@ -MKDIR_P = @MKDIR_P@ -NM = @NM@ -NMEDIT = @NMEDIT@ -OBJDUMP = @OBJDUMP@ -OBJEXT = @OBJEXT@ -OPENSSL_CFLAGS = @OPENSSL_CFLAGS@ -OPENSSL_LIBS = @OPENSSL_LIBS@ -OTOOL = @OTOOL@ -OTOOL64 = @OTOOL64@ -PACKAGE = @PACKAGE@ -PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ -PACKAGE_NAME = @PACKAGE_NAME@ -PACKAGE_STRING = @PACKAGE_STRING@ -PACKAGE_TARNAME = @PACKAGE_TARNAME@ -PACKAGE_URL = @PACKAGE_URL@ -PACKAGE_VERSION = @PACKAGE_VERSION@ -PACKAGE_VERSION_NUM = @PACKAGE_VERSION_NUM@ -PATH_SEPARATOR = @PATH_SEPARATOR@ -PKG_CONFIG = @PKG_CONFIG@ -PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ -PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ -PYTHON = @PYTHON@ -PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@ -PYTHON_PLATFORM = @PYTHON_PLATFORM@ -PYTHON_PREFIX = @PYTHON_PREFIX@ -PYTHON_VERSION = @PYTHON_VERSION@ -RANLIB = @RANLIB@ -SED = @SED@ -SET_MAKE = @SET_MAKE@ -SHELL = @SHELL@ -STRIP = @STRIP@ -SYSTEMD_CFLAGS = @SYSTEMD_CFLAGS@ -SYSTEMD_LIBS = @SYSTEMD_LIBS@ -TESTLDADD = @TESTLDADD@ -VERSION = @VERSION@ -WARNCFLAGS = @WARNCFLAGS@ -WARNCXXFLAGS = @WARNCXXFLAGS@ -WOLFSSL_CFLAGS = @WOLFSSL_CFLAGS@ -WOLFSSL_LIBS = @WOLFSSL_LIBS@ -ZLIB_CFLAGS = @ZLIB_CFLAGS@ -ZLIB_LIBS = @ZLIB_LIBS@ -abs_builddir = @abs_builddir@ -abs_srcdir = @abs_srcdir@ -abs_top_builddir = @abs_top_builddir@ -abs_top_srcdir = @abs_top_srcdir@ -ac_ct_AR = @ac_ct_AR@ -ac_ct_CC = @ac_ct_CC@ -ac_ct_CXX = @ac_ct_CXX@ -ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ -am__include = @am__include@ -am__leading_dot = @am__leading_dot@ -am__quote = @am__quote@ -am__tar = @am__tar@ -am__untar = @am__untar@ -bindir = @bindir@ -build = @build@ -build_alias = @build_alias@ -build_cpu = @build_cpu@ -build_os = @build_os@ -build_vendor = @build_vendor@ -builddir = @builddir@ -datadir = @datadir@ -datarootdir = @datarootdir@ -docdir = @docdir@ -dvidir = @dvidir@ -exec_prefix = @exec_prefix@ -host = @host@ -host_alias = @host_alias@ -host_cpu = @host_cpu@ -host_os = @host_os@ -host_vendor = @host_vendor@ -htmldir = @htmldir@ -includedir = @includedir@ -infodir = @infodir@ -install_sh = @install_sh@ -libdir = @libdir@ -libexecdir = @libexecdir@ -localedir = @localedir@ -localstatedir = @localstatedir@ -mandir = @mandir@ -mkdir_p = @mkdir_p@ -oldincludedir = @oldincludedir@ -pdfdir = @pdfdir@ -pkgpyexecdir = @pkgpyexecdir@ -pkgpythondir = @pkgpythondir@ -prefix = @prefix@ -program_transform_name = @program_transform_name@ -psdir = @psdir@ -pyexecdir = @pyexecdir@ -pythondir = @pythondir@ -runstatedir = @runstatedir@ -sbindir = @sbindir@ -sharedstatedir = @sharedstatedir@ -srcdir = @srcdir@ -sysconfdir = @sysconfdir@ -target = @target@ -target_alias = @target_alias@ -target_cpu = @target_cpu@ -target_os = @target_os@ -target_vendor = @target_vendor@ -top_build_prefix = @top_build_prefix@ -top_builddir = @top_builddir@ -top_srcdir = @top_srcdir@ - -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -SUBDIRS = includes -EXTRA_DIST = Makefile.msvc CMakeLists.txt version.rc.in -AM_CFLAGS = $(WARNCFLAGS) $(EXTRACFLAG) -AM_CPPFLAGS = -I$(srcdir)/includes -I$(builddir)/includes -DBUILDING_NGHTTP2 \ - @DEFS@ - -AM_LDFLAGS = @LIBTOOL_LDFLAGS@ -pkgconfigdir = $(libdir)/pkgconfig -pkgconfig_DATA = libnghttp2.pc -DISTCLEANFILES = $(pkgconfig_DATA) -lib_LTLIBRARIES = libnghttp2.la -OBJECTS = nghttp2_pq.c nghttp2_map.c nghttp2_queue.c \ - nghttp2_frame.c \ - nghttp2_buf.c \ - nghttp2_stream.c nghttp2_outbound_item.c \ - nghttp2_session.c nghttp2_submit.c \ - nghttp2_helper.c \ - nghttp2_alpn.c \ - nghttp2_hd.c nghttp2_hd_huffman.c nghttp2_hd_huffman_data.c \ - nghttp2_version.c \ - nghttp2_priority_spec.c \ - nghttp2_option.c \ - nghttp2_callbacks.c \ - nghttp2_mem.c \ - nghttp2_http.c \ - nghttp2_rcbuf.c \ - nghttp2_extpri.c \ - nghttp2_ratelim.c \ - nghttp2_time.c \ - nghttp2_debug.c \ - sfparse.c - -HFILES = nghttp2_pq.h nghttp2_int.h nghttp2_map.h nghttp2_queue.h \ - nghttp2_frame.h \ - nghttp2_buf.h \ - nghttp2_session.h nghttp2_helper.h nghttp2_stream.h nghttp2_int.h \ - nghttp2_alpn.h \ - nghttp2_submit.h nghttp2_outbound_item.h \ - nghttp2_net.h \ - nghttp2_hd.h nghttp2_hd_huffman.h \ - nghttp2_priority_spec.h \ - nghttp2_option.h \ - nghttp2_callbacks.h \ - nghttp2_mem.h \ - nghttp2_http.h \ - nghttp2_rcbuf.h \ - nghttp2_extpri.h \ - nghttp2_ratelim.h \ - nghttp2_time.h \ - nghttp2_debug.h \ - sfparse.h - -libnghttp2_la_SOURCES = $(HFILES) $(OBJECTS) -libnghttp2_la_LDFLAGS = $(AM_LDFLAGS) -no-undefined \ - -version-info $(LT_CURRENT):$(LT_REVISION):$(LT_AGE) - -all: all-recursive - -.SUFFIXES: -.SUFFIXES: .c .lo .o .obj -$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) - @for dep in $?; do \ - case '$(am__configure_deps)' in \ - *$$dep*) \ - ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ - && { if test -f $@; then exit 0; else break; fi; }; \ - exit 1;; \ - esac; \ - done; \ - echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu lib/Makefile'; \ - $(am__cd) $(top_srcdir) && \ - $(AUTOMAKE) --gnu lib/Makefile -Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status - @case '$?' in \ - *config.status*) \ - cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ - *) \ - echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \ - cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \ - esac; - -$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) - cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh - -$(top_srcdir)/configure: $(am__configure_deps) - cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh -$(ACLOCAL_M4): $(am__aclocal_m4_deps) - cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh -$(am__aclocal_m4_deps): -libnghttp2.pc: $(top_builddir)/config.status $(srcdir)/libnghttp2.pc.in - cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ - -install-libLTLIBRARIES: $(lib_LTLIBRARIES) - @$(NORMAL_INSTALL) - @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ - list2=; for p in $$list; do \ - if test -f $$p; then \ - list2="$$list2 $$p"; \ - else :; fi; \ - done; \ - test -z "$$list2" || { \ - echo " $(MKDIR_P) '$(DESTDIR)$(libdir)'"; \ - $(MKDIR_P) "$(DESTDIR)$(libdir)" || exit 1; \ - echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(libdir)'"; \ - $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(libdir)"; \ - } - -uninstall-libLTLIBRARIES: - @$(NORMAL_UNINSTALL) - @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ - for p in $$list; do \ - $(am__strip_dir) \ - echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(libdir)/$$f'"; \ - $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(libdir)/$$f"; \ - done - -clean-libLTLIBRARIES: - -test -z "$(lib_LTLIBRARIES)" || rm -f $(lib_LTLIBRARIES) - @list='$(lib_LTLIBRARIES)'; \ - locs=`for p in $$list; do echo $$p; done | \ - sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \ - sort -u`; \ - test -z "$$locs" || { \ - echo rm -f $${locs}; \ - rm -f $${locs}; \ - } - -libnghttp2.la: $(libnghttp2_la_OBJECTS) $(libnghttp2_la_DEPENDENCIES) $(EXTRA_libnghttp2_la_DEPENDENCIES) - $(AM_V_CCLD)$(libnghttp2_la_LINK) -rpath $(libdir) $(libnghttp2_la_OBJECTS) $(libnghttp2_la_LIBADD) $(LIBS) - -mostlyclean-compile: - -rm -f *.$(OBJEXT) - -distclean-compile: - -rm -f *.tab.c - -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nghttp2_alpn.Plo@am__quote@ # am--include-marker -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nghttp2_buf.Plo@am__quote@ # am--include-marker -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nghttp2_callbacks.Plo@am__quote@ # am--include-marker -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nghttp2_debug.Plo@am__quote@ # am--include-marker -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nghttp2_extpri.Plo@am__quote@ # am--include-marker -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nghttp2_frame.Plo@am__quote@ # am--include-marker -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nghttp2_hd.Plo@am__quote@ # am--include-marker -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nghttp2_hd_huffman.Plo@am__quote@ # am--include-marker -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nghttp2_hd_huffman_data.Plo@am__quote@ # am--include-marker -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nghttp2_helper.Plo@am__quote@ # am--include-marker -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nghttp2_http.Plo@am__quote@ # am--include-marker -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nghttp2_map.Plo@am__quote@ # am--include-marker -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nghttp2_mem.Plo@am__quote@ # am--include-marker -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nghttp2_option.Plo@am__quote@ # am--include-marker -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nghttp2_outbound_item.Plo@am__quote@ # am--include-marker -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nghttp2_pq.Plo@am__quote@ # am--include-marker -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nghttp2_priority_spec.Plo@am__quote@ # am--include-marker -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nghttp2_queue.Plo@am__quote@ # am--include-marker -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nghttp2_ratelim.Plo@am__quote@ # am--include-marker -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nghttp2_rcbuf.Plo@am__quote@ # am--include-marker -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nghttp2_session.Plo@am__quote@ # am--include-marker -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nghttp2_stream.Plo@am__quote@ # am--include-marker -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nghttp2_submit.Plo@am__quote@ # am--include-marker -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nghttp2_time.Plo@am__quote@ # am--include-marker -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nghttp2_version.Plo@am__quote@ # am--include-marker -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sfparse.Plo@am__quote@ # am--include-marker - -$(am__depfiles_remade): - @$(MKDIR_P) $(@D) - @echo '# dummy' >$@-t && $(am__mv) $@-t $@ - -am--depfiles: $(am__depfiles_remade) - -.c.o: -@am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\ -@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\ -@am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $< - -.c.obj: -@am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.obj$$||'`;\ -@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ `$(CYGPATH_W) '$<'` &&\ -@am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'` - -.c.lo: -@am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.lo$$||'`;\ -@am__fastdepCC_TRUE@ $(LTCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\ -@am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $< - -mostlyclean-libtool: - -rm -f *.lo - -clean-libtool: - -rm -rf .libs _libs -install-pkgconfigDATA: $(pkgconfig_DATA) - @$(NORMAL_INSTALL) - @list='$(pkgconfig_DATA)'; test -n "$(pkgconfigdir)" || list=; \ - if test -n "$$list"; then \ - echo " $(MKDIR_P) '$(DESTDIR)$(pkgconfigdir)'"; \ - $(MKDIR_P) "$(DESTDIR)$(pkgconfigdir)" || exit 1; \ - fi; \ - for p in $$list; do \ - if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ - echo "$$d$$p"; \ - done | $(am__base_list) | \ - while read files; do \ - echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(pkgconfigdir)'"; \ - $(INSTALL_DATA) $$files "$(DESTDIR)$(pkgconfigdir)" || exit $$?; \ - done - -uninstall-pkgconfigDATA: - @$(NORMAL_UNINSTALL) - @list='$(pkgconfig_DATA)'; test -n "$(pkgconfigdir)" || list=; \ - files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ - dir='$(DESTDIR)$(pkgconfigdir)'; $(am__uninstall_files_from_dir) - -# This directory's subdirectories are mostly independent; you can cd -# into them and run 'make' without going through this Makefile. -# To change the values of 'make' variables: instead of editing Makefiles, -# (1) if the variable is set in 'config.status', edit 'config.status' -# (which will cause the Makefiles to be regenerated when you run 'make'); -# (2) otherwise, pass the desired values on the 'make' command line. -$(am__recursive_targets): - @fail=; \ - if $(am__make_keepgoing); then \ - failcom='fail=yes'; \ - else \ - failcom='exit 1'; \ - fi; \ - dot_seen=no; \ - target=`echo $@ | sed s/-recursive//`; \ - case "$@" in \ - distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \ - *) list='$(SUBDIRS)' ;; \ - esac; \ - for subdir in $$list; do \ - echo "Making $$target in $$subdir"; \ - if test "$$subdir" = "."; then \ - dot_seen=yes; \ - local_target="$$target-am"; \ - else \ - local_target="$$target"; \ - fi; \ - ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ - || eval $$failcom; \ - done; \ - if test "$$dot_seen" = "no"; then \ - $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ - fi; test -z "$$fail" - -ID: $(am__tagged_files) - $(am__define_uniq_tagged_files); mkid -fID $$unique -tags: tags-recursive -TAGS: tags - -tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) - set x; \ - here=`pwd`; \ - if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \ - include_option=--etags-include; \ - empty_fix=.; \ - else \ - include_option=--include; \ - empty_fix=; \ - fi; \ - list='$(SUBDIRS)'; for subdir in $$list; do \ - if test "$$subdir" = .; then :; else \ - test ! -f $$subdir/TAGS || \ - set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \ - fi; \ - done; \ - $(am__define_uniq_tagged_files); \ - shift; \ - if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ - test -n "$$unique" || unique=$$empty_fix; \ - if test $$# -gt 0; then \ - $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ - "$$@" $$unique; \ - else \ - $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ - $$unique; \ - fi; \ - fi -ctags: ctags-recursive - -CTAGS: ctags -ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) - $(am__define_uniq_tagged_files); \ - test -z "$(CTAGS_ARGS)$$unique" \ - || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ - $$unique - -GTAGS: - here=`$(am__cd) $(top_builddir) && pwd` \ - && $(am__cd) $(top_srcdir) \ - && gtags -i $(GTAGS_ARGS) "$$here" -cscopelist: cscopelist-recursive - -cscopelist-am: $(am__tagged_files) - list='$(am__tagged_files)'; \ - case "$(srcdir)" in \ - [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ - *) sdir=$(subdir)/$(srcdir) ;; \ - esac; \ - for i in $$list; do \ - if test -f "$$i"; then \ - echo "$(subdir)/$$i"; \ - else \ - echo "$$sdir/$$i"; \ - fi; \ - done >> $(top_builddir)/cscope.files - -distclean-tags: - -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags -distdir: $(BUILT_SOURCES) - $(MAKE) $(AM_MAKEFLAGS) distdir-am - -distdir-am: $(DISTFILES) - @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ - topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ - list='$(DISTFILES)'; \ - dist_files=`for file in $$list; do echo $$file; done | \ - sed -e "s|^$$srcdirstrip/||;t" \ - -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ - case $$dist_files in \ - */*) $(MKDIR_P) `echo "$$dist_files" | \ - sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ - sort -u` ;; \ - esac; \ - for file in $$dist_files; do \ - if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ - if test -d $$d/$$file; then \ - dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ - if test -d "$(distdir)/$$file"; then \ - find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ - fi; \ - if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ - cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ - find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ - fi; \ - cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ - else \ - test -f "$(distdir)/$$file" \ - || cp -p $$d/$$file "$(distdir)/$$file" \ - || exit 1; \ - fi; \ - done - @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ - if test "$$subdir" = .; then :; else \ - $(am__make_dryrun) \ - || test -d "$(distdir)/$$subdir" \ - || $(MKDIR_P) "$(distdir)/$$subdir" \ - || exit 1; \ - dir1=$$subdir; dir2="$(distdir)/$$subdir"; \ - $(am__relativize); \ - new_distdir=$$reldir; \ - dir1=$$subdir; dir2="$(top_distdir)"; \ - $(am__relativize); \ - new_top_distdir=$$reldir; \ - echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \ - echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \ - ($(am__cd) $$subdir && \ - $(MAKE) $(AM_MAKEFLAGS) \ - top_distdir="$$new_top_distdir" \ - distdir="$$new_distdir" \ - am__remove_distdir=: \ - am__skip_length_check=: \ - am__skip_mode_fix=: \ - distdir) \ - || exit 1; \ - fi; \ - done -check-am: all-am -check: check-recursive -all-am: Makefile $(LTLIBRARIES) $(DATA) -installdirs: installdirs-recursive -installdirs-am: - for dir in "$(DESTDIR)$(libdir)" "$(DESTDIR)$(pkgconfigdir)"; do \ - test -z "$$dir" || $(MKDIR_P) "$$dir"; \ - done -install: install-recursive -install-exec: install-exec-recursive -install-data: install-data-recursive -uninstall: uninstall-recursive - -install-am: all-am - @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am - -installcheck: installcheck-recursive -install-strip: - if test -z '$(STRIP)'; then \ - $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ - install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ - install; \ - else \ - $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ - install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ - "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ - fi -mostlyclean-generic: - -clean-generic: - -distclean-generic: - -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) - -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) - -test -z "$(DISTCLEANFILES)" || rm -f $(DISTCLEANFILES) - -maintainer-clean-generic: - @echo "This command is intended for maintainers to use" - @echo "it deletes files that may require special tools to rebuild." -clean: clean-recursive - -clean-am: clean-generic clean-libLTLIBRARIES clean-libtool \ - mostlyclean-am - -distclean: distclean-recursive - -rm -f ./$(DEPDIR)/nghttp2_alpn.Plo - -rm -f ./$(DEPDIR)/nghttp2_buf.Plo - -rm -f ./$(DEPDIR)/nghttp2_callbacks.Plo - -rm -f ./$(DEPDIR)/nghttp2_debug.Plo - -rm -f ./$(DEPDIR)/nghttp2_extpri.Plo - -rm -f ./$(DEPDIR)/nghttp2_frame.Plo - -rm -f ./$(DEPDIR)/nghttp2_hd.Plo - -rm -f ./$(DEPDIR)/nghttp2_hd_huffman.Plo - -rm -f ./$(DEPDIR)/nghttp2_hd_huffman_data.Plo - -rm -f ./$(DEPDIR)/nghttp2_helper.Plo - -rm -f ./$(DEPDIR)/nghttp2_http.Plo - -rm -f ./$(DEPDIR)/nghttp2_map.Plo - -rm -f ./$(DEPDIR)/nghttp2_mem.Plo - -rm -f ./$(DEPDIR)/nghttp2_option.Plo - -rm -f ./$(DEPDIR)/nghttp2_outbound_item.Plo - -rm -f ./$(DEPDIR)/nghttp2_pq.Plo - -rm -f ./$(DEPDIR)/nghttp2_priority_spec.Plo - -rm -f ./$(DEPDIR)/nghttp2_queue.Plo - -rm -f ./$(DEPDIR)/nghttp2_ratelim.Plo - -rm -f ./$(DEPDIR)/nghttp2_rcbuf.Plo - -rm -f ./$(DEPDIR)/nghttp2_session.Plo - -rm -f ./$(DEPDIR)/nghttp2_stream.Plo - -rm -f ./$(DEPDIR)/nghttp2_submit.Plo - -rm -f ./$(DEPDIR)/nghttp2_time.Plo - -rm -f ./$(DEPDIR)/nghttp2_version.Plo - -rm -f ./$(DEPDIR)/sfparse.Plo - -rm -f Makefile -distclean-am: clean-am distclean-compile distclean-generic \ - distclean-tags - -dvi: dvi-recursive - -dvi-am: - -html: html-recursive - -html-am: - -info: info-recursive - -info-am: - -install-data-am: install-pkgconfigDATA - -install-dvi: install-dvi-recursive - -install-dvi-am: - -install-exec-am: install-libLTLIBRARIES - -install-html: install-html-recursive - -install-html-am: - -install-info: install-info-recursive - -install-info-am: - -install-man: - -install-pdf: install-pdf-recursive - -install-pdf-am: - -install-ps: install-ps-recursive - -install-ps-am: - -installcheck-am: - -maintainer-clean: maintainer-clean-recursive - -rm -f ./$(DEPDIR)/nghttp2_alpn.Plo - -rm -f ./$(DEPDIR)/nghttp2_buf.Plo - -rm -f ./$(DEPDIR)/nghttp2_callbacks.Plo - -rm -f ./$(DEPDIR)/nghttp2_debug.Plo - -rm -f ./$(DEPDIR)/nghttp2_extpri.Plo - -rm -f ./$(DEPDIR)/nghttp2_frame.Plo - -rm -f ./$(DEPDIR)/nghttp2_hd.Plo - -rm -f ./$(DEPDIR)/nghttp2_hd_huffman.Plo - -rm -f ./$(DEPDIR)/nghttp2_hd_huffman_data.Plo - -rm -f ./$(DEPDIR)/nghttp2_helper.Plo - -rm -f ./$(DEPDIR)/nghttp2_http.Plo - -rm -f ./$(DEPDIR)/nghttp2_map.Plo - -rm -f ./$(DEPDIR)/nghttp2_mem.Plo - -rm -f ./$(DEPDIR)/nghttp2_option.Plo - -rm -f ./$(DEPDIR)/nghttp2_outbound_item.Plo - -rm -f ./$(DEPDIR)/nghttp2_pq.Plo - -rm -f ./$(DEPDIR)/nghttp2_priority_spec.Plo - -rm -f ./$(DEPDIR)/nghttp2_queue.Plo - -rm -f ./$(DEPDIR)/nghttp2_ratelim.Plo - -rm -f ./$(DEPDIR)/nghttp2_rcbuf.Plo - -rm -f ./$(DEPDIR)/nghttp2_session.Plo - -rm -f ./$(DEPDIR)/nghttp2_stream.Plo - -rm -f ./$(DEPDIR)/nghttp2_submit.Plo - -rm -f ./$(DEPDIR)/nghttp2_time.Plo - -rm -f ./$(DEPDIR)/nghttp2_version.Plo - -rm -f ./$(DEPDIR)/sfparse.Plo - -rm -f Makefile -maintainer-clean-am: distclean-am maintainer-clean-generic - -mostlyclean: mostlyclean-recursive - -mostlyclean-am: mostlyclean-compile mostlyclean-generic \ - mostlyclean-libtool - -pdf: pdf-recursive - -pdf-am: - -ps: ps-recursive - -ps-am: - -uninstall-am: uninstall-libLTLIBRARIES uninstall-pkgconfigDATA - -.MAKE: $(am__recursive_targets) install-am install-strip - -.PHONY: $(am__recursive_targets) CTAGS GTAGS TAGS all all-am \ - am--depfiles check check-am clean clean-generic \ - clean-libLTLIBRARIES clean-libtool cscopelist-am ctags \ - ctags-am distclean distclean-compile distclean-generic \ - distclean-libtool distclean-tags distdir dvi dvi-am html \ - html-am info info-am install install-am install-data \ - install-data-am install-dvi install-dvi-am install-exec \ - install-exec-am install-html install-html-am install-info \ - install-info-am install-libLTLIBRARIES install-man install-pdf \ - install-pdf-am install-pkgconfigDATA install-ps install-ps-am \ - install-strip installcheck installcheck-am installdirs \ - installdirs-am maintainer-clean maintainer-clean-generic \ - mostlyclean mostlyclean-compile mostlyclean-generic \ - mostlyclean-libtool pdf pdf-am ps ps-am tags tags-am uninstall \ - uninstall-am uninstall-libLTLIBRARIES uninstall-pkgconfigDATA - -.PRECIOUS: Makefile - - -# Tell versions [3.59,3.63) of GNU make to not export all variables. -# Otherwise a system limit (for SysV at least) may be exceeded. -.NOEXPORT: diff --git a/3rdparty/exported/nghttp2/Makefile.msvc b/3rdparty/exported/nghttp2/Makefile.msvc deleted file mode 100644 index 752389e0fc48..000000000000 --- a/3rdparty/exported/nghttp2/Makefile.msvc +++ /dev/null @@ -1,254 +0,0 @@ -# -# GNU Makefile for nghttp2 / MSVC. -# -# By G. Vanem 2013 -# Updated 3/2015 by Remo Eichenberger @remoe -# The MIT License apply. -# - -THIS_MAKEFILE := $(lastword $(MAKEFILE_LIST)) - -_VERSION := $(shell grep AC_INIT ../configure.ac | cut -d'[' -f3 | sed -e 's/-DEV//g' -e 's/], //g') -_VERSION := $(subst ., ,$(_VERSION)) -VER_MAJOR := $(word 1,$(_VERSION)) -VER_MINOR := $(word 2,$(_VERSION)) -VER_MICRO := $(word 3,$(_VERSION)) -VERSION := $(VER_MAJOR).$(VER_MINOR).$(VER_MICRO) -VERSION_NUM := (($(VER_MAJOR) << 16) + ($(VER_MINOR) << 8) + $(VER_MICRO)) - -GENERATED := 'Generated by $(realpath Makefile.MSVC)' - -OBJ_DIR := MSVC_obj -#SUFFIX :=-vc90-mt-x86 - -# -# Where to copy nghttp2.dll + lib + headers to. -# Note: 'make install' is not in default targets. Do it explicitly. -# -TARGET_DIR ?= ../_VC_ROOT -VC_ROOT := $(abspath $(TARGET_DIR)) -INSTALL_BIN := $(VC_ROOT)/bin -INSTALL_LIB := $(VC_ROOT)/lib -INSTALL_HDR := $(VC_ROOT)/include -DLL_R := $(OBJ_DIR)/nghttp2$(SUFFIX).dll -DLL_D := $(OBJ_DIR)/nghttp2d$(SUFFIX).dll -LIB_R := $(OBJ_DIR)/nghttp2-static.lib -LIB_D := $(OBJ_DIR)/nghttp2d-static.lib -IMP_R := $(OBJ_DIR)/nghttp2.lib -IMP_D := $(OBJ_DIR)/nghttp2d.lib - -# -# Build for DEBUG-model and RELEASE at the same time. -# -TARGETS := $(LIB_R) $(DLL_R) $(IMP_R) \ - $(LIB_D) $(DLL_D) $(IMP_D) - -EXT_LIBS = - -NGHTTP2_PDB_R := $(OBJ_DIR)/nghttp2.pdb -NGHTTP2_PDB_D := $(OBJ_DIR)/nghttp2d.pdb - -CC = cl -LD := link -AR := lib -#CC := icl -#LD := xilink -#AR := xilib -RC := rc -CFLAGS := -I./includes -Dssize_t=long - -CFLAGS_R := -nologo -MD -W3 -Z7 -DBUILDING_NGHTTP2 -CFLAGS_D := -nologo -MDd -W3 -Z7 -DBUILDING_NGHTTP2 \ - -Ot -D_DEBUG -GF -RTCs -RTCu # -RTCc -GS - -LDFLAGS := -nologo -MAP -debug -incremental:no -opt:ref,icf -MANIFEST # -verbose - - -NGHTTP2_SRC := nghttp2_pq.c \ - nghttp2_map.c \ - nghttp2_queue.c \ - nghttp2_frame.c \ - nghttp2_buf.c \ - nghttp2_stream.c \ - nghttp2_outbound_item.c \ - nghttp2_session.c \ - nghttp2_submit.c \ - nghttp2_helper.c \ - nghttp2_alpn.c \ - nghttp2_hd.c \ - nghttp2_hd_huffman.c \ - nghttp2_hd_huffman_data.c \ - nghttp2_version.c \ - nghttp2_priority_spec.c \ - nghttp2_option.c \ - nghttp2_callbacks.c \ - nghttp2_mem.c \ - nghttp2_http.c \ - nghttp2_rcbuf.c - -NGHTTP2_OBJ_R := $(addprefix $(OBJ_DIR)/r_, $(notdir $(NGHTTP2_SRC:.c=.obj))) -NGHTTP2_OBJ_D := $(addprefix $(OBJ_DIR)/d_, $(notdir $(NGHTTP2_SRC:.c=.obj))) - -.PHONY: all intro test_ver install copy_headers_and_libs \ - install_nghttp2_pyd_0 install_nghttp2_pyd_1 \ - build_nghttp2_pyd_0 build_nghttp2_pyd_1 \ - clean_nghttp2_pyd_0 clean_nghttp2_pyd_1 - - -all: intro includes/nghttp2/nghttp2ver.h $(OBJ_DIR) $(TARGETS) - @echo 'Welcome to NgHTTP2 (release + debug).' - @echo 'Do a "make -f Makefile.MSVC install" at own risk!' - -intro: - @echo 'Building NgHTTP (MSVC) ver. "$(VERSION)".' - -test_ver: - @echo '$$(VERSION): "$(VERSION)".' - @echo '$$(_VERSION): "$(_VERSION)".' - @echo '$$(VER_MAJOR): "$(VER_MAJOR)".' - @echo '$$(VER_MINOR): "$(VER_MINOR)".' - @echo '$$(VER_MICRO): "$(VER_MICRO)".' - -$(OBJ_DIR): - - mkdir $(OBJ_DIR) - -install: includes/nghttp2/nghttp2.h includes/nghttp2/nghttp2ver.h \ - $(TARGETS) \ - copy_headers_and_libs - -# -# This MUST be done before using the 'install_nghttp2_pyd_1' rule. -# -copy_headers_and_libs: - - mkdir -p $(INSTALL_HDR)/nghttp2 $(INSTALL_BIN) $(INSTALL_LIB) - cp --update $(addprefix includes/nghttp2/, nghttp2.h nghttp2ver.h) $(INSTALL_HDR)/nghttp2 - cp --update $(DLL_R) $(DLL_D) $(NGHTTP2_PDB_R) $(NGHTTP2_PDB_D) $(INSTALL_BIN) - cp --update $(IMP_R) $(IMP_D) $(LIB_R) $(LIB_D) $(INSTALL_LIB) - @echo - -$(LIB_R): $(NGHTTP2_OBJ_R) - $(AR) -nologo -out:$@ $^ - @echo - -$(LIB_D): $(NGHTTP2_OBJ_D) - $(AR) -nologo -out:$@ $^ - @echo - - -$(IMP_R): $(DLL_R) - -$(DLL_R): $(NGHTTP2_OBJ_R) $(OBJ_DIR)/r_nghttp2.res - $(LD) $(LDFLAGS) -dll -out:$@ -implib:$(IMP_R) $(NGHTTP2_OBJ_R) -PDB:$(NGHTTP2_PDB_R) $(OBJ_DIR)/r_nghttp2.res $(EXT_LIBS) - mt -nologo -manifest $@.manifest -outputresource:$@\;2 - @echo - -$(IMP_D): $(DLL_D) - -$(DLL_D): $(NGHTTP2_OBJ_D) $(OBJ_DIR)/d_nghttp2.res - $(LD) $(LDFLAGS) -dll -out:$@ -implib:$(IMP_D) $(NGHTTP2_OBJ_D) -PDB:$(NGHTTP2_PDB_D) $(OBJ_DIR)/d_nghttp2.res $(EXT_LIBS) - mt -nologo -manifest $@.manifest -outputresource:$@\;2 - @echo - - -WIN_OBJDIR:=$(shell cygpath -w $(abspath $(OBJ_DIR))) -WIN_OBJDIR:=$(subst \,/,$(WIN_OBJDIR)) - -$(OBJ_DIR)/r_%.obj: %.c $(THIS_MAKEFILE) - $(CC) $(CFLAGS_R) $(CFLAGS) -Fo$@ -c $< - @echo - -$(OBJ_DIR)/d_%.obj: %.c $(THIS_MAKEFILE) - $(CC) $(CFLAGS_D) $(CFLAGS) -Fo$@ -c $< - @echo - -$(OBJ_DIR)/r_nghttp2.res: $(OBJ_DIR)/nghttp2.rc $(THIS_MAKEFILE) - $(RC) -D_RELEASE -Fo $@ $< - @echo - -$(OBJ_DIR)/d_nghttp2.res: $(OBJ_DIR)/nghttp2.rc $(THIS_MAKEFILE) - $(RC) -D_DEBUG -Fo $@ $< - @echo - -includes/nghttp2/nghttp2ver.h: includes/nghttp2/nghttp2ver.h.in $(THIS_MAKEFILE) - sed < includes/nghttp2/nghttp2ver.h.in \ - -e 's/@PACKAGE_VERSION@/$(VERSION)/g' \ - -e 's/@PACKAGE_VERSION_NUM@/$(VERSION_NUM)/g' > $@ - touch --reference=includes/nghttp2/nghttp2ver.h.in $@ - - -define RES_FILE - #include - - VS_VERSION_INFO VERSIONINFO - FILEVERSION $(VER_MAJOR), $(VER_MINOR), $(VER_MICRO), 0 - PRODUCTVERSION $(VER_MAJOR), $(VER_MINOR), $(VER_MICRO), 0 - FILEFLAGSMASK 0x3fL - FILEOS 0x40004L - FILETYPE 0x2L - FILESUBTYPE 0x0L - #ifdef _DEBUG - #define VER_STR "$(VERSION).0 (MSVC debug)" - #define DBG "d" - FILEFLAGS 0x1L - #else - #define VER_STR "$(VERSION).0 (MSVC release)" - #define DBG "" - FILEFLAGS 0x0L - #endif - BEGIN - BLOCK "StringFileInfo" - BEGIN - BLOCK "040904b0" - BEGIN - VALUE "CompanyName", "http://tatsuhiro-t.github.io/nghttp2/" - VALUE "FileDescription", "nghttp2; HTTP/2 C library" - VALUE "FileVersion", VER_STR - VALUE "InternalName", "nghttp2" DBG - VALUE "LegalCopyright", "The MIT License" - VALUE "LegalTrademarks", "" - VALUE "OriginalFilename", "nghttp2" DBG ".dll" - VALUE "ProductName", "NGHTTP2." - VALUE "ProductVersion", VER_STR - END - END - BLOCK "VarFileInfo" - BEGIN - VALUE "Translation", 0x409, 1200 - END - END -endef - -export RES_FILE - -$(OBJ_DIR)/nghttp2.rc: Makefile.MSVC - @echo 'Generating $@...' - @echo ' /* $(GENERATED). DO NOT EDIT.' > $@ - @echo ' */' >> $@ - @echo "$$RES_FILE" >> $@ - -clean: - rm -f $(OBJ_DIR)/* includes/nghttp2/nghttp2ver.h - @echo - -vclean realclean: clean - - rm -rf $(OBJ_DIR) - - rm -f .depend.MSVC - -# -# Use gcc to generated the dependencies. No MSVC specific args please! -# -REPLACE_R = 's/\(.*\)\.o: /\n$$(OBJ_DIR)\/r_\1.obj: /' -REPLACE_D = 's/\(.*\)\.o: /\n$$(OBJ_DIR)\/d_\1.obj: /' - -depend: includes/nghttp2/nghttp2ver.h - @echo '# $(GENERATED). DO NOT EDIT.' > .depend.MSVC - gcc -MM $(CFLAGS) $(NGHTTP2_SRC) >> .depend.tmp - @echo '#' >> .depend.MSVC - @echo '# Release lib objects:' >> .depend.MSVC - sed -e $(REPLACE_R) .depend.tmp >> .depend.MSVC - @echo '#' >> .depend.MSVC - @echo '# Debug lib objects:' >> .depend.MSVC - sed -e $(REPLACE_D) .depend.tmp >> .depend.MSVC - rm -f .depend.tmp - --include .depend.MSVC diff --git a/3rdparty/exported/nghttp2/includes/CMakeLists.txt b/3rdparty/exported/nghttp2/includes/CMakeLists.txt deleted file mode 100644 index 17de2ec691ef..000000000000 --- a/3rdparty/exported/nghttp2/includes/CMakeLists.txt +++ /dev/null @@ -1,4 +0,0 @@ -install(FILES - nghttp2/nghttp2.h - "${CMAKE_CURRENT_BINARY_DIR}/nghttp2/nghttp2ver.h" - DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/nghttp2") diff --git a/3rdparty/exported/nghttp2/includes/Makefile.am b/3rdparty/exported/nghttp2/includes/Makefile.am deleted file mode 100644 index c07cb4d2c025..000000000000 --- a/3rdparty/exported/nghttp2/includes/Makefile.am +++ /dev/null @@ -1,26 +0,0 @@ -# nghttp2 - HTTP/2 C Library - -# Copyright (c) 2012 Tatsuhiro Tsujikawa - -# Permission is hereby granted, free of charge, to any person obtaining -# a copy of this software and associated documentation files (the -# "Software"), to deal in the Software without restriction, including -# without limitation the rights to use, copy, modify, merge, publish, -# distribute, sublicense, and/or sell copies of the Software, and to -# permit persons to whom the Software is furnished to do so, subject to -# the following conditions: - -# The above copyright notice and this permission notice shall be -# included in all copies or substantial portions of the Software. - -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - -EXTRA_DIST = CMakeLists.txt - -nobase_include_HEADERS = nghttp2/nghttp2.h nghttp2/nghttp2ver.h diff --git a/3rdparty/exported/nghttp2/includes/Makefile.in b/3rdparty/exported/nghttp2/includes/Makefile.in deleted file mode 100644 index 778dcb874c92..000000000000 --- a/3rdparty/exported/nghttp2/includes/Makefile.in +++ /dev/null @@ -1,664 +0,0 @@ -# Makefile.in generated by automake 1.16.5 from Makefile.am. -# @configure_input@ - -# Copyright (C) 1994-2021 Free Software Foundation, Inc. - -# This Makefile.in is free software; the Free Software Foundation -# gives unlimited permission to copy and/or distribute it, -# with or without modifications, as long as this notice is preserved. - -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY, to the extent permitted by law; without -# even the implied warranty of MERCHANTABILITY or FITNESS FOR A -# PARTICULAR PURPOSE. - -@SET_MAKE@ - -# nghttp2 - HTTP/2 C Library - -# Copyright (c) 2012 Tatsuhiro Tsujikawa - -# Permission is hereby granted, free of charge, to any person obtaining -# a copy of this software and associated documentation files (the -# "Software"), to deal in the Software without restriction, including -# without limitation the rights to use, copy, modify, merge, publish, -# distribute, sublicense, and/or sell copies of the Software, and to -# permit persons to whom the Software is furnished to do so, subject to -# the following conditions: - -# The above copyright notice and this permission notice shall be -# included in all copies or substantial portions of the Software. - -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - -VPATH = @srcdir@ -am__is_gnu_make = { \ - if test -z '$(MAKELEVEL)'; then \ - false; \ - elif test -n '$(MAKE_HOST)'; then \ - true; \ - elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ - true; \ - else \ - false; \ - fi; \ -} -am__make_running_with_option = \ - case $${target_option-} in \ - ?) ;; \ - *) echo "am__make_running_with_option: internal error: invalid" \ - "target option '$${target_option-}' specified" >&2; \ - exit 1;; \ - esac; \ - has_opt=no; \ - sane_makeflags=$$MAKEFLAGS; \ - if $(am__is_gnu_make); then \ - sane_makeflags=$$MFLAGS; \ - else \ - case $$MAKEFLAGS in \ - *\\[\ \ ]*) \ - bs=\\; \ - sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ - | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ - esac; \ - fi; \ - skip_next=no; \ - strip_trailopt () \ - { \ - flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ - }; \ - for flg in $$sane_makeflags; do \ - test $$skip_next = yes && { skip_next=no; continue; }; \ - case $$flg in \ - *=*|--*) continue;; \ - -*I) strip_trailopt 'I'; skip_next=yes;; \ - -*I?*) strip_trailopt 'I';; \ - -*O) strip_trailopt 'O'; skip_next=yes;; \ - -*O?*) strip_trailopt 'O';; \ - -*l) strip_trailopt 'l'; skip_next=yes;; \ - -*l?*) strip_trailopt 'l';; \ - -[dEDm]) skip_next=yes;; \ - -[JT]) skip_next=yes;; \ - esac; \ - case $$flg in \ - *$$target_option*) has_opt=yes; break;; \ - esac; \ - done; \ - test $$has_opt = yes -am__make_dryrun = (target_option=n; $(am__make_running_with_option)) -am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) -pkgdatadir = $(datadir)/@PACKAGE@ -pkgincludedir = $(includedir)/@PACKAGE@ -pkglibdir = $(libdir)/@PACKAGE@ -pkglibexecdir = $(libexecdir)/@PACKAGE@ -am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd -install_sh_DATA = $(install_sh) -c -m 644 -install_sh_PROGRAM = $(install_sh) -c -install_sh_SCRIPT = $(install_sh) -c -INSTALL_HEADER = $(INSTALL_DATA) -transform = $(program_transform_name) -NORMAL_INSTALL = : -PRE_INSTALL = : -POST_INSTALL = : -NORMAL_UNINSTALL = : -PRE_UNINSTALL = : -POST_UNINSTALL = : -build_triplet = @build@ -host_triplet = @host@ -target_triplet = @target@ -subdir = lib/includes -ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 -am__aclocal_m4_deps = $(top_srcdir)/m4/ax_check_compile_flag.m4 \ - $(top_srcdir)/m4/ax_cxx_compile_stdcxx.m4 \ - $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \ - $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \ - $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/configure.ac -am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ - $(ACLOCAL_M4) -DIST_COMMON = $(srcdir)/Makefile.am $(nobase_include_HEADERS) \ - $(am__DIST_COMMON) -mkinstalldirs = $(install_sh) -d -CONFIG_HEADER = $(top_builddir)/config.h -CONFIG_CLEAN_FILES = -CONFIG_CLEAN_VPATH_FILES = -AM_V_P = $(am__v_P_@AM_V@) -am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) -am__v_P_0 = false -am__v_P_1 = : -AM_V_GEN = $(am__v_GEN_@AM_V@) -am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) -am__v_GEN_0 = @echo " GEN " $@; -am__v_GEN_1 = -AM_V_at = $(am__v_at_@AM_V@) -am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) -am__v_at_0 = @ -am__v_at_1 = -SOURCES = -DIST_SOURCES = -am__can_run_installinfo = \ - case $$AM_UPDATE_INFO_DIR in \ - n|no|NO) false;; \ - *) (install-info --version) >/dev/null 2>&1;; \ - esac -am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; -am__vpath_adj = case $$p in \ - $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ - *) f=$$p;; \ - esac; -am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; -am__install_max = 40 -am__nobase_strip_setup = \ - srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` -am__nobase_strip = \ - for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" -am__nobase_list = $(am__nobase_strip_setup); \ - for p in $$list; do echo "$$p $$p"; done | \ - sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ - $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ - if (++n[$$2] == $(am__install_max)) \ - { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ - END { for (dir in files) print dir, files[dir] }' -am__base_list = \ - sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ - sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' -am__uninstall_files_from_dir = { \ - test -z "$$files" \ - || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \ - || { echo " ( cd '$$dir' && rm -f" $$files ")"; \ - $(am__cd) "$$dir" && rm -f $$files; }; \ - } -am__installdirs = "$(DESTDIR)$(includedir)" -HEADERS = $(nobase_include_HEADERS) -am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) -# Read a list of newline-separated strings from the standard input, -# and print each of them once, without duplicates. Input order is -# *not* preserved. -am__uniquify_input = $(AWK) '\ - BEGIN { nonempty = 0; } \ - { items[$$0] = 1; nonempty = 1; } \ - END { if (nonempty) { for (i in items) print i; }; } \ -' -# Make sure the list of sources is unique. This is necessary because, -# e.g., the same source file might be shared among _SOURCES variables -# for different programs/libraries. -am__define_uniq_tagged_files = \ - list='$(am__tagged_files)'; \ - unique=`for i in $$list; do \ - if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ - done | $(am__uniquify_input)` -am__DIST_COMMON = $(srcdir)/Makefile.in -DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) -ACLOCAL = @ACLOCAL@ -AMTAR = @AMTAR@ -AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ -APPLDFLAGS = @APPLDFLAGS@ -AR = @AR@ -AUTOCONF = @AUTOCONF@ -AUTOHEADER = @AUTOHEADER@ -AUTOMAKE = @AUTOMAKE@ -AWK = @AWK@ -BPFCFLAGS = @BPFCFLAGS@ -CC = @CC@ -CCDEPMODE = @CCDEPMODE@ -CFLAGS = @CFLAGS@ -CPP = @CPP@ -CPPFLAGS = @CPPFLAGS@ -CSCOPE = @CSCOPE@ -CTAGS = @CTAGS@ -CXX = @CXX@ -CXX1XCXXFLAGS = @CXX1XCXXFLAGS@ -CXXCPP = @CXXCPP@ -CXXDEPMODE = @CXXDEPMODE@ -CXXFLAGS = @CXXFLAGS@ -CYGPATH_W = @CYGPATH_W@ -DEFS = @DEFS@ -DEPDIR = @DEPDIR@ -DLLTOOL = @DLLTOOL@ -DSYMUTIL = @DSYMUTIL@ -DUMPBIN = @DUMPBIN@ -ECHO_C = @ECHO_C@ -ECHO_N = @ECHO_N@ -ECHO_T = @ECHO_T@ -EGREP = @EGREP@ -ETAGS = @ETAGS@ -EXEEXT = @EXEEXT@ -EXTRABPFCFLAGS = @EXTRABPFCFLAGS@ -EXTRACFLAG = @EXTRACFLAG@ -EXTRA_DEFS = @EXTRA_DEFS@ -FGREP = @FGREP@ -FILECMD = @FILECMD@ -GREP = @GREP@ -HAVE_CXX20 = @HAVE_CXX20@ -INSTALL = @INSTALL@ -INSTALL_DATA = @INSTALL_DATA@ -INSTALL_PROGRAM = @INSTALL_PROGRAM@ -INSTALL_SCRIPT = @INSTALL_SCRIPT@ -INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ -JANSSON_CFLAGS = @JANSSON_CFLAGS@ -JANSSON_LIBS = @JANSSON_LIBS@ -JEMALLOC_CFLAGS = @JEMALLOC_CFLAGS@ -JEMALLOC_LIBS = @JEMALLOC_LIBS@ -LD = @LD@ -LDFLAGS = @LDFLAGS@ -LIBBPF_CFLAGS = @LIBBPF_CFLAGS@ -LIBBPF_LIBS = @LIBBPF_LIBS@ -LIBBROTLIDEC_CFLAGS = @LIBBROTLIDEC_CFLAGS@ -LIBBROTLIDEC_LIBS = @LIBBROTLIDEC_LIBS@ -LIBBROTLIENC_CFLAGS = @LIBBROTLIENC_CFLAGS@ -LIBBROTLIENC_LIBS = @LIBBROTLIENC_LIBS@ -LIBCARES_CFLAGS = @LIBCARES_CFLAGS@ -LIBCARES_LIBS = @LIBCARES_LIBS@ -LIBEVENT_OPENSSL_CFLAGS = @LIBEVENT_OPENSSL_CFLAGS@ -LIBEVENT_OPENSSL_LIBS = @LIBEVENT_OPENSSL_LIBS@ -LIBEV_CFLAGS = @LIBEV_CFLAGS@ -LIBEV_LIBS = @LIBEV_LIBS@ -LIBMRUBY_CFLAGS = @LIBMRUBY_CFLAGS@ -LIBMRUBY_LIBS = @LIBMRUBY_LIBS@ -LIBNGHTTP3_CFLAGS = @LIBNGHTTP3_CFLAGS@ -LIBNGHTTP3_LIBS = @LIBNGHTTP3_LIBS@ -LIBNGTCP2_CFLAGS = @LIBNGTCP2_CFLAGS@ -LIBNGTCP2_CRYPTO_BORINGSSL_CFLAGS = @LIBNGTCP2_CRYPTO_BORINGSSL_CFLAGS@ -LIBNGTCP2_CRYPTO_BORINGSSL_LIBS = @LIBNGTCP2_CRYPTO_BORINGSSL_LIBS@ -LIBNGTCP2_CRYPTO_QUICTLS_CFLAGS = @LIBNGTCP2_CRYPTO_QUICTLS_CFLAGS@ -LIBNGTCP2_CRYPTO_QUICTLS_LIBS = @LIBNGTCP2_CRYPTO_QUICTLS_LIBS@ -LIBNGTCP2_CRYPTO_WOLFSSL_CFLAGS = @LIBNGTCP2_CRYPTO_WOLFSSL_CFLAGS@ -LIBNGTCP2_CRYPTO_WOLFSSL_LIBS = @LIBNGTCP2_CRYPTO_WOLFSSL_LIBS@ -LIBNGTCP2_LIBS = @LIBNGTCP2_LIBS@ -LIBOBJS = @LIBOBJS@ -LIBS = @LIBS@ -LIBTOOL = @LIBTOOL@ -LIBTOOL_LDFLAGS = @LIBTOOL_LDFLAGS@ -LIBXML2_CFLAGS = @LIBXML2_CFLAGS@ -LIBXML2_LIBS = @LIBXML2_LIBS@ -LIPO = @LIPO@ -LN_S = @LN_S@ -LTLIBOBJS = @LTLIBOBJS@ -LT_AGE = @LT_AGE@ -LT_CURRENT = @LT_CURRENT@ -LT_REVISION = @LT_REVISION@ -LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@ -MAKEINFO = @MAKEINFO@ -MANIFEST_TOOL = @MANIFEST_TOOL@ -MKDIR_P = @MKDIR_P@ -NM = @NM@ -NMEDIT = @NMEDIT@ -OBJDUMP = @OBJDUMP@ -OBJEXT = @OBJEXT@ -OPENSSL_CFLAGS = @OPENSSL_CFLAGS@ -OPENSSL_LIBS = @OPENSSL_LIBS@ -OTOOL = @OTOOL@ -OTOOL64 = @OTOOL64@ -PACKAGE = @PACKAGE@ -PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ -PACKAGE_NAME = @PACKAGE_NAME@ -PACKAGE_STRING = @PACKAGE_STRING@ -PACKAGE_TARNAME = @PACKAGE_TARNAME@ -PACKAGE_URL = @PACKAGE_URL@ -PACKAGE_VERSION = @PACKAGE_VERSION@ -PACKAGE_VERSION_NUM = @PACKAGE_VERSION_NUM@ -PATH_SEPARATOR = @PATH_SEPARATOR@ -PKG_CONFIG = @PKG_CONFIG@ -PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ -PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ -PYTHON = @PYTHON@ -PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@ -PYTHON_PLATFORM = @PYTHON_PLATFORM@ -PYTHON_PREFIX = @PYTHON_PREFIX@ -PYTHON_VERSION = @PYTHON_VERSION@ -RANLIB = @RANLIB@ -SED = @SED@ -SET_MAKE = @SET_MAKE@ -SHELL = @SHELL@ -STRIP = @STRIP@ -SYSTEMD_CFLAGS = @SYSTEMD_CFLAGS@ -SYSTEMD_LIBS = @SYSTEMD_LIBS@ -TESTLDADD = @TESTLDADD@ -VERSION = @VERSION@ -WARNCFLAGS = @WARNCFLAGS@ -WARNCXXFLAGS = @WARNCXXFLAGS@ -WOLFSSL_CFLAGS = @WOLFSSL_CFLAGS@ -WOLFSSL_LIBS = @WOLFSSL_LIBS@ -ZLIB_CFLAGS = @ZLIB_CFLAGS@ -ZLIB_LIBS = @ZLIB_LIBS@ -abs_builddir = @abs_builddir@ -abs_srcdir = @abs_srcdir@ -abs_top_builddir = @abs_top_builddir@ -abs_top_srcdir = @abs_top_srcdir@ -ac_ct_AR = @ac_ct_AR@ -ac_ct_CC = @ac_ct_CC@ -ac_ct_CXX = @ac_ct_CXX@ -ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ -am__include = @am__include@ -am__leading_dot = @am__leading_dot@ -am__quote = @am__quote@ -am__tar = @am__tar@ -am__untar = @am__untar@ -bindir = @bindir@ -build = @build@ -build_alias = @build_alias@ -build_cpu = @build_cpu@ -build_os = @build_os@ -build_vendor = @build_vendor@ -builddir = @builddir@ -datadir = @datadir@ -datarootdir = @datarootdir@ -docdir = @docdir@ -dvidir = @dvidir@ -exec_prefix = @exec_prefix@ -host = @host@ -host_alias = @host_alias@ -host_cpu = @host_cpu@ -host_os = @host_os@ -host_vendor = @host_vendor@ -htmldir = @htmldir@ -includedir = @includedir@ -infodir = @infodir@ -install_sh = @install_sh@ -libdir = @libdir@ -libexecdir = @libexecdir@ -localedir = @localedir@ -localstatedir = @localstatedir@ -mandir = @mandir@ -mkdir_p = @mkdir_p@ -oldincludedir = @oldincludedir@ -pdfdir = @pdfdir@ -pkgpyexecdir = @pkgpyexecdir@ -pkgpythondir = @pkgpythondir@ -prefix = @prefix@ -program_transform_name = @program_transform_name@ -psdir = @psdir@ -pyexecdir = @pyexecdir@ -pythondir = @pythondir@ -runstatedir = @runstatedir@ -sbindir = @sbindir@ -sharedstatedir = @sharedstatedir@ -srcdir = @srcdir@ -sysconfdir = @sysconfdir@ -target = @target@ -target_alias = @target_alias@ -target_cpu = @target_cpu@ -target_os = @target_os@ -target_vendor = @target_vendor@ -top_build_prefix = @top_build_prefix@ -top_builddir = @top_builddir@ -top_srcdir = @top_srcdir@ -EXTRA_DIST = CMakeLists.txt -nobase_include_HEADERS = nghttp2/nghttp2.h nghttp2/nghttp2ver.h -all: all-am - -.SUFFIXES: -$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) - @for dep in $?; do \ - case '$(am__configure_deps)' in \ - *$$dep*) \ - ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ - && { if test -f $@; then exit 0; else break; fi; }; \ - exit 1;; \ - esac; \ - done; \ - echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu lib/includes/Makefile'; \ - $(am__cd) $(top_srcdir) && \ - $(AUTOMAKE) --gnu lib/includes/Makefile -Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status - @case '$?' in \ - *config.status*) \ - cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ - *) \ - echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \ - cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \ - esac; - -$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) - cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh - -$(top_srcdir)/configure: $(am__configure_deps) - cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh -$(ACLOCAL_M4): $(am__aclocal_m4_deps) - cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh -$(am__aclocal_m4_deps): - -mostlyclean-libtool: - -rm -f *.lo - -clean-libtool: - -rm -rf .libs _libs -install-nobase_includeHEADERS: $(nobase_include_HEADERS) - @$(NORMAL_INSTALL) - @list='$(nobase_include_HEADERS)'; test -n "$(includedir)" || list=; \ - if test -n "$$list"; then \ - echo " $(MKDIR_P) '$(DESTDIR)$(includedir)'"; \ - $(MKDIR_P) "$(DESTDIR)$(includedir)" || exit 1; \ - fi; \ - $(am__nobase_list) | while read dir files; do \ - xfiles=; for file in $$files; do \ - if test -f "$$file"; then xfiles="$$xfiles $$file"; \ - else xfiles="$$xfiles $(srcdir)/$$file"; fi; done; \ - test -z "$$xfiles" || { \ - test "x$$dir" = x. || { \ - echo " $(MKDIR_P) '$(DESTDIR)$(includedir)/$$dir'"; \ - $(MKDIR_P) "$(DESTDIR)$(includedir)/$$dir"; }; \ - echo " $(INSTALL_HEADER) $$xfiles '$(DESTDIR)$(includedir)/$$dir'"; \ - $(INSTALL_HEADER) $$xfiles "$(DESTDIR)$(includedir)/$$dir" || exit $$?; }; \ - done - -uninstall-nobase_includeHEADERS: - @$(NORMAL_UNINSTALL) - @list='$(nobase_include_HEADERS)'; test -n "$(includedir)" || list=; \ - $(am__nobase_strip_setup); files=`$(am__nobase_strip)`; \ - dir='$(DESTDIR)$(includedir)'; $(am__uninstall_files_from_dir) - -ID: $(am__tagged_files) - $(am__define_uniq_tagged_files); mkid -fID $$unique -tags: tags-am -TAGS: tags - -tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) - set x; \ - here=`pwd`; \ - $(am__define_uniq_tagged_files); \ - shift; \ - if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ - test -n "$$unique" || unique=$$empty_fix; \ - if test $$# -gt 0; then \ - $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ - "$$@" $$unique; \ - else \ - $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ - $$unique; \ - fi; \ - fi -ctags: ctags-am - -CTAGS: ctags -ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) - $(am__define_uniq_tagged_files); \ - test -z "$(CTAGS_ARGS)$$unique" \ - || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ - $$unique - -GTAGS: - here=`$(am__cd) $(top_builddir) && pwd` \ - && $(am__cd) $(top_srcdir) \ - && gtags -i $(GTAGS_ARGS) "$$here" -cscopelist: cscopelist-am - -cscopelist-am: $(am__tagged_files) - list='$(am__tagged_files)'; \ - case "$(srcdir)" in \ - [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ - *) sdir=$(subdir)/$(srcdir) ;; \ - esac; \ - for i in $$list; do \ - if test -f "$$i"; then \ - echo "$(subdir)/$$i"; \ - else \ - echo "$$sdir/$$i"; \ - fi; \ - done >> $(top_builddir)/cscope.files - -distclean-tags: - -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags -distdir: $(BUILT_SOURCES) - $(MAKE) $(AM_MAKEFLAGS) distdir-am - -distdir-am: $(DISTFILES) - @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ - topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ - list='$(DISTFILES)'; \ - dist_files=`for file in $$list; do echo $$file; done | \ - sed -e "s|^$$srcdirstrip/||;t" \ - -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ - case $$dist_files in \ - */*) $(MKDIR_P) `echo "$$dist_files" | \ - sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ - sort -u` ;; \ - esac; \ - for file in $$dist_files; do \ - if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ - if test -d $$d/$$file; then \ - dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ - if test -d "$(distdir)/$$file"; then \ - find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ - fi; \ - if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ - cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ - find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ - fi; \ - cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ - else \ - test -f "$(distdir)/$$file" \ - || cp -p $$d/$$file "$(distdir)/$$file" \ - || exit 1; \ - fi; \ - done -check-am: all-am -check: check-am -all-am: Makefile $(HEADERS) -installdirs: - for dir in "$(DESTDIR)$(includedir)"; do \ - test -z "$$dir" || $(MKDIR_P) "$$dir"; \ - done -install: install-am -install-exec: install-exec-am -install-data: install-data-am -uninstall: uninstall-am - -install-am: all-am - @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am - -installcheck: installcheck-am -install-strip: - if test -z '$(STRIP)'; then \ - $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ - install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ - install; \ - else \ - $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ - install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ - "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ - fi -mostlyclean-generic: - -clean-generic: - -distclean-generic: - -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) - -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) - -maintainer-clean-generic: - @echo "This command is intended for maintainers to use" - @echo "it deletes files that may require special tools to rebuild." -clean: clean-am - -clean-am: clean-generic clean-libtool mostlyclean-am - -distclean: distclean-am - -rm -f Makefile -distclean-am: clean-am distclean-generic distclean-tags - -dvi: dvi-am - -dvi-am: - -html: html-am - -html-am: - -info: info-am - -info-am: - -install-data-am: install-nobase_includeHEADERS - -install-dvi: install-dvi-am - -install-dvi-am: - -install-exec-am: - -install-html: install-html-am - -install-html-am: - -install-info: install-info-am - -install-info-am: - -install-man: - -install-pdf: install-pdf-am - -install-pdf-am: - -install-ps: install-ps-am - -install-ps-am: - -installcheck-am: - -maintainer-clean: maintainer-clean-am - -rm -f Makefile -maintainer-clean-am: distclean-am maintainer-clean-generic - -mostlyclean: mostlyclean-am - -mostlyclean-am: mostlyclean-generic mostlyclean-libtool - -pdf: pdf-am - -pdf-am: - -ps: ps-am - -ps-am: - -uninstall-am: uninstall-nobase_includeHEADERS - -.MAKE: install-am install-strip - -.PHONY: CTAGS GTAGS TAGS all all-am check check-am clean clean-generic \ - clean-libtool cscopelist-am ctags ctags-am distclean \ - distclean-generic distclean-libtool distclean-tags distdir dvi \ - dvi-am html html-am info info-am install install-am \ - install-data install-data-am install-dvi install-dvi-am \ - install-exec install-exec-am install-html install-html-am \ - install-info install-info-am install-man \ - install-nobase_includeHEADERS install-pdf install-pdf-am \ - install-ps install-ps-am install-strip installcheck \ - installcheck-am installdirs maintainer-clean \ - maintainer-clean-generic mostlyclean mostlyclean-generic \ - mostlyclean-libtool pdf pdf-am ps ps-am tags tags-am uninstall \ - uninstall-am uninstall-nobase_includeHEADERS - -.PRECIOUS: Makefile - - -# Tell versions [3.59,3.63) of GNU make to not export all variables. -# Otherwise a system limit (for SysV at least) may be exceeded. -.NOEXPORT: diff --git a/3rdparty/exported/nghttp2/includes/nghttp2/nghttp2.h b/3rdparty/exported/nghttp2/includes/nghttp2/nghttp2.h deleted file mode 100644 index 2ef49b8d68f4..000000000000 --- a/3rdparty/exported/nghttp2/includes/nghttp2/nghttp2.h +++ /dev/null @@ -1,7017 +0,0 @@ -/* - * nghttp2 - HTTP/2 C Library - * - * Copyright (c) 2013, 2014 Tatsuhiro Tsujikawa - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE - * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION - * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION - * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ -#ifndef NGHTTP2_H -#define NGHTTP2_H - -/* Define WIN32 when build target is Win32 API (borrowed from - libcurl) */ -#if (defined(_WIN32) || defined(__WIN32__)) && !defined(WIN32) -# define WIN32 -#endif - -/* Compatibility for non-Clang compilers */ -#ifndef __has_declspec_attribute -# define __has_declspec_attribute(x) 0 -#endif - -#ifdef __cplusplus -extern "C" { -#endif - -#include -#if defined(_MSC_VER) && (_MSC_VER < 1800) -/* MSVC < 2013 does not have inttypes.h because it is not C99 - compliant. See compiler macros and version number in - https://sourceforge.net/p/predef/wiki/Compilers/ */ -# include -#else /* !defined(_MSC_VER) || (_MSC_VER >= 1800) */ -# include -#endif /* !defined(_MSC_VER) || (_MSC_VER >= 1800) */ -#include -#include -#include - -#include - -#ifdef NGHTTP2_STATICLIB -# define NGHTTP2_EXTERN -#elif defined(WIN32) || \ - (__has_declspec_attribute(dllexport) && __has_declspec_attribute(dllimport)) -# ifdef BUILDING_NGHTTP2 -# define NGHTTP2_EXTERN __declspec(dllexport) -# else /* !BUILDING_NGHTTP2 */ -# define NGHTTP2_EXTERN __declspec(dllimport) -# endif /* !BUILDING_NGHTTP2 */ -#else /* !defined(WIN32) */ -# ifdef BUILDING_NGHTTP2 -# define NGHTTP2_EXTERN __attribute__((visibility("default"))) -# else /* !BUILDING_NGHTTP2 */ -# define NGHTTP2_EXTERN -# endif /* !BUILDING_NGHTTP2 */ -#endif /* !defined(WIN32) */ - -#ifdef BUILDING_NGHTTP2 -# undef NGHTTP2_NO_SSIZE_T -#endif /* BUILDING_NGHTTP2 */ - -/** - * @typedef - * - * :type:`nghttp2_ssize` is a signed counterpart of size_t. - */ -typedef ptrdiff_t nghttp2_ssize; - -/** - * @macro - * - * The protocol version identification string of this library - * supports. This identifier is used if HTTP/2 is used over TLS. - */ -#define NGHTTP2_PROTO_VERSION_ID "h2" -/** - * @macro - * - * The length of :macro:`NGHTTP2_PROTO_VERSION_ID`. - */ -#define NGHTTP2_PROTO_VERSION_ID_LEN 2 - -/** - * @macro - * - * The serialized form of ALPN protocol identifier this library - * supports. Notice that first byte is the length of following - * protocol identifier. This is the same wire format of `TLS ALPN - * extension `_. This is useful - * to process incoming ALPN tokens in wire format. - */ -#define NGHTTP2_PROTO_ALPN "\x2h2" - -/** - * @macro - * - * The length of :macro:`NGHTTP2_PROTO_ALPN`. - */ -#define NGHTTP2_PROTO_ALPN_LEN (sizeof(NGHTTP2_PROTO_ALPN) - 1) - -/** - * @macro - * - * The protocol version identification string of this library - * supports. This identifier is used if HTTP/2 is used over cleartext - * TCP. - */ -#define NGHTTP2_CLEARTEXT_PROTO_VERSION_ID "h2c" - -/** - * @macro - * - * The length of :macro:`NGHTTP2_CLEARTEXT_PROTO_VERSION_ID`. - */ -#define NGHTTP2_CLEARTEXT_PROTO_VERSION_ID_LEN 3 - -struct nghttp2_session; -/** - * @struct - * - * The primary structure to hold the resources needed for a HTTP/2 - * session. The details of this structure are intentionally hidden - * from the public API. - */ -typedef struct nghttp2_session nghttp2_session; - -/** - * @macro - * - * The age of :type:`nghttp2_info` - */ -#define NGHTTP2_VERSION_AGE 1 - -/** - * @struct - * - * This struct is what `nghttp2_version()` returns. It holds - * information about the particular nghttp2 version. - */ -typedef struct { - /** - * Age of this struct. This instance of nghttp2 sets it to - * :macro:`NGHTTP2_VERSION_AGE` but a future version may bump it and - * add more struct fields at the bottom - */ - int age; - /** - * the :macro:`NGHTTP2_VERSION_NUM` number (since age ==1) - */ - int version_num; - /** - * points to the :macro:`NGHTTP2_VERSION` string (since age ==1) - */ - const char *version_str; - /** - * points to the :macro:`NGHTTP2_PROTO_VERSION_ID` string this - * instance implements (since age ==1) - */ - const char *proto_str; - /* -------- the above fields all exist when age == 1 */ -} nghttp2_info; - -/** - * @macro - * - * .. warning:: - * - * Deprecated. :rfc:`7540` priorities are deprecated by - * :rfc:`9113`. Consider migrating to :rfc:`9218` extensible - * prioritization scheme. - * - * The default weight of stream dependency. - */ -#define NGHTTP2_DEFAULT_WEIGHT 16 - -/** - * @macro - * - * .. warning:: - * - * Deprecated. :rfc:`7540` priorities are deprecated by - * :rfc:`9113`. Consider migrating to :rfc:`9218` extensible - * prioritization scheme. - * - * The maximum weight of stream dependency. - */ -#define NGHTTP2_MAX_WEIGHT 256 - -/** - * @macro - * - * .. warning:: - * - * Deprecated. :rfc:`7540` priorities are deprecated by - * :rfc:`9113`. Consider migrating to :rfc:`9218` extensible - * prioritization scheme. - * - * The minimum weight of stream dependency. - */ -#define NGHTTP2_MIN_WEIGHT 1 - -/** - * @macro - * - * The maximum window size - */ -#define NGHTTP2_MAX_WINDOW_SIZE ((int32_t)((1U << 31) - 1)) - -/** - * @macro - * - * The initial window size for stream level flow control. - */ -#define NGHTTP2_INITIAL_WINDOW_SIZE ((1 << 16) - 1) -/** - * @macro - * - * The initial window size for connection level flow control. - */ -#define NGHTTP2_INITIAL_CONNECTION_WINDOW_SIZE ((1 << 16) - 1) - -/** - * @macro - * - * The default header table size. - */ -#define NGHTTP2_DEFAULT_HEADER_TABLE_SIZE (1 << 12) - -/** - * @macro - * - * The client magic string, which is the first 24 bytes byte string of - * client connection preface. - */ -#define NGHTTP2_CLIENT_MAGIC "PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n" - -/** - * @macro - * - * The length of :macro:`NGHTTP2_CLIENT_MAGIC`. - */ -#define NGHTTP2_CLIENT_MAGIC_LEN 24 - -/** - * @macro - * - * The default max number of settings per SETTINGS frame - */ -#define NGHTTP2_DEFAULT_MAX_SETTINGS 32 - -/** - * @enum - * - * Error codes used in this library. The code range is [-999, -500], - * inclusive. The following values are defined: - */ -typedef enum { - /** - * Invalid argument passed. - */ - NGHTTP2_ERR_INVALID_ARGUMENT = -501, - /** - * Out of buffer space. - */ - NGHTTP2_ERR_BUFFER_ERROR = -502, - /** - * The specified protocol version is not supported. - */ - NGHTTP2_ERR_UNSUPPORTED_VERSION = -503, - /** - * Used as a return value from :type:`nghttp2_send_callback2`, - * :type:`nghttp2_recv_callback` and - * :type:`nghttp2_send_data_callback` to indicate that the operation - * would block. - */ - NGHTTP2_ERR_WOULDBLOCK = -504, - /** - * General protocol error - */ - NGHTTP2_ERR_PROTO = -505, - /** - * The frame is invalid. - */ - NGHTTP2_ERR_INVALID_FRAME = -506, - /** - * The peer performed a shutdown on the connection. - */ - NGHTTP2_ERR_EOF = -507, - /** - * Used as a return value from - * :func:`nghttp2_data_source_read_callback2` to indicate that data - * transfer is postponed. See - * :func:`nghttp2_data_source_read_callback2` for details. - */ - NGHTTP2_ERR_DEFERRED = -508, - /** - * Stream ID has reached the maximum value. Therefore no stream ID - * is available. - */ - NGHTTP2_ERR_STREAM_ID_NOT_AVAILABLE = -509, - /** - * The stream is already closed; or the stream ID is invalid. - */ - NGHTTP2_ERR_STREAM_CLOSED = -510, - /** - * RST_STREAM has been added to the outbound queue. The stream is - * in closing state. - */ - NGHTTP2_ERR_STREAM_CLOSING = -511, - /** - * The transmission is not allowed for this stream (e.g., a frame - * with END_STREAM flag set has already sent). - */ - NGHTTP2_ERR_STREAM_SHUT_WR = -512, - /** - * The stream ID is invalid. - */ - NGHTTP2_ERR_INVALID_STREAM_ID = -513, - /** - * The state of the stream is not valid (e.g., DATA cannot be sent - * to the stream if response HEADERS has not been sent). - */ - NGHTTP2_ERR_INVALID_STREAM_STATE = -514, - /** - * Another DATA frame has already been deferred. - */ - NGHTTP2_ERR_DEFERRED_DATA_EXIST = -515, - /** - * Starting new stream is not allowed (e.g., GOAWAY has been sent - * and/or received). - */ - NGHTTP2_ERR_START_STREAM_NOT_ALLOWED = -516, - /** - * GOAWAY has already been sent. - */ - NGHTTP2_ERR_GOAWAY_ALREADY_SENT = -517, - /** - * The received frame contains the invalid header block (e.g., There - * are duplicate header names; or the header names are not encoded - * in US-ASCII character set and not lower cased; or the header name - * is zero-length string; or the header value contains multiple - * in-sequence NUL bytes). - */ - NGHTTP2_ERR_INVALID_HEADER_BLOCK = -518, - /** - * Indicates that the context is not suitable to perform the - * requested operation. - */ - NGHTTP2_ERR_INVALID_STATE = -519, - /** - * The user callback function failed due to the temporal error. - */ - NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE = -521, - /** - * The length of the frame is invalid, either too large or too small. - */ - NGHTTP2_ERR_FRAME_SIZE_ERROR = -522, - /** - * Header block inflate/deflate error. - */ - NGHTTP2_ERR_HEADER_COMP = -523, - /** - * Flow control error - */ - NGHTTP2_ERR_FLOW_CONTROL = -524, - /** - * Insufficient buffer size given to function. - */ - NGHTTP2_ERR_INSUFF_BUFSIZE = -525, - /** - * Callback was paused by the application - */ - NGHTTP2_ERR_PAUSE = -526, - /** - * There are too many in-flight SETTING frame and no more - * transmission of SETTINGS is allowed. - */ - NGHTTP2_ERR_TOO_MANY_INFLIGHT_SETTINGS = -527, - /** - * The server push is disabled. - */ - NGHTTP2_ERR_PUSH_DISABLED = -528, - /** - * DATA or HEADERS frame for a given stream has been already - * submitted and has not been fully processed yet. Application - * should wait for the transmission of the previously submitted - * frame before submitting another. - */ - NGHTTP2_ERR_DATA_EXIST = -529, - /** - * The current session is closing due to a connection error or - * `nghttp2_session_terminate_session()` is called. - */ - NGHTTP2_ERR_SESSION_CLOSING = -530, - /** - * Invalid HTTP header field was received and stream is going to be - * closed. - */ - NGHTTP2_ERR_HTTP_HEADER = -531, - /** - * Violation in HTTP messaging rule. - */ - NGHTTP2_ERR_HTTP_MESSAGING = -532, - /** - * Stream was refused. - */ - NGHTTP2_ERR_REFUSED_STREAM = -533, - /** - * Unexpected internal error, but recovered. - */ - NGHTTP2_ERR_INTERNAL = -534, - /** - * Indicates that a processing was canceled. - */ - NGHTTP2_ERR_CANCEL = -535, - /** - * When a local endpoint expects to receive SETTINGS frame, it - * receives an other type of frame. - */ - NGHTTP2_ERR_SETTINGS_EXPECTED = -536, - /** - * When a local endpoint receives too many settings entries - * in a single SETTINGS frame. - */ - NGHTTP2_ERR_TOO_MANY_SETTINGS = -537, - /** - * The errors < :enum:`nghttp2_error.NGHTTP2_ERR_FATAL` mean that - * the library is under unexpected condition and processing was - * terminated (e.g., out of memory). If application receives this - * error code, it must stop using that :type:`nghttp2_session` - * object and only allowed operation for that object is deallocate - * it using `nghttp2_session_del()`. - */ - NGHTTP2_ERR_FATAL = -900, - /** - * Out of memory. This is a fatal error. - */ - NGHTTP2_ERR_NOMEM = -901, - /** - * The user callback function failed. This is a fatal error. - */ - NGHTTP2_ERR_CALLBACK_FAILURE = -902, - /** - * Invalid client magic (see :macro:`NGHTTP2_CLIENT_MAGIC`) was - * received and further processing is not possible. - */ - NGHTTP2_ERR_BAD_CLIENT_MAGIC = -903, - /** - * Possible flooding by peer was detected in this HTTP/2 session. - * Flooding is measured by how many PING and SETTINGS frames with - * ACK flag set are queued for transmission. These frames are - * response for the peer initiated frames, and peer can cause memory - * exhaustion on server side to send these frames forever and does - * not read network. - */ - NGHTTP2_ERR_FLOODED = -904, - /** - * When a local endpoint receives too many CONTINUATION frames - * following a HEADER frame. - */ - NGHTTP2_ERR_TOO_MANY_CONTINUATIONS = -905, -} nghttp2_error; - -/** - * @struct - * - * The object representing single contiguous buffer. - */ -typedef struct { - /** - * The pointer to the buffer. - */ - uint8_t *base; - /** - * The length of the buffer. - */ - size_t len; -} nghttp2_vec; - -struct nghttp2_rcbuf; - -/** - * @struct - * - * The object representing reference counted buffer. The details of - * this structure are intentionally hidden from the public API. - */ -typedef struct nghttp2_rcbuf nghttp2_rcbuf; - -/** - * @function - * - * Increments the reference count of |rcbuf| by 1. - */ -NGHTTP2_EXTERN void nghttp2_rcbuf_incref(nghttp2_rcbuf *rcbuf); - -/** - * @function - * - * Decrements the reference count of |rcbuf| by 1. If the reference - * count becomes zero, the object pointed by |rcbuf| will be freed. - * In this case, application must not use |rcbuf| again. - */ -NGHTTP2_EXTERN void nghttp2_rcbuf_decref(nghttp2_rcbuf *rcbuf); - -/** - * @function - * - * Returns the underlying buffer managed by |rcbuf|. - */ -NGHTTP2_EXTERN nghttp2_vec nghttp2_rcbuf_get_buf(nghttp2_rcbuf *rcbuf); - -/** - * @function - * - * Returns nonzero if the underlying buffer is statically allocated, - * and 0 otherwise. This can be useful for language bindings that wish - * to avoid creating duplicate strings for these buffers. - */ -NGHTTP2_EXTERN int nghttp2_rcbuf_is_static(const nghttp2_rcbuf *rcbuf); - -/** - * @enum - * - * The flags for header field name/value pair. - */ -typedef enum { - /** - * No flag set. - */ - NGHTTP2_NV_FLAG_NONE = 0, - /** - * Indicates that this name/value pair must not be indexed ("Literal - * Header Field never Indexed" representation must be used in HPACK - * encoding). Other implementation calls this bit as "sensitive". - */ - NGHTTP2_NV_FLAG_NO_INDEX = 0x01, - /** - * This flag is set solely by application. If this flag is set, the - * library does not make a copy of header field name. This could - * improve performance. - */ - NGHTTP2_NV_FLAG_NO_COPY_NAME = 0x02, - /** - * This flag is set solely by application. If this flag is set, the - * library does not make a copy of header field value. This could - * improve performance. - */ - NGHTTP2_NV_FLAG_NO_COPY_VALUE = 0x04 -} nghttp2_nv_flag; - -/** - * @struct - * - * The name/value pair, which mainly used to represent header fields. - */ -typedef struct { - /** - * The |name| byte string. If this struct is presented from library - * (e.g., :type:`nghttp2_on_frame_recv_callback`), |name| is - * guaranteed to be NULL-terminated. For some callbacks - * (:type:`nghttp2_before_frame_send_callback`, - * :type:`nghttp2_on_frame_send_callback`, and - * :type:`nghttp2_on_frame_not_send_callback`), it may not be - * NULL-terminated if header field is passed from application with - * the flag :enum:`nghttp2_nv_flag.NGHTTP2_NV_FLAG_NO_COPY_NAME`). - * When application is constructing this struct, |name| is not - * required to be NULL-terminated. - */ - uint8_t *name; - /** - * The |value| byte string. If this struct is presented from - * library (e.g., :type:`nghttp2_on_frame_recv_callback`), |value| - * is guaranteed to be NULL-terminated. For some callbacks - * (:type:`nghttp2_before_frame_send_callback`, - * :type:`nghttp2_on_frame_send_callback`, and - * :type:`nghttp2_on_frame_not_send_callback`), it may not be - * NULL-terminated if header field is passed from application with - * the flag :enum:`nghttp2_nv_flag.NGHTTP2_NV_FLAG_NO_COPY_VALUE`). - * When application is constructing this struct, |value| is not - * required to be NULL-terminated. - */ - uint8_t *value; - /** - * The length of the |name|, excluding terminating NULL. - */ - size_t namelen; - /** - * The length of the |value|, excluding terminating NULL. - */ - size_t valuelen; - /** - * Bitwise OR of one or more of :type:`nghttp2_nv_flag`. - */ - uint8_t flags; -} nghttp2_nv; - -/** - * @enum - * - * The frame types in HTTP/2 specification. - */ -typedef enum { - /** - * The DATA frame. - */ - NGHTTP2_DATA = 0, - /** - * The HEADERS frame. - */ - NGHTTP2_HEADERS = 0x01, - /** - * The PRIORITY frame. - */ - NGHTTP2_PRIORITY = 0x02, - /** - * The RST_STREAM frame. - */ - NGHTTP2_RST_STREAM = 0x03, - /** - * The SETTINGS frame. - */ - NGHTTP2_SETTINGS = 0x04, - /** - * The PUSH_PROMISE frame. - */ - NGHTTP2_PUSH_PROMISE = 0x05, - /** - * The PING frame. - */ - NGHTTP2_PING = 0x06, - /** - * The GOAWAY frame. - */ - NGHTTP2_GOAWAY = 0x07, - /** - * The WINDOW_UPDATE frame. - */ - NGHTTP2_WINDOW_UPDATE = 0x08, - /** - * The CONTINUATION frame. This frame type won't be passed to any - * callbacks because the library processes this frame type and its - * preceding HEADERS/PUSH_PROMISE as a single frame. - */ - NGHTTP2_CONTINUATION = 0x09, - /** - * The ALTSVC frame, which is defined in `RFC 7383 - * `_. - */ - NGHTTP2_ALTSVC = 0x0a, - /** - * The ORIGIN frame, which is defined by `RFC 8336 - * `_. - */ - NGHTTP2_ORIGIN = 0x0c, - /** - * The PRIORITY_UPDATE frame, which is defined by :rfc:`9218`. - */ - NGHTTP2_PRIORITY_UPDATE = 0x10 -} nghttp2_frame_type; - -/** - * @enum - * - * The flags for HTTP/2 frames. This enum defines all flags for all - * frames. - */ -typedef enum { - /** - * No flag set. - */ - NGHTTP2_FLAG_NONE = 0, - /** - * The END_STREAM flag. - */ - NGHTTP2_FLAG_END_STREAM = 0x01, - /** - * The END_HEADERS flag. - */ - NGHTTP2_FLAG_END_HEADERS = 0x04, - /** - * The ACK flag. - */ - NGHTTP2_FLAG_ACK = 0x01, - /** - * The PADDED flag. - */ - NGHTTP2_FLAG_PADDED = 0x08, - /** - * The PRIORITY flag. - */ - NGHTTP2_FLAG_PRIORITY = 0x20 -} nghttp2_flag; - -/** - * @enum - * The SETTINGS ID. - */ -typedef enum { - /** - * SETTINGS_HEADER_TABLE_SIZE - */ - NGHTTP2_SETTINGS_HEADER_TABLE_SIZE = 0x01, - /** - * SETTINGS_ENABLE_PUSH - */ - NGHTTP2_SETTINGS_ENABLE_PUSH = 0x02, - /** - * SETTINGS_MAX_CONCURRENT_STREAMS - */ - NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS = 0x03, - /** - * SETTINGS_INITIAL_WINDOW_SIZE - */ - NGHTTP2_SETTINGS_INITIAL_WINDOW_SIZE = 0x04, - /** - * SETTINGS_MAX_FRAME_SIZE - */ - NGHTTP2_SETTINGS_MAX_FRAME_SIZE = 0x05, - /** - * SETTINGS_MAX_HEADER_LIST_SIZE - */ - NGHTTP2_SETTINGS_MAX_HEADER_LIST_SIZE = 0x06, - /** - * SETTINGS_ENABLE_CONNECT_PROTOCOL - * (`RFC 8441 `_) - */ - NGHTTP2_SETTINGS_ENABLE_CONNECT_PROTOCOL = 0x08, - /** - * SETTINGS_NO_RFC7540_PRIORITIES (:rfc:`9218`) - */ - NGHTTP2_SETTINGS_NO_RFC7540_PRIORITIES = 0x09 -} nghttp2_settings_id; -/* Note: If we add SETTINGS, update the capacity of - NGHTTP2_INBOUND_NUM_IV as well */ - -/** - * @macro - * - * .. warning:: - * - * Deprecated. The initial max concurrent streams is 0xffffffffu. - * - * Default maximum number of incoming concurrent streams. Use - * `nghttp2_submit_settings()` with - * :enum:`nghttp2_settings_id.NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS` - * to change the maximum number of incoming concurrent streams. - * - * .. note:: - * - * The maximum number of outgoing concurrent streams is 100 by - * default. - */ -#define NGHTTP2_INITIAL_MAX_CONCURRENT_STREAMS ((1U << 31) - 1) - -/** - * @enum - * The status codes for the RST_STREAM and GOAWAY frames. - */ -typedef enum { - /** - * No errors. - */ - NGHTTP2_NO_ERROR = 0x00, - /** - * PROTOCOL_ERROR - */ - NGHTTP2_PROTOCOL_ERROR = 0x01, - /** - * INTERNAL_ERROR - */ - NGHTTP2_INTERNAL_ERROR = 0x02, - /** - * FLOW_CONTROL_ERROR - */ - NGHTTP2_FLOW_CONTROL_ERROR = 0x03, - /** - * SETTINGS_TIMEOUT - */ - NGHTTP2_SETTINGS_TIMEOUT = 0x04, - /** - * STREAM_CLOSED - */ - NGHTTP2_STREAM_CLOSED = 0x05, - /** - * FRAME_SIZE_ERROR - */ - NGHTTP2_FRAME_SIZE_ERROR = 0x06, - /** - * REFUSED_STREAM - */ - NGHTTP2_REFUSED_STREAM = 0x07, - /** - * CANCEL - */ - NGHTTP2_CANCEL = 0x08, - /** - * COMPRESSION_ERROR - */ - NGHTTP2_COMPRESSION_ERROR = 0x09, - /** - * CONNECT_ERROR - */ - NGHTTP2_CONNECT_ERROR = 0x0a, - /** - * ENHANCE_YOUR_CALM - */ - NGHTTP2_ENHANCE_YOUR_CALM = 0x0b, - /** - * INADEQUATE_SECURITY - */ - NGHTTP2_INADEQUATE_SECURITY = 0x0c, - /** - * HTTP_1_1_REQUIRED - */ - NGHTTP2_HTTP_1_1_REQUIRED = 0x0d -} nghttp2_error_code; - -/** - * @struct - * The frame header. - */ -typedef struct { - /** - * The length field of this frame, excluding frame header. - */ - size_t length; - /** - * The stream identifier (aka, stream ID) - */ - int32_t stream_id; - /** - * The type of this frame. See `nghttp2_frame_type`. - */ - uint8_t type; - /** - * The flags. - */ - uint8_t flags; - /** - * Reserved bit in frame header. Currently, this is always set to 0 - * and application should not expect something useful in here. - */ - uint8_t reserved; -} nghttp2_frame_hd; - -/** - * @union - * - * This union represents the some kind of data source passed to - * :type:`nghttp2_data_source_read_callback2`. - */ -typedef union { - /** - * The integer field, suitable for a file descriptor. - */ - int fd; - /** - * The pointer to an arbitrary object. - */ - void *ptr; -} nghttp2_data_source; - -/** - * @enum - * - * The flags used to set in |data_flags| output parameter in - * :type:`nghttp2_data_source_read_callback2`. - */ -typedef enum { - /** - * No flag set. - */ - NGHTTP2_DATA_FLAG_NONE = 0, - /** - * Indicates EOF was sensed. - */ - NGHTTP2_DATA_FLAG_EOF = 0x01, - /** - * Indicates that END_STREAM flag must not be set even if - * NGHTTP2_DATA_FLAG_EOF is set. Usually this flag is used to send - * trailer fields with `nghttp2_submit_request2()` or - * `nghttp2_submit_response2()`. - */ - NGHTTP2_DATA_FLAG_NO_END_STREAM = 0x02, - /** - * Indicates that application will send complete DATA frame in - * :type:`nghttp2_send_data_callback`. - */ - NGHTTP2_DATA_FLAG_NO_COPY = 0x04 -} nghttp2_data_flag; - -#ifndef NGHTTP2_NO_SSIZE_T -/** - * @functypedef - * - * .. warning:: - * - * Deprecated. Use :type:`nghttp2_data_source_read_callback2` - * instead. - * - * Callback function invoked when the library wants to read data from - * the |source|. The read data is sent in the stream |stream_id|. - * The implementation of this function must read at most |length| - * bytes of data from |source| (or possibly other places) and store - * them in |buf| and return number of data stored in |buf|. If EOF is - * reached, set :enum:`nghttp2_data_flag.NGHTTP2_DATA_FLAG_EOF` flag - * in |*data_flags|. - * - * Sometime it is desirable to avoid copying data into |buf| and let - * application to send data directly. To achieve this, set - * :enum:`nghttp2_data_flag.NGHTTP2_DATA_FLAG_NO_COPY` to - * |*data_flags| (and possibly other flags, just like when we do - * copy), and return the number of bytes to send without copying data - * into |buf|. The library, seeing - * :enum:`nghttp2_data_flag.NGHTTP2_DATA_FLAG_NO_COPY`, will invoke - * :type:`nghttp2_send_data_callback`. The application must send - * complete DATA frame in that callback. - * - * If this callback is set by `nghttp2_submit_request()`, - * `nghttp2_submit_response()` or `nghttp2_submit_headers()` and - * `nghttp2_submit_data()` with flag parameter - * :enum:`nghttp2_flag.NGHTTP2_FLAG_END_STREAM` set, and - * :enum:`nghttp2_data_flag.NGHTTP2_DATA_FLAG_EOF` flag is set to - * |*data_flags|, DATA frame will have END_STREAM flag set. Usually, - * this is expected behaviour and all are fine. One exception is send - * trailer fields. You cannot send trailer fields after sending frame - * with END_STREAM set. To avoid this problem, one can set - * :enum:`nghttp2_data_flag.NGHTTP2_DATA_FLAG_NO_END_STREAM` along - * with :enum:`nghttp2_data_flag.NGHTTP2_DATA_FLAG_EOF` to signal the - * library not to set END_STREAM in DATA frame. Then application can - * use `nghttp2_submit_trailer()` to send trailer fields. - * `nghttp2_submit_trailer()` can be called inside this callback. - * - * If the application wants to postpone DATA frames (e.g., - * asynchronous I/O, or reading data blocks for long time), it is - * achieved by returning :enum:`nghttp2_error.NGHTTP2_ERR_DEFERRED` - * without reading any data in this invocation. The library removes - * DATA frame from the outgoing queue temporarily. To move back - * deferred DATA frame to outgoing queue, call - * `nghttp2_session_resume_data()`. - * - * By default, |length| is limited to 16KiB at maximum. If peer - * allows larger frames, application can enlarge transmission buffer - * size. See :type:`nghttp2_data_source_read_length_callback` for - * more details. - * - * If the application just wants to return from - * `nghttp2_session_send()` or `nghttp2_session_mem_send()` without - * sending anything, return :enum:`nghttp2_error.NGHTTP2_ERR_PAUSE`. - * - * In case of error, there are 2 choices. Returning - * :enum:`nghttp2_error.NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE` will - * close the stream by issuing RST_STREAM with - * :enum:`nghttp2_error_code.NGHTTP2_INTERNAL_ERROR`. If a different - * error code is desirable, use `nghttp2_submit_rst_stream()` with a - * desired error code and then return - * :enum:`nghttp2_error.NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE`. - * Returning :enum:`nghttp2_error.NGHTTP2_ERR_CALLBACK_FAILURE` will - * signal the entire session failure. - */ -typedef ssize_t (*nghttp2_data_source_read_callback)( - nghttp2_session *session, int32_t stream_id, uint8_t *buf, size_t length, - uint32_t *data_flags, nghttp2_data_source *source, void *user_data); - -#endif /* NGHTTP2_NO_SSIZE_T */ - -/** - * @functypedef - * - * Callback function invoked when the library wants to read data from - * the |source|. The read data is sent in the stream |stream_id|. - * The implementation of this function must read at most |length| - * bytes of data from |source| (or possibly other places) and store - * them in |buf| and return number of data stored in |buf|. If EOF is - * reached, set :enum:`nghttp2_data_flag.NGHTTP2_DATA_FLAG_EOF` flag - * in |*data_flags|. - * - * Sometime it is desirable to avoid copying data into |buf| and let - * application to send data directly. To achieve this, set - * :enum:`nghttp2_data_flag.NGHTTP2_DATA_FLAG_NO_COPY` to - * |*data_flags| (and possibly other flags, just like when we do - * copy), and return the number of bytes to send without copying data - * into |buf|. The library, seeing - * :enum:`nghttp2_data_flag.NGHTTP2_DATA_FLAG_NO_COPY`, will invoke - * :type:`nghttp2_send_data_callback`. The application must send - * complete DATA frame in that callback. - * - * If this callback is set by `nghttp2_submit_request2()`, - * `nghttp2_submit_response2()` or `nghttp2_submit_headers()` and - * `nghttp2_submit_data2()` with flag parameter - * :enum:`nghttp2_flag.NGHTTP2_FLAG_END_STREAM` set, and - * :enum:`nghttp2_data_flag.NGHTTP2_DATA_FLAG_EOF` flag is set to - * |*data_flags|, DATA frame will have END_STREAM flag set. Usually, - * this is expected behaviour and all are fine. One exception is send - * trailer fields. You cannot send trailer fields after sending frame - * with END_STREAM set. To avoid this problem, one can set - * :enum:`nghttp2_data_flag.NGHTTP2_DATA_FLAG_NO_END_STREAM` along - * with :enum:`nghttp2_data_flag.NGHTTP2_DATA_FLAG_EOF` to signal the - * library not to set END_STREAM in DATA frame. Then application can - * use `nghttp2_submit_trailer()` to send trailer fields. - * `nghttp2_submit_trailer()` can be called inside this callback. - * - * If the application wants to postpone DATA frames (e.g., - * asynchronous I/O, or reading data blocks for long time), it is - * achieved by returning :enum:`nghttp2_error.NGHTTP2_ERR_DEFERRED` - * without reading any data in this invocation. The library removes - * DATA frame from the outgoing queue temporarily. To move back - * deferred DATA frame to outgoing queue, call - * `nghttp2_session_resume_data()`. - * - * By default, |length| is limited to 16KiB at maximum. If peer - * allows larger frames, application can enlarge transmission buffer - * size. See :type:`nghttp2_data_source_read_length_callback` for - * more details. - * - * If the application just wants to return from - * `nghttp2_session_send()` or `nghttp2_session_mem_send2()` without - * sending anything, return :enum:`nghttp2_error.NGHTTP2_ERR_PAUSE`. - * - * In case of error, there are 2 choices. Returning - * :enum:`nghttp2_error.NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE` will - * close the stream by issuing RST_STREAM with - * :enum:`nghttp2_error_code.NGHTTP2_INTERNAL_ERROR`. If a different - * error code is desirable, use `nghttp2_submit_rst_stream()` with a - * desired error code and then return - * :enum:`nghttp2_error.NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE`. - * Returning :enum:`nghttp2_error.NGHTTP2_ERR_CALLBACK_FAILURE` will - * signal the entire session failure. - */ -typedef nghttp2_ssize (*nghttp2_data_source_read_callback2)( - nghttp2_session *session, int32_t stream_id, uint8_t *buf, size_t length, - uint32_t *data_flags, nghttp2_data_source *source, void *user_data); - -#ifndef NGHTTP2_NO_SSIZE_T -/** - * @struct - * - * .. warning:: - * - * Deprecated. Use :type:`nghttp2_data_provider2` instead. - * - * This struct represents the data source and the way to read a chunk - * of data from it. - */ -typedef struct { - /** - * The data source. - */ - nghttp2_data_source source; - /** - * The callback function to read a chunk of data from the |source|. - */ - nghttp2_data_source_read_callback read_callback; -} nghttp2_data_provider; - -#endif /* NGHTTP2_NO_SSIZE_T */ - -/** - * @struct - * - * This struct represents the data source and the way to read a chunk - * of data from it. - */ -typedef struct { - /** - * The data source. - */ - nghttp2_data_source source; - /** - * The callback function to read a chunk of data from the |source|. - */ - nghttp2_data_source_read_callback2 read_callback; -} nghttp2_data_provider2; - -/** - * @struct - * - * The DATA frame. The received data is delivered via - * :type:`nghttp2_on_data_chunk_recv_callback`. - */ -typedef struct { - nghttp2_frame_hd hd; - /** - * The length of the padding in this frame. This includes PAD_HIGH - * and PAD_LOW. - */ - size_t padlen; -} nghttp2_data; - -/** - * @enum - * - * The category of HEADERS, which indicates the role of the frame. In - * HTTP/2 spec, request, response, push response and other arbitrary - * headers (e.g., trailer fields) are all called just HEADERS. To - * give the application the role of incoming HEADERS frame, we define - * several categories. - */ -typedef enum { - /** - * The HEADERS frame is opening new stream, which is analogous to - * SYN_STREAM in SPDY. - */ - NGHTTP2_HCAT_REQUEST = 0, - /** - * The HEADERS frame is the first response headers, which is - * analogous to SYN_REPLY in SPDY. - */ - NGHTTP2_HCAT_RESPONSE = 1, - /** - * The HEADERS frame is the first headers sent against reserved - * stream. - */ - NGHTTP2_HCAT_PUSH_RESPONSE = 2, - /** - * The HEADERS frame which does not apply for the above categories, - * which is analogous to HEADERS in SPDY. If non-final response - * (e.g., status 1xx) is used, final response HEADERS frame will be - * categorized here. - */ - NGHTTP2_HCAT_HEADERS = 3 -} nghttp2_headers_category; - -/** - * @struct - * - * .. warning:: - * - * Deprecated. :rfc:`7540` priorities are deprecated by - * :rfc:`9113`. Consider migrating to :rfc:`9218` extensible - * prioritization scheme. - * - * The structure to specify stream dependency. - */ -typedef struct { - /** - * The stream ID of the stream to depend on. Specifying 0 makes - * stream not depend any other stream. - */ - int32_t stream_id; - /** - * The weight of this dependency. - */ - int32_t weight; - /** - * nonzero means exclusive dependency - */ - uint8_t exclusive; -} nghttp2_priority_spec; - -/** - * @struct - * - * The HEADERS frame. It has the following members: - */ -typedef struct { - /** - * The frame header. - */ - nghttp2_frame_hd hd; - /** - * The length of the padding in this frame. This includes PAD_HIGH - * and PAD_LOW. - */ - size_t padlen; - /** - * .. warning:: - * - * Deprecated. :rfc:`7540` priorities are deprecated by - * :rfc:`9113`. Consider migrating to :rfc:`9218` extensible - * prioritization scheme. - * - * The priority specification - */ - nghttp2_priority_spec pri_spec; - /** - * The name/value pairs. - */ - nghttp2_nv *nva; - /** - * The number of name/value pairs in |nva|. - */ - size_t nvlen; - /** - * The category of this HEADERS frame. - */ - nghttp2_headers_category cat; -} nghttp2_headers; - -/** - * @struct - * - * .. warning:: - * - * Deprecated. :rfc:`7540` priorities are deprecated by - * :rfc:`9113`. Consider migrating to :rfc:`9218` extensible - * prioritization scheme. - * - * The PRIORITY frame. It has the following members: - */ -typedef struct { - /** - * The frame header. - */ - nghttp2_frame_hd hd; - /** - * The priority specification. - */ - nghttp2_priority_spec pri_spec; -} nghttp2_priority; - -/** - * @struct - * - * The RST_STREAM frame. It has the following members: - */ -typedef struct { - /** - * The frame header. - */ - nghttp2_frame_hd hd; - /** - * The error code. See :type:`nghttp2_error_code`. - */ - uint32_t error_code; -} nghttp2_rst_stream; - -/** - * @struct - * - * The SETTINGS ID/Value pair. It has the following members: - */ -typedef struct { - /** - * The SETTINGS ID. See :type:`nghttp2_settings_id`. - */ - int32_t settings_id; - /** - * The value of this entry. - */ - uint32_t value; -} nghttp2_settings_entry; - -/** - * @struct - * - * The SETTINGS frame. It has the following members: - */ -typedef struct { - /** - * The frame header. - */ - nghttp2_frame_hd hd; - /** - * The number of SETTINGS ID/Value pairs in |iv|. - */ - size_t niv; - /** - * The pointer to the array of SETTINGS ID/Value pair. - */ - nghttp2_settings_entry *iv; -} nghttp2_settings; - -/** - * @struct - * - * The PUSH_PROMISE frame. It has the following members: - */ -typedef struct { - /** - * The frame header. - */ - nghttp2_frame_hd hd; - /** - * The length of the padding in this frame. This includes PAD_HIGH - * and PAD_LOW. - */ - size_t padlen; - /** - * The name/value pairs. - */ - nghttp2_nv *nva; - /** - * The number of name/value pairs in |nva|. - */ - size_t nvlen; - /** - * The promised stream ID - */ - int32_t promised_stream_id; - /** - * Reserved bit. Currently this is always set to 0 and application - * should not expect something useful in here. - */ - uint8_t reserved; -} nghttp2_push_promise; - -/** - * @struct - * - * The PING frame. It has the following members: - */ -typedef struct { - /** - * The frame header. - */ - nghttp2_frame_hd hd; - /** - * The opaque data - */ - uint8_t opaque_data[8]; -} nghttp2_ping; - -/** - * @struct - * - * The GOAWAY frame. It has the following members: - */ -typedef struct { - /** - * The frame header. - */ - nghttp2_frame_hd hd; - /** - * The last stream stream ID. - */ - int32_t last_stream_id; - /** - * The error code. See :type:`nghttp2_error_code`. - */ - uint32_t error_code; - /** - * The additional debug data - */ - uint8_t *opaque_data; - /** - * The length of |opaque_data| member. - */ - size_t opaque_data_len; - /** - * Reserved bit. Currently this is always set to 0 and application - * should not expect something useful in here. - */ - uint8_t reserved; -} nghttp2_goaway; - -/** - * @struct - * - * The WINDOW_UPDATE frame. It has the following members: - */ -typedef struct { - /** - * The frame header. - */ - nghttp2_frame_hd hd; - /** - * The window size increment. - */ - int32_t window_size_increment; - /** - * Reserved bit. Currently this is always set to 0 and application - * should not expect something useful in here. - */ - uint8_t reserved; -} nghttp2_window_update; - -/** - * @struct - * - * The extension frame. It has following members: - */ -typedef struct { - /** - * The frame header. - */ - nghttp2_frame_hd hd; - /** - * The pointer to extension payload. The exact pointer type is - * determined by hd.type. - * - * Currently, no extension is supported. This is a place holder for - * the future extensions. - */ - void *payload; -} nghttp2_extension; - -/** - * @union - * - * This union includes all frames to pass them to various function - * calls as nghttp2_frame type. The CONTINUATION frame is omitted - * from here because the library deals with it internally. - */ -typedef union { - /** - * The frame header, which is convenient to inspect frame header. - */ - nghttp2_frame_hd hd; - /** - * The DATA frame. - */ - nghttp2_data data; - /** - * The HEADERS frame. - */ - nghttp2_headers headers; - /** - * The PRIORITY frame. - */ - nghttp2_priority priority; - /** - * The RST_STREAM frame. - */ - nghttp2_rst_stream rst_stream; - /** - * The SETTINGS frame. - */ - nghttp2_settings settings; - /** - * The PUSH_PROMISE frame. - */ - nghttp2_push_promise push_promise; - /** - * The PING frame. - */ - nghttp2_ping ping; - /** - * The GOAWAY frame. - */ - nghttp2_goaway goaway; - /** - * The WINDOW_UPDATE frame. - */ - nghttp2_window_update window_update; - /** - * The extension frame. - */ - nghttp2_extension ext; -} nghttp2_frame; - -#ifndef NGHTTP2_NO_SSIZE_T -/** - * @functypedef - * - * .. warning:: - * - * Deprecated. Use :type:`nghttp2_send_callback2` instead. - * - * Callback function invoked when |session| wants to send data to the - * remote peer. The implementation of this function must send at most - * |length| bytes of data stored in |data|. The |flags| is currently - * not used and always 0. It must return the number of bytes sent if - * it succeeds. If it cannot send any single byte without blocking, - * it must return :enum:`nghttp2_error.NGHTTP2_ERR_WOULDBLOCK`. For - * other errors, it must return - * :enum:`nghttp2_error.NGHTTP2_ERR_CALLBACK_FAILURE`. The - * |user_data| pointer is the third argument passed in to the call to - * `nghttp2_session_client_new()` or `nghttp2_session_server_new()`. - * - * This callback is required if the application uses - * `nghttp2_session_send()` to send data to the remote endpoint. If - * the application uses solely `nghttp2_session_mem_send()` instead, - * this callback function is unnecessary. - * - * To set this callback to :type:`nghttp2_session_callbacks`, use - * `nghttp2_session_callbacks_set_send_callback()`. - * - * .. note:: - * - * The |length| may be very small. If that is the case, and - * application disables Nagle algorithm (``TCP_NODELAY``), then just - * writing |data| to the network stack leads to very small packet, - * and it is very inefficient. An application should be responsible - * to buffer up small chunks of data as necessary to avoid this - * situation. - */ -typedef ssize_t (*nghttp2_send_callback)(nghttp2_session *session, - const uint8_t *data, size_t length, - int flags, void *user_data); - -#endif /* NGHTTP2_NO_SSIZE_T */ - -/** - * @functypedef - * - * Callback function invoked when |session| wants to send data to the - * remote peer. The implementation of this function must send at most - * |length| bytes of data stored in |data|. The |flags| is currently - * not used and always 0. It must return the number of bytes sent if - * it succeeds. If it cannot send any single byte without blocking, - * it must return :enum:`nghttp2_error.NGHTTP2_ERR_WOULDBLOCK`. For - * other errors, it must return - * :enum:`nghttp2_error.NGHTTP2_ERR_CALLBACK_FAILURE`. The - * |user_data| pointer is the third argument passed in to the call to - * `nghttp2_session_client_new()` or `nghttp2_session_server_new()`. - * - * This callback is required if the application uses - * `nghttp2_session_send()` to send data to the remote endpoint. If - * the application uses solely `nghttp2_session_mem_send2()` instead, - * this callback function is unnecessary. - * - * To set this callback to :type:`nghttp2_session_callbacks`, use - * `nghttp2_session_callbacks_set_send_callback2()`. - * - * .. note:: - * - * The |length| may be very small. If that is the case, and - * application disables Nagle algorithm (``TCP_NODELAY``), then just - * writing |data| to the network stack leads to very small packet, - * and it is very inefficient. An application should be responsible - * to buffer up small chunks of data as necessary to avoid this - * situation. - */ -typedef nghttp2_ssize (*nghttp2_send_callback2)(nghttp2_session *session, - const uint8_t *data, - size_t length, int flags, - void *user_data); - -/** - * @functypedef - * - * Callback function invoked when - * :enum:`nghttp2_data_flag.NGHTTP2_DATA_FLAG_NO_COPY` is used in - * :type:`nghttp2_data_source_read_callback` to send complete DATA - * frame. - * - * The |frame| is a DATA frame to send. The |framehd| is the - * serialized frame header (9 bytes). The |length| is the length of - * application data to send (this does not include padding). The - * |source| is the same pointer passed to - * :type:`nghttp2_data_source_read_callback`. - * - * The application first must send frame header |framehd| of length 9 - * bytes. If ``frame->data.padlen > 0``, send 1 byte of value - * ``frame->data.padlen - 1``. Then send exactly |length| bytes of - * application data. Finally, if ``frame->data.padlen > 1``, send - * ``frame->data.padlen - 1`` bytes of zero as padding. - * - * The application has to send complete DATA frame in this callback. - * If all data were written successfully, return 0. - * - * If it cannot send any data at all, just return - * :enum:`nghttp2_error.NGHTTP2_ERR_WOULDBLOCK`; the library will call - * this callback with the same parameters later (It is recommended to - * send complete DATA frame at once in this function to deal with - * error; if partial frame data has already sent, it is impossible to - * send another data in that state, and all we can do is tear down - * connection). When data is fully processed, but application wants - * to make `nghttp2_session_mem_send2()` or `nghttp2_session_send()` - * return immediately without processing next frames, return - * :enum:`nghttp2_error.NGHTTP2_ERR_PAUSE`. If application decided to - * reset this stream, return - * :enum:`nghttp2_error.NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE`, then - * the library will send RST_STREAM with INTERNAL_ERROR as error code. - * The application can also return - * :enum:`nghttp2_error.NGHTTP2_ERR_CALLBACK_FAILURE`, which will - * result in connection closure. Returning any other value is treated - * as :enum:`nghttp2_error.NGHTTP2_ERR_CALLBACK_FAILURE` is returned. - */ -typedef int (*nghttp2_send_data_callback)(nghttp2_session *session, - nghttp2_frame *frame, - const uint8_t *framehd, size_t length, - nghttp2_data_source *source, - void *user_data); - -#ifndef NGHTTP2_NO_SSIZE_T -/** - * @functypedef - * - * .. warning:: - * - * Deprecated. Use :type:`nghttp2_recv_callback2` instead. - * - * Callback function invoked when |session| wants to receive data from - * the remote peer. The implementation of this function must read at - * most |length| bytes of data and store it in |buf|. The |flags| is - * currently not used and always 0. It must return the number of - * bytes written in |buf| if it succeeds. If it cannot read any - * single byte without blocking, it must return - * :enum:`nghttp2_error.NGHTTP2_ERR_WOULDBLOCK`. If it gets EOF - * before it reads any single byte, it must return - * :enum:`nghttp2_error.NGHTTP2_ERR_EOF`. For other errors, it must - * return :enum:`nghttp2_error.NGHTTP2_ERR_CALLBACK_FAILURE`. - * Returning 0 is treated as - * :enum:`nghttp2_error.NGHTTP2_ERR_WOULDBLOCK`. The |user_data| - * pointer is the third argument passed in to the call to - * `nghttp2_session_client_new()` or `nghttp2_session_server_new()`. - * - * This callback is required if the application uses - * `nghttp2_session_recv()` to receive data from the remote endpoint. - * If the application uses solely `nghttp2_session_mem_recv()` - * instead, this callback function is unnecessary. - * - * To set this callback to :type:`nghttp2_session_callbacks`, use - * `nghttp2_session_callbacks_set_recv_callback()`. - */ -typedef ssize_t (*nghttp2_recv_callback)(nghttp2_session *session, uint8_t *buf, - size_t length, int flags, - void *user_data); - -#endif /* NGHTTP2_NO_SSIZE_T */ - -/** - * @functypedef - * - * Callback function invoked when |session| wants to receive data from - * the remote peer. The implementation of this function must read at - * most |length| bytes of data and store it in |buf|. The |flags| is - * currently not used and always 0. It must return the number of - * bytes written in |buf| if it succeeds. If it cannot read any - * single byte without blocking, it must return - * :enum:`nghttp2_error.NGHTTP2_ERR_WOULDBLOCK`. If it gets EOF - * before it reads any single byte, it must return - * :enum:`nghttp2_error.NGHTTP2_ERR_EOF`. For other errors, it must - * return :enum:`nghttp2_error.NGHTTP2_ERR_CALLBACK_FAILURE`. - * Returning 0 is treated as - * :enum:`nghttp2_error.NGHTTP2_ERR_WOULDBLOCK`. The |user_data| - * pointer is the third argument passed in to the call to - * `nghttp2_session_client_new()` or `nghttp2_session_server_new()`. - * - * This callback is required if the application uses - * `nghttp2_session_recv()` to receive data from the remote endpoint. - * If the application uses solely `nghttp2_session_mem_recv2()` - * instead, this callback function is unnecessary. - * - * To set this callback to :type:`nghttp2_session_callbacks`, use - * `nghttp2_session_callbacks_set_recv_callback2()`. - */ -typedef nghttp2_ssize (*nghttp2_recv_callback2)(nghttp2_session *session, - uint8_t *buf, size_t length, - int flags, void *user_data); - -/** - * @functypedef - * - * Callback function invoked by `nghttp2_session_recv()` and - * `nghttp2_session_mem_recv2()` when a frame is received. The - * |user_data| pointer is the third argument passed in to the call to - * `nghttp2_session_client_new()` or `nghttp2_session_server_new()`. - * - * If frame is HEADERS or PUSH_PROMISE, the ``nva`` and ``nvlen`` - * member of their data structure are always ``NULL`` and 0 - * respectively. The header name/value pairs are emitted via - * :type:`nghttp2_on_header_callback`. - * - * Only HEADERS and DATA frame can signal the end of incoming data. - * If ``frame->hd.flags & NGHTTP2_FLAG_END_STREAM`` is nonzero, the - * |frame| is the last frame from the remote peer in this stream. - * - * This callback won't be called for CONTINUATION frames. - * HEADERS/PUSH_PROMISE + CONTINUATIONs are treated as single frame. - * - * The implementation of this function must return 0 if it succeeds. - * If nonzero value is returned, it is treated as fatal error and - * `nghttp2_session_recv()` and `nghttp2_session_mem_recv2()` - * functions immediately return - * :enum:`nghttp2_error.NGHTTP2_ERR_CALLBACK_FAILURE`. - * - * To set this callback to :type:`nghttp2_session_callbacks`, use - * `nghttp2_session_callbacks_set_on_frame_recv_callback()`. - */ -typedef int (*nghttp2_on_frame_recv_callback)(nghttp2_session *session, - const nghttp2_frame *frame, - void *user_data); - -/** - * @functypedef - * - * Callback function invoked by `nghttp2_session_recv()` and - * `nghttp2_session_mem_recv2()` when an invalid non-DATA frame is - * received. The error is indicated by the |lib_error_code|, which is - * one of the values defined in :type:`nghttp2_error`. When this - * callback function is invoked, the library automatically submits - * either RST_STREAM or GOAWAY frame. The |user_data| pointer is the - * third argument passed in to the call to - * `nghttp2_session_client_new()` or `nghttp2_session_server_new()`. - * - * If frame is HEADERS or PUSH_PROMISE, the ``nva`` and ``nvlen`` - * member of their data structure are always ``NULL`` and 0 - * respectively. - * - * The implementation of this function must return 0 if it succeeds. - * If nonzero is returned, it is treated as fatal error and - * `nghttp2_session_recv()` and `nghttp2_session_mem_recv2()` - * functions immediately return - * :enum:`nghttp2_error.NGHTTP2_ERR_CALLBACK_FAILURE`. - * - * To set this callback to :type:`nghttp2_session_callbacks`, use - * `nghttp2_session_callbacks_set_on_invalid_frame_recv_callback()`. - */ -typedef int (*nghttp2_on_invalid_frame_recv_callback)( - nghttp2_session *session, const nghttp2_frame *frame, int lib_error_code, - void *user_data); - -/** - * @functypedef - * - * Callback function invoked when a chunk of data in DATA frame is - * received. The |stream_id| is the stream ID this DATA frame belongs - * to. The |flags| is the flags of DATA frame which this data chunk - * is contained. ``(flags & NGHTTP2_FLAG_END_STREAM) != 0`` does not - * necessarily mean this chunk of data is the last one in the stream. - * You should use :type:`nghttp2_on_frame_recv_callback` to know all - * data frames are received. The |user_data| pointer is the third - * argument passed in to the call to `nghttp2_session_client_new()` or - * `nghttp2_session_server_new()`. - * - * If the application uses `nghttp2_session_mem_recv2()`, it can - * return :enum:`nghttp2_error.NGHTTP2_ERR_PAUSE` to make - * `nghttp2_session_mem_recv2()` return without processing further - * input bytes. The memory by pointed by the |data| is retained until - * `nghttp2_session_mem_recv2()` or `nghttp2_session_recv()` is - * called. The application must retain the input bytes which was used - * to produce the |data| parameter, because it may refer to the memory - * region included in the input bytes. - * - * The implementation of this function must return 0 if it succeeds. - * If nonzero is returned, it is treated as fatal error, and - * `nghttp2_session_recv()` and `nghttp2_session_mem_recv2()` - * functions immediately return - * :enum:`nghttp2_error.NGHTTP2_ERR_CALLBACK_FAILURE`. - * - * To set this callback to :type:`nghttp2_session_callbacks`, use - * `nghttp2_session_callbacks_set_on_data_chunk_recv_callback()`. - */ -typedef int (*nghttp2_on_data_chunk_recv_callback)(nghttp2_session *session, - uint8_t flags, - int32_t stream_id, - const uint8_t *data, - size_t len, void *user_data); - -/** - * @functypedef - * - * Callback function invoked just before the non-DATA frame |frame| is - * sent. The |user_data| pointer is the third argument passed in to - * the call to `nghttp2_session_client_new()` or - * `nghttp2_session_server_new()`. - * - * The implementation of this function must return 0 if it succeeds. - * It can also return :enum:`nghttp2_error.NGHTTP2_ERR_CANCEL` to - * cancel the transmission of the given frame. - * - * If there is a fatal error while executing this callback, the - * implementation should return - * :enum:`nghttp2_error.NGHTTP2_ERR_CALLBACK_FAILURE`, which makes - * `nghttp2_session_send()` and `nghttp2_session_mem_send2()` - * functions immediately return - * :enum:`nghttp2_error.NGHTTP2_ERR_CALLBACK_FAILURE`. - * - * If the other value is returned, it is treated as if - * :enum:`nghttp2_error.NGHTTP2_ERR_CALLBACK_FAILURE` is returned. - * But the implementation should not rely on this since the library - * may define new return value to extend its capability. - * - * To set this callback to :type:`nghttp2_session_callbacks`, use - * `nghttp2_session_callbacks_set_before_frame_send_callback()`. - */ -typedef int (*nghttp2_before_frame_send_callback)(nghttp2_session *session, - const nghttp2_frame *frame, - void *user_data); - -/** - * @functypedef - * - * Callback function invoked after the frame |frame| is sent. The - * |user_data| pointer is the third argument passed in to the call to - * `nghttp2_session_client_new()` or `nghttp2_session_server_new()`. - * - * The implementation of this function must return 0 if it succeeds. - * If nonzero is returned, it is treated as fatal error and - * `nghttp2_session_send()` and `nghttp2_session_mem_send2()` - * functions immediately return - * :enum:`nghttp2_error.NGHTTP2_ERR_CALLBACK_FAILURE`. - * - * To set this callback to :type:`nghttp2_session_callbacks`, use - * `nghttp2_session_callbacks_set_on_frame_send_callback()`. - */ -typedef int (*nghttp2_on_frame_send_callback)(nghttp2_session *session, - const nghttp2_frame *frame, - void *user_data); - -/** - * @functypedef - * - * Callback function invoked after the non-DATA frame |frame| is not - * sent because of the error. The error is indicated by the - * |lib_error_code|, which is one of the values defined in - * :type:`nghttp2_error`. The |user_data| pointer is the third - * argument passed in to the call to `nghttp2_session_client_new()` or - * `nghttp2_session_server_new()`. - * - * The implementation of this function must return 0 if it succeeds. - * If nonzero is returned, it is treated as fatal error and - * `nghttp2_session_send()` and `nghttp2_session_mem_send2()` - * functions immediately return - * :enum:`nghttp2_error.NGHTTP2_ERR_CALLBACK_FAILURE`. - * - * `nghttp2_session_get_stream_user_data()` can be used to get - * associated data. - * - * To set this callback to :type:`nghttp2_session_callbacks`, use - * `nghttp2_session_callbacks_set_on_frame_not_send_callback()`. - */ -typedef int (*nghttp2_on_frame_not_send_callback)(nghttp2_session *session, - const nghttp2_frame *frame, - int lib_error_code, - void *user_data); - -/** - * @functypedef - * - * Callback function invoked when the stream |stream_id| is closed. - * The reason of closure is indicated by the |error_code|. The - * |error_code| is usually one of :enum:`nghttp2_error_code`, but that - * is not guaranteed. The stream_user_data, which was specified in - * `nghttp2_submit_request2()` or `nghttp2_submit_headers()`, is still - * available in this function. The |user_data| pointer is the third - * argument passed in to the call to `nghttp2_session_client_new()` or - * `nghttp2_session_server_new()`. - * - * This function is also called for a stream in reserved state. - * - * The implementation of this function must return 0 if it succeeds. - * If nonzero is returned, it is treated as fatal error and - * `nghttp2_session_recv()`, `nghttp2_session_mem_recv2()`, - * `nghttp2_session_send()`, and `nghttp2_session_mem_send2()` - * functions immediately return - * :enum:`nghttp2_error.NGHTTP2_ERR_CALLBACK_FAILURE`. - * - * To set this callback to :type:`nghttp2_session_callbacks`, use - * `nghttp2_session_callbacks_set_on_stream_close_callback()`. - */ -typedef int (*nghttp2_on_stream_close_callback)(nghttp2_session *session, - int32_t stream_id, - uint32_t error_code, - void *user_data); - -/** - * @functypedef - * - * Callback function invoked when the reception of header block in - * HEADERS or PUSH_PROMISE is started. Each header name/value pair - * will be emitted by :type:`nghttp2_on_header_callback`. - * - * The ``frame->hd.flags`` may not have - * :enum:`nghttp2_flag.NGHTTP2_FLAG_END_HEADERS` flag set, which - * indicates that one or more CONTINUATION frames are involved. But - * the application does not need to care about that because the header - * name/value pairs are emitted transparently regardless of - * CONTINUATION frames. - * - * The server applications probably create an object to store - * information about new stream if ``frame->hd.type == - * NGHTTP2_HEADERS`` and ``frame->headers.cat == - * NGHTTP2_HCAT_REQUEST``. If |session| is configured as server side, - * ``frame->headers.cat`` is either ``NGHTTP2_HCAT_REQUEST`` - * containing request headers or ``NGHTTP2_HCAT_HEADERS`` containing - * trailer fields and never get PUSH_PROMISE in this callback. - * - * For the client applications, ``frame->hd.type`` is either - * ``NGHTTP2_HEADERS`` or ``NGHTTP2_PUSH_PROMISE``. In case of - * ``NGHTTP2_HEADERS``, ``frame->headers.cat == - * NGHTTP2_HCAT_RESPONSE`` means that it is the first response - * headers, but it may be non-final response which is indicated by 1xx - * status code. In this case, there may be zero or more HEADERS frame - * with ``frame->headers.cat == NGHTTP2_HCAT_HEADERS`` which has - * non-final response code and finally client gets exactly one HEADERS - * frame with ``frame->headers.cat == NGHTTP2_HCAT_HEADERS`` - * containing final response headers (non-1xx status code). The - * trailer fields also has ``frame->headers.cat == - * NGHTTP2_HCAT_HEADERS`` which does not contain any status code. - * - * Returning - * :enum:`nghttp2_error.NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE` will - * close the stream (promised stream if frame is PUSH_PROMISE) by - * issuing RST_STREAM with - * :enum:`nghttp2_error_code.NGHTTP2_INTERNAL_ERROR`. In this case, - * :type:`nghttp2_on_header_callback` and - * :type:`nghttp2_on_frame_recv_callback` will not be invoked. If a - * different error code is desirable, use - * `nghttp2_submit_rst_stream()` with a desired error code and then - * return :enum:`nghttp2_error.NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE`. - * Again, use ``frame->push_promise.promised_stream_id`` as stream_id - * parameter in `nghttp2_submit_rst_stream()` if frame is - * PUSH_PROMISE. - * - * The implementation of this function must return 0 if it succeeds. - * It can return - * :enum:`nghttp2_error.NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE` to - * reset the stream (promised stream if frame is PUSH_PROMISE). For - * critical errors, it must return - * :enum:`nghttp2_error.NGHTTP2_ERR_CALLBACK_FAILURE`. If the other - * value is returned, it is treated as if - * :enum:`nghttp2_error.NGHTTP2_ERR_CALLBACK_FAILURE` is returned. If - * :enum:`nghttp2_error.NGHTTP2_ERR_CALLBACK_FAILURE` is returned, - * `nghttp2_session_mem_recv2()` function will immediately return - * :enum:`nghttp2_error.NGHTTP2_ERR_CALLBACK_FAILURE`. - * - * To set this callback to :type:`nghttp2_session_callbacks`, use - * `nghttp2_session_callbacks_set_on_begin_headers_callback()`. - */ -typedef int (*nghttp2_on_begin_headers_callback)(nghttp2_session *session, - const nghttp2_frame *frame, - void *user_data); - -/** - * @functypedef - * - * Callback function invoked when a header name/value pair is received - * for the |frame|. The |name| of length |namelen| is header name. - * The |value| of length |valuelen| is header value. The |flags| is - * bitwise OR of one or more of :type:`nghttp2_nv_flag`. - * - * If :enum:`nghttp2_nv_flag.NGHTTP2_NV_FLAG_NO_INDEX` is set in - * |flags|, the receiver must not index this name/value pair when - * forwarding it to the next hop. More specifically, "Literal Header - * Field never Indexed" representation must be used in HPACK encoding. - * - * When this callback is invoked, ``frame->hd.type`` is either - * :enum:`nghttp2_frame_type.NGHTTP2_HEADERS` or - * :enum:`nghttp2_frame_type.NGHTTP2_PUSH_PROMISE`. After all header - * name/value pairs are processed with this callback, and no error has - * been detected, :type:`nghttp2_on_frame_recv_callback` will be - * invoked. If there is an error in decompression, - * :type:`nghttp2_on_frame_recv_callback` for the |frame| will not be - * invoked. - * - * Both |name| and |value| are guaranteed to be NULL-terminated. The - * |namelen| and |valuelen| do not include terminal NULL. If - * `nghttp2_option_set_no_http_messaging()` is used with nonzero - * value, NULL character may be included in |name| or |value| before - * terminating NULL. - * - * Please note that unless `nghttp2_option_set_no_http_messaging()` is - * used, nghttp2 library does perform validation against the |name| - * and the |value| using `nghttp2_check_header_name()` and - * `nghttp2_check_header_value()`. In addition to this, nghttp2 - * performs validation based on HTTP Messaging rule, which is briefly - * explained in :ref:`http-messaging` section. - * - * If the application uses `nghttp2_session_mem_recv2()`, it can - * return :enum:`nghttp2_error.NGHTTP2_ERR_PAUSE` to make - * `nghttp2_session_mem_recv2()` return without processing further - * input bytes. The memory pointed by |frame|, |name| and |value| - * parameters are retained until `nghttp2_session_mem_recv2()` or - * `nghttp2_session_recv()` is called. The application must retain - * the input bytes which was used to produce these parameters, because - * it may refer to the memory region included in the input bytes. - * - * Returning - * :enum:`nghttp2_error.NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE` will - * close the stream (promised stream if frame is PUSH_PROMISE) by - * issuing RST_STREAM with - * :enum:`nghttp2_error_code.NGHTTP2_INTERNAL_ERROR`. In this case, - * :type:`nghttp2_on_header_callback` and - * :type:`nghttp2_on_frame_recv_callback` will not be invoked. If a - * different error code is desirable, use - * `nghttp2_submit_rst_stream()` with a desired error code and then - * return :enum:`nghttp2_error.NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE`. - * Again, use ``frame->push_promise.promised_stream_id`` as stream_id - * parameter in `nghttp2_submit_rst_stream()` if frame is - * PUSH_PROMISE. - * - * The implementation of this function must return 0 if it succeeds. - * It may return :enum:`nghttp2_error.NGHTTP2_ERR_PAUSE` or - * :enum:`nghttp2_error.NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE`. For - * other critical failures, it must return - * :enum:`nghttp2_error.NGHTTP2_ERR_CALLBACK_FAILURE`. If the other - * nonzero value is returned, it is treated as - * :enum:`nghttp2_error.NGHTTP2_ERR_CALLBACK_FAILURE`. If - * :enum:`nghttp2_error.NGHTTP2_ERR_CALLBACK_FAILURE` is returned, - * `nghttp2_session_recv()` and `nghttp2_session_mem_recv2()` - * functions immediately return - * :enum:`nghttp2_error.NGHTTP2_ERR_CALLBACK_FAILURE`. - * - * To set this callback to :type:`nghttp2_session_callbacks`, use - * `nghttp2_session_callbacks_set_on_header_callback()`. - * - * .. warning:: - * - * Application should properly limit the total buffer size to store - * incoming header fields. Without it, peer may send large number - * of header fields or large header fields to cause out of memory in - * local endpoint. Due to how HPACK works, peer can do this - * effectively without using much memory on their own. - */ -typedef int (*nghttp2_on_header_callback)(nghttp2_session *session, - const nghttp2_frame *frame, - const uint8_t *name, size_t namelen, - const uint8_t *value, size_t valuelen, - uint8_t flags, void *user_data); - -/** - * @functypedef - * - * Callback function invoked when a header name/value pair is received - * for the |frame|. The |name| is header name. The |value| is header - * value. The |flags| is bitwise OR of one or more of - * :type:`nghttp2_nv_flag`. - * - * This callback behaves like :type:`nghttp2_on_header_callback`, - * except that |name| and |value| are stored in reference counted - * buffer. If application wishes to keep these references without - * copying them, use `nghttp2_rcbuf_incref()` to increment their - * reference count. It is the application's responsibility to call - * `nghttp2_rcbuf_decref()` if they called `nghttp2_rcbuf_incref()` so - * as not to leak memory. If the |session| is created by - * `nghttp2_session_server_new3()` or `nghttp2_session_client_new3()`, - * the function to free memory is the one belongs to the mem - * parameter. As long as this free function alives, |name| and - * |value| can live after |session| was destroyed. - */ -typedef int (*nghttp2_on_header_callback2)(nghttp2_session *session, - const nghttp2_frame *frame, - nghttp2_rcbuf *name, - nghttp2_rcbuf *value, uint8_t flags, - void *user_data); - -/** - * @functypedef - * - * Callback function invoked when a invalid header name/value pair is - * received for the |frame|. - * - * The parameter and behaviour are similar to - * :type:`nghttp2_on_header_callback`. The difference is that this - * callback is only invoked when a invalid header name/value pair is - * received which is treated as stream error if this callback is not - * set. Only invalid regular header field are passed to this - * callback. In other words, invalid pseudo header field is not - * passed to this callback. Also header fields which includes upper - * cased latter are also treated as error without passing them to this - * callback. - * - * This callback is only considered if HTTP messaging validation is - * turned on (which is on by default, see - * `nghttp2_option_set_no_http_messaging()`). - * - * With this callback, application inspects the incoming invalid - * field, and it also can reset stream from this callback by returning - * :enum:`nghttp2_error.NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE`. By - * default, the error code is - * :enum:`nghttp2_error_code.NGHTTP2_PROTOCOL_ERROR`. To change the - * error code, call `nghttp2_submit_rst_stream()` with the error code - * of choice in addition to returning - * :enum:`nghttp2_error.NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE`. - * - * If 0 is returned, the header field is ignored, and the stream is - * not reset. - */ -typedef int (*nghttp2_on_invalid_header_callback)( - nghttp2_session *session, const nghttp2_frame *frame, const uint8_t *name, - size_t namelen, const uint8_t *value, size_t valuelen, uint8_t flags, - void *user_data); - -/** - * @functypedef - * - * Callback function invoked when a invalid header name/value pair is - * received for the |frame|. - * - * The parameter and behaviour are similar to - * :type:`nghttp2_on_header_callback2`. The difference is that this - * callback is only invoked when a invalid header name/value pair is - * received which is silently ignored if this callback is not set. - * Only invalid regular header field are passed to this callback. In - * other words, invalid pseudo header field is not passed to this - * callback. Also header fields which includes upper cased latter are - * also treated as error without passing them to this callback. - * - * This callback is only considered if HTTP messaging validation is - * turned on (which is on by default, see - * `nghttp2_option_set_no_http_messaging()`). - * - * With this callback, application inspects the incoming invalid - * field, and it also can reset stream from this callback by returning - * :enum:`nghttp2_error.NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE`. By - * default, the error code is - * :enum:`nghttp2_error_code.NGHTTP2_INTERNAL_ERROR`. To change the - * error code, call `nghttp2_submit_rst_stream()` with the error code - * of choice in addition to returning - * :enum:`nghttp2_error.NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE`. - */ -typedef int (*nghttp2_on_invalid_header_callback2)( - nghttp2_session *session, const nghttp2_frame *frame, nghttp2_rcbuf *name, - nghttp2_rcbuf *value, uint8_t flags, void *user_data); - -#ifndef NGHTTP2_NO_SSIZE_T -/** - * @functypedef - * - * .. warning:: - * - * Deprecated. Use :type:`nghttp2_select_padding_callback2` - * instead. - * - * Callback function invoked when the library asks application how - * many padding bytes are required for the transmission of the - * |frame|. The application must choose the total length of payload - * including padded bytes in range [frame->hd.length, max_payloadlen], - * inclusive. Choosing number not in this range will be treated as - * :enum:`nghttp2_error.NGHTTP2_ERR_CALLBACK_FAILURE`. Returning - * ``frame->hd.length`` means no padding is added. Returning - * :enum:`nghttp2_error.NGHTTP2_ERR_CALLBACK_FAILURE` will make - * `nghttp2_session_send()` and `nghttp2_session_mem_send()` functions - * immediately return - * :enum:`nghttp2_error.NGHTTP2_ERR_CALLBACK_FAILURE`. - * - * To set this callback to :type:`nghttp2_session_callbacks`, use - * `nghttp2_session_callbacks_set_select_padding_callback()`. - */ -typedef ssize_t (*nghttp2_select_padding_callback)(nghttp2_session *session, - const nghttp2_frame *frame, - size_t max_payloadlen, - void *user_data); - -#endif /* NGHTTP2_NO_SSIZE_T */ - -/** - * @functypedef - * - * Callback function invoked when the library asks application how - * many padding bytes are required for the transmission of the - * |frame|. The application must choose the total length of payload - * including padded bytes in range [frame->hd.length, max_payloadlen], - * inclusive. Choosing number not in this range will be treated as - * :enum:`nghttp2_error.NGHTTP2_ERR_CALLBACK_FAILURE`. Returning - * ``frame->hd.length`` means no padding is added. Returning - * :enum:`nghttp2_error.NGHTTP2_ERR_CALLBACK_FAILURE` will make - * `nghttp2_session_send()` and `nghttp2_session_mem_send2()` - * functions immediately return - * :enum:`nghttp2_error.NGHTTP2_ERR_CALLBACK_FAILURE`. - * - * To set this callback to :type:`nghttp2_session_callbacks`, use - * `nghttp2_session_callbacks_set_select_padding_callback2()`. - */ -typedef nghttp2_ssize (*nghttp2_select_padding_callback2)( - nghttp2_session *session, const nghttp2_frame *frame, size_t max_payloadlen, - void *user_data); - -#ifndef NGHTTP2_NO_SSIZE_T -/** - * @functypedef - * - * .. warning:: - * - * Deprecated. Use - * :type:`nghttp2_data_source_read_length_callback2` instead. - * - * Callback function invoked when library wants to get max length of - * data to send data to the remote peer. The implementation of this - * function should return a value in the following range. [1, - * min(|session_remote_window_size|, |stream_remote_window_size|, - * |remote_max_frame_size|)]. If a value greater than this range is - * returned than the max allow value will be used. Returning a value - * smaller than this range is treated as - * :enum:`nghttp2_error.NGHTTP2_ERR_CALLBACK_FAILURE`. The - * |frame_type| is provided for future extensibility and identifies - * the type of frame (see :type:`nghttp2_frame_type`) for which to get - * the length for. Currently supported frame types are: - * :enum:`nghttp2_frame_type.NGHTTP2_DATA`. - * - * This callback can be used to control the length in bytes for which - * :type:`nghttp2_data_source_read_callback` is allowed to send to the - * remote endpoint. This callback is optional. Returning - * :enum:`nghttp2_error.NGHTTP2_ERR_CALLBACK_FAILURE` will signal the - * entire session failure. - * - * To set this callback to :type:`nghttp2_session_callbacks`, use - * `nghttp2_session_callbacks_set_data_source_read_length_callback()`. - */ -typedef ssize_t (*nghttp2_data_source_read_length_callback)( - nghttp2_session *session, uint8_t frame_type, int32_t stream_id, - int32_t session_remote_window_size, int32_t stream_remote_window_size, - uint32_t remote_max_frame_size, void *user_data); - -#endif /* NGHTTP2_NO_SSIZE_T */ - -/** - * @functypedef - * - * Callback function invoked when library wants to get max length of - * data to send data to the remote peer. The implementation of this - * function should return a value in the following range. [1, - * min(|session_remote_window_size|, |stream_remote_window_size|, - * |remote_max_frame_size|)]. If a value greater than this range is - * returned than the max allow value will be used. Returning a value - * smaller than this range is treated as - * :enum:`nghttp2_error.NGHTTP2_ERR_CALLBACK_FAILURE`. The - * |frame_type| is provided for future extensibility and identifies - * the type of frame (see :type:`nghttp2_frame_type`) for which to get - * the length for. Currently supported frame types are: - * :enum:`nghttp2_frame_type.NGHTTP2_DATA`. - * - * This callback can be used to control the length in bytes for which - * :type:`nghttp2_data_source_read_callback` is allowed to send to the - * remote endpoint. This callback is optional. Returning - * :enum:`nghttp2_error.NGHTTP2_ERR_CALLBACK_FAILURE` will signal the - * entire session failure. - * - * To set this callback to :type:`nghttp2_session_callbacks`, use - * `nghttp2_session_callbacks_set_data_source_read_length_callback2()`. - */ -typedef nghttp2_ssize (*nghttp2_data_source_read_length_callback2)( - nghttp2_session *session, uint8_t frame_type, int32_t stream_id, - int32_t session_remote_window_size, int32_t stream_remote_window_size, - uint32_t remote_max_frame_size, void *user_data); - -/** - * @functypedef - * - * Callback function invoked when a frame header is received. The - * |hd| points to received frame header. - * - * Unlike :type:`nghttp2_on_frame_recv_callback`, this callback will - * also be called when frame header of CONTINUATION frame is received. - * - * If both :type:`nghttp2_on_begin_frame_callback` and - * :type:`nghttp2_on_begin_headers_callback` are set and HEADERS or - * PUSH_PROMISE is received, :type:`nghttp2_on_begin_frame_callback` - * will be called first. - * - * The implementation of this function must return 0 if it succeeds. - * If nonzero value is returned, it is treated as fatal error and - * `nghttp2_session_recv()` and `nghttp2_session_mem_recv2()` - * functions immediately return - * :enum:`nghttp2_error.NGHTTP2_ERR_CALLBACK_FAILURE`. - * - * To set this callback to :type:`nghttp2_session_callbacks`, use - * `nghttp2_session_callbacks_set_on_begin_frame_callback()`. - */ -typedef int (*nghttp2_on_begin_frame_callback)(nghttp2_session *session, - const nghttp2_frame_hd *hd, - void *user_data); - -/** - * @functypedef - * - * Callback function invoked when chunk of extension frame payload is - * received. The |hd| points to frame header. The received - * chunk is |data| of length |len|. - * - * The implementation of this function must return 0 if it succeeds. - * - * To abort processing this extension frame, return - * :enum:`nghttp2_error.NGHTTP2_ERR_CANCEL`. - * - * If fatal error occurred, application should return - * :enum:`nghttp2_error.NGHTTP2_ERR_CALLBACK_FAILURE`. In this case, - * `nghttp2_session_recv()` and `nghttp2_session_mem_recv2()` - * functions immediately return - * :enum:`nghttp2_error.NGHTTP2_ERR_CALLBACK_FAILURE`. If the other - * values are returned, currently they are treated as - * :enum:`nghttp2_error.NGHTTP2_ERR_CALLBACK_FAILURE`. - */ -typedef int (*nghttp2_on_extension_chunk_recv_callback)( - nghttp2_session *session, const nghttp2_frame_hd *hd, const uint8_t *data, - size_t len, void *user_data); - -/** - * @functypedef - * - * Callback function invoked when library asks the application to - * unpack extension payload from its wire format. The extension - * payload has been passed to the application using - * :type:`nghttp2_on_extension_chunk_recv_callback`. The frame header - * is already unpacked by the library and provided as |hd|. - * - * To receive extension frames, the application must tell desired - * extension frame type to the library using - * `nghttp2_option_set_user_recv_extension_type()`. - * - * The implementation of this function may store the pointer to the - * created object as a result of unpacking in |*payload|, and returns - * 0. The pointer stored in |*payload| is opaque to the library, and - * the library does not own its pointer. |*payload| is initialized as - * ``NULL``. The |*payload| is available as ``frame->ext.payload`` in - * :type:`nghttp2_on_frame_recv_callback`. Therefore if application - * can free that memory inside :type:`nghttp2_on_frame_recv_callback` - * callback. Of course, application has a liberty not to use - * |*payload|, and do its own mechanism to process extension frames. - * - * To abort processing this extension frame, return - * :enum:`nghttp2_error.NGHTTP2_ERR_CANCEL`. - * - * If fatal error occurred, application should return - * :enum:`nghttp2_error.NGHTTP2_ERR_CALLBACK_FAILURE`. In this case, - * `nghttp2_session_recv()` and `nghttp2_session_mem_recv2()` - * functions immediately return - * :enum:`nghttp2_error.NGHTTP2_ERR_CALLBACK_FAILURE`. If the other - * values are returned, currently they are treated as - * :enum:`nghttp2_error.NGHTTP2_ERR_CALLBACK_FAILURE`. - */ -typedef int (*nghttp2_unpack_extension_callback)(nghttp2_session *session, - void **payload, - const nghttp2_frame_hd *hd, - void *user_data); - -#ifndef NGHTTP2_NO_SSIZE_T -/** - * @functypedef - * - * .. warning:: - * - * Deprecated. Use :type:`nghttp2_pack_extension_callback2` - * instead. - * - * Callback function invoked when library asks the application to pack - * extension payload in its wire format. The frame header will be - * packed by library. Application must pack payload only. - * ``frame->ext.payload`` is the object passed to - * `nghttp2_submit_extension()` as payload parameter. Application - * must pack extension payload to the |buf| of its capacity |len| - * bytes. The |len| is at least 16KiB. - * - * The implementation of this function should return the number of - * bytes written into |buf| when it succeeds. - * - * To abort processing this extension frame, return - * :enum:`nghttp2_error.NGHTTP2_ERR_CANCEL`, and - * :type:`nghttp2_on_frame_not_send_callback` will be invoked. - * - * If fatal error occurred, application should return - * :enum:`nghttp2_error.NGHTTP2_ERR_CALLBACK_FAILURE`. In this case, - * `nghttp2_session_send()` and `nghttp2_session_mem_send()` functions - * immediately return - * :enum:`nghttp2_error.NGHTTP2_ERR_CALLBACK_FAILURE`. If the other - * values are returned, currently they are treated as - * :enum:`nghttp2_error.NGHTTP2_ERR_CALLBACK_FAILURE`. If the return - * value is strictly larger than |len|, it is treated as - * :enum:`nghttp2_error.NGHTTP2_ERR_CALLBACK_FAILURE`. - */ -typedef ssize_t (*nghttp2_pack_extension_callback)(nghttp2_session *session, - uint8_t *buf, size_t len, - const nghttp2_frame *frame, - void *user_data); - -#endif /* NGHTTP2_NO_SSIZE_T */ - -/** - * @functypedef - * - * Callback function invoked when library asks the application to pack - * extension payload in its wire format. The frame header will be - * packed by library. Application must pack payload only. - * ``frame->ext.payload`` is the object passed to - * `nghttp2_submit_extension()` as payload parameter. Application - * must pack extension payload to the |buf| of its capacity |len| - * bytes. The |len| is at least 16KiB. - * - * The implementation of this function should return the number of - * bytes written into |buf| when it succeeds. - * - * To abort processing this extension frame, return - * :enum:`nghttp2_error.NGHTTP2_ERR_CANCEL`, and - * :type:`nghttp2_on_frame_not_send_callback` will be invoked. - * - * If fatal error occurred, application should return - * :enum:`nghttp2_error.NGHTTP2_ERR_CALLBACK_FAILURE`. In this case, - * `nghttp2_session_send()` and `nghttp2_session_mem_send2()` - * functions immediately return - * :enum:`nghttp2_error.NGHTTP2_ERR_CALLBACK_FAILURE`. If the other - * values are returned, currently they are treated as - * :enum:`nghttp2_error.NGHTTP2_ERR_CALLBACK_FAILURE`. If the return - * value is strictly larger than |len|, it is treated as - * :enum:`nghttp2_error.NGHTTP2_ERR_CALLBACK_FAILURE`. - */ -typedef nghttp2_ssize (*nghttp2_pack_extension_callback2)( - nghttp2_session *session, uint8_t *buf, size_t len, - const nghttp2_frame *frame, void *user_data); - -/** - * @functypedef - * - * .. warning:: - * - * Deprecated. Use :type:`nghttp2_error_callback2` instead. - * - * Callback function invoked when library provides the error message - * intended for human consumption. This callback is solely for - * debugging purpose. The |msg| is typically NULL-terminated string - * of length |len|. |len| does not include the sentinel NULL - * character. - * - * The format of error message may change between nghttp2 library - * versions. The application should not depend on the particular - * format. - * - * Normally, application should return 0 from this callback. If fatal - * error occurred while doing something in this callback, application - * should return :enum:`nghttp2_error.NGHTTP2_ERR_CALLBACK_FAILURE`. - * In this case, library will return immediately with return value - * :enum:`nghttp2_error.NGHTTP2_ERR_CALLBACK_FAILURE`. Currently, if - * nonzero value is returned from this callback, they are treated as - * :enum:`nghttp2_error.NGHTTP2_ERR_CALLBACK_FAILURE`, but application - * should not rely on this details. - */ -typedef int (*nghttp2_error_callback)(nghttp2_session *session, const char *msg, - size_t len, void *user_data); - -/** - * @functypedef - * - * Callback function invoked when library provides the error code, and - * message. This callback is solely for debugging purpose. - * |lib_error_code| is one of error code defined in - * :enum:`nghttp2_error`. The |msg| is typically NULL-terminated - * string of length |len|, and intended for human consumption. |len| - * does not include the sentinel NULL character. - * - * The format of error message may change between nghttp2 library - * versions. The application should not depend on the particular - * format. - * - * Normally, application should return 0 from this callback. If fatal - * error occurred while doing something in this callback, application - * should return :enum:`nghttp2_error.NGHTTP2_ERR_CALLBACK_FAILURE`. - * In this case, library will return immediately with return value - * :enum:`nghttp2_error.NGHTTP2_ERR_CALLBACK_FAILURE`. Currently, if - * nonzero value is returned from this callback, they are treated as - * :enum:`nghttp2_error.NGHTTP2_ERR_CALLBACK_FAILURE`, but application - * should not rely on this details. - */ -typedef int (*nghttp2_error_callback2)(nghttp2_session *session, - int lib_error_code, const char *msg, - size_t len, void *user_data); - -struct nghttp2_session_callbacks; - -/** - * @struct - * - * Callback functions for :type:`nghttp2_session`. The details of - * this structure are intentionally hidden from the public API. - */ -typedef struct nghttp2_session_callbacks nghttp2_session_callbacks; - -/** - * @function - * - * Initializes |*callbacks_ptr| with NULL values. - * - * The initialized object can be used when initializing multiple - * :type:`nghttp2_session` objects. - * - * When the application finished using this object, it can use - * `nghttp2_session_callbacks_del()` to free its memory. - * - * This function returns 0 if it succeeds, or one of the following - * negative error codes: - * - * :enum:`nghttp2_error.NGHTTP2_ERR_NOMEM` - * Out of memory. - */ -NGHTTP2_EXTERN int -nghttp2_session_callbacks_new(nghttp2_session_callbacks **callbacks_ptr); - -/** - * @function - * - * Frees any resources allocated for |callbacks|. If |callbacks| is - * ``NULL``, this function does nothing. - */ -NGHTTP2_EXTERN void -nghttp2_session_callbacks_del(nghttp2_session_callbacks *callbacks); - -#ifndef NGHTTP2_NO_SSIZE_T -/** - * @function - * - * .. warning:: - * - * Deprecated. Use `nghttp2_session_callbacks_set_send_callback2()` - * with :type:`nghttp2_send_callback2` instead. - * - * Sets callback function invoked when a session wants to send data to - * the remote peer. This callback is not necessary if the application - * uses solely `nghttp2_session_mem_send()` to serialize data to - * transmit. - */ -NGHTTP2_EXTERN void nghttp2_session_callbacks_set_send_callback( - nghttp2_session_callbacks *cbs, nghttp2_send_callback send_callback); - -#endif /* NGHTTP2_NO_SSIZE_T */ - -/** - * @function - * - * Sets callback function invoked when a session wants to send data to - * the remote peer. This callback is not necessary if the application - * uses solely `nghttp2_session_mem_send2()` to serialize data to - * transmit. - */ -NGHTTP2_EXTERN void nghttp2_session_callbacks_set_send_callback2( - nghttp2_session_callbacks *cbs, nghttp2_send_callback2 send_callback); - -#ifndef NGHTTP2_NO_SSIZE_T -/** - * @function - * - * .. warning:: - * - * Deprecated. Use `nghttp2_session_callbacks_set_recv_callback2()` - * with :type:`nghttp2_recv_callback2` instead. - * - * Sets callback function invoked when the a session wants to receive - * data from the remote peer. This callback is not necessary if the - * application uses solely `nghttp2_session_mem_recv()` to process - * received data. - */ -NGHTTP2_EXTERN void nghttp2_session_callbacks_set_recv_callback( - nghttp2_session_callbacks *cbs, nghttp2_recv_callback recv_callback); - -#endif /* NGHTTP2_NO_SSIZE_T */ - -/** - * @function - * - * Sets callback function invoked when the a session wants to receive - * data from the remote peer. This callback is not necessary if the - * application uses solely `nghttp2_session_mem_recv2()` to process - * received data. - */ -NGHTTP2_EXTERN void nghttp2_session_callbacks_set_recv_callback2( - nghttp2_session_callbacks *cbs, nghttp2_recv_callback2 recv_callback); - -/** - * @function - * - * Sets callback function invoked by `nghttp2_session_recv()` and - * `nghttp2_session_mem_recv2()` when a frame is received. - */ -NGHTTP2_EXTERN void nghttp2_session_callbacks_set_on_frame_recv_callback( - nghttp2_session_callbacks *cbs, - nghttp2_on_frame_recv_callback on_frame_recv_callback); - -/** - * @function - * - * Sets callback function invoked by `nghttp2_session_recv()` and - * `nghttp2_session_mem_recv2()` when an invalid non-DATA frame is - * received. - */ -NGHTTP2_EXTERN void -nghttp2_session_callbacks_set_on_invalid_frame_recv_callback( - nghttp2_session_callbacks *cbs, - nghttp2_on_invalid_frame_recv_callback on_invalid_frame_recv_callback); - -/** - * @function - * - * Sets callback function invoked when a chunk of data in DATA frame - * is received. - */ -NGHTTP2_EXTERN void nghttp2_session_callbacks_set_on_data_chunk_recv_callback( - nghttp2_session_callbacks *cbs, - nghttp2_on_data_chunk_recv_callback on_data_chunk_recv_callback); - -/** - * @function - * - * Sets callback function invoked before a non-DATA frame is sent. - */ -NGHTTP2_EXTERN void nghttp2_session_callbacks_set_before_frame_send_callback( - nghttp2_session_callbacks *cbs, - nghttp2_before_frame_send_callback before_frame_send_callback); - -/** - * @function - * - * Sets callback function invoked after a frame is sent. - */ -NGHTTP2_EXTERN void nghttp2_session_callbacks_set_on_frame_send_callback( - nghttp2_session_callbacks *cbs, - nghttp2_on_frame_send_callback on_frame_send_callback); - -/** - * @function - * - * Sets callback function invoked when a non-DATA frame is not sent - * because of an error. - */ -NGHTTP2_EXTERN void nghttp2_session_callbacks_set_on_frame_not_send_callback( - nghttp2_session_callbacks *cbs, - nghttp2_on_frame_not_send_callback on_frame_not_send_callback); - -/** - * @function - * - * Sets callback function invoked when the stream is closed. - */ -NGHTTP2_EXTERN void nghttp2_session_callbacks_set_on_stream_close_callback( - nghttp2_session_callbacks *cbs, - nghttp2_on_stream_close_callback on_stream_close_callback); - -/** - * @function - * - * Sets callback function invoked when the reception of header block - * in HEADERS or PUSH_PROMISE is started. - */ -NGHTTP2_EXTERN void nghttp2_session_callbacks_set_on_begin_headers_callback( - nghttp2_session_callbacks *cbs, - nghttp2_on_begin_headers_callback on_begin_headers_callback); - -/** - * @function - * - * Sets callback function invoked when a header name/value pair is - * received. If both - * `nghttp2_session_callbacks_set_on_header_callback()` and - * `nghttp2_session_callbacks_set_on_header_callback2()` are used to - * set callbacks, the latter has the precedence. - */ -NGHTTP2_EXTERN void nghttp2_session_callbacks_set_on_header_callback( - nghttp2_session_callbacks *cbs, - nghttp2_on_header_callback on_header_callback); - -/** - * @function - * - * Sets callback function invoked when a header name/value pair is - * received. - */ -NGHTTP2_EXTERN void nghttp2_session_callbacks_set_on_header_callback2( - nghttp2_session_callbacks *cbs, - nghttp2_on_header_callback2 on_header_callback2); - -/** - * @function - * - * Sets callback function invoked when a invalid header name/value - * pair is received. If both - * `nghttp2_session_callbacks_set_on_invalid_header_callback()` and - * `nghttp2_session_callbacks_set_on_invalid_header_callback2()` are - * used to set callbacks, the latter takes the precedence. - */ -NGHTTP2_EXTERN void nghttp2_session_callbacks_set_on_invalid_header_callback( - nghttp2_session_callbacks *cbs, - nghttp2_on_invalid_header_callback on_invalid_header_callback); - -/** - * @function - * - * Sets callback function invoked when a invalid header name/value - * pair is received. - */ -NGHTTP2_EXTERN void nghttp2_session_callbacks_set_on_invalid_header_callback2( - nghttp2_session_callbacks *cbs, - nghttp2_on_invalid_header_callback2 on_invalid_header_callback2); - -#ifndef NGHTTP2_NO_SSIZE_T -/** - * @function - * - * .. warning:: - * - * Deprecated. Use - * `nghttp2_session_callbacks_set_select_padding_callback2()` with - * :type:`nghttp2_select_padding_callback2` instead. - * - * Sets callback function invoked when the library asks application - * how many padding bytes are required for the transmission of the - * given frame. - */ -NGHTTP2_EXTERN void nghttp2_session_callbacks_set_select_padding_callback( - nghttp2_session_callbacks *cbs, - nghttp2_select_padding_callback select_padding_callback); - -#endif /* NGHTTP2_NO_SSIZE_T */ - -/** - * @function - * - * Sets callback function invoked when the library asks application - * how many padding bytes are required for the transmission of the - * given frame. - */ -NGHTTP2_EXTERN void nghttp2_session_callbacks_set_select_padding_callback2( - nghttp2_session_callbacks *cbs, - nghttp2_select_padding_callback2 select_padding_callback); - -#ifndef NGHTTP2_NO_SSIZE_T -/** - * @function - * - * .. warning:: - * - * Deprecated. Use - * `nghttp2_session_callbacks_set_data_source_read_length_callback2()` - * with :type:`nghttp2_data_source_read_length_callback2` instead. - * - * Sets callback function determine the length allowed in - * :type:`nghttp2_data_source_read_callback`. - */ -NGHTTP2_EXTERN void -nghttp2_session_callbacks_set_data_source_read_length_callback( - nghttp2_session_callbacks *cbs, - nghttp2_data_source_read_length_callback data_source_read_length_callback); - -#endif /* NGHTTP2_NO_SSIZE_T */ - -/** - * @function - * - * Sets callback function determine the length allowed in - * :type:`nghttp2_data_source_read_callback2`. - */ -NGHTTP2_EXTERN void -nghttp2_session_callbacks_set_data_source_read_length_callback2( - nghttp2_session_callbacks *cbs, - nghttp2_data_source_read_length_callback2 data_source_read_length_callback); - -/** - * @function - * - * Sets callback function invoked when a frame header is received. - */ -NGHTTP2_EXTERN void nghttp2_session_callbacks_set_on_begin_frame_callback( - nghttp2_session_callbacks *cbs, - nghttp2_on_begin_frame_callback on_begin_frame_callback); - -/** - * @function - * - * Sets callback function invoked when - * :enum:`nghttp2_data_flag.NGHTTP2_DATA_FLAG_NO_COPY` is used in - * :type:`nghttp2_data_source_read_callback2` to avoid data copy. - */ -NGHTTP2_EXTERN void nghttp2_session_callbacks_set_send_data_callback( - nghttp2_session_callbacks *cbs, - nghttp2_send_data_callback send_data_callback); - -#ifndef NGHTTP2_NO_SSIZE_T -/** - * @function - * - * .. warning:: - * - * Deprecated. Use - * `nghttp2_session_callbacks_set_pack_extension_callback2()` with - * :type:`nghttp2_pack_extension_callback2` instead. - * - * Sets callback function invoked when the library asks the - * application to pack extension frame payload in wire format. - */ -NGHTTP2_EXTERN void nghttp2_session_callbacks_set_pack_extension_callback( - nghttp2_session_callbacks *cbs, - nghttp2_pack_extension_callback pack_extension_callback); - -#endif /* NGHTTP2_NO_SSIZE_T */ - -/** - * @function - * - * Sets callback function invoked when the library asks the - * application to pack extension frame payload in wire format. - */ -NGHTTP2_EXTERN void nghttp2_session_callbacks_set_pack_extension_callback2( - nghttp2_session_callbacks *cbs, - nghttp2_pack_extension_callback2 pack_extension_callback); - -/** - * @function - * - * Sets callback function invoked when the library asks the - * application to unpack extension frame payload from wire format. - */ -NGHTTP2_EXTERN void nghttp2_session_callbacks_set_unpack_extension_callback( - nghttp2_session_callbacks *cbs, - nghttp2_unpack_extension_callback unpack_extension_callback); - -/** - * @function - * - * Sets callback function invoked when chunk of extension frame - * payload is received. - */ -NGHTTP2_EXTERN void -nghttp2_session_callbacks_set_on_extension_chunk_recv_callback( - nghttp2_session_callbacks *cbs, - nghttp2_on_extension_chunk_recv_callback on_extension_chunk_recv_callback); - -/** - * @function - * - * .. warning:: - * - * Deprecated. Use - * `nghttp2_session_callbacks_set_error_callback2()` with - * :type:`nghttp2_error_callback2` instead. - * - * Sets callback function invoked when library tells error message to - * the application. - * - * If both :type:`nghttp2_error_callback` and - * :type:`nghttp2_error_callback2` are set, the latter takes - * precedence. - */ -NGHTTP2_EXTERN void nghttp2_session_callbacks_set_error_callback( - nghttp2_session_callbacks *cbs, nghttp2_error_callback error_callback); - -/** - * @function - * - * Sets callback function invoked when library tells error code, and - * message to the application. - * - * If both :type:`nghttp2_error_callback` and - * :type:`nghttp2_error_callback2` are set, the latter takes - * precedence. - */ -NGHTTP2_EXTERN void nghttp2_session_callbacks_set_error_callback2( - nghttp2_session_callbacks *cbs, nghttp2_error_callback2 error_callback2); - -/** - * @functypedef - * - * Custom memory allocator to replace malloc(). The |mem_user_data| - * is the mem_user_data member of :type:`nghttp2_mem` structure. - */ -typedef void *(*nghttp2_malloc)(size_t size, void *mem_user_data); - -/** - * @functypedef - * - * Custom memory allocator to replace free(). The |mem_user_data| is - * the mem_user_data member of :type:`nghttp2_mem` structure. - */ -typedef void (*nghttp2_free)(void *ptr, void *mem_user_data); - -/** - * @functypedef - * - * Custom memory allocator to replace calloc(). The |mem_user_data| - * is the mem_user_data member of :type:`nghttp2_mem` structure. - */ -typedef void *(*nghttp2_calloc)(size_t nmemb, size_t size, void *mem_user_data); - -/** - * @functypedef - * - * Custom memory allocator to replace realloc(). The |mem_user_data| - * is the mem_user_data member of :type:`nghttp2_mem` structure. - */ -typedef void *(*nghttp2_realloc)(void *ptr, size_t size, void *mem_user_data); - -/** - * @struct - * - * Custom memory allocator functions and user defined pointer. The - * |mem_user_data| member is passed to each allocator function. This - * can be used, for example, to achieve per-session memory pool. - * - * In the following example code, ``my_malloc``, ``my_free``, - * ``my_calloc`` and ``my_realloc`` are the replacement of the - * standard allocators ``malloc``, ``free``, ``calloc`` and - * ``realloc`` respectively:: - * - * void *my_malloc_cb(size_t size, void *mem_user_data) { - * return my_malloc(size); - * } - * - * void my_free_cb(void *ptr, void *mem_user_data) { my_free(ptr); } - * - * void *my_calloc_cb(size_t nmemb, size_t size, void *mem_user_data) { - * return my_calloc(nmemb, size); - * } - * - * void *my_realloc_cb(void *ptr, size_t size, void *mem_user_data) { - * return my_realloc(ptr, size); - * } - * - * void session_new() { - * nghttp2_session *session; - * nghttp2_session_callbacks *callbacks; - * nghttp2_mem mem = {NULL, my_malloc_cb, my_free_cb, my_calloc_cb, - * my_realloc_cb}; - * - * ... - * - * nghttp2_session_client_new3(&session, callbacks, NULL, NULL, &mem); - * - * ... - * } - */ -typedef struct { - /** - * An arbitrary user supplied data. This is passed to each - * allocator function. - */ - void *mem_user_data; - /** - * Custom allocator function to replace malloc(). - */ - nghttp2_malloc malloc; - /** - * Custom allocator function to replace free(). - */ - nghttp2_free free; - /** - * Custom allocator function to replace calloc(). - */ - nghttp2_calloc calloc; - /** - * Custom allocator function to replace realloc(). - */ - nghttp2_realloc realloc; -} nghttp2_mem; - -struct nghttp2_option; - -/** - * @struct - * - * Configuration options for :type:`nghttp2_session`. The details of - * this structure are intentionally hidden from the public API. - */ -typedef struct nghttp2_option nghttp2_option; - -/** - * @function - * - * Initializes |*option_ptr| with default values. - * - * When the application finished using this object, it can use - * `nghttp2_option_del()` to free its memory. - * - * This function returns 0 if it succeeds, or one of the following - * negative error codes: - * - * :enum:`nghttp2_error.NGHTTP2_ERR_NOMEM` - * Out of memory. - */ -NGHTTP2_EXTERN int nghttp2_option_new(nghttp2_option **option_ptr); - -/** - * @function - * - * Frees any resources allocated for |option|. If |option| is - * ``NULL``, this function does nothing. - */ -NGHTTP2_EXTERN void nghttp2_option_del(nghttp2_option *option); - -/** - * @function - * - * This option prevents the library from sending WINDOW_UPDATE for a - * connection automatically. If this option is set to nonzero, the - * library won't send WINDOW_UPDATE for DATA until application calls - * `nghttp2_session_consume()` to indicate the consumed amount of - * data. Don't use `nghttp2_submit_window_update()` for this purpose. - * By default, this option is set to zero. - */ -NGHTTP2_EXTERN void -nghttp2_option_set_no_auto_window_update(nghttp2_option *option, int val); - -/** - * @function - * - * This option sets the SETTINGS_MAX_CONCURRENT_STREAMS value of - * remote endpoint as if it is received in SETTINGS frame. Without - * specifying this option, the maximum number of outgoing concurrent - * streams is initially limited to 100 to avoid issues when the local - * endpoint submits lots of requests before receiving initial SETTINGS - * frame from the remote endpoint, since sending them at once to the - * remote endpoint could lead to rejection of some of the requests. - * This value will be overwritten when the local endpoint receives - * initial SETTINGS frame from the remote endpoint, either to the - * value advertised in SETTINGS_MAX_CONCURRENT_STREAMS or to the - * default value (unlimited) if none was advertised. - */ -NGHTTP2_EXTERN void -nghttp2_option_set_peer_max_concurrent_streams(nghttp2_option *option, - uint32_t val); - -/** - * @function - * - * By default, nghttp2 library, if configured as server, requires - * first 24 bytes of client magic byte string (MAGIC). In most cases, - * this will simplify the implementation of server. But sometimes - * server may want to detect the application protocol based on first - * few bytes on clear text communication. - * - * If this option is used with nonzero |val|, nghttp2 library does not - * handle MAGIC. It still checks following SETTINGS frame. This - * means that applications should deal with MAGIC by themselves. - * - * If this option is not used or used with zero value, if MAGIC does - * not match :macro:`NGHTTP2_CLIENT_MAGIC`, `nghttp2_session_recv()` - * and `nghttp2_session_mem_recv2()` will return error - * :enum:`nghttp2_error.NGHTTP2_ERR_BAD_CLIENT_MAGIC`, which is fatal - * error. - */ -NGHTTP2_EXTERN void -nghttp2_option_set_no_recv_client_magic(nghttp2_option *option, int val); - -/** - * @function - * - * By default, nghttp2 library enforces subset of HTTP Messaging rules - * described in `HTTP/2 specification, section 8 - * `_. See - * :ref:`http-messaging` section for details. For those applications - * who use nghttp2 library as non-HTTP use, give nonzero to |val| to - * disable this enforcement. Please note that disabling this feature - * does not change the fundamental client and server model of HTTP. - * That is, even if the validation is disabled, only client can send - * requests. - */ -NGHTTP2_EXTERN void nghttp2_option_set_no_http_messaging(nghttp2_option *option, - int val); - -/** - * @function - * - * RFC 7540 does not enforce any limit on the number of incoming - * reserved streams (in RFC 7540 terms, streams in reserved (remote) - * state). This only affects client side, since only server can push - * streams. Malicious server can push arbitrary number of streams, - * and make client's memory exhausted. This option can set the - * maximum number of such incoming streams to avoid possible memory - * exhaustion. If this option is set, and pushed streams are - * automatically closed on reception, without calling user provided - * callback, if they exceed the given limit. The default value is - * 200. If session is configured as server side, this option has no - * effect. Server can control the number of streams to push. - */ -NGHTTP2_EXTERN void -nghttp2_option_set_max_reserved_remote_streams(nghttp2_option *option, - uint32_t val); - -/** - * @function - * - * Sets extension frame type the application is willing to handle with - * user defined callbacks (see - * :type:`nghttp2_on_extension_chunk_recv_callback` and - * :type:`nghttp2_unpack_extension_callback`). The |type| is - * extension frame type, and must be strictly greater than 0x9. - * Otherwise, this function does nothing. The application can call - * this function multiple times to set more than one frame type to - * receive. The application does not have to call this function if it - * just sends extension frames. - */ -NGHTTP2_EXTERN void -nghttp2_option_set_user_recv_extension_type(nghttp2_option *option, - uint8_t type); - -/** - * @function - * - * Sets extension frame type the application is willing to receive - * using builtin handler. The |type| is the extension frame type to - * receive, and must be strictly greater than 0x9. Otherwise, this - * function does nothing. The application can call this function - * multiple times to set more than one frame type to receive. The - * application does not have to call this function if it just sends - * extension frames. - * - * If same frame type is passed to both - * `nghttp2_option_set_builtin_recv_extension_type()` and - * `nghttp2_option_set_user_recv_extension_type()`, the latter takes - * precedence. - */ -NGHTTP2_EXTERN void -nghttp2_option_set_builtin_recv_extension_type(nghttp2_option *option, - uint8_t type); - -/** - * @function - * - * This option prevents the library from sending PING frame with ACK - * flag set automatically when PING frame without ACK flag set is - * received. If this option is set to nonzero, the library won't send - * PING frame with ACK flag set in the response for incoming PING - * frame. The application can send PING frame with ACK flag set using - * `nghttp2_submit_ping()` with :enum:`nghttp2_flag.NGHTTP2_FLAG_ACK` - * as flags parameter. - */ -NGHTTP2_EXTERN void nghttp2_option_set_no_auto_ping_ack(nghttp2_option *option, - int val); - -/** - * @function - * - * This option sets the maximum length of header block (a set of - * header fields per one HEADERS frame) to send. The length of a - * given set of header fields is calculated using - * `nghttp2_hd_deflate_bound()`. The default value is 64KiB. If - * application attempts to send header fields larger than this limit, - * the transmission of the frame fails with error code - * :enum:`nghttp2_error.NGHTTP2_ERR_FRAME_SIZE_ERROR`. - */ -NGHTTP2_EXTERN void -nghttp2_option_set_max_send_header_block_length(nghttp2_option *option, - size_t val); - -/** - * @function - * - * This option sets the maximum dynamic table size for deflating - * header fields. The default value is 4KiB. In HTTP/2, receiver of - * deflated header block can specify maximum dynamic table size. The - * actual maximum size is the minimum of the size receiver specified - * and this option value. - */ -NGHTTP2_EXTERN void -nghttp2_option_set_max_deflate_dynamic_table_size(nghttp2_option *option, - size_t val); - -/** - * @function - * - * This option prevents the library from retaining closed streams to - * maintain the priority tree. If this option is set to nonzero, - * applications can discard closed stream completely to save memory. - * - * If - * :enum:`nghttp2_settings_id.NGHTTP2_SETTINGS_NO_RFC7540_PRIORITIES` - * of value of 1 is submitted via `nghttp2_submit_settings()`, any - * closed streams are not retained regardless of this option. - */ -NGHTTP2_EXTERN void nghttp2_option_set_no_closed_streams(nghttp2_option *option, - int val); - -/** - * @function - * - * This function sets the maximum number of outgoing SETTINGS ACK and - * PING ACK frames retained in :type:`nghttp2_session` object. If - * more than those frames are retained, the peer is considered to be - * misbehaving and session will be closed. The default value is 1000. - */ -NGHTTP2_EXTERN void nghttp2_option_set_max_outbound_ack(nghttp2_option *option, - size_t val); - -/** - * @function - * - * This function sets the maximum number of SETTINGS entries per - * SETTINGS frame that will be accepted. If more than those entries - * are received, the peer is considered to be misbehaving and session - * will be closed. The default value is 32. - */ -NGHTTP2_EXTERN void nghttp2_option_set_max_settings(nghttp2_option *option, - size_t val); - -/** - * @function - * - * This option, if set to nonzero, allows server to fallback to - * :rfc:`7540` priorities if SETTINGS_NO_RFC7540_PRIORITIES was not - * received from client, and server submitted - * :enum:`nghttp2_settings_id.NGHTTP2_SETTINGS_NO_RFC7540_PRIORITIES` - * = 1 via `nghttp2_submit_settings()`. Most of the advanced - * functionality for RFC 7540 priorities are still disabled. This - * fallback only enables the minimal feature set of RFC 7540 - * priorities to deal with priority signaling from client. - * - * Client session ignores this option. - */ -NGHTTP2_EXTERN void -nghttp2_option_set_server_fallback_rfc7540_priorities(nghttp2_option *option, - int val); - -/** - * @function - * - * This option, if set to nonzero, turns off RFC 9113 leading and - * trailing white spaces validation against HTTP field value. Some - * important fields, such as HTTP/2 pseudo header fields, are - * validated more strictly and this option does not apply to them. - */ -NGHTTP2_EXTERN void -nghttp2_option_set_no_rfc9113_leading_and_trailing_ws_validation( - nghttp2_option *option, int val); - -/** - * @function - * - * This function sets the rate limit for the incoming stream reset - * (RST_STREAM frame). It is server use only. It is a token-bucket - * based rate limiter. |burst| specifies the number of tokens that is - * initially available. The maximum number of tokens is capped to - * this value. |rate| specifies the number of tokens that are - * regenerated per second. An incoming RST_STREAM consumes one token. - * If there is no token available, GOAWAY is sent to tear down the - * connection. |burst| and |rate| default to 1000 and 33 - * respectively. - */ -NGHTTP2_EXTERN void -nghttp2_option_set_stream_reset_rate_limit(nghttp2_option *option, - uint64_t burst, uint64_t rate); - -/** - * @function - * - * This function sets the maximum number of CONTINUATION frames - * following an incoming HEADER frame. If more than those frames are - * received, the remote endpoint is considered to be misbehaving and - * session will be closed. The default value is 8. - */ -NGHTTP2_EXTERN void nghttp2_option_set_max_continuations(nghttp2_option *option, - size_t val); - -/** - * @function - * - * Initializes |*session_ptr| for client use. The all members of - * |callbacks| are copied to |*session_ptr|. Therefore |*session_ptr| - * does not store |callbacks|. The |user_data| is an arbitrary user - * supplied data, which will be passed to the callback functions. - * - * The :type:`nghttp2_send_callback2` must be specified. If the - * application code uses `nghttp2_session_recv()`, the - * :type:`nghttp2_recv_callback` must be specified. The other members - * of |callbacks| can be ``NULL``. - * - * If this function fails, |*session_ptr| is left untouched. - * - * This function returns 0 if it succeeds, or one of the following - * negative error codes: - * - * :enum:`nghttp2_error.NGHTTP2_ERR_NOMEM` - * Out of memory. - */ -NGHTTP2_EXTERN int -nghttp2_session_client_new(nghttp2_session **session_ptr, - const nghttp2_session_callbacks *callbacks, - void *user_data); - -/** - * @function - * - * Initializes |*session_ptr| for server use. The all members of - * |callbacks| are copied to |*session_ptr|. Therefore |*session_ptr| - * does not store |callbacks|. The |user_data| is an arbitrary user - * supplied data, which will be passed to the callback functions. - * - * The :type:`nghttp2_send_callback2` must be specified. If the - * application code uses `nghttp2_session_recv()`, the - * :type:`nghttp2_recv_callback` must be specified. The other members - * of |callbacks| can be ``NULL``. - * - * If this function fails, |*session_ptr| is left untouched. - * - * This function returns 0 if it succeeds, or one of the following - * negative error codes: - * - * :enum:`nghttp2_error.NGHTTP2_ERR_NOMEM` - * Out of memory. - */ -NGHTTP2_EXTERN int -nghttp2_session_server_new(nghttp2_session **session_ptr, - const nghttp2_session_callbacks *callbacks, - void *user_data); - -/** - * @function - * - * Like `nghttp2_session_client_new()`, but with additional options - * specified in the |option|. - * - * The |option| can be ``NULL`` and the call is equivalent to - * `nghttp2_session_client_new()`. - * - * This function does not take ownership |option|. The application is - * responsible for freeing |option| if it finishes using the object. - * - * The library code does not refer to |option| after this function - * returns. - * - * This function returns 0 if it succeeds, or one of the following - * negative error codes: - * - * :enum:`nghttp2_error.NGHTTP2_ERR_NOMEM` - * Out of memory. - */ -NGHTTP2_EXTERN int -nghttp2_session_client_new2(nghttp2_session **session_ptr, - const nghttp2_session_callbacks *callbacks, - void *user_data, const nghttp2_option *option); - -/** - * @function - * - * Like `nghttp2_session_server_new()`, but with additional options - * specified in the |option|. - * - * The |option| can be ``NULL`` and the call is equivalent to - * `nghttp2_session_server_new()`. - * - * This function does not take ownership |option|. The application is - * responsible for freeing |option| if it finishes using the object. - * - * The library code does not refer to |option| after this function - * returns. - * - * This function returns 0 if it succeeds, or one of the following - * negative error codes: - * - * :enum:`nghttp2_error.NGHTTP2_ERR_NOMEM` - * Out of memory. - */ -NGHTTP2_EXTERN int -nghttp2_session_server_new2(nghttp2_session **session_ptr, - const nghttp2_session_callbacks *callbacks, - void *user_data, const nghttp2_option *option); - -/** - * @function - * - * Like `nghttp2_session_client_new2()`, but with additional custom - * memory allocator specified in the |mem|. - * - * The |mem| can be ``NULL`` and the call is equivalent to - * `nghttp2_session_client_new2()`. - * - * This function does not take ownership |mem|. The application is - * responsible for freeing |mem|. - * - * The library code does not refer to |mem| pointer after this - * function returns, so the application can safely free it. - * - * This function returns 0 if it succeeds, or one of the following - * negative error codes: - * - * :enum:`nghttp2_error.NGHTTP2_ERR_NOMEM` - * Out of memory. - */ -NGHTTP2_EXTERN int nghttp2_session_client_new3( - nghttp2_session **session_ptr, const nghttp2_session_callbacks *callbacks, - void *user_data, const nghttp2_option *option, nghttp2_mem *mem); - -/** - * @function - * - * Like `nghttp2_session_server_new2()`, but with additional custom - * memory allocator specified in the |mem|. - * - * The |mem| can be ``NULL`` and the call is equivalent to - * `nghttp2_session_server_new2()`. - * - * This function does not take ownership |mem|. The application is - * responsible for freeing |mem|. - * - * The library code does not refer to |mem| pointer after this - * function returns, so the application can safely free it. - * - * This function returns 0 if it succeeds, or one of the following - * negative error codes: - * - * :enum:`nghttp2_error.NGHTTP2_ERR_NOMEM` - * Out of memory. - */ -NGHTTP2_EXTERN int nghttp2_session_server_new3( - nghttp2_session **session_ptr, const nghttp2_session_callbacks *callbacks, - void *user_data, const nghttp2_option *option, nghttp2_mem *mem); - -/** - * @function - * - * Frees any resources allocated for |session|. If |session| is - * ``NULL``, this function does nothing. - */ -NGHTTP2_EXTERN void nghttp2_session_del(nghttp2_session *session); - -/** - * @function - * - * Sends pending frames to the remote peer. - * - * This function retrieves the highest prioritized frame from the - * outbound queue and sends it to the remote peer. It does this as - * many times as possible until the user callback - * :type:`nghttp2_send_callback2` returns - * :enum:`nghttp2_error.NGHTTP2_ERR_WOULDBLOCK`, the outbound queue - * becomes empty or flow control is triggered (remote window size - * becomes depleted or maximum number of concurrent streams is - * reached). This function calls several callback functions which are - * passed when initializing the |session|. Here is the simple time - * chart which tells when each callback is invoked: - * - * 1. Get the next frame to send from outbound queue. - * - * 2. Prepare transmission of the frame. - * - * 3. If the control frame cannot be sent because some preconditions - * are not met (e.g., request HEADERS cannot be sent after GOAWAY), - * :type:`nghttp2_on_frame_not_send_callback` is invoked. Abort - * the following steps. - * - * 4. If the frame is HEADERS, PUSH_PROMISE or DATA, - * :type:`nghttp2_select_padding_callback` is invoked. - * - * 5. If the frame is request HEADERS, the stream is opened here. - * - * 6. :type:`nghttp2_before_frame_send_callback` is invoked. - * - * 7. If :enum:`nghttp2_error.NGHTTP2_ERR_CANCEL` is returned from - * :type:`nghttp2_before_frame_send_callback`, the current frame - * transmission is canceled, and - * :type:`nghttp2_on_frame_not_send_callback` is invoked. Abort - * the following steps. - * - * 8. :type:`nghttp2_send_callback2` is invoked one or more times to - * send the frame. - * - * 9. :type:`nghttp2_on_frame_send_callback` is invoked. - * - * 10. If the transmission of the frame triggers closure of the - * stream, the stream is closed and - * :type:`nghttp2_on_stream_close_callback` is invoked. - * - * This function returns 0 if it succeeds, or one of the following - * negative error codes: - * - * :enum:`nghttp2_error.NGHTTP2_ERR_NOMEM` - * Out of memory. - * :enum:`nghttp2_error.NGHTTP2_ERR_CALLBACK_FAILURE` - * The callback function failed. - */ -NGHTTP2_EXTERN int nghttp2_session_send(nghttp2_session *session); - -#ifndef NGHTTP2_NO_SSIZE_T -/** - * @function - * - * .. warning:: - * - * Deprecated. Use `nghttp2_session_mem_send2()` instead. - * - * Returns the serialized data to send. - * - * This function behaves like `nghttp2_session_send()` except that it - * does not use :type:`nghttp2_send_callback` to transmit data. - * Instead, it assigns the pointer to the serialized data to the - * |*data_ptr| and returns its length. The other callbacks are called - * in the same way as they are in `nghttp2_session_send()`. - * - * If no data is available to send, this function returns 0. - * - * This function may not return all serialized data in one invocation. - * To get all data, call this function repeatedly until it returns 0 - * or one of negative error codes. - * - * The assigned |*data_ptr| is valid until the next call of - * `nghttp2_session_mem_send()` or `nghttp2_session_send()`. - * - * The caller must send all data before sending the next chunk of - * data. - * - * This function returns the length of the data pointed by the - * |*data_ptr| if it succeeds, or one of the following negative error - * codes: - * - * :enum:`nghttp2_error.NGHTTP2_ERR_NOMEM` - * Out of memory. - * - * .. note:: - * - * This function may produce very small byte string. If that is the - * case, and application disables Nagle algorithm (``TCP_NODELAY``), - * then writing this small chunk leads to very small packet, and it - * is very inefficient. An application should be responsible to - * buffer up small chunks of data as necessary to avoid this - * situation. - */ -NGHTTP2_EXTERN ssize_t nghttp2_session_mem_send(nghttp2_session *session, - const uint8_t **data_ptr); - -#endif /* NGHTTP2_NO_SSIZE_T */ - -/** - * @function - * - * Returns the serialized data to send. - * - * This function behaves like `nghttp2_session_send()` except that it - * does not use :type:`nghttp2_send_callback2` to transmit data. - * Instead, it assigns the pointer to the serialized data to the - * |*data_ptr| and returns its length. The other callbacks are called - * in the same way as they are in `nghttp2_session_send()`. - * - * If no data is available to send, this function returns 0. - * - * This function may not return all serialized data in one invocation. - * To get all data, call this function repeatedly until it returns 0 - * or one of negative error codes. - * - * The assigned |*data_ptr| is valid until the next call of - * `nghttp2_session_mem_send2()` or `nghttp2_session_send()`. - * - * The caller must send all data before sending the next chunk of - * data. - * - * This function returns the length of the data pointed by the - * |*data_ptr| if it succeeds, or one of the following negative error - * codes: - * - * :enum:`nghttp2_error.NGHTTP2_ERR_NOMEM` - * Out of memory. - * - * .. note:: - * - * This function may produce very small byte string. If that is the - * case, and application disables Nagle algorithm (``TCP_NODELAY``), - * then writing this small chunk leads to very small packet, and it - * is very inefficient. An application should be responsible to - * buffer up small chunks of data as necessary to avoid this - * situation. - */ -NGHTTP2_EXTERN nghttp2_ssize -nghttp2_session_mem_send2(nghttp2_session *session, const uint8_t **data_ptr); - -/** - * @function - * - * Receives frames from the remote peer. - * - * This function receives as many frames as possible until the user - * callback :type:`nghttp2_recv_callback` returns - * :enum:`nghttp2_error.NGHTTP2_ERR_WOULDBLOCK`. This function calls - * several callback functions which are passed when initializing the - * |session|. Here is the simple time chart which tells when each - * callback is invoked: - * - * 1. :type:`nghttp2_recv_callback` is invoked one or more times to - * receive frame header. - * - * 2. When frame header is received, - * :type:`nghttp2_on_begin_frame_callback` is invoked. - * - * 3. If the frame is DATA frame: - * - * 1. :type:`nghttp2_recv_callback` is invoked to receive DATA - * payload. For each chunk of data, - * :type:`nghttp2_on_data_chunk_recv_callback` is invoked. - * - * 2. If one DATA frame is completely received, - * :type:`nghttp2_on_frame_recv_callback` is invoked. If the - * reception of the frame triggers the closure of the stream, - * :type:`nghttp2_on_stream_close_callback` is invoked. - * - * 4. If the frame is the control frame: - * - * 1. :type:`nghttp2_recv_callback` is invoked one or more times to - * receive whole frame. - * - * 2. If the received frame is valid, then following actions are - * taken. If the frame is either HEADERS or PUSH_PROMISE, - * :type:`nghttp2_on_begin_headers_callback` is invoked. Then - * :type:`nghttp2_on_header_callback` is invoked for each header - * name/value pair. For invalid header field, - * :type:`nghttp2_on_invalid_header_callback` is called. After - * all name/value pairs are emitted successfully, - * :type:`nghttp2_on_frame_recv_callback` is invoked. For other - * frames, :type:`nghttp2_on_frame_recv_callback` is invoked. - * If the reception of the frame triggers the closure of the - * stream, :type:`nghttp2_on_stream_close_callback` is invoked. - * - * 3. If the received frame is unpacked but is interpreted as - * invalid, :type:`nghttp2_on_invalid_frame_recv_callback` is - * invoked. - * - * This function returns 0 if it succeeds, or one of the following - * negative error codes: - * - * :enum:`nghttp2_error.NGHTTP2_ERR_EOF` - * The remote peer did shutdown on the connection. - * :enum:`nghttp2_error.NGHTTP2_ERR_NOMEM` - * Out of memory. - * :enum:`nghttp2_error.NGHTTP2_ERR_CALLBACK_FAILURE` - * The callback function failed. - * :enum:`nghttp2_error.NGHTTP2_ERR_BAD_CLIENT_MAGIC` - * Invalid client magic was detected. This error only returns - * when |session| was configured as server and - * `nghttp2_option_set_no_recv_client_magic()` is not used with - * nonzero value. - * :enum:`nghttp2_error.NGHTTP2_ERR_FLOODED` - * Flooding was detected in this HTTP/2 session, and it must be - * closed. This is most likely caused by misbehaviour of peer. - */ -NGHTTP2_EXTERN int nghttp2_session_recv(nghttp2_session *session); - -#ifndef NGHTTP2_NO_SSIZE_T -/** - * @function - * - * .. warning:: - * - * Deprecated. Use `nghttp2_session_mem_recv2()` instead. - * - * Processes data |in| as an input from the remote endpoint. The - * |inlen| indicates the number of bytes to receive in the |in|. - * - * This function behaves like `nghttp2_session_recv()` except that it - * does not use :type:`nghttp2_recv_callback` to receive data; the - * |in| is the only data for the invocation of this function. If all - * bytes are processed, this function returns. The other callbacks - * are called in the same way as they are in `nghttp2_session_recv()`. - * - * In the current implementation, this function always tries to - * processes |inlen| bytes of input data unless either an error occurs or - * :enum:`nghttp2_error.NGHTTP2_ERR_PAUSE` is returned from - * :type:`nghttp2_on_header_callback` or - * :type:`nghttp2_on_data_chunk_recv_callback`. If - * :enum:`nghttp2_error.NGHTTP2_ERR_PAUSE` is used, the return value - * includes the number of bytes which was used to produce the data or - * frame for the callback. - * - * This function returns the number of processed bytes, or one of the - * following negative error codes: - * - * :enum:`nghttp2_error.NGHTTP2_ERR_NOMEM` - * Out of memory. - * :enum:`nghttp2_error.NGHTTP2_ERR_CALLBACK_FAILURE` - * The callback function failed. - * :enum:`nghttp2_error.NGHTTP2_ERR_BAD_CLIENT_MAGIC` - * Invalid client magic was detected. This error only returns - * when |session| was configured as server and - * `nghttp2_option_set_no_recv_client_magic()` is not used with - * nonzero value. - * :enum:`nghttp2_error.NGHTTP2_ERR_FLOODED` - * Flooding was detected in this HTTP/2 session, and it must be - * closed. This is most likely caused by misbehaviour of peer. - */ -NGHTTP2_EXTERN ssize_t nghttp2_session_mem_recv(nghttp2_session *session, - const uint8_t *in, - size_t inlen); - -#endif /* NGHTTP2_NO_SSIZE_T */ - -/** - * @function - * - * Processes data |in| as an input from the remote endpoint. The - * |inlen| indicates the number of bytes to receive in the |in|. - * - * This function behaves like `nghttp2_session_recv()` except that it - * does not use :type:`nghttp2_recv_callback` to receive data; the - * |in| is the only data for the invocation of this function. If all - * bytes are processed, this function returns. The other callbacks - * are called in the same way as they are in `nghttp2_session_recv()`. - * - * In the current implementation, this function always tries to - * processes |inlen| bytes of input data unless either an error occurs or - * :enum:`nghttp2_error.NGHTTP2_ERR_PAUSE` is returned from - * :type:`nghttp2_on_header_callback` or - * :type:`nghttp2_on_data_chunk_recv_callback`. If - * :enum:`nghttp2_error.NGHTTP2_ERR_PAUSE` is used, the return value - * includes the number of bytes which was used to produce the data or - * frame for the callback. - * - * This function returns the number of processed bytes, or one of the - * following negative error codes: - * - * :enum:`nghttp2_error.NGHTTP2_ERR_NOMEM` - * Out of memory. - * :enum:`nghttp2_error.NGHTTP2_ERR_CALLBACK_FAILURE` - * The callback function failed. - * :enum:`nghttp2_error.NGHTTP2_ERR_BAD_CLIENT_MAGIC` - * Invalid client magic was detected. This error only returns - * when |session| was configured as server and - * `nghttp2_option_set_no_recv_client_magic()` is not used with - * nonzero value. - * :enum:`nghttp2_error.NGHTTP2_ERR_FLOODED` - * Flooding was detected in this HTTP/2 session, and it must be - * closed. This is most likely caused by misbehaviour of peer. - */ -NGHTTP2_EXTERN nghttp2_ssize nghttp2_session_mem_recv2(nghttp2_session *session, - const uint8_t *in, - size_t inlen); - -/** - * @function - * - * Puts back previously deferred DATA frame in the stream |stream_id| - * to the outbound queue. - * - * This function returns 0 if it succeeds, or one of the following - * negative error codes: - * - * :enum:`nghttp2_error.NGHTTP2_ERR_INVALID_ARGUMENT` - * The stream does not exist; or no deferred data exist. - * :enum:`nghttp2_error.NGHTTP2_ERR_NOMEM` - * Out of memory. - */ -NGHTTP2_EXTERN int nghttp2_session_resume_data(nghttp2_session *session, - int32_t stream_id); - -/** - * @function - * - * Returns nonzero value if |session| wants to receive data from the - * remote peer. - * - * If both `nghttp2_session_want_read()` and - * `nghttp2_session_want_write()` return 0, the application should - * drop the connection. - */ -NGHTTP2_EXTERN int nghttp2_session_want_read(nghttp2_session *session); - -/** - * @function - * - * Returns nonzero value if |session| wants to send data to the remote - * peer. - * - * If both `nghttp2_session_want_read()` and - * `nghttp2_session_want_write()` return 0, the application should - * drop the connection. - */ -NGHTTP2_EXTERN int nghttp2_session_want_write(nghttp2_session *session); - -/** - * @function - * - * Returns stream_user_data for the stream |stream_id|. The - * stream_user_data is provided by `nghttp2_submit_request2()`, - * `nghttp2_submit_headers()` or - * `nghttp2_session_set_stream_user_data()`. Unless it is set using - * `nghttp2_session_set_stream_user_data()`, if the stream is - * initiated by the remote endpoint, stream_user_data is always - * ``NULL``. If the stream does not exist, this function returns - * ``NULL``. - */ -NGHTTP2_EXTERN void * -nghttp2_session_get_stream_user_data(nghttp2_session *session, - int32_t stream_id); - -/** - * @function - * - * Sets the |stream_user_data| to the stream denoted by the - * |stream_id|. If a stream user data is already set to the stream, - * it is replaced with the |stream_user_data|. It is valid to specify - * ``NULL`` in the |stream_user_data|, which nullifies the associated - * data pointer. - * - * It is valid to set the |stream_user_data| to the stream reserved by - * PUSH_PROMISE frame. - * - * This function returns 0 if it succeeds, or one of following - * negative error codes: - * - * :enum:`nghttp2_error.NGHTTP2_ERR_INVALID_ARGUMENT` - * The stream does not exist - */ -NGHTTP2_EXTERN int -nghttp2_session_set_stream_user_data(nghttp2_session *session, - int32_t stream_id, void *stream_user_data); - -/** - * @function - * - * Sets |user_data| to |session|, overwriting the existing user data - * specified in `nghttp2_session_client_new()`, or - * `nghttp2_session_server_new()`. - */ -NGHTTP2_EXTERN void nghttp2_session_set_user_data(nghttp2_session *session, - void *user_data); - -/** - * @function - * - * Returns the number of frames in the outbound queue. This does not - * include the deferred DATA frames. - */ -NGHTTP2_EXTERN size_t -nghttp2_session_get_outbound_queue_size(nghttp2_session *session); - -/** - * @function - * - * Returns the number of DATA payload in bytes received without - * WINDOW_UPDATE transmission for the stream |stream_id|. The local - * (receive) window size can be adjusted by - * `nghttp2_submit_window_update()`. This function takes into account - * that and returns effective data length. In particular, if the - * local window size is reduced by submitting negative - * window_size_increment with `nghttp2_submit_window_update()`, this - * function returns the number of bytes less than actually received. - * - * This function returns -1 if it fails. - */ -NGHTTP2_EXTERN int32_t nghttp2_session_get_stream_effective_recv_data_length( - nghttp2_session *session, int32_t stream_id); - -/** - * @function - * - * Returns the local (receive) window size for the stream |stream_id|. - * The local window size can be adjusted by - * `nghttp2_submit_window_update()`. This function takes into account - * that and returns effective window size. - * - * This function does not take into account the amount of received - * data from the remote endpoint. Use - * `nghttp2_session_get_stream_local_window_size()` to know the amount - * of data the remote endpoint can send without receiving stream level - * WINDOW_UPDATE frame. Note that each stream is still subject to the - * connection level flow control. - * - * This function returns -1 if it fails. - */ -NGHTTP2_EXTERN int32_t nghttp2_session_get_stream_effective_local_window_size( - nghttp2_session *session, int32_t stream_id); - -/** - * @function - * - * Returns the amount of flow-controlled payload (e.g., DATA) that the - * remote endpoint can send without receiving stream level - * WINDOW_UPDATE frame. It is also subject to the connection level - * flow control. So the actual amount of data to send is - * min(`nghttp2_session_get_stream_local_window_size()`, - * `nghttp2_session_get_local_window_size()`). - * - * This function returns -1 if it fails. - */ -NGHTTP2_EXTERN int32_t nghttp2_session_get_stream_local_window_size( - nghttp2_session *session, int32_t stream_id); - -/** - * @function - * - * Returns the number of DATA payload in bytes received without - * WINDOW_UPDATE transmission for a connection. The local (receive) - * window size can be adjusted by `nghttp2_submit_window_update()`. - * This function takes into account that and returns effective data - * length. In particular, if the local window size is reduced by - * submitting negative window_size_increment with - * `nghttp2_submit_window_update()`, this function returns the number - * of bytes less than actually received. - * - * This function returns -1 if it fails. - */ -NGHTTP2_EXTERN int32_t -nghttp2_session_get_effective_recv_data_length(nghttp2_session *session); - -/** - * @function - * - * Returns the local (receive) window size for a connection. The - * local window size can be adjusted by - * `nghttp2_submit_window_update()`. This function takes into account - * that and returns effective window size. - * - * This function does not take into account the amount of received - * data from the remote endpoint. Use - * `nghttp2_session_get_local_window_size()` to know the amount of - * data the remote endpoint can send without receiving - * connection-level WINDOW_UPDATE frame. Note that each stream is - * still subject to the stream level flow control. - * - * This function returns -1 if it fails. - */ -NGHTTP2_EXTERN int32_t -nghttp2_session_get_effective_local_window_size(nghttp2_session *session); - -/** - * @function - * - * Returns the amount of flow-controlled payload (e.g., DATA) that the - * remote endpoint can send without receiving connection level - * WINDOW_UPDATE frame. Note that each stream is still subject to the - * stream level flow control (see - * `nghttp2_session_get_stream_local_window_size()`). - * - * This function returns -1 if it fails. - */ -NGHTTP2_EXTERN int32_t -nghttp2_session_get_local_window_size(nghttp2_session *session); - -/** - * @function - * - * Returns the remote window size for a given stream |stream_id|. - * - * This is the amount of flow-controlled payload (e.g., DATA) that the - * local endpoint can send without stream level WINDOW_UPDATE. There - * is also connection level flow control, so the effective size of - * payload that the local endpoint can actually send is - * min(`nghttp2_session_get_stream_remote_window_size()`, - * `nghttp2_session_get_remote_window_size()`). - * - * This function returns -1 if it fails. - */ -NGHTTP2_EXTERN int32_t nghttp2_session_get_stream_remote_window_size( - nghttp2_session *session, int32_t stream_id); - -/** - * @function - * - * Returns the remote window size for a connection. - * - * This function always succeeds. - */ -NGHTTP2_EXTERN int32_t -nghttp2_session_get_remote_window_size(nghttp2_session *session); - -/** - * @function - * - * Returns 1 if local peer half closed the given stream |stream_id|. - * Returns 0 if it did not. Returns -1 if no such stream exists. - */ -NGHTTP2_EXTERN int -nghttp2_session_get_stream_local_close(nghttp2_session *session, - int32_t stream_id); - -/** - * @function - * - * Returns 1 if remote peer half closed the given stream |stream_id|. - * Returns 0 if it did not. Returns -1 if no such stream exists. - */ -NGHTTP2_EXTERN int -nghttp2_session_get_stream_remote_close(nghttp2_session *session, - int32_t stream_id); - -/** - * @function - * - * Returns the current dynamic table size of HPACK inflater, including - * the overhead 32 bytes per entry described in RFC 7541. - */ -NGHTTP2_EXTERN size_t -nghttp2_session_get_hd_inflate_dynamic_table_size(nghttp2_session *session); - -/** - * @function - * - * Returns the current dynamic table size of HPACK deflater including - * the overhead 32 bytes per entry described in RFC 7541. - */ -NGHTTP2_EXTERN size_t -nghttp2_session_get_hd_deflate_dynamic_table_size(nghttp2_session *session); - -/** - * @function - * - * Signals the session so that the connection should be terminated. - * - * The last stream ID is the minimum value between the stream ID of a - * stream for which :type:`nghttp2_on_frame_recv_callback` was called - * most recently and the last stream ID we have sent to the peer - * previously. - * - * The |error_code| is the error code of this GOAWAY frame. The - * pre-defined error code is one of :enum:`nghttp2_error_code`. - * - * After the transmission, both `nghttp2_session_want_read()` and - * `nghttp2_session_want_write()` return 0. - * - * This function should be called when the connection should be - * terminated after sending GOAWAY. If the remaining streams should - * be processed after GOAWAY, use `nghttp2_submit_goaway()` instead. - * - * This function returns 0 if it succeeds, or one of the following - * negative error codes: - * - * :enum:`nghttp2_error.NGHTTP2_ERR_NOMEM` - * Out of memory. - */ -NGHTTP2_EXTERN int nghttp2_session_terminate_session(nghttp2_session *session, - uint32_t error_code); - -/** - * @function - * - * Signals the session so that the connection should be terminated. - * - * This function behaves like `nghttp2_session_terminate_session()`, - * but the last stream ID can be specified by the application for fine - * grained control of stream. The HTTP/2 specification does not allow - * last_stream_id to be increased. So the actual value sent as - * last_stream_id is the minimum value between the given - * |last_stream_id| and the last_stream_id we have previously sent to - * the peer. - * - * The |last_stream_id| is peer's stream ID or 0. So if |session| is - * initialized as client, |last_stream_id| must be even or 0. If - * |session| is initialized as server, |last_stream_id| must be odd or - * 0. - * - * This function returns 0 if it succeeds, or one of the following - * negative error codes: - * - * :enum:`nghttp2_error.NGHTTP2_ERR_NOMEM` - * Out of memory. - * :enum:`nghttp2_error.NGHTTP2_ERR_INVALID_ARGUMENT` - * The |last_stream_id| is invalid. - */ -NGHTTP2_EXTERN int nghttp2_session_terminate_session2(nghttp2_session *session, - int32_t last_stream_id, - uint32_t error_code); - -/** - * @function - * - * Signals to the client that the server started graceful shutdown - * procedure. - * - * This function is only usable for server. If this function is - * called with client side session, this function returns - * :enum:`nghttp2_error.NGHTTP2_ERR_INVALID_STATE`. - * - * To gracefully shutdown HTTP/2 session, server should call this - * function to send GOAWAY with last_stream_id (1u << 31) - 1. And - * after some delay (e.g., 1 RTT), send another GOAWAY with the stream - * ID that the server has some processing using - * `nghttp2_submit_goaway()`. See also - * `nghttp2_session_get_last_proc_stream_id()`. - * - * Unlike `nghttp2_submit_goaway()`, this function just sends GOAWAY - * and does nothing more. This is a mere indication to the client - * that session shutdown is imminent. The application should call - * `nghttp2_submit_goaway()` with appropriate last_stream_id after - * this call. - * - * If one or more GOAWAY frame have been already sent by either - * `nghttp2_submit_goaway()` or `nghttp2_session_terminate_session()`, - * this function has no effect. - * - * This function returns 0 if it succeeds, or one of the following - * negative error codes: - * - * :enum:`nghttp2_error.NGHTTP2_ERR_NOMEM` - * Out of memory. - * :enum:`nghttp2_error.NGHTTP2_ERR_INVALID_STATE` - * The |session| is initialized as client. - */ -NGHTTP2_EXTERN int nghttp2_submit_shutdown_notice(nghttp2_session *session); - -/** - * @function - * - * Returns the value of SETTINGS |id| notified by a remote endpoint. - * The |id| must be one of values defined in - * :enum:`nghttp2_settings_id`. - */ -NGHTTP2_EXTERN uint32_t nghttp2_session_get_remote_settings( - nghttp2_session *session, nghttp2_settings_id id); - -/** - * @function - * - * Returns the value of SETTINGS |id| of local endpoint acknowledged - * by the remote endpoint. The |id| must be one of the values defined - * in :enum:`nghttp2_settings_id`. - */ -NGHTTP2_EXTERN uint32_t nghttp2_session_get_local_settings( - nghttp2_session *session, nghttp2_settings_id id); - -/** - * @function - * - * Tells the |session| that next stream ID is |next_stream_id|. The - * |next_stream_id| must be equal or greater than the value returned - * by `nghttp2_session_get_next_stream_id()`. - * - * This function returns 0 if it succeeds, or one of the following - * negative error codes: - * - * :enum:`nghttp2_error.NGHTTP2_ERR_INVALID_ARGUMENT` - * The |next_stream_id| is strictly less than the value - * `nghttp2_session_get_next_stream_id()` returns; or - * |next_stream_id| is invalid (e.g., even integer for client, or - * odd integer for server). - */ -NGHTTP2_EXTERN int nghttp2_session_set_next_stream_id(nghttp2_session *session, - int32_t next_stream_id); - -/** - * @function - * - * Returns the next outgoing stream ID. Notice that return type is - * uint32_t. If we run out of stream ID for this session, this - * function returns 1 << 31. - */ -NGHTTP2_EXTERN uint32_t -nghttp2_session_get_next_stream_id(nghttp2_session *session); - -/** - * @function - * - * Tells the |session| that |size| bytes for a stream denoted by - * |stream_id| were consumed by application and are ready to - * WINDOW_UPDATE. The consumed bytes are counted towards both - * connection and stream level WINDOW_UPDATE (see - * `nghttp2_session_consume_connection()` and - * `nghttp2_session_consume_stream()` to update consumption - * independently). This function is intended to be used without - * automatic window update (see - * `nghttp2_option_set_no_auto_window_update()`). - * - * This function returns 0 if it succeeds, or one of the following - * negative error codes: - * - * :enum:`nghttp2_error.NGHTTP2_ERR_NOMEM` - * Out of memory. - * :enum:`nghttp2_error.NGHTTP2_ERR_INVALID_ARGUMENT` - * The |stream_id| is 0. - * :enum:`nghttp2_error.NGHTTP2_ERR_INVALID_STATE` - * Automatic WINDOW_UPDATE is not disabled. - */ -NGHTTP2_EXTERN int nghttp2_session_consume(nghttp2_session *session, - int32_t stream_id, size_t size); - -/** - * @function - * - * Like `nghttp2_session_consume()`, but this only tells library that - * |size| bytes were consumed only for connection level. Note that - * HTTP/2 maintains connection and stream level flow control windows - * independently. - * - * This function returns 0 if it succeeds, or one of the following - * negative error codes: - * - * :enum:`nghttp2_error.NGHTTP2_ERR_NOMEM` - * Out of memory. - * :enum:`nghttp2_error.NGHTTP2_ERR_INVALID_STATE` - * Automatic WINDOW_UPDATE is not disabled. - */ -NGHTTP2_EXTERN int nghttp2_session_consume_connection(nghttp2_session *session, - size_t size); - -/** - * @function - * - * Like `nghttp2_session_consume()`, but this only tells library that - * |size| bytes were consumed only for stream denoted by |stream_id|. - * Note that HTTP/2 maintains connection and stream level flow control - * windows independently. - * - * This function returns 0 if it succeeds, or one of the following - * negative error codes: - * - * :enum:`nghttp2_error.NGHTTP2_ERR_NOMEM` - * Out of memory. - * :enum:`nghttp2_error.NGHTTP2_ERR_INVALID_ARGUMENT` - * The |stream_id| is 0. - * :enum:`nghttp2_error.NGHTTP2_ERR_INVALID_STATE` - * Automatic WINDOW_UPDATE is not disabled. - */ -NGHTTP2_EXTERN int nghttp2_session_consume_stream(nghttp2_session *session, - int32_t stream_id, - size_t size); - -/** - * @function - * - * .. warning:: - * - * Deprecated. :rfc:`7540` priorities are deprecated by - * :rfc:`9113`. Consider migrating to :rfc:`9218` extensible - * prioritization scheme. In the future release after the end of - * 2024, this function will always return 0 without doing anything. - * - * Changes priority of existing stream denoted by |stream_id|. The - * new priority specification is |pri_spec|. - * - * The priority is changed silently and instantly, and no PRIORITY - * frame will be sent to notify the peer of this change. This - * function may be useful for server to change the priority of pushed - * stream. - * - * If |session| is initialized as server, and ``pri_spec->stream_id`` - * points to the idle stream, the idle stream is created if it does - * not exist. The created idle stream will depend on root stream - * (stream 0) with weight 16. - * - * Otherwise, if stream denoted by ``pri_spec->stream_id`` is not - * found, we use default priority instead of given |pri_spec|. That - * is make stream depend on root stream with weight 16. - * - * If - * :enum:`nghttp2_settings_id.NGHTTP2_SETTINGS_NO_RFC7540_PRIORITIES` - * of value of 1 is submitted via `nghttp2_submit_settings()`, this - * function does nothing and returns 0. - * - * This function returns 0 if it succeeds, or one of the following - * negative error codes: - * - * :enum:`nghttp2_error.NGHTTP2_ERR_NOMEM` - * Out of memory. - * :enum:`nghttp2_error.NGHTTP2_ERR_INVALID_ARGUMENT` - * Attempted to depend on itself; or no stream exist for the given - * |stream_id|; or |stream_id| is 0 - */ -NGHTTP2_EXTERN int -nghttp2_session_change_stream_priority(nghttp2_session *session, - int32_t stream_id, - const nghttp2_priority_spec *pri_spec); - -/** - * @function - * - * .. warning:: - * - * Deprecated. :rfc:`7540` priorities are deprecated by - * :rfc:`9113`. Consider migrating to :rfc:`9218` extensible - * prioritization scheme. In the future release after the end of - * 2024, this function will always return 0 without doing anything. - * - * Creates idle stream with the given |stream_id|, and priority - * |pri_spec|. - * - * The stream creation is done without sending PRIORITY frame, which - * means that peer does not know about the existence of this idle - * stream in the local endpoint. - * - * RFC 7540 does not disallow the use of creation of idle stream with - * odd or even stream ID regardless of client or server. So this - * function can create odd or even stream ID regardless of client or - * server. But probably it is a bit safer to use the stream ID the - * local endpoint can initiate (in other words, use odd stream ID for - * client, and even stream ID for server), to avoid potential - * collision from peer's instruction. Also we can use - * `nghttp2_session_set_next_stream_id()` to avoid to open created - * idle streams accidentally if we follow this recommendation. - * - * If |session| is initialized as server, and ``pri_spec->stream_id`` - * points to the idle stream, the idle stream is created if it does - * not exist. The created idle stream will depend on root stream - * (stream 0) with weight 16. - * - * Otherwise, if stream denoted by ``pri_spec->stream_id`` is not - * found, we use default priority instead of given |pri_spec|. That - * is make stream depend on root stream with weight 16. - * - * If - * :enum:`nghttp2_settings_id.NGHTTP2_SETTINGS_NO_RFC7540_PRIORITIES` - * of value of 1 is submitted via `nghttp2_submit_settings()`, this - * function does nothing and returns 0. - * - * This function returns 0 if it succeeds, or one of the following - * negative error codes: - * - * :enum:`nghttp2_error.NGHTTP2_ERR_NOMEM` - * Out of memory. - * :enum:`nghttp2_error.NGHTTP2_ERR_INVALID_ARGUMENT` - * Attempted to depend on itself; or stream denoted by |stream_id| - * already exists; or |stream_id| cannot be used to create idle - * stream (in other words, local endpoint has already opened - * stream ID greater than or equal to the given stream ID; or - * |stream_id| is 0 - */ -NGHTTP2_EXTERN int -nghttp2_session_create_idle_stream(nghttp2_session *session, int32_t stream_id, - const nghttp2_priority_spec *pri_spec); - -/** - * @function - * - * .. warning:: - * - * This function is deprecated in favor of - * `nghttp2_session_upgrade2()`, because this function lacks the - * parameter to tell the library the request method used in the - * original HTTP request. This information is required for client - * to validate actual response body length against content-length - * header field (see `nghttp2_option_set_no_http_messaging()`). If - * HEAD is used in request, the length of response body must be 0 - * regardless of value included in content-length header field. - * - * Performs post-process of HTTP Upgrade request. This function can - * be called from both client and server, but the behavior is very - * different in each other. - * - * If called from client side, the |settings_payload| must be the - * value sent in ``HTTP2-Settings`` header field and must be decoded - * by base64url decoder. The |settings_payloadlen| is the length of - * |settings_payload|. The |settings_payload| is unpacked and its - * setting values will be submitted using `nghttp2_submit_settings()`. - * This means that the client application code does not need to submit - * SETTINGS by itself. The stream with stream ID=1 is opened and the - * |stream_user_data| is used for its stream_user_data. The opened - * stream becomes half-closed (local) state. - * - * If called from server side, the |settings_payload| must be the - * value received in ``HTTP2-Settings`` header field and must be - * decoded by base64url decoder. The |settings_payloadlen| is the - * length of |settings_payload|. It is treated as if the SETTINGS - * frame with that payload is received. Thus, callback functions for - * the reception of SETTINGS frame will be invoked. The stream with - * stream ID=1 is opened. The |stream_user_data| is ignored. The - * opened stream becomes half-closed (remote). - * - * This function returns 0 if it succeeds, or one of the following - * negative error codes: - * - * :enum:`nghttp2_error.NGHTTP2_ERR_NOMEM` - * Out of memory. - * :enum:`nghttp2_error.NGHTTP2_ERR_INVALID_ARGUMENT` - * The |settings_payload| is badly formed. - * :enum:`nghttp2_error.NGHTTP2_ERR_PROTO` - * The stream ID 1 is already used or closed; or is not available. - */ -NGHTTP2_EXTERN int nghttp2_session_upgrade(nghttp2_session *session, - const uint8_t *settings_payload, - size_t settings_payloadlen, - void *stream_user_data); - -/** - * @function - * - * Performs post-process of HTTP Upgrade request. This function can - * be called from both client and server, but the behavior is very - * different in each other. - * - * If called from client side, the |settings_payload| must be the - * value sent in ``HTTP2-Settings`` header field and must be decoded - * by base64url decoder. The |settings_payloadlen| is the length of - * |settings_payload|. The |settings_payload| is unpacked and its - * setting values will be submitted using `nghttp2_submit_settings()`. - * This means that the client application code does not need to submit - * SETTINGS by itself. The stream with stream ID=1 is opened and the - * |stream_user_data| is used for its stream_user_data. The opened - * stream becomes half-closed (local) state. - * - * If called from server side, the |settings_payload| must be the - * value received in ``HTTP2-Settings`` header field and must be - * decoded by base64url decoder. The |settings_payloadlen| is the - * length of |settings_payload|. It is treated as if the SETTINGS - * frame with that payload is received. Thus, callback functions for - * the reception of SETTINGS frame will be invoked. The stream with - * stream ID=1 is opened. The |stream_user_data| is ignored. The - * opened stream becomes half-closed (remote). - * - * If the request method is HEAD, pass nonzero value to - * |head_request|. Otherwise, pass 0. - * - * This function returns 0 if it succeeds, or one of the following - * negative error codes: - * - * :enum:`nghttp2_error.NGHTTP2_ERR_NOMEM` - * Out of memory. - * :enum:`nghttp2_error.NGHTTP2_ERR_INVALID_ARGUMENT` - * The |settings_payload| is badly formed. - * :enum:`nghttp2_error.NGHTTP2_ERR_PROTO` - * The stream ID 1 is already used or closed; or is not available. - */ -NGHTTP2_EXTERN int nghttp2_session_upgrade2(nghttp2_session *session, - const uint8_t *settings_payload, - size_t settings_payloadlen, - int head_request, - void *stream_user_data); - -#ifndef NGHTTP2_NO_SSIZE_T -/** - * @function - * - * .. warning:: - * - * Deprecated. Use `nghttp2_pack_settings_payload2()` instead. - * - * Serializes the SETTINGS values |iv| in the |buf|. The size of the - * |buf| is specified by |buflen|. The number of entries in the |iv| - * array is given by |niv|. The required space in |buf| for the |niv| - * entries is ``6*niv`` bytes and if the given buffer is too small, an - * error is returned. This function is used mainly for creating a - * SETTINGS payload to be sent with the ``HTTP2-Settings`` header - * field in an HTTP Upgrade request. The data written in |buf| is NOT - * base64url encoded and the application is responsible for encoding. - * - * This function returns the number of bytes written in |buf|, or one - * of the following negative error codes: - * - * :enum:`nghttp2_error.NGHTTP2_ERR_INVALID_ARGUMENT` - * The |iv| contains duplicate settings ID or invalid value. - * - * :enum:`nghttp2_error.NGHTTP2_ERR_INSUFF_BUFSIZE` - * The provided |buflen| size is too small to hold the output. - */ -NGHTTP2_EXTERN ssize_t nghttp2_pack_settings_payload( - uint8_t *buf, size_t buflen, const nghttp2_settings_entry *iv, size_t niv); - -#endif /* NGHTTP2_NO_SSIZE_T */ - -/** - * @function - * - * Serializes the SETTINGS values |iv| in the |buf|. The size of the - * |buf| is specified by |buflen|. The number of entries in the |iv| - * array is given by |niv|. The required space in |buf| for the |niv| - * entries is ``6*niv`` bytes and if the given buffer is too small, an - * error is returned. This function is used mainly for creating a - * SETTINGS payload to be sent with the ``HTTP2-Settings`` header - * field in an HTTP Upgrade request. The data written in |buf| is NOT - * base64url encoded and the application is responsible for encoding. - * - * This function returns the number of bytes written in |buf|, or one - * of the following negative error codes: - * - * :enum:`nghttp2_error.NGHTTP2_ERR_INVALID_ARGUMENT` - * The |iv| contains duplicate settings ID or invalid value. - * - * :enum:`nghttp2_error.NGHTTP2_ERR_INSUFF_BUFSIZE` - * The provided |buflen| size is too small to hold the output. - */ -NGHTTP2_EXTERN nghttp2_ssize nghttp2_pack_settings_payload2( - uint8_t *buf, size_t buflen, const nghttp2_settings_entry *iv, size_t niv); - -/** - * @function - * - * Returns string describing the |lib_error_code|. The - * |lib_error_code| must be one of the :enum:`nghttp2_error`. - */ -NGHTTP2_EXTERN const char *nghttp2_strerror(int lib_error_code); - -/** - * @function - * - * Returns string representation of HTTP/2 error code |error_code| - * (e.g., ``PROTOCOL_ERROR`` is returned if ``error_code == - * NGHTTP2_PROTOCOL_ERROR``). If string representation is unknown for - * given |error_code|, this function returns string ``unknown``. - */ -NGHTTP2_EXTERN const char *nghttp2_http2_strerror(uint32_t error_code); - -/** - * @function - * - * .. warning:: - * - * Deprecated. :rfc:`7540` priorities are deprecated by - * :rfc:`9113`. Consider migrating to :rfc:`9218` extensible - * prioritization scheme. - * - * Initializes |pri_spec| with the |stream_id| of the stream to depend - * on with |weight| and its exclusive flag. If |exclusive| is - * nonzero, exclusive flag is set. - * - * The |weight| must be in [:macro:`NGHTTP2_MIN_WEIGHT`, - * :macro:`NGHTTP2_MAX_WEIGHT`], inclusive. - */ -NGHTTP2_EXTERN void nghttp2_priority_spec_init(nghttp2_priority_spec *pri_spec, - int32_t stream_id, - int32_t weight, int exclusive); - -/** - * @function - * - * .. warning:: - * - * Deprecated. :rfc:`7540` priorities are deprecated by - * :rfc:`9113`. Consider migrating to :rfc:`9218` extensible - * prioritization scheme. - * - * Initializes |pri_spec| with the default values. The default values - * are: stream_id = 0, weight = :macro:`NGHTTP2_DEFAULT_WEIGHT` and - * exclusive = 0. - */ -NGHTTP2_EXTERN void -nghttp2_priority_spec_default_init(nghttp2_priority_spec *pri_spec); - -/** - * @function - * - * .. warning:: - * - * Deprecated. :rfc:`7540` priorities are deprecated by - * :rfc:`9113`. Consider migrating to :rfc:`9218` extensible - * prioritization scheme. - * - * Returns nonzero if the |pri_spec| is filled with default values. - */ -NGHTTP2_EXTERN int -nghttp2_priority_spec_check_default(const nghttp2_priority_spec *pri_spec); - -#ifndef NGHTTP2_NO_SSIZE_T -/** - * @function - * - * .. warning:: - * - * Deprecated. Use `nghttp2_submit_request2()` instead. - * - * Submits HEADERS frame and optionally one or more DATA frames. - * - * The |pri_spec| is a deprecated priority specification of this - * request. ``NULL`` means the default priority (see - * `nghttp2_priority_spec_default_init()`). To specify the priority, - * use `nghttp2_priority_spec_init()`. If |pri_spec| is not ``NULL``, - * this function will copy its data members. - * - * The ``pri_spec->weight`` must be in [:macro:`NGHTTP2_MIN_WEIGHT`, - * :macro:`NGHTTP2_MAX_WEIGHT`], inclusive. If ``pri_spec->weight`` - * is strictly less than :macro:`NGHTTP2_MIN_WEIGHT`, it becomes - * :macro:`NGHTTP2_MIN_WEIGHT`. If it is strictly greater than - * :macro:`NGHTTP2_MAX_WEIGHT`, it becomes - * :macro:`NGHTTP2_MAX_WEIGHT`. - * - * If - * :enum:`nghttp2_settings_id.NGHTTP2_SETTINGS_NO_RFC7540_PRIORITIES` - * of value of 1 is received by a remote endpoint, |pri_spec| is - * ignored, and treated as if ``NULL`` is specified. - * - * The |nva| is an array of name/value pair :type:`nghttp2_nv` with - * |nvlen| elements. The application is responsible to include - * required pseudo-header fields (header field whose name starts with - * ":") in |nva| and must place pseudo-headers before regular header - * fields. - * - * This function creates copies of all name/value pairs in |nva|. It - * also lower-cases all names in |nva|. The order of elements in - * |nva| is preserved. For header fields with - * :enum:`nghttp2_nv_flag.NGHTTP2_NV_FLAG_NO_COPY_NAME` and - * :enum:`nghttp2_nv_flag.NGHTTP2_NV_FLAG_NO_COPY_VALUE` are set, - * header field name and value are not copied respectively. With - * :enum:`nghttp2_nv_flag.NGHTTP2_NV_FLAG_NO_COPY_NAME`, application - * is responsible to pass header field name in lowercase. The - * application should maintain the references to them until - * :type:`nghttp2_on_frame_send_callback` or - * :type:`nghttp2_on_frame_not_send_callback` is called. - * - * HTTP/2 specification has requirement about header fields in the - * request HEADERS. See the specification for more details. - * - * If |data_prd| is not ``NULL``, it provides data which will be sent - * in subsequent DATA frames. In this case, a method that allows - * request message bodies - * (https://tools.ietf.org/html/rfc7231#section-4) must be specified - * with ``:method`` key in |nva| (e.g. ``POST``). This function does - * not take ownership of the |data_prd|. The function copies the - * members of the |data_prd|. If |data_prd| is ``NULL``, HEADERS have - * END_STREAM set. The |stream_user_data| is data associated to the - * stream opened by this request and can be an arbitrary pointer, - * which can be retrieved later by - * `nghttp2_session_get_stream_user_data()`. - * - * This function returns assigned stream ID if it succeeds, or one of - * the following negative error codes: - * - * :enum:`nghttp2_error.NGHTTP2_ERR_NOMEM` - * Out of memory. - * :enum:`nghttp2_error.NGHTTP2_ERR_STREAM_ID_NOT_AVAILABLE` - * No stream ID is available because maximum stream ID was - * reached. - * :enum:`nghttp2_error.NGHTTP2_ERR_INVALID_ARGUMENT` - * Trying to depend on itself (new stream ID equals - * ``pri_spec->stream_id``). - * :enum:`nghttp2_error.NGHTTP2_ERR_PROTO` - * The |session| is server session. - * - * .. warning:: - * - * This function returns assigned stream ID if it succeeds. But - * that stream is not created yet. The application must not submit - * frame to that stream ID before - * :type:`nghttp2_before_frame_send_callback` is called for this - * frame. This means `nghttp2_session_get_stream_user_data()` does - * not work before the callback. But - * `nghttp2_session_set_stream_user_data()` handles this situation - * specially, and it can set data to a stream during this period. - * - */ -NGHTTP2_EXTERN int32_t nghttp2_submit_request( - nghttp2_session *session, const nghttp2_priority_spec *pri_spec, - const nghttp2_nv *nva, size_t nvlen, const nghttp2_data_provider *data_prd, - void *stream_user_data); - -#endif /* NGHTTP2_NO_SSIZE_T */ - -/** - * @function - * - * Submits HEADERS frame and optionally one or more DATA frames. - * - * The |pri_spec| is a deprecated priority specification of this - * request. ``NULL`` means the default priority (see - * `nghttp2_priority_spec_default_init()`). To specify the priority, - * use `nghttp2_priority_spec_init()`. If |pri_spec| is not ``NULL``, - * this function will copy its data members. In the future release - * after the end of 2024, this function will ignore |pri_spec| and - * behave as if ``NULL`` is given. - * - * The ``pri_spec->weight`` must be in [:macro:`NGHTTP2_MIN_WEIGHT`, - * :macro:`NGHTTP2_MAX_WEIGHT`], inclusive. If ``pri_spec->weight`` - * is strictly less than :macro:`NGHTTP2_MIN_WEIGHT`, it becomes - * :macro:`NGHTTP2_MIN_WEIGHT`. If it is strictly greater than - * :macro:`NGHTTP2_MAX_WEIGHT`, it becomes - * :macro:`NGHTTP2_MAX_WEIGHT`. - * - * If - * :enum:`nghttp2_settings_id.NGHTTP2_SETTINGS_NO_RFC7540_PRIORITIES` - * of value of 1 is received by a remote endpoint, |pri_spec| is - * ignored, and treated as if ``NULL`` is specified. - * - * The |nva| is an array of name/value pair :type:`nghttp2_nv` with - * |nvlen| elements. The application is responsible to include - * required pseudo-header fields (header field whose name starts with - * ":") in |nva| and must place pseudo-headers before regular header - * fields. - * - * This function creates copies of all name/value pairs in |nva|. It - * also lower-cases all names in |nva|. The order of elements in - * |nva| is preserved. For header fields with - * :enum:`nghttp2_nv_flag.NGHTTP2_NV_FLAG_NO_COPY_NAME` and - * :enum:`nghttp2_nv_flag.NGHTTP2_NV_FLAG_NO_COPY_VALUE` are set, - * header field name and value are not copied respectively. With - * :enum:`nghttp2_nv_flag.NGHTTP2_NV_FLAG_NO_COPY_NAME`, application - * is responsible to pass header field name in lowercase. The - * application should maintain the references to them until - * :type:`nghttp2_on_frame_send_callback` or - * :type:`nghttp2_on_frame_not_send_callback` is called. - * - * HTTP/2 specification has requirement about header fields in the - * request HEADERS. See the specification for more details. - * - * If |data_prd| is not ``NULL``, it provides data which will be sent - * in subsequent DATA frames. In this case, a method that allows - * request message bodies - * (https://tools.ietf.org/html/rfc7231#section-4) must be specified - * with ``:method`` key in |nva| (e.g. ``POST``). This function does - * not take ownership of the |data_prd|. The function copies the - * members of the |data_prd|. If |data_prd| is ``NULL``, HEADERS have - * END_STREAM set. The |stream_user_data| is data associated to the - * stream opened by this request and can be an arbitrary pointer, - * which can be retrieved later by - * `nghttp2_session_get_stream_user_data()`. - * - * This function returns assigned stream ID if it succeeds, or one of - * the following negative error codes: - * - * :enum:`nghttp2_error.NGHTTP2_ERR_NOMEM` - * Out of memory. - * :enum:`nghttp2_error.NGHTTP2_ERR_STREAM_ID_NOT_AVAILABLE` - * No stream ID is available because maximum stream ID was - * reached. - * :enum:`nghttp2_error.NGHTTP2_ERR_INVALID_ARGUMENT` - * Trying to depend on itself (new stream ID equals - * ``pri_spec->stream_id``). - * :enum:`nghttp2_error.NGHTTP2_ERR_PROTO` - * The |session| is server session. - * - * .. warning:: - * - * This function returns assigned stream ID if it succeeds. But - * that stream is not created yet. The application must not submit - * frame to that stream ID before - * :type:`nghttp2_before_frame_send_callback` is called for this - * frame. This means `nghttp2_session_get_stream_user_data()` does - * not work before the callback. But - * `nghttp2_session_set_stream_user_data()` handles this situation - * specially, and it can set data to a stream during this period. - * - */ -NGHTTP2_EXTERN int32_t nghttp2_submit_request2( - nghttp2_session *session, const nghttp2_priority_spec *pri_spec, - const nghttp2_nv *nva, size_t nvlen, const nghttp2_data_provider2 *data_prd, - void *stream_user_data); - -#ifndef NGHTTP2_NO_SSIZE_T -/** - * @function - * - * .. warning:: - * - * Deprecated. Use `nghttp2_submit_response2()` instead. - * - * Submits response HEADERS frame and optionally one or more DATA - * frames against the stream |stream_id|. - * - * The |nva| is an array of name/value pair :type:`nghttp2_nv` with - * |nvlen| elements. The application is responsible to include - * required pseudo-header fields (header field whose name starts with - * ":") in |nva| and must place pseudo-headers before regular header - * fields. - * - * This function creates copies of all name/value pairs in |nva|. It - * also lower-cases all names in |nva|. The order of elements in - * |nva| is preserved. For header fields with - * :enum:`nghttp2_nv_flag.NGHTTP2_NV_FLAG_NO_COPY_NAME` and - * :enum:`nghttp2_nv_flag.NGHTTP2_NV_FLAG_NO_COPY_VALUE` are set, - * header field name and value are not copied respectively. With - * :enum:`nghttp2_nv_flag.NGHTTP2_NV_FLAG_NO_COPY_NAME`, application - * is responsible to pass header field name in lowercase. The - * application should maintain the references to them until - * :type:`nghttp2_on_frame_send_callback` or - * :type:`nghttp2_on_frame_not_send_callback` is called. - * - * HTTP/2 specification has requirement about header fields in the - * response HEADERS. See the specification for more details. - * - * If |data_prd| is not ``NULL``, it provides data which will be sent - * in subsequent DATA frames. This function does not take ownership - * of the |data_prd|. The function copies the members of the - * |data_prd|. If |data_prd| is ``NULL``, HEADERS will have - * END_STREAM flag set. - * - * This method can be used as normal HTTP response and push response. - * When pushing a resource using this function, the |session| must be - * configured using `nghttp2_session_server_new()` or its variants and - * the target stream denoted by the |stream_id| must be reserved using - * `nghttp2_submit_push_promise()`. - * - * To send non-final response headers (e.g., HTTP status 101), don't - * use this function because this function half-closes the outbound - * stream. Instead, use `nghttp2_submit_headers()` for this purpose. - * - * This function returns 0 if it succeeds, or one of the following - * negative error codes: - * - * :enum:`nghttp2_error.NGHTTP2_ERR_NOMEM` - * Out of memory. - * :enum:`nghttp2_error.NGHTTP2_ERR_INVALID_ARGUMENT` - * The |stream_id| is 0. - * :enum:`nghttp2_error.NGHTTP2_ERR_DATA_EXIST` - * DATA or HEADERS has been already submitted and not fully - * processed yet. Normally, this does not happen, but when - * application wrongly calls `nghttp2_submit_response()` twice, - * this may happen. - * :enum:`nghttp2_error.NGHTTP2_ERR_PROTO` - * The |session| is client session. - * - * .. warning:: - * - * Calling this function twice for the same stream ID may lead to - * program crash. It is generally considered to a programming error - * to commit response twice. - */ -NGHTTP2_EXTERN int -nghttp2_submit_response(nghttp2_session *session, int32_t stream_id, - const nghttp2_nv *nva, size_t nvlen, - const nghttp2_data_provider *data_prd); - -#endif /* NGHTTP2_NO_SSIZE_T */ - -/** - * @function - * - * Submits response HEADERS frame and optionally one or more DATA - * frames against the stream |stream_id|. - * - * The |nva| is an array of name/value pair :type:`nghttp2_nv` with - * |nvlen| elements. The application is responsible to include - * required pseudo-header fields (header field whose name starts with - * ":") in |nva| and must place pseudo-headers before regular header - * fields. - * - * This function creates copies of all name/value pairs in |nva|. It - * also lower-cases all names in |nva|. The order of elements in - * |nva| is preserved. For header fields with - * :enum:`nghttp2_nv_flag.NGHTTP2_NV_FLAG_NO_COPY_NAME` and - * :enum:`nghttp2_nv_flag.NGHTTP2_NV_FLAG_NO_COPY_VALUE` are set, - * header field name and value are not copied respectively. With - * :enum:`nghttp2_nv_flag.NGHTTP2_NV_FLAG_NO_COPY_NAME`, application - * is responsible to pass header field name in lowercase. The - * application should maintain the references to them until - * :type:`nghttp2_on_frame_send_callback` or - * :type:`nghttp2_on_frame_not_send_callback` is called. - * - * HTTP/2 specification has requirement about header fields in the - * response HEADERS. See the specification for more details. - * - * If |data_prd| is not ``NULL``, it provides data which will be sent - * in subsequent DATA frames. This function does not take ownership - * of the |data_prd|. The function copies the members of the - * |data_prd|. If |data_prd| is ``NULL``, HEADERS will have - * END_STREAM flag set. - * - * This method can be used as normal HTTP response and push response. - * When pushing a resource using this function, the |session| must be - * configured using `nghttp2_session_server_new()` or its variants and - * the target stream denoted by the |stream_id| must be reserved using - * `nghttp2_submit_push_promise()`. - * - * To send non-final response headers (e.g., HTTP status 101), don't - * use this function because this function half-closes the outbound - * stream. Instead, use `nghttp2_submit_headers()` for this purpose. - * - * This function returns 0 if it succeeds, or one of the following - * negative error codes: - * - * :enum:`nghttp2_error.NGHTTP2_ERR_NOMEM` - * Out of memory. - * :enum:`nghttp2_error.NGHTTP2_ERR_INVALID_ARGUMENT` - * The |stream_id| is 0. - * :enum:`nghttp2_error.NGHTTP2_ERR_DATA_EXIST` - * DATA or HEADERS has been already submitted and not fully - * processed yet. Normally, this does not happen, but when - * application wrongly calls `nghttp2_submit_response2()` twice, - * this may happen. - * :enum:`nghttp2_error.NGHTTP2_ERR_PROTO` - * The |session| is client session. - * - * .. warning:: - * - * Calling this function twice for the same stream ID may lead to - * program crash. It is generally considered to a programming error - * to commit response twice. - */ -NGHTTP2_EXTERN int -nghttp2_submit_response2(nghttp2_session *session, int32_t stream_id, - const nghttp2_nv *nva, size_t nvlen, - const nghttp2_data_provider2 *data_prd); - -/** - * @function - * - * Submits trailer fields HEADERS against the stream |stream_id|. - * - * The |nva| is an array of name/value pair :type:`nghttp2_nv` with - * |nvlen| elements. The application must not include pseudo-header - * fields (headers whose names starts with ":") in |nva|. - * - * This function creates copies of all name/value pairs in |nva|. It - * also lower-cases all names in |nva|. The order of elements in - * |nva| is preserved. For header fields with - * :enum:`nghttp2_nv_flag.NGHTTP2_NV_FLAG_NO_COPY_NAME` and - * :enum:`nghttp2_nv_flag.NGHTTP2_NV_FLAG_NO_COPY_VALUE` are set, - * header field name and value are not copied respectively. With - * :enum:`nghttp2_nv_flag.NGHTTP2_NV_FLAG_NO_COPY_NAME`, application - * is responsible to pass header field name in lowercase. The - * application should maintain the references to them until - * :type:`nghttp2_on_frame_send_callback` or - * :type:`nghttp2_on_frame_not_send_callback` is called. - * - * For server, trailer fields must follow response HEADERS or response - * DATA without END_STREAM flat set. The library does not enforce - * this requirement, and applications should do this for themselves. - * If `nghttp2_submit_trailer()` is called before any response HEADERS - * submission (usually by `nghttp2_submit_response2()`), the content - * of |nva| will be sent as response headers, which will result in - * error. - * - * This function has the same effect with `nghttp2_submit_headers()`, - * with flags = :enum:`nghttp2_flag.NGHTTP2_FLAG_END_STREAM` and both - * pri_spec and stream_user_data to NULL. - * - * To submit trailer fields after `nghttp2_submit_response2()` is - * called, the application has to specify - * :type:`nghttp2_data_provider2` to `nghttp2_submit_response2()`. - * Inside of :type:`nghttp2_data_source_read_callback2`, when setting - * :enum:`nghttp2_data_flag.NGHTTP2_DATA_FLAG_EOF`, also set - * :enum:`nghttp2_data_flag.NGHTTP2_DATA_FLAG_NO_END_STREAM`. After - * that, the application can send trailer fields using - * `nghttp2_submit_trailer()`. `nghttp2_submit_trailer()` can be used - * inside :type:`nghttp2_data_source_read_callback2`. - * - * This function returns 0 if it succeeds and |stream_id| is -1. - * Otherwise, this function returns 0 if it succeeds, or one of the - * following negative error codes: - * - * :enum:`nghttp2_error.NGHTTP2_ERR_NOMEM` - * Out of memory. - * :enum:`nghttp2_error.NGHTTP2_ERR_INVALID_ARGUMENT` - * The |stream_id| is 0. - */ -NGHTTP2_EXTERN int nghttp2_submit_trailer(nghttp2_session *session, - int32_t stream_id, - const nghttp2_nv *nva, size_t nvlen); - -/** - * @function - * - * Submits HEADERS frame. The |flags| is bitwise OR of the - * following values: - * - * * :enum:`nghttp2_flag.NGHTTP2_FLAG_END_STREAM` - * - * If |flags| includes :enum:`nghttp2_flag.NGHTTP2_FLAG_END_STREAM`, - * this frame has END_STREAM flag set. - * - * The library handles the CONTINUATION frame internally and it - * correctly sets END_HEADERS to the last sequence of the PUSH_PROMISE - * or CONTINUATION frame. - * - * If the |stream_id| is -1, this frame is assumed as request (i.e., - * request HEADERS frame which opens new stream). In this case, the - * assigned stream ID will be returned. Otherwise, specify stream ID - * in |stream_id|. - * - * The |pri_spec| is a deprecated priority specification of this - * request. ``NULL`` means the default priority (see - * `nghttp2_priority_spec_default_init()`). To specify the priority, - * use `nghttp2_priority_spec_init()`. If |pri_spec| is not ``NULL``, - * this function will copy its data members. In the future release - * after the end of 2024, this function will ignore |pri_spec| and - * behave as if ``NULL`` is given. - * - * The ``pri_spec->weight`` must be in [:macro:`NGHTTP2_MIN_WEIGHT`, - * :macro:`NGHTTP2_MAX_WEIGHT`], inclusive. If ``pri_spec->weight`` - * is strictly less than :macro:`NGHTTP2_MIN_WEIGHT`, it becomes - * :macro:`NGHTTP2_MIN_WEIGHT`. If it is strictly greater than - * :macro:`NGHTTP2_MAX_WEIGHT`, it becomes :macro:`NGHTTP2_MAX_WEIGHT`. - * - * If - * :enum:`nghttp2_settings_id.NGHTTP2_SETTINGS_NO_RFC7540_PRIORITIES` - * of value of 1 is received by a remote endpoint, |pri_spec| is - * ignored, and treated as if ``NULL`` is specified. - * - * The |nva| is an array of name/value pair :type:`nghttp2_nv` with - * |nvlen| elements. The application is responsible to include - * required pseudo-header fields (header field whose name starts with - * ":") in |nva| and must place pseudo-headers before regular header - * fields. - * - * This function creates copies of all name/value pairs in |nva|. It - * also lower-cases all names in |nva|. The order of elements in - * |nva| is preserved. For header fields with - * :enum:`nghttp2_nv_flag.NGHTTP2_NV_FLAG_NO_COPY_NAME` and - * :enum:`nghttp2_nv_flag.NGHTTP2_NV_FLAG_NO_COPY_VALUE` are set, - * header field name and value are not copied respectively. With - * :enum:`nghttp2_nv_flag.NGHTTP2_NV_FLAG_NO_COPY_NAME`, application - * is responsible to pass header field name in lowercase. The - * application should maintain the references to them until - * :type:`nghttp2_on_frame_send_callback` or - * :type:`nghttp2_on_frame_not_send_callback` is called. - * - * The |stream_user_data| is a pointer to an arbitrary data which is - * associated to the stream this frame will open. Therefore it is - * only used if this frame opens streams, in other words, it changes - * stream state from idle or reserved to open. - * - * This function is low-level in a sense that the application code can - * specify flags directly. For usual HTTP request, - * `nghttp2_submit_request2()` is useful. Likewise, for HTTP - * response, prefer `nghttp2_submit_response2()`. - * - * This function returns newly assigned stream ID if it succeeds and - * |stream_id| is -1. Otherwise, this function returns 0 if it - * succeeds, or one of the following negative error codes: - * - * :enum:`nghttp2_error.NGHTTP2_ERR_NOMEM` - * Out of memory. - * :enum:`nghttp2_error.NGHTTP2_ERR_STREAM_ID_NOT_AVAILABLE` - * No stream ID is available because maximum stream ID was - * reached. - * :enum:`nghttp2_error.NGHTTP2_ERR_INVALID_ARGUMENT` - * The |stream_id| is 0; or trying to depend on itself (stream ID - * equals ``pri_spec->stream_id``). - * :enum:`nghttp2_error.NGHTTP2_ERR_DATA_EXIST` - * DATA or HEADERS has been already submitted and not fully - * processed yet. This happens if stream denoted by |stream_id| - * is in reserved state. - * :enum:`nghttp2_error.NGHTTP2_ERR_PROTO` - * The |stream_id| is -1, and |session| is server session. - * - * .. warning:: - * - * This function returns assigned stream ID if it succeeds and - * |stream_id| is -1. But that stream is not opened yet. The - * application must not submit frame to that stream ID before - * :type:`nghttp2_before_frame_send_callback` is called for this - * frame. - * - */ -NGHTTP2_EXTERN int32_t nghttp2_submit_headers( - nghttp2_session *session, uint8_t flags, int32_t stream_id, - const nghttp2_priority_spec *pri_spec, const nghttp2_nv *nva, size_t nvlen, - void *stream_user_data); - -#ifndef NGHTTP2_NO_SSIZE_T -/** - * @function - * - * .. warning:: - * - * Deprecated. Use `nghttp2_submit_data2()` instead. - * - * Submits one or more DATA frames to the stream |stream_id|. The - * data to be sent are provided by |data_prd|. If |flags| contains - * :enum:`nghttp2_flag.NGHTTP2_FLAG_END_STREAM`, the last DATA frame - * has END_STREAM flag set. - * - * This function does not take ownership of the |data_prd|. The - * function copies the members of the |data_prd|. - * - * This function returns 0 if it succeeds, or one of the following - * negative error codes: - * - * :enum:`nghttp2_error.NGHTTP2_ERR_NOMEM` - * Out of memory. - * :enum:`nghttp2_error.NGHTTP2_ERR_DATA_EXIST` - * DATA or HEADERS has been already submitted and not fully - * processed yet. - * :enum:`nghttp2_error.NGHTTP2_ERR_INVALID_ARGUMENT` - * The |stream_id| is 0. - * :enum:`nghttp2_error.NGHTTP2_ERR_STREAM_CLOSED` - * The stream was already closed; or the |stream_id| is invalid. - * - * .. note:: - * - * Currently, only one DATA or HEADERS is allowed for a stream at a - * time. Submitting these frames more than once before first DATA - * or HEADERS is finished results in - * :enum:`nghttp2_error.NGHTTP2_ERR_DATA_EXIST` error code. The - * earliest callback which tells that previous frame is done is - * :type:`nghttp2_on_frame_send_callback`. In side that callback, - * new data can be submitted using `nghttp2_submit_data()`. Of - * course, all data except for last one must not have - * :enum:`nghttp2_flag.NGHTTP2_FLAG_END_STREAM` flag set in |flags|. - * This sounds a bit complicated, and we recommend to use - * `nghttp2_submit_request()` and `nghttp2_submit_response()` to - * avoid this cascading issue. The experience shows that for HTTP - * use, these two functions are enough to implement both client and - * server. - */ -NGHTTP2_EXTERN int nghttp2_submit_data(nghttp2_session *session, uint8_t flags, - int32_t stream_id, - const nghttp2_data_provider *data_prd); - -#endif /* NGHTTP2_NO_SSIZE_T */ - -/** - * @function - * - * Submits one or more DATA frames to the stream |stream_id|. The - * data to be sent are provided by |data_prd|. If |flags| contains - * :enum:`nghttp2_flag.NGHTTP2_FLAG_END_STREAM`, the last DATA frame - * has END_STREAM flag set. - * - * This function does not take ownership of the |data_prd|. The - * function copies the members of the |data_prd|. - * - * This function returns 0 if it succeeds, or one of the following - * negative error codes: - * - * :enum:`nghttp2_error.NGHTTP2_ERR_NOMEM` - * Out of memory. - * :enum:`nghttp2_error.NGHTTP2_ERR_DATA_EXIST` - * DATA or HEADERS has been already submitted and not fully - * processed yet. - * :enum:`nghttp2_error.NGHTTP2_ERR_INVALID_ARGUMENT` - * The |stream_id| is 0. - * :enum:`nghttp2_error.NGHTTP2_ERR_STREAM_CLOSED` - * The stream was already closed; or the |stream_id| is invalid. - * - * .. note:: - * - * Currently, only one DATA or HEADERS is allowed for a stream at a - * time. Submitting these frames more than once before first DATA - * or HEADERS is finished results in - * :enum:`nghttp2_error.NGHTTP2_ERR_DATA_EXIST` error code. The - * earliest callback which tells that previous frame is done is - * :type:`nghttp2_on_frame_send_callback`. In side that callback, - * new data can be submitted using `nghttp2_submit_data2()`. Of - * course, all data except for last one must not have - * :enum:`nghttp2_flag.NGHTTP2_FLAG_END_STREAM` flag set in |flags|. - * This sounds a bit complicated, and we recommend to use - * `nghttp2_submit_request2()` and `nghttp2_submit_response2()` to - * avoid this cascading issue. The experience shows that for HTTP - * use, these two functions are enough to implement both client and - * server. - */ -NGHTTP2_EXTERN int nghttp2_submit_data2(nghttp2_session *session, uint8_t flags, - int32_t stream_id, - const nghttp2_data_provider2 *data_prd); - -/** - * @function - * - * .. warning:: - * - * Deprecated. :rfc:`7540` priorities are deprecated by - * :rfc:`9113`. Consider migrating to :rfc:`9218` extensible - * prioritization scheme. In the future release after the end of - * 2024, this function will always return 0 without doing anything. - * - * Submits PRIORITY frame to change the priority of stream |stream_id| - * to the priority specification |pri_spec|. - * - * The |flags| is currently ignored and should be - * :enum:`nghttp2_flag.NGHTTP2_FLAG_NONE`. - * - * The |pri_spec| is a deprecated priority specification of this - * request. ``NULL`` is not allowed for this function. To specify the - * priority, use `nghttp2_priority_spec_init()`. This function will - * copy its data members. - * - * The ``pri_spec->weight`` must be in [:macro:`NGHTTP2_MIN_WEIGHT`, - * :macro:`NGHTTP2_MAX_WEIGHT`], inclusive. If ``pri_spec->weight`` - * is strictly less than :macro:`NGHTTP2_MIN_WEIGHT`, it becomes - * :macro:`NGHTTP2_MIN_WEIGHT`. If it is strictly greater than - * :macro:`NGHTTP2_MAX_WEIGHT`, it becomes - * :macro:`NGHTTP2_MAX_WEIGHT`. - * - * If - * :enum:`nghttp2_settings_id.NGHTTP2_SETTINGS_NO_RFC7540_PRIORITIES` - * of value of 1 is received by a remote endpoint, this function does - * nothing and returns 0. - * - * This function returns 0 if it succeeds, or one of the following - * negative error codes: - * - * :enum:`nghttp2_error.NGHTTP2_ERR_NOMEM` - * Out of memory. - * :enum:`nghttp2_error.NGHTTP2_ERR_INVALID_ARGUMENT` - * The |stream_id| is 0; or the |pri_spec| is NULL; or trying to - * depend on itself. - */ -NGHTTP2_EXTERN int -nghttp2_submit_priority(nghttp2_session *session, uint8_t flags, - int32_t stream_id, - const nghttp2_priority_spec *pri_spec); - -/** - * @macro - * - * :macro:`NGHTTP2_EXTPRI_DEFAULT_URGENCY` is the default urgency - * level for :rfc:`9218` extensible priorities. - */ -#define NGHTTP2_EXTPRI_DEFAULT_URGENCY 3 - -/** - * @macro - * - * :macro:`NGHTTP2_EXTPRI_URGENCY_HIGH` is the highest urgency level - * for :rfc:`9218` extensible priorities. - */ -#define NGHTTP2_EXTPRI_URGENCY_HIGH 0 - -/** - * @macro - * - * :macro:`NGHTTP2_EXTPRI_URGENCY_LOW` is the lowest urgency level for - * :rfc:`9218` extensible priorities. - */ -#define NGHTTP2_EXTPRI_URGENCY_LOW 7 - -/** - * @macro - * - * :macro:`NGHTTP2_EXTPRI_URGENCY_LEVELS` is the number of urgency - * levels for :rfc:`9218` extensible priorities. - */ -#define NGHTTP2_EXTPRI_URGENCY_LEVELS (NGHTTP2_EXTPRI_URGENCY_LOW + 1) - -/** - * @struct - * - * :type:`nghttp2_extpri` is :rfc:`9218` extensible priorities - * specification for a stream. - */ -typedef struct nghttp2_extpri { - /** - * :member:`urgency` is the urgency of a stream, it must be in - * [:macro:`NGHTTP2_EXTPRI_URGENCY_HIGH`, - * :macro:`NGHTTP2_EXTPRI_URGENCY_LOW`], inclusive, and 0 is the - * highest urgency. - */ - uint32_t urgency; - /** - * :member:`inc` indicates that a content can be processed - * incrementally or not. If inc is 0, it cannot be processed - * incrementally. If inc is 1, it can be processed incrementally. - * Other value is not permitted. - */ - int inc; -} nghttp2_extpri; - -/** - * @function - * - * Submits RST_STREAM frame to cancel/reject the stream |stream_id| - * with the error code |error_code|. - * - * The pre-defined error code is one of :enum:`nghttp2_error_code`. - * - * The |flags| is currently ignored and should be - * :enum:`nghttp2_flag.NGHTTP2_FLAG_NONE`. - * - * This function returns 0 if it succeeds, or one of the following - * negative error codes: - * - * :enum:`nghttp2_error.NGHTTP2_ERR_NOMEM` - * Out of memory. - * :enum:`nghttp2_error.NGHTTP2_ERR_INVALID_ARGUMENT` - * The |stream_id| is 0. - */ -NGHTTP2_EXTERN int nghttp2_submit_rst_stream(nghttp2_session *session, - uint8_t flags, int32_t stream_id, - uint32_t error_code); - -/** - * @function - * - * Stores local settings and submits SETTINGS frame. The |iv| is the - * pointer to the array of :type:`nghttp2_settings_entry`. The |niv| - * indicates the number of :type:`nghttp2_settings_entry`. - * - * The |flags| is currently ignored and should be - * :enum:`nghttp2_flag.NGHTTP2_FLAG_NONE`. - * - * This function does not take ownership of the |iv|. This function - * copies all the elements in the |iv|. - * - * While updating individual stream's local window size, if the window - * size becomes strictly larger than NGHTTP2_MAX_WINDOW_SIZE, - * RST_STREAM is issued against such a stream. - * - * SETTINGS with :enum:`nghttp2_flag.NGHTTP2_FLAG_ACK` is - * automatically submitted by the library and application could not - * send it at its will. - * - * This function returns 0 if it succeeds, or one of the following - * negative error codes: - * - * :enum:`nghttp2_error.NGHTTP2_ERR_INVALID_ARGUMENT` - * The |iv| contains invalid value (e.g., initial window size - * strictly greater than (1 << 31) - 1. - * :enum:`nghttp2_error.NGHTTP2_ERR_NOMEM` - * Out of memory. - */ -NGHTTP2_EXTERN int nghttp2_submit_settings(nghttp2_session *session, - uint8_t flags, - const nghttp2_settings_entry *iv, - size_t niv); - -/** - * @function - * - * Submits PUSH_PROMISE frame. - * - * The |flags| is currently ignored. The library handles the - * CONTINUATION frame internally and it correctly sets END_HEADERS to - * the last sequence of the PUSH_PROMISE or CONTINUATION frame. - * - * The |stream_id| must be client initiated stream ID. - * - * The |nva| is an array of name/value pair :type:`nghttp2_nv` with - * |nvlen| elements. The application is responsible to include - * required pseudo-header fields (header field whose name starts with - * ":") in |nva| and must place pseudo-headers before regular header - * fields. - * - * This function creates copies of all name/value pairs in |nva|. It - * also lower-cases all names in |nva|. The order of elements in - * |nva| is preserved. For header fields with - * :enum:`nghttp2_nv_flag.NGHTTP2_NV_FLAG_NO_COPY_NAME` and - * :enum:`nghttp2_nv_flag.NGHTTP2_NV_FLAG_NO_COPY_VALUE` are set, - * header field name and value are not copied respectively. With - * :enum:`nghttp2_nv_flag.NGHTTP2_NV_FLAG_NO_COPY_NAME`, application - * is responsible to pass header field name in lowercase. The - * application should maintain the references to them until - * :type:`nghttp2_on_frame_send_callback` or - * :type:`nghttp2_on_frame_not_send_callback` is called. - * - * The |promised_stream_user_data| is a pointer to an arbitrary data - * which is associated to the promised stream this frame will open and - * make it in reserved state. It is available using - * `nghttp2_session_get_stream_user_data()`. The application can - * access it in :type:`nghttp2_before_frame_send_callback` and - * :type:`nghttp2_on_frame_send_callback` of this frame. - * - * The client side is not allowed to use this function. - * - * To submit response headers and data, use - * `nghttp2_submit_response2()`. - * - * This function returns assigned promised stream ID if it succeeds, - * or one of the following negative error codes: - * - * :enum:`nghttp2_error.NGHTTP2_ERR_NOMEM` - * Out of memory. - * :enum:`nghttp2_error.NGHTTP2_ERR_PROTO` - * This function was invoked when |session| is initialized as - * client. - * :enum:`nghttp2_error.NGHTTP2_ERR_STREAM_ID_NOT_AVAILABLE` - * No stream ID is available because maximum stream ID was - * reached. - * :enum:`nghttp2_error.NGHTTP2_ERR_INVALID_ARGUMENT` - * The |stream_id| is 0; The |stream_id| does not designate stream - * that peer initiated. - * :enum:`nghttp2_error.NGHTTP2_ERR_STREAM_CLOSED` - * The stream was already closed; or the |stream_id| is invalid. - * - * .. warning:: - * - * This function returns assigned promised stream ID if it succeeds. - * As of 1.16.0, stream object for pushed resource is created when - * this function succeeds. In that case, the application can submit - * push response for the promised frame. - * - * In 1.15.0 or prior versions, pushed stream is not opened yet when - * this function succeeds. The application must not submit frame to - * that stream ID before :type:`nghttp2_before_frame_send_callback` - * is called for this frame. - * - */ -NGHTTP2_EXTERN int32_t nghttp2_submit_push_promise( - nghttp2_session *session, uint8_t flags, int32_t stream_id, - const nghttp2_nv *nva, size_t nvlen, void *promised_stream_user_data); - -/** - * @function - * - * Submits PING frame. You don't have to send PING back when you - * received PING frame. The library automatically submits PING frame - * in this case. - * - * The |flags| is bitwise OR of 0 or more of the following value. - * - * * :enum:`nghttp2_flag.NGHTTP2_FLAG_ACK` - * - * Unless `nghttp2_option_set_no_auto_ping_ack()` is used, the |flags| - * should be :enum:`nghttp2_flag.NGHTTP2_FLAG_NONE`. - * - * If the |opaque_data| is non ``NULL``, then it should point to the 8 - * bytes array of memory to specify opaque data to send with PING - * frame. If the |opaque_data| is ``NULL``, zero-cleared 8 bytes will - * be sent as opaque data. - * - * This function returns 0 if it succeeds, or one of the following - * negative error codes: - * - * :enum:`nghttp2_error.NGHTTP2_ERR_NOMEM` - * Out of memory. - */ -NGHTTP2_EXTERN int nghttp2_submit_ping(nghttp2_session *session, uint8_t flags, - const uint8_t *opaque_data); - -/** - * @function - * - * Submits GOAWAY frame with the last stream ID |last_stream_id| and - * the error code |error_code|. - * - * The pre-defined error code is one of :enum:`nghttp2_error_code`. - * - * The |flags| is currently ignored and should be - * :enum:`nghttp2_flag.NGHTTP2_FLAG_NONE`. - * - * The |last_stream_id| is peer's stream ID or 0. So if |session| is - * initialized as client, |last_stream_id| must be even or 0. If - * |session| is initialized as server, |last_stream_id| must be odd or - * 0. - * - * The HTTP/2 specification says last_stream_id must not be increased - * from the value previously sent. So the actual value sent as - * last_stream_id is the minimum value between the given - * |last_stream_id| and the last_stream_id previously sent to the - * peer. - * - * If the |opaque_data| is not ``NULL`` and |opaque_data_len| is not - * zero, those data will be sent as additional debug data. The - * library makes a copy of the memory region pointed by |opaque_data| - * with the length |opaque_data_len|, so the caller does not need to - * keep this memory after the return of this function. If the - * |opaque_data_len| is 0, the |opaque_data| could be ``NULL``. - * - * After successful transmission of GOAWAY, following things happen. - * All incoming streams having strictly more than |last_stream_id| are - * closed. All incoming HEADERS which starts new stream are simply - * ignored. After all active streams are handled, both - * `nghttp2_session_want_read()` and `nghttp2_session_want_write()` - * return 0 and the application can close session. - * - * This function returns 0 if it succeeds, or one of the following - * negative error codes: - * - * :enum:`nghttp2_error.NGHTTP2_ERR_NOMEM` - * Out of memory. - * :enum:`nghttp2_error.NGHTTP2_ERR_INVALID_ARGUMENT` - * The |opaque_data_len| is too large; the |last_stream_id| is - * invalid. - */ -NGHTTP2_EXTERN int nghttp2_submit_goaway(nghttp2_session *session, - uint8_t flags, int32_t last_stream_id, - uint32_t error_code, - const uint8_t *opaque_data, - size_t opaque_data_len); - -/** - * @function - * - * Returns the last stream ID of a stream for which - * :type:`nghttp2_on_frame_recv_callback` was invoked most recently. - * The returned value can be used as last_stream_id parameter for - * `nghttp2_submit_goaway()` and - * `nghttp2_session_terminate_session2()`. - * - * This function always succeeds. - */ -NGHTTP2_EXTERN int32_t -nghttp2_session_get_last_proc_stream_id(nghttp2_session *session); - -/** - * @function - * - * Returns nonzero if new request can be sent from local endpoint. - * - * This function return 0 if request is not allowed for this session. - * There are several reasons why request is not allowed. Some of the - * reasons are: session is server; stream ID has been spent; GOAWAY - * has been sent or received. - * - * The application can call `nghttp2_submit_request2()` without - * consulting this function. In that case, - * `nghttp2_submit_request2()` may return error. Or, request is - * failed to sent, and :type:`nghttp2_on_stream_close_callback` is - * called. - */ -NGHTTP2_EXTERN int -nghttp2_session_check_request_allowed(nghttp2_session *session); - -/** - * @function - * - * Returns nonzero if |session| is initialized as server side session. - */ -NGHTTP2_EXTERN int -nghttp2_session_check_server_session(nghttp2_session *session); - -/** - * @function - * - * Submits WINDOW_UPDATE frame. - * - * The |flags| is currently ignored and should be - * :enum:`nghttp2_flag.NGHTTP2_FLAG_NONE`. - * - * The |stream_id| is the stream ID to send this WINDOW_UPDATE. To - * send connection level WINDOW_UPDATE, specify 0 to |stream_id|. - * - * If the |window_size_increment| is positive, the WINDOW_UPDATE with - * that value as window_size_increment is queued. If the - * |window_size_increment| is larger than the received bytes from the - * remote endpoint, the local window size is increased by that - * difference. If the sole purpose is to increase the local window - * size, consider to use `nghttp2_session_set_local_window_size()`. - * - * If the |window_size_increment| is negative, the local window size - * is decreased by -|window_size_increment|. If automatic - * WINDOW_UPDATE is enabled - * (`nghttp2_option_set_no_auto_window_update()`), and the library - * decided that the WINDOW_UPDATE should be submitted, then - * WINDOW_UPDATE is queued with the current received bytes count. If - * the sole purpose is to decrease the local window size, consider to - * use `nghttp2_session_set_local_window_size()`. - * - * If the |window_size_increment| is 0, the function does nothing and - * returns 0. - * - * This function returns 0 if it succeeds, or one of the following - * negative error codes: - * - * :enum:`nghttp2_error.NGHTTP2_ERR_FLOW_CONTROL` - * The local window size overflow or gets negative. - * :enum:`nghttp2_error.NGHTTP2_ERR_NOMEM` - * Out of memory. - */ -NGHTTP2_EXTERN int nghttp2_submit_window_update(nghttp2_session *session, - uint8_t flags, - int32_t stream_id, - int32_t window_size_increment); - -/** - * @function - * - * Set local window size (local endpoints's window size) to the given - * |window_size| for the given stream denoted by |stream_id|. To - * change connection level window size, specify 0 to |stream_id|. To - * increase window size, this function may submit WINDOW_UPDATE frame - * to transmission queue. - * - * The |flags| is currently ignored and should be - * :enum:`nghttp2_flag.NGHTTP2_FLAG_NONE`. - * - * This sounds similar to `nghttp2_submit_window_update()`, but there - * are 2 differences. The first difference is that this function - * takes the absolute value of window size to set, rather than the - * delta. To change the window size, this may be easier to use since - * the application just declares the intended window size, rather than - * calculating delta. The second difference is that - * `nghttp2_submit_window_update()` affects the received bytes count - * which has not acked yet. By the specification of - * `nghttp2_submit_window_update()`, to strictly increase the local - * window size, we have to submit delta including all received bytes - * count, which might not be desirable in some cases. On the other - * hand, this function does not affect the received bytes count. It - * just sets the local window size to the given value. - * - * This function returns 0 if it succeeds, or one of the following - * negative error codes: - * - * :enum:`nghttp2_error.NGHTTP2_ERR_INVALID_ARGUMENT` - * The |stream_id| is negative. - * :enum:`nghttp2_error.NGHTTP2_ERR_NOMEM` - * Out of memory. - */ -NGHTTP2_EXTERN int -nghttp2_session_set_local_window_size(nghttp2_session *session, uint8_t flags, - int32_t stream_id, int32_t window_size); - -/** - * @function - * - * Submits extension frame. - * - * Application can pass arbitrary frame flags and stream ID in |flags| - * and |stream_id| respectively. The |payload| is opaque pointer, and - * it can be accessible though ``frame->ext.payload`` in - * :type:`nghttp2_pack_extension_callback2`. The library will not own - * passed |payload| pointer. - * - * The application must set :type:`nghttp2_pack_extension_callback2` - * using `nghttp2_session_callbacks_set_pack_extension_callback2()`. - * - * The application should retain the memory pointed by |payload| until - * the transmission of extension frame is done (which is indicated by - * :type:`nghttp2_on_frame_send_callback`), or transmission fails - * (which is indicated by :type:`nghttp2_on_frame_not_send_callback`). - * If application does not touch this memory region after packing it - * into a wire format, application can free it inside - * :type:`nghttp2_pack_extension_callback2`. - * - * The standard HTTP/2 frame cannot be sent with this function, so - * |type| must be strictly grater than 0x9. Otherwise, this function - * will fail with error code - * :enum:`nghttp2_error.NGHTTP2_ERR_INVALID_ARGUMENT`. - * - * This function returns 0 if it succeeds, or one of the following - * negative error codes: - * - * :enum:`nghttp2_error.NGHTTP2_ERR_INVALID_STATE` - * If :type:`nghttp2_pack_extension_callback2` is not set. - * :enum:`nghttp2_error.NGHTTP2_ERR_INVALID_ARGUMENT` - * If |type| specifies standard HTTP/2 frame type. The frame - * types in the rage [0x0, 0x9], both inclusive, are standard - * HTTP/2 frame type, and cannot be sent using this function. - * :enum:`nghttp2_error.NGHTTP2_ERR_NOMEM` - * Out of memory - */ -NGHTTP2_EXTERN int nghttp2_submit_extension(nghttp2_session *session, - uint8_t type, uint8_t flags, - int32_t stream_id, void *payload); - -/** - * @struct - * - * The payload of ALTSVC frame. ALTSVC frame is a non-critical - * extension to HTTP/2. If this frame is received, and - * `nghttp2_option_set_user_recv_extension_type()` is not set, and - * `nghttp2_option_set_builtin_recv_extension_type()` is set for - * :enum:`nghttp2_frame_type.NGHTTP2_ALTSVC`, - * ``nghttp2_extension.payload`` will point to this struct. - * - * It has the following members: - */ -typedef struct { - /** - * The pointer to origin which this alternative service is - * associated with. This is not necessarily NULL-terminated. - */ - uint8_t *origin; - /** - * The length of the |origin|. - */ - size_t origin_len; - /** - * The pointer to Alt-Svc field value contained in ALTSVC frame. - * This is not necessarily NULL-terminated. - */ - uint8_t *field_value; - /** - * The length of the |field_value|. - */ - size_t field_value_len; -} nghttp2_ext_altsvc; - -/** - * @function - * - * Submits ALTSVC frame. - * - * ALTSVC frame is a non-critical extension to HTTP/2, and defined in - * `RFC 7383 `_. - * - * The |flags| is currently ignored and should be - * :enum:`nghttp2_flag.NGHTTP2_FLAG_NONE`. - * - * The |origin| points to the origin this alternative service is - * associated with. The |origin_len| is the length of the origin. If - * |stream_id| is 0, the origin must be specified. If |stream_id| is - * not zero, the origin must be empty (in other words, |origin_len| - * must be 0). - * - * The ALTSVC frame is only usable from server side. If this function - * is invoked with client side session, this function returns - * :enum:`nghttp2_error.NGHTTP2_ERR_INVALID_STATE`. - * - * This function returns 0 if it succeeds, or one of the following - * negative error codes: - * - * :enum:`nghttp2_error.NGHTTP2_ERR_NOMEM` - * Out of memory - * :enum:`nghttp2_error.NGHTTP2_ERR_INVALID_STATE` - * The function is called from client side session - * :enum:`nghttp2_error.NGHTTP2_ERR_INVALID_ARGUMENT` - * The sum of |origin_len| and |field_value_len| is larger than - * 16382; or |origin_len| is 0 while |stream_id| is 0; or - * |origin_len| is not 0 while |stream_id| is not 0. - */ -NGHTTP2_EXTERN int nghttp2_submit_altsvc(nghttp2_session *session, - uint8_t flags, int32_t stream_id, - const uint8_t *origin, - size_t origin_len, - const uint8_t *field_value, - size_t field_value_len); - -/** - * @struct - * - * The single entry of an origin. - */ -typedef struct { - /** - * The pointer to origin. No validation is made against this field - * by the library. This is not necessarily NULL-terminated. - */ - uint8_t *origin; - /** - * The length of the |origin|. - */ - size_t origin_len; -} nghttp2_origin_entry; - -/** - * @struct - * - * The payload of ORIGIN frame. ORIGIN frame is a non-critical - * extension to HTTP/2 and defined by `RFC 8336 - * `_. - * - * If this frame is received, and - * `nghttp2_option_set_user_recv_extension_type()` is not set, and - * `nghttp2_option_set_builtin_recv_extension_type()` is set for - * :enum:`nghttp2_frame_type.NGHTTP2_ORIGIN`, - * ``nghttp2_extension.payload`` will point to this struct. - * - * It has the following members: - */ -typedef struct { - /** - * The number of origins contained in |ov|. - */ - size_t nov; - /** - * The pointer to the array of origins contained in ORIGIN frame. - */ - nghttp2_origin_entry *ov; -} nghttp2_ext_origin; - -/** - * @function - * - * Submits ORIGIN frame. - * - * ORIGIN frame is a non-critical extension to HTTP/2 and defined by - * `RFC 8336 `_. - * - * The |flags| is currently ignored and should be - * :enum:`nghttp2_flag.NGHTTP2_FLAG_NONE`. - * - * The |ov| points to the array of origins. The |nov| specifies the - * number of origins included in |ov|. This function creates copies - * of all elements in |ov|. - * - * The ORIGIN frame is only usable by a server. If this function is - * invoked with client side session, this function returns - * :enum:`nghttp2_error.NGHTTP2_ERR_INVALID_STATE`. - * - * :enum:`nghttp2_error.NGHTTP2_ERR_NOMEM` - * Out of memory - * :enum:`nghttp2_error.NGHTTP2_ERR_INVALID_STATE` - * The function is called from client side session. - * :enum:`nghttp2_error.NGHTTP2_ERR_INVALID_ARGUMENT` - * There are too many origins, or an origin is too large to fit - * into a default frame payload. - */ -NGHTTP2_EXTERN int nghttp2_submit_origin(nghttp2_session *session, - uint8_t flags, - const nghttp2_origin_entry *ov, - size_t nov); - -/** - * @struct - * - * The payload of PRIORITY_UPDATE frame. PRIORITY_UPDATE frame is a - * non-critical extension to HTTP/2. If this frame is received, and - * `nghttp2_option_set_user_recv_extension_type()` is not set, and - * `nghttp2_option_set_builtin_recv_extension_type()` is set for - * :enum:`nghttp2_frame_type.NGHTTP2_PRIORITY_UPDATE`, - * ``nghttp2_extension.payload`` will point to this struct. - * - * It has the following members: - */ -typedef struct { - /** - * The stream ID of the stream whose priority is updated. - */ - int32_t stream_id; - /** - * The pointer to Priority field value. It is not necessarily - * NULL-terminated. - */ - uint8_t *field_value; - /** - * The length of the :member:`field_value`. - */ - size_t field_value_len; -} nghttp2_ext_priority_update; - -/** - * @function - * - * Submits PRIORITY_UPDATE frame. - * - * PRIORITY_UPDATE frame is a non-critical extension to HTTP/2, and - * defined in :rfc:`9218#section-7.1`. - * - * The |flags| is currently ignored and should be - * :enum:`nghttp2_flag.NGHTTP2_FLAG_NONE`. - * - * The |stream_id| is the ID of stream which is prioritized. The - * |field_value| points to the Priority field value. The - * |field_value_len| is the length of the Priority field value. - * - * If this function is called by server, - * :enum:`nghttp2_error.NGHTTP2_ERR_INVALID_STATE` is returned. - * - * If - * :enum:`nghttp2_settings_id.NGHTTP2_SETTINGS_NO_RFC7540_PRIORITIES` - * of value of 0 is received by a remote endpoint (or it is omitted), - * this function does nothing and returns 0. - * - * This function returns 0 if it succeeds, or one of the following - * negative error codes: - * - * :enum:`nghttp2_error.NGHTTP2_ERR_NOMEM` - * Out of memory - * :enum:`nghttp2_error.NGHTTP2_ERR_INVALID_STATE` - * The function is called from server side session - * :enum:`nghttp2_error.NGHTTP2_ERR_INVALID_ARGUMENT` - * The |field_value_len| is larger than 16380; or |stream_id| is - * 0. - */ -NGHTTP2_EXTERN int nghttp2_submit_priority_update(nghttp2_session *session, - uint8_t flags, - int32_t stream_id, - const uint8_t *field_value, - size_t field_value_len); - -/** - * @function - * - * Changes the priority of the existing stream denoted by |stream_id|. - * The new priority is |extpri|. This function is meant to be used by - * server for :rfc:`9218` extensible prioritization scheme. - * - * If |session| is initialized as client, this function returns - * :enum:`nghttp2_error.NGHTTP2_ERR_INVALID_STATE`. For client, use - * `nghttp2_submit_priority_update()` instead. - * - * If :member:`extpri->urgency ` is out of - * bound, it is set to :macro:`NGHTTP2_EXTPRI_URGENCY_LOW`. - * - * If |ignore_client_signal| is nonzero, server starts to ignore - * client priority signals for this stream. - * - * If - * :enum:`nghttp2_settings_id.NGHTTP2_SETTINGS_NO_RFC7540_PRIORITIES` - * of value of 1 is not submitted via `nghttp2_submit_settings()`, - * this function does nothing and returns 0. - * - * :enum:`nghttp2_error.NGHTTP2_ERR_NOMEM` - * Out of memory. - * :enum:`nghttp2_error.NGHTTP2_ERR_INVALID_STATE` - * The |session| is initialized as client. - * :enum:`nghttp2_error.NGHTTP2_ERR_INVALID_ARGUMENT` - * |stream_id| is zero; or a stream denoted by |stream_id| is not - * found. - */ -NGHTTP2_EXTERN int nghttp2_session_change_extpri_stream_priority( - nghttp2_session *session, int32_t stream_id, const nghttp2_extpri *extpri, - int ignore_client_signal); - -/** - * @function - * - * Stores the stream priority of the existing stream denoted by - * |stream_id| in the object pointed by |extpri|. This function is - * meant to be used by server for :rfc:`9218` extensible - * prioritization scheme. - * - * If |session| is initialized as client, this function returns - * :enum:`nghttp2_error.NGHTTP2_ERR_INVALID_STATE`. - * - * If - * :enum:`nghttp2_settings_id.NGHTTP2_SETTINGS_NO_RFC7540_PRIORITIES` - * of value of 1 is not submitted via `nghttp2_submit_settings()`, - * this function does nothing and returns 0. - * - * This function returns 0 if it succeeds, or one of the following - * negative error codes: - * - * :enum:`nghttp2_error.NGHTTP2_ERR_INVALID_STATE` - * The |session| is initialized as client. - * :enum:`nghttp2_error.NGHTTP2_ERR_INVALID_ARGUMENT` - * |stream_id| is zero; or a stream denoted by |stream_id| is not - * found. - */ -NGHTTP2_EXTERN int nghttp2_session_get_extpri_stream_priority( - nghttp2_session *session, nghttp2_extpri *extpri, int32_t stream_id); - -/** - * @function - * - * Parses Priority header field value pointed by |value| of length - * |len|, and stores the result in the object pointed by |extpri|. - * Priority header field is defined in :rfc:`9218`. - * - * This function does not initialize the object pointed by |extpri| - * before storing the result. It only assigns the values that the - * parser correctly extracted to fields. - * - * This function returns 0 if it succeeds, or one of the following - * negative error codes: - * - * :enum:`nghttp2_error.NGHTTP2_ERR_INVALID_ARGUMENT` - * Failed to parse the header field value. - */ -NGHTTP2_EXTERN int nghttp2_extpri_parse_priority(nghttp2_extpri *extpri, - const uint8_t *value, - size_t len); - -/** - * @function - * - * Compares ``lhs->name`` of length ``lhs->namelen`` bytes and - * ``rhs->name`` of length ``rhs->namelen`` bytes. Returns negative - * integer if ``lhs->name`` is found to be less than ``rhs->name``; or - * returns positive integer if ``lhs->name`` is found to be greater - * than ``rhs->name``; or returns 0 otherwise. - */ -NGHTTP2_EXTERN int nghttp2_nv_compare_name(const nghttp2_nv *lhs, - const nghttp2_nv *rhs); - -/** - * @function - * - * .. warning:: - * - * Deprecated. Use `nghttp2_select_alpn` instead. - * - * A helper function for dealing with ALPN in server side. The |in| - * contains peer's protocol list in preferable order. The format of - * |in| is length-prefixed and not null-terminated. For example, - * ``h2`` and ``http/1.1`` stored in |in| like this:: - * - * in[0] = 2 - * in[1..2] = "h2" - * in[3] = 8 - * in[4..11] = "http/1.1" - * inlen = 12 - * - * The selection algorithm is as follows: - * - * 1. If peer's list contains HTTP/2 protocol the library supports, - * it is selected and returns 1. The following step is not taken. - * - * 2. If peer's list contains ``http/1.1``, this function selects - * ``http/1.1`` and returns 0. The following step is not taken. - * - * 3. This function selects nothing and returns -1 (So called - * non-overlap case). In this case, |out| and |outlen| are left - * untouched. - * - * Selecting ``h2`` means that ``h2`` is written into |*out| and its - * length (which is 2) is assigned to |*outlen|. - * - * For ALPN, refer to https://tools.ietf.org/html/rfc7301 - * - * To use this method you should do something like:: - * - * static int alpn_select_proto_cb(SSL* ssl, - * const unsigned char **out, - * unsigned char *outlen, - * const unsigned char *in, - * unsigned int inlen, - * void *arg) - * { - * int rv; - * rv = nghttp2_select_next_protocol((unsigned char**)out, outlen, - * in, inlen); - * if (rv == -1) { - * return SSL_TLSEXT_ERR_NOACK; - * } - * if (rv == 1) { - * ((MyType*)arg)->http2_selected = 1; - * } - * return SSL_TLSEXT_ERR_OK; - * } - * ... - * SSL_CTX_set_alpn_select_cb(ssl_ctx, alpn_select_proto_cb, my_obj); - * - */ -NGHTTP2_EXTERN int nghttp2_select_next_protocol(unsigned char **out, - unsigned char *outlen, - const unsigned char *in, - unsigned int inlen); - -/** - * @function - * - * A helper function for dealing with ALPN in server side. The |in| - * contains peer's protocol list in preferable order. The format of - * |in| is length-prefixed and not null-terminated. For example, - * ``h2`` and ``http/1.1`` stored in |in| like this:: - * - * in[0] = 2 - * in[1..2] = "h2" - * in[3] = 8 - * in[4..11] = "http/1.1" - * inlen = 12 - * - * The selection algorithm is as follows: - * - * 1. If peer's list contains HTTP/2 protocol the library supports, - * it is selected and returns 1. The following step is not taken. - * - * 2. If peer's list contains ``http/1.1``, this function selects - * ``http/1.1`` and returns 0. The following step is not taken. - * - * 3. This function selects nothing and returns -1 (So called - * non-overlap case). In this case, |out| and |outlen| are left - * untouched. - * - * Selecting ``h2`` means that ``h2`` is written into |*out| and its - * length (which is 2) is assigned to |*outlen|. - * - * For ALPN, refer to https://tools.ietf.org/html/rfc7301 - * - * To use this method you should do something like:: - * - * static int alpn_select_proto_cb(SSL* ssl, - * const unsigned char **out, - * unsigned char *outlen, - * const unsigned char *in, - * unsigned int inlen, - * void *arg) - * { - * int rv; - * rv = nghttp2_select_alpn(out, outlen, in, inlen); - * if (rv == -1) { - * return SSL_TLSEXT_ERR_NOACK; - * } - * if (rv == 1) { - * ((MyType*)arg)->http2_selected = 1; - * } - * return SSL_TLSEXT_ERR_OK; - * } - * ... - * SSL_CTX_set_alpn_select_cb(ssl_ctx, alpn_select_proto_cb, my_obj); - * - */ -NGHTTP2_EXTERN int nghttp2_select_alpn(const unsigned char **out, - unsigned char *outlen, - const unsigned char *in, - unsigned int inlen); - -/** - * @function - * - * Returns a pointer to a nghttp2_info struct with version information - * about the run-time library in use. The |least_version| argument - * can be set to a 24 bit numerical value for the least accepted - * version number and if the condition is not met, this function will - * return a ``NULL``. Pass in 0 to skip the version checking. - */ -NGHTTP2_EXTERN nghttp2_info *nghttp2_version(int least_version); - -/** - * @function - * - * Returns nonzero if the :type:`nghttp2_error` library error code - * |lib_error| is fatal. - */ -NGHTTP2_EXTERN int nghttp2_is_fatal(int lib_error_code); - -/** - * @function - * - * Returns nonzero if HTTP header field name |name| of length |len| is - * valid according to http://tools.ietf.org/html/rfc7230#section-3.2 - * - * Because this is a header field name in HTTP2, the upper cased alphabet - * is treated as error. - */ -NGHTTP2_EXTERN int nghttp2_check_header_name(const uint8_t *name, size_t len); - -/** - * @function - * - * Returns nonzero if HTTP header field value |value| of length |len| - * is valid according to - * http://tools.ietf.org/html/rfc7230#section-3.2 - * - * This function is considered obsolete, and application should - * consider to use `nghttp2_check_header_value_rfc9113()` instead. - */ -NGHTTP2_EXTERN int nghttp2_check_header_value(const uint8_t *value, size_t len); - -/** - * @function - * - * Returns nonzero if HTTP header field value |value| of length |len| - * is valid according to - * http://tools.ietf.org/html/rfc7230#section-3.2, plus - * https://datatracker.ietf.org/doc/html/rfc9113#section-8.2.1 - */ -NGHTTP2_EXTERN int nghttp2_check_header_value_rfc9113(const uint8_t *value, - size_t len); - -/** - * @function - * - * Returns nonzero if the |value| which is supposed to be the value of - * the :method header field is valid according to - * https://datatracker.ietf.org/doc/html/rfc7231#section-4 and - * https://datatracker.ietf.org/doc/html/rfc7230#section-3.2.6 - */ -NGHTTP2_EXTERN int nghttp2_check_method(const uint8_t *value, size_t len); - -/** - * @function - * - * Returns nonzero if the |value| which is supposed to be the value of - * the :path header field is valid according to - * https://datatracker.ietf.org/doc/html/rfc7540#section-8.1.2.3 - * - * |value| is valid if it merely consists of the allowed characters. - * In particular, it does not check whether |value| follows the syntax - * of path. The allowed characters are all characters valid by - * `nghttp2_check_header_value` minus SPC and HT. - */ -NGHTTP2_EXTERN int nghttp2_check_path(const uint8_t *value, size_t len); - -/** - * @function - * - * Returns nonzero if the |value| which is supposed to be the value of the - * :authority or host header field is valid according to - * https://tools.ietf.org/html/rfc3986#section-3.2 - * - * Note that :authority and host field values are not authority. They - * do not include userinfo in RFC 3986, see - * https://datatracker.ietf.org/doc/html/rfc3986#section-3.2.2, that - * is, it does not include '@'. This function treats '@' as a valid - * character. - * - * |value| is valid if it merely consists of the allowed characters. - * In particular, it does not check whether |value| follows the syntax - * of authority. - */ -NGHTTP2_EXTERN int nghttp2_check_authority(const uint8_t *value, size_t len); - -/* HPACK API */ - -struct nghttp2_hd_deflater; - -/** - * @struct - * - * HPACK deflater object. - */ -typedef struct nghttp2_hd_deflater nghttp2_hd_deflater; - -/** - * @function - * - * Initializes |*deflater_ptr| for deflating name/values pairs. - * - * The |max_deflate_dynamic_table_size| is the upper bound of header - * table size the deflater will use. - * - * If this function fails, |*deflater_ptr| is left untouched. - * - * This function returns 0 if it succeeds, or one of the following - * negative error codes: - * - * :enum:`nghttp2_error.NGHTTP2_ERR_NOMEM` - * Out of memory. - */ -NGHTTP2_EXTERN int -nghttp2_hd_deflate_new(nghttp2_hd_deflater **deflater_ptr, - size_t max_deflate_dynamic_table_size); - -/** - * @function - * - * Like `nghttp2_hd_deflate_new()`, but with additional custom memory - * allocator specified in the |mem|. - * - * The |mem| can be ``NULL`` and the call is equivalent to - * `nghttp2_hd_deflate_new()`. - * - * This function does not take ownership |mem|. The application is - * responsible for freeing |mem|. - * - * The library code does not refer to |mem| pointer after this - * function returns, so the application can safely free it. - */ -NGHTTP2_EXTERN int -nghttp2_hd_deflate_new2(nghttp2_hd_deflater **deflater_ptr, - size_t max_deflate_dynamic_table_size, - nghttp2_mem *mem); - -/** - * @function - * - * Deallocates any resources allocated for |deflater|. - */ -NGHTTP2_EXTERN void nghttp2_hd_deflate_del(nghttp2_hd_deflater *deflater); - -/** - * @function - * - * Changes header table size of the |deflater| to - * |settings_max_dynamic_table_size| bytes. This may trigger eviction - * in the dynamic table. - * - * The |settings_max_dynamic_table_size| should be the value received - * in SETTINGS_HEADER_TABLE_SIZE. - * - * The deflater never uses more memory than - * ``max_deflate_dynamic_table_size`` bytes specified in - * `nghttp2_hd_deflate_new()`. Therefore, if - * |settings_max_dynamic_table_size| > - * ``max_deflate_dynamic_table_size``, resulting maximum table size - * becomes ``max_deflate_dynamic_table_size``. - * - * This function returns 0 if it succeeds, or one of the following - * negative error codes: - * - * :enum:`nghttp2_error.NGHTTP2_ERR_NOMEM` - * Out of memory. - */ -NGHTTP2_EXTERN int -nghttp2_hd_deflate_change_table_size(nghttp2_hd_deflater *deflater, - size_t settings_max_dynamic_table_size); - -#ifndef NGHTTP2_NO_SSIZE_T -/** - * @function - * - * .. warning:: - * - * Deprecated. Use `nghttp2_hd_deflate_hd2()` instead. - * - * Deflates the |nva|, which has the |nvlen| name/value pairs, into - * the |buf| of length |buflen|. - * - * If |buf| is not large enough to store the deflated header block, - * this function fails with - * :enum:`nghttp2_error.NGHTTP2_ERR_INSUFF_BUFSIZE`. The caller - * should use `nghttp2_hd_deflate_bound()` to know the upper bound of - * buffer size required to deflate given header name/value pairs. - * - * Once this function fails, subsequent call of this function always - * returns :enum:`nghttp2_error.NGHTTP2_ERR_HEADER_COMP`. - * - * After this function returns, it is safe to delete the |nva|. - * - * This function returns the number of bytes written to |buf| if it - * succeeds, or one of the following negative error codes: - * - * :enum:`nghttp2_error.NGHTTP2_ERR_NOMEM` - * Out of memory. - * :enum:`nghttp2_error.NGHTTP2_ERR_HEADER_COMP` - * Deflation process has failed. - * :enum:`nghttp2_error.NGHTTP2_ERR_INSUFF_BUFSIZE` - * The provided |buflen| size is too small to hold the output. - */ -NGHTTP2_EXTERN ssize_t nghttp2_hd_deflate_hd(nghttp2_hd_deflater *deflater, - uint8_t *buf, size_t buflen, - const nghttp2_nv *nva, - size_t nvlen); - -#endif /* NGHTTP2_NO_SSIZE_T */ - -/** - * @function - * - * Deflates the |nva|, which has the |nvlen| name/value pairs, into - * the |buf| of length |buflen|. - * - * If |buf| is not large enough to store the deflated header block, - * this function fails with - * :enum:`nghttp2_error.NGHTTP2_ERR_INSUFF_BUFSIZE`. The caller - * should use `nghttp2_hd_deflate_bound()` to know the upper bound of - * buffer size required to deflate given header name/value pairs. - * - * Once this function fails, subsequent call of this function always - * returns :enum:`nghttp2_error.NGHTTP2_ERR_HEADER_COMP`. - * - * After this function returns, it is safe to delete the |nva|. - * - * This function returns the number of bytes written to |buf| if it - * succeeds, or one of the following negative error codes: - * - * :enum:`nghttp2_error.NGHTTP2_ERR_NOMEM` - * Out of memory. - * :enum:`nghttp2_error.NGHTTP2_ERR_HEADER_COMP` - * Deflation process has failed. - * :enum:`nghttp2_error.NGHTTP2_ERR_INSUFF_BUFSIZE` - * The provided |buflen| size is too small to hold the output. - */ -NGHTTP2_EXTERN nghttp2_ssize -nghttp2_hd_deflate_hd2(nghttp2_hd_deflater *deflater, uint8_t *buf, - size_t buflen, const nghttp2_nv *nva, size_t nvlen); - -#ifndef NGHTTP2_NO_SSIZE_T -/** - * @function - * - * .. warning:: - * - * Deprecated. Use `nghttp2_hd_deflate_hd_vec2()` instead. - * - * Deflates the |nva|, which has the |nvlen| name/value pairs, into - * the |veclen| size of buf vector |vec|. The each size of buffer - * must be set in len field of :type:`nghttp2_vec`. If and only if - * one chunk is filled up completely, next chunk will be used. If - * |vec| is not large enough to store the deflated header block, this - * function fails with - * :enum:`nghttp2_error.NGHTTP2_ERR_INSUFF_BUFSIZE`. The caller - * should use `nghttp2_hd_deflate_bound()` to know the upper bound of - * buffer size required to deflate given header name/value pairs. - * - * Once this function fails, subsequent call of this function always - * returns :enum:`nghttp2_error.NGHTTP2_ERR_HEADER_COMP`. - * - * After this function returns, it is safe to delete the |nva|. - * - * This function returns the number of bytes written to |vec| if it - * succeeds, or one of the following negative error codes: - * - * :enum:`nghttp2_error.NGHTTP2_ERR_NOMEM` - * Out of memory. - * :enum:`nghttp2_error.NGHTTP2_ERR_HEADER_COMP` - * Deflation process has failed. - * :enum:`nghttp2_error.NGHTTP2_ERR_INSUFF_BUFSIZE` - * The provided |buflen| size is too small to hold the output. - */ -NGHTTP2_EXTERN ssize_t nghttp2_hd_deflate_hd_vec(nghttp2_hd_deflater *deflater, - const nghttp2_vec *vec, - size_t veclen, - const nghttp2_nv *nva, - size_t nvlen); - -#endif /* NGHTTP2_NO_SSIZE_T */ - -/** - * @function - * - * Deflates the |nva|, which has the |nvlen| name/value pairs, into - * the |veclen| size of buf vector |vec|. The each size of buffer - * must be set in len field of :type:`nghttp2_vec`. If and only if - * one chunk is filled up completely, next chunk will be used. If - * |vec| is not large enough to store the deflated header block, this - * function fails with - * :enum:`nghttp2_error.NGHTTP2_ERR_INSUFF_BUFSIZE`. The caller - * should use `nghttp2_hd_deflate_bound()` to know the upper bound of - * buffer size required to deflate given header name/value pairs. - * - * Once this function fails, subsequent call of this function always - * returns :enum:`nghttp2_error.NGHTTP2_ERR_HEADER_COMP`. - * - * After this function returns, it is safe to delete the |nva|. - * - * This function returns the number of bytes written to |vec| if it - * succeeds, or one of the following negative error codes: - * - * :enum:`nghttp2_error.NGHTTP2_ERR_NOMEM` - * Out of memory. - * :enum:`nghttp2_error.NGHTTP2_ERR_HEADER_COMP` - * Deflation process has failed. - * :enum:`nghttp2_error.NGHTTP2_ERR_INSUFF_BUFSIZE` - * The provided |buflen| size is too small to hold the output. - */ -NGHTTP2_EXTERN nghttp2_ssize nghttp2_hd_deflate_hd_vec2( - nghttp2_hd_deflater *deflater, const nghttp2_vec *vec, size_t veclen, - const nghttp2_nv *nva, size_t nvlen); - -/** - * @function - * - * Returns an upper bound on the compressed size after deflation of - * |nva| of length |nvlen|. - */ -NGHTTP2_EXTERN size_t nghttp2_hd_deflate_bound(nghttp2_hd_deflater *deflater, - const nghttp2_nv *nva, - size_t nvlen); - -/** - * @function - * - * Returns the number of entries that header table of |deflater| - * contains. This is the sum of the number of static table and - * dynamic table, so the return value is at least 61. - */ -NGHTTP2_EXTERN -size_t nghttp2_hd_deflate_get_num_table_entries(nghttp2_hd_deflater *deflater); - -/** - * @function - * - * Returns the table entry denoted by |idx| from header table of - * |deflater|. The |idx| is 1-based, and idx=1 returns first entry of - * static table. idx=62 returns first entry of dynamic table if it - * exists. Specifying idx=0 is error, and this function returns NULL. - * If |idx| is strictly greater than the number of entries the tables - * contain, this function returns NULL. - */ -NGHTTP2_EXTERN -const nghttp2_nv * -nghttp2_hd_deflate_get_table_entry(nghttp2_hd_deflater *deflater, size_t idx); - -/** - * @function - * - * Returns the used dynamic table size, including the overhead 32 - * bytes per entry described in RFC 7541. - */ -NGHTTP2_EXTERN -size_t nghttp2_hd_deflate_get_dynamic_table_size(nghttp2_hd_deflater *deflater); - -/** - * @function - * - * Returns the maximum dynamic table size. - */ -NGHTTP2_EXTERN -size_t -nghttp2_hd_deflate_get_max_dynamic_table_size(nghttp2_hd_deflater *deflater); - -struct nghttp2_hd_inflater; - -/** - * @struct - * - * HPACK inflater object. - */ -typedef struct nghttp2_hd_inflater nghttp2_hd_inflater; - -/** - * @function - * - * Initializes |*inflater_ptr| for inflating name/values pairs. - * - * If this function fails, |*inflater_ptr| is left untouched. - * - * This function returns 0 if it succeeds, or one of the following - * negative error codes: - * - * :enum:`nghttp2_error.NGHTTP2_ERR_NOMEM` - * Out of memory. - */ -NGHTTP2_EXTERN int nghttp2_hd_inflate_new(nghttp2_hd_inflater **inflater_ptr); - -/** - * @function - * - * Like `nghttp2_hd_inflate_new()`, but with additional custom memory - * allocator specified in the |mem|. - * - * The |mem| can be ``NULL`` and the call is equivalent to - * `nghttp2_hd_inflate_new()`. - * - * This function does not take ownership |mem|. The application is - * responsible for freeing |mem|. - * - * The library code does not refer to |mem| pointer after this - * function returns, so the application can safely free it. - */ -NGHTTP2_EXTERN int nghttp2_hd_inflate_new2(nghttp2_hd_inflater **inflater_ptr, - nghttp2_mem *mem); - -/** - * @function - * - * Deallocates any resources allocated for |inflater|. - */ -NGHTTP2_EXTERN void nghttp2_hd_inflate_del(nghttp2_hd_inflater *inflater); - -/** - * @function - * - * Changes header table size in the |inflater|. This may trigger - * eviction in the dynamic table. - * - * The |settings_max_dynamic_table_size| should be the value - * transmitted in SETTINGS_HEADER_TABLE_SIZE. - * - * This function must not be called while header block is being - * inflated. In other words, this function must be called after - * initialization of |inflater|, but before calling - * `nghttp2_hd_inflate_hd3()`, or after - * `nghttp2_hd_inflate_end_headers()`. Otherwise, - * `NGHTTP2_ERR_INVALID_STATE` was returned. - * - * This function returns 0 if it succeeds, or one of the following - * negative error codes: - * - * :enum:`nghttp2_error.NGHTTP2_ERR_NOMEM` - * Out of memory. - * :enum:`nghttp2_error.NGHTTP2_ERR_INVALID_STATE` - * The function is called while header block is being inflated. - * Probably, application missed to call - * `nghttp2_hd_inflate_end_headers()`. - */ -NGHTTP2_EXTERN int -nghttp2_hd_inflate_change_table_size(nghttp2_hd_inflater *inflater, - size_t settings_max_dynamic_table_size); - -/** - * @enum - * - * The flags for header inflation. - */ -typedef enum { - /** - * No flag set. - */ - NGHTTP2_HD_INFLATE_NONE = 0, - /** - * Indicates all headers were inflated. - */ - NGHTTP2_HD_INFLATE_FINAL = 0x01, - /** - * Indicates a header was emitted. - */ - NGHTTP2_HD_INFLATE_EMIT = 0x02 -} nghttp2_hd_inflate_flag; - -#ifndef NGHTTP2_NO_SSIZE_T -/** - * @function - * - * .. warning:: - * - * Deprecated. Use `nghttp2_hd_inflate_hd2()` instead. - * - * Inflates name/value block stored in |in| with length |inlen|. This - * function performs decompression. For each successful emission of - * header name/value pair, - * :enum:`nghttp2_hd_inflate_flag.NGHTTP2_HD_INFLATE_EMIT` is set in - * |*inflate_flags| and name/value pair is assigned to the |nv_out| - * and the function returns. The caller must not free the members of - * |nv_out|. - * - * The |nv_out| may include pointers to the memory region in the |in|. - * The caller must retain the |in| while the |nv_out| is used. - * - * The application should call this function repeatedly until the - * ``(*inflate_flags) & NGHTTP2_HD_INFLATE_FINAL`` is nonzero and - * return value is non-negative. This means the all input values are - * processed successfully. Then the application must call - * `nghttp2_hd_inflate_end_headers()` to prepare for the next header - * block input. - * - * The caller can feed complete compressed header block. It also can - * feed it in several chunks. The caller must set |in_final| to - * nonzero if the given input is the last block of the compressed - * header. - * - * This function returns the number of bytes processed if it succeeds, - * or one of the following negative error codes: - * - * :enum:`nghttp2_error.NGHTTP2_ERR_NOMEM` - * Out of memory. - * :enum:`nghttp2_error.NGHTTP2_ERR_HEADER_COMP` - * Inflation process has failed. - * :enum:`nghttp2_error.NGHTTP2_ERR_BUFFER_ERROR` - * The header field name or value is too large. - * - * Example follows:: - * - * int inflate_header_block(nghttp2_hd_inflater *hd_inflater, - * uint8_t *in, size_t inlen, int final) - * { - * ssize_t rv; - * - * for(;;) { - * nghttp2_nv nv; - * int inflate_flags = 0; - * - * rv = nghttp2_hd_inflate_hd(hd_inflater, &nv, &inflate_flags, - * in, inlen, final); - * - * if(rv < 0) { - * fprintf(stderr, "inflate failed with error code %zd", rv); - * return -1; - * } - * - * in += rv; - * inlen -= rv; - * - * if(inflate_flags & NGHTTP2_HD_INFLATE_EMIT) { - * fwrite(nv.name, nv.namelen, 1, stderr); - * fprintf(stderr, ": "); - * fwrite(nv.value, nv.valuelen, 1, stderr); - * fprintf(stderr, "\n"); - * } - * if(inflate_flags & NGHTTP2_HD_INFLATE_FINAL) { - * nghttp2_hd_inflate_end_headers(hd_inflater); - * break; - * } - * if((inflate_flags & NGHTTP2_HD_INFLATE_EMIT) == 0 && - * inlen == 0) { - * break; - * } - * } - * - * return 0; - * } - * - */ -NGHTTP2_EXTERN ssize_t nghttp2_hd_inflate_hd(nghttp2_hd_inflater *inflater, - nghttp2_nv *nv_out, - int *inflate_flags, uint8_t *in, - size_t inlen, int in_final); - -#endif /* NGHTTP2_NO_SSIZE_T */ - -#ifndef NGHTTP2_NO_SSIZE_T -/** - * @function - * - * .. warning:: - * - * Deprecated. Use `nghttp2_hd_inflate_hd3()` instead. - * - * Inflates name/value block stored in |in| with length |inlen|. This - * function performs decompression. For each successful emission of - * header name/value pair, - * :enum:`nghttp2_hd_inflate_flag.NGHTTP2_HD_INFLATE_EMIT` is set in - * |*inflate_flags| and name/value pair is assigned to the |nv_out| - * and the function returns. The caller must not free the members of - * |nv_out|. - * - * The |nv_out| may include pointers to the memory region in the |in|. - * The caller must retain the |in| while the |nv_out| is used. - * - * The application should call this function repeatedly until the - * ``(*inflate_flags) & NGHTTP2_HD_INFLATE_FINAL`` is nonzero and - * return value is non-negative. If that happens, all given input - * data (|inlen| bytes) are processed successfully. Then the - * application must call `nghttp2_hd_inflate_end_headers()` to prepare - * for the next header block input. - * - * In other words, if |in_final| is nonzero, and this function returns - * |inlen|, you can assert that - * :enum:`nghttp2_hd_inflate_final.NGHTTP2_HD_INFLATE_FINAL` is set in - * |*inflate_flags|. - * - * The caller can feed complete compressed header block. It also can - * feed it in several chunks. The caller must set |in_final| to - * nonzero if the given input is the last block of the compressed - * header. - * - * This function returns the number of bytes processed if it succeeds, - * or one of the following negative error codes: - * - * :enum:`nghttp2_error.NGHTTP2_ERR_NOMEM` - * Out of memory. - * :enum:`nghttp2_error.NGHTTP2_ERR_HEADER_COMP` - * Inflation process has failed. - * :enum:`nghttp2_error.NGHTTP2_ERR_BUFFER_ERROR` - * The header field name or value is too large. - * - * Example follows:: - * - * int inflate_header_block(nghttp2_hd_inflater *hd_inflater, - * uint8_t *in, size_t inlen, int final) - * { - * ssize_t rv; - * - * for(;;) { - * nghttp2_nv nv; - * int inflate_flags = 0; - * - * rv = nghttp2_hd_inflate_hd2(hd_inflater, &nv, &inflate_flags, - * in, inlen, final); - * - * if(rv < 0) { - * fprintf(stderr, "inflate failed with error code %zd", rv); - * return -1; - * } - * - * in += rv; - * inlen -= rv; - * - * if(inflate_flags & NGHTTP2_HD_INFLATE_EMIT) { - * fwrite(nv.name, nv.namelen, 1, stderr); - * fprintf(stderr, ": "); - * fwrite(nv.value, nv.valuelen, 1, stderr); - * fprintf(stderr, "\n"); - * } - * if(inflate_flags & NGHTTP2_HD_INFLATE_FINAL) { - * nghttp2_hd_inflate_end_headers(hd_inflater); - * break; - * } - * if((inflate_flags & NGHTTP2_HD_INFLATE_EMIT) == 0 && - * inlen == 0) { - * break; - * } - * } - * - * return 0; - * } - * - */ -NGHTTP2_EXTERN ssize_t nghttp2_hd_inflate_hd2(nghttp2_hd_inflater *inflater, - nghttp2_nv *nv_out, - int *inflate_flags, - const uint8_t *in, size_t inlen, - int in_final); - -#endif /* NGHTTP2_NO_SSIZE_T */ - -/** - * @function - * - * Inflates name/value block stored in |in| with length |inlen|. This - * function performs decompression. For each successful emission of - * header name/value pair, - * :enum:`nghttp2_hd_inflate_flag.NGHTTP2_HD_INFLATE_EMIT` is set in - * |*inflate_flags| and name/value pair is assigned to the |nv_out| - * and the function returns. The caller must not free the members of - * |nv_out|. - * - * The |nv_out| may include pointers to the memory region in the |in|. - * The caller must retain the |in| while the |nv_out| is used. - * - * The application should call this function repeatedly until the - * ``(*inflate_flags) & NGHTTP2_HD_INFLATE_FINAL`` is nonzero and - * return value is non-negative. If that happens, all given input - * data (|inlen| bytes) are processed successfully. Then the - * application must call `nghttp2_hd_inflate_end_headers()` to prepare - * for the next header block input. - * - * In other words, if |in_final| is nonzero, and this function returns - * |inlen|, you can assert that - * :enum:`nghttp2_hd_inflate_final.NGHTTP2_HD_INFLATE_FINAL` is set in - * |*inflate_flags|. - * - * The caller can feed complete compressed header block. It also can - * feed it in several chunks. The caller must set |in_final| to - * nonzero if the given input is the last block of the compressed - * header. - * - * This function returns the number of bytes processed if it succeeds, - * or one of the following negative error codes: - * - * :enum:`nghttp2_error.NGHTTP2_ERR_NOMEM` - * Out of memory. - * :enum:`nghttp2_error.NGHTTP2_ERR_HEADER_COMP` - * Inflation process has failed. - * :enum:`nghttp2_error.NGHTTP2_ERR_BUFFER_ERROR` - * The header field name or value is too large. - * - * Example follows:: - * - * int inflate_header_block(nghttp2_hd_inflater *hd_inflater, - * uint8_t *in, size_t inlen, int final) - * { - * nghttp2_ssize rv; - * - * for(;;) { - * nghttp2_nv nv; - * int inflate_flags = 0; - * - * rv = nghttp2_hd_inflate_hd3(hd_inflater, &nv, &inflate_flags, - * in, inlen, final); - * - * if(rv < 0) { - * fprintf(stderr, "inflate failed with error code %td", rv); - * return -1; - * } - * - * in += rv; - * inlen -= rv; - * - * if(inflate_flags & NGHTTP2_HD_INFLATE_EMIT) { - * fwrite(nv.name, nv.namelen, 1, stderr); - * fprintf(stderr, ": "); - * fwrite(nv.value, nv.valuelen, 1, stderr); - * fprintf(stderr, "\n"); - * } - * if(inflate_flags & NGHTTP2_HD_INFLATE_FINAL) { - * nghttp2_hd_inflate_end_headers(hd_inflater); - * break; - * } - * if((inflate_flags & NGHTTP2_HD_INFLATE_EMIT) == 0 && - * inlen == 0) { - * break; - * } - * } - * - * return 0; - * } - * - */ -NGHTTP2_EXTERN nghttp2_ssize nghttp2_hd_inflate_hd3( - nghttp2_hd_inflater *inflater, nghttp2_nv *nv_out, int *inflate_flags, - const uint8_t *in, size_t inlen, int in_final); - -/** - * @function - * - * Signals the end of decompression for one header block. - * - * This function returns 0 if it succeeds. Currently this function - * always succeeds. - */ -NGHTTP2_EXTERN int -nghttp2_hd_inflate_end_headers(nghttp2_hd_inflater *inflater); - -/** - * @function - * - * Returns the number of entries that header table of |inflater| - * contains. This is the sum of the number of static table and - * dynamic table, so the return value is at least 61. - */ -NGHTTP2_EXTERN -size_t nghttp2_hd_inflate_get_num_table_entries(nghttp2_hd_inflater *inflater); - -/** - * @function - * - * Returns the table entry denoted by |idx| from header table of - * |inflater|. The |idx| is 1-based, and idx=1 returns first entry of - * static table. idx=62 returns first entry of dynamic table if it - * exists. Specifying idx=0 is error, and this function returns NULL. - * If |idx| is strictly greater than the number of entries the tables - * contain, this function returns NULL. - */ -NGHTTP2_EXTERN -const nghttp2_nv * -nghttp2_hd_inflate_get_table_entry(nghttp2_hd_inflater *inflater, size_t idx); - -/** - * @function - * - * Returns the used dynamic table size, including the overhead 32 - * bytes per entry described in RFC 7541. - */ -NGHTTP2_EXTERN -size_t nghttp2_hd_inflate_get_dynamic_table_size(nghttp2_hd_inflater *inflater); - -/** - * @function - * - * Returns the maximum dynamic table size. - */ -NGHTTP2_EXTERN -size_t -nghttp2_hd_inflate_get_max_dynamic_table_size(nghttp2_hd_inflater *inflater); - -struct nghttp2_stream; - -/** - * @struct - * - * The structure to represent HTTP/2 stream. The details of this - * structure are intentionally hidden from the public API. - */ -typedef struct nghttp2_stream nghttp2_stream; - -/** - * @function - * - * Returns pointer to :type:`nghttp2_stream` object denoted by - * |stream_id|. If stream was not found, returns NULL. - * - * Returns imaginary root stream (see - * `nghttp2_session_get_root_stream()`) if 0 is given in |stream_id|. - * - * Unless |stream_id| == 0, the returned pointer is valid until next - * call of `nghttp2_session_send()`, `nghttp2_session_mem_send2()`, - * `nghttp2_session_recv()`, and `nghttp2_session_mem_recv2()`. - */ -NGHTTP2_EXTERN nghttp2_stream * -nghttp2_session_find_stream(nghttp2_session *session, int32_t stream_id); - -/** - * @enum - * - * State of stream as described in RFC 7540. - */ -typedef enum { - /** - * idle state. - */ - NGHTTP2_STREAM_STATE_IDLE = 1, - /** - * open state. - */ - NGHTTP2_STREAM_STATE_OPEN, - /** - * reserved (local) state. - */ - NGHTTP2_STREAM_STATE_RESERVED_LOCAL, - /** - * reserved (remote) state. - */ - NGHTTP2_STREAM_STATE_RESERVED_REMOTE, - /** - * half closed (local) state. - */ - NGHTTP2_STREAM_STATE_HALF_CLOSED_LOCAL, - /** - * half closed (remote) state. - */ - NGHTTP2_STREAM_STATE_HALF_CLOSED_REMOTE, - /** - * closed state. - */ - NGHTTP2_STREAM_STATE_CLOSED -} nghttp2_stream_proto_state; - -/** - * @function - * - * Returns state of |stream|. The root stream retrieved by - * `nghttp2_session_get_root_stream()` will have stream state - * :enum:`nghttp2_stream_proto_state.NGHTTP2_STREAM_STATE_IDLE`. - */ -NGHTTP2_EXTERN nghttp2_stream_proto_state -nghttp2_stream_get_state(nghttp2_stream *stream); - -/** - * @function - * - * .. warning:: - * - * Deprecated. :rfc:`7540` priorities are deprecated by - * :rfc:`9113`. Consider migrating to :rfc:`9218` extensible - * prioritization scheme. - * - * Returns root of dependency tree, which is imaginary stream with - * stream ID 0. The returned pointer is valid until |session| is - * freed by `nghttp2_session_del()`. - */ -NGHTTP2_EXTERN nghttp2_stream * -nghttp2_session_get_root_stream(nghttp2_session *session); - -/** - * @function - * - * .. warning:: - * - * Deprecated. :rfc:`7540` priorities are deprecated by - * :rfc:`9113`. Consider migrating to :rfc:`9218` extensible - * prioritization scheme. In the future release after the end of - * 2024, this function will always return NULL. - * - * Returns the parent stream of |stream| in dependency tree. Returns - * NULL if there is no such stream. - */ -NGHTTP2_EXTERN nghttp2_stream * -nghttp2_stream_get_parent(nghttp2_stream *stream); - -NGHTTP2_EXTERN int32_t nghttp2_stream_get_stream_id(nghttp2_stream *stream); - -/** - * @function - * - * .. warning:: - * - * Deprecated. :rfc:`7540` priorities are deprecated by - * :rfc:`9113`. Consider migrating to :rfc:`9218` extensible - * prioritization scheme. In the future release after the end of - * 2024, this function will always return NULL. - * - * Returns the next sibling stream of |stream| in dependency tree. - * Returns NULL if there is no such stream. - */ -NGHTTP2_EXTERN nghttp2_stream * -nghttp2_stream_get_next_sibling(nghttp2_stream *stream); - -/** - * @function - * - * .. warning:: - * - * Deprecated. :rfc:`7540` priorities are deprecated by - * :rfc:`9113`. Consider migrating to :rfc:`9218` extensible - * prioritization scheme. In the future release after the end of - * 2024, this function will always return NULL. - * - * Returns the previous sibling stream of |stream| in dependency tree. - * Returns NULL if there is no such stream. - */ -NGHTTP2_EXTERN nghttp2_stream * -nghttp2_stream_get_previous_sibling(nghttp2_stream *stream); - -/** - * @function - * - * .. warning:: - * - * Deprecated. :rfc:`7540` priorities are deprecated by - * :rfc:`9113`. Consider migrating to :rfc:`9218` extensible - * prioritization scheme. In the future release after the end of - * 2024, this function will always return NULL. - * - * Returns the first child stream of |stream| in dependency tree. - * Returns NULL if there is no such stream. - */ -NGHTTP2_EXTERN nghttp2_stream * -nghttp2_stream_get_first_child(nghttp2_stream *stream); - -/** - * @function - * - * .. warning:: - * - * Deprecated. :rfc:`7540` priorities are deprecated by - * :rfc:`9113`. Consider migrating to :rfc:`9218` extensible - * prioritization scheme. In the future release after the end of - * 2024, this function will always return - * :macro:`NGHTTP2_DEFAULT_WEIGHT`. - * - * Returns dependency weight to the parent stream of |stream|. - */ -NGHTTP2_EXTERN int32_t nghttp2_stream_get_weight(nghttp2_stream *stream); - -/** - * @function - * - * .. warning:: - * - * Deprecated. :rfc:`7540` priorities are deprecated by - * :rfc:`9113`. Consider migrating to :rfc:`9218` extensible - * prioritization scheme. In the future release after the end of - * 2024, this function will always return 0. - * - * Returns the sum of the weight for |stream|'s children. - */ -NGHTTP2_EXTERN int32_t -nghttp2_stream_get_sum_dependency_weight(nghttp2_stream *stream); - -/** - * @functypedef - * - * Callback function invoked when the library outputs debug logging. - * The function is called with arguments suitable for ``vfprintf(3)`` - * - * The debug output is only enabled if the library is built with - * ``DEBUGBUILD`` macro defined. - */ -typedef void (*nghttp2_debug_vprintf_callback)(const char *format, - va_list args); - -/** - * @function - * - * Sets a debug output callback called by the library when built with - * ``DEBUGBUILD`` macro defined. If this option is not used, debug - * log is written into standard error output. - * - * For builds without ``DEBUGBUILD`` macro defined, this function is - * noop. - * - * Note that building with ``DEBUGBUILD`` may cause significant - * performance penalty to libnghttp2 because of extra processing. It - * should be used for debugging purpose only. - * - * .. Warning:: - * - * Building with ``DEBUGBUILD`` may cause significant performance - * penalty to libnghttp2 because of extra processing. It should be - * used for debugging purpose only. We write this two times because - * this is important. - */ -NGHTTP2_EXTERN void nghttp2_set_debug_vprintf_callback( - nghttp2_debug_vprintf_callback debug_vprintf_callback); - -#ifdef __cplusplus -} -#endif - -#endif /* NGHTTP2_H */ diff --git a/3rdparty/exported/nghttp2/includes/nghttp2/nghttp2ver.h b/3rdparty/exported/nghttp2/includes/nghttp2/nghttp2ver.h deleted file mode 100644 index 827c99896846..000000000000 --- a/3rdparty/exported/nghttp2/includes/nghttp2/nghttp2ver.h +++ /dev/null @@ -1,42 +0,0 @@ -/* - * nghttp2 - HTTP/2 C Library - * - * Copyright (c) 2012, 2013 Tatsuhiro Tsujikawa - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE - * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION - * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION - * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ -#ifndef NGHTTP2VER_H -#define NGHTTP2VER_H - -/** - * @macro - * Version number of the nghttp2 library release - */ -#define NGHTTP2_VERSION "1.64.0" - -/** - * @macro - * Numerical representation of the version number of the nghttp2 library - * release. This is a 24 bit number with 8 bits for major number, 8 bits - * for minor and 8 bits for patch. Version 1.2.3 becomes 0x010203. - */ -#define NGHTTP2_VERSION_NUM 0x014000 - -#endif /* NGHTTP2VER_H */ diff --git a/3rdparty/exported/nghttp2/includes/nghttp2/nghttp2ver.h.in b/3rdparty/exported/nghttp2/includes/nghttp2/nghttp2ver.h.in deleted file mode 100644 index 7717a647f755..000000000000 --- a/3rdparty/exported/nghttp2/includes/nghttp2/nghttp2ver.h.in +++ /dev/null @@ -1,42 +0,0 @@ -/* - * nghttp2 - HTTP/2 C Library - * - * Copyright (c) 2012, 2013 Tatsuhiro Tsujikawa - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE - * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION - * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION - * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ -#ifndef NGHTTP2VER_H -#define NGHTTP2VER_H - -/** - * @macro - * Version number of the nghttp2 library release - */ -#define NGHTTP2_VERSION "@PACKAGE_VERSION@" - -/** - * @macro - * Numerical representation of the version number of the nghttp2 library - * release. This is a 24 bit number with 8 bits for major number, 8 bits - * for minor and 8 bits for patch. Version 1.2.3 becomes 0x010203. - */ -#define NGHTTP2_VERSION_NUM @PACKAGE_VERSION_NUM@ - -#endif /* NGHTTP2VER_H */ diff --git a/3rdparty/exported/nghttp2/libnghttp2.pc.in b/3rdparty/exported/nghttp2/libnghttp2.pc.in deleted file mode 100644 index da6938f28473..000000000000 --- a/3rdparty/exported/nghttp2/libnghttp2.pc.in +++ /dev/null @@ -1,33 +0,0 @@ -# nghttp2 - HTTP/2 C Library - -# Copyright (c) 2012, 2013 Tatsuhiro Tsujikawa - -# Permission is hereby granted, free of charge, to any person obtaining -# a copy of this software and associated documentation files (the -# "Software"), to deal in the Software without restriction, including -# without limitation the rights to use, copy, modify, merge, publish, -# distribute, sublicense, and/or sell copies of the Software, and to -# permit persons to whom the Software is furnished to do so, subject to -# the following conditions: - -# The above copyright notice and this permission notice shall be -# included in all copies or substantial portions of the Software. - -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -prefix=@prefix@ -exec_prefix=@exec_prefix@ -libdir=@libdir@ -includedir=@includedir@ - -Name: libnghttp2 -Description: HTTP/2 C library -URL: https://github.com/tatsuhiro-t/nghttp2 -Version: @VERSION@ -Libs: -L${libdir} -lnghttp2 -Cflags: -I${includedir} diff --git a/3rdparty/exported/nghttp2/nghttp2_alpn.c b/3rdparty/exported/nghttp2/nghttp2_alpn.c deleted file mode 100644 index 33c5885f8d88..000000000000 --- a/3rdparty/exported/nghttp2/nghttp2_alpn.c +++ /dev/null @@ -1,70 +0,0 @@ -/* - * nghttp2 - HTTP/2 C Library - * - * Copyright (c) 2012 Tatsuhiro Tsujikawa - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE - * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION - * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION - * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ -#include "nghttp2_alpn.h" - -#include - -static int select_alpn(const unsigned char **out, unsigned char *outlen, - const unsigned char *in, unsigned int inlen, - const char *key, unsigned int keylen) { - unsigned int i; - for (i = 0; i + keylen <= inlen; i += (unsigned int)(in[i] + 1)) { - if (memcmp(&in[i], key, keylen) == 0) { - *out = (unsigned char *)&in[i + 1]; - *outlen = in[i]; - return 0; - } - } - return -1; -} - -#define NGHTTP2_HTTP_1_1_ALPN "\x8http/1.1" -#define NGHTTP2_HTTP_1_1_ALPN_LEN (sizeof(NGHTTP2_HTTP_1_1_ALPN) - 1) - -int nghttp2_select_next_protocol(unsigned char **out, unsigned char *outlen, - const unsigned char *in, unsigned int inlen) { - if (select_alpn((const unsigned char **)out, outlen, in, inlen, - NGHTTP2_PROTO_ALPN, NGHTTP2_PROTO_ALPN_LEN) == 0) { - return 1; - } - if (select_alpn((const unsigned char **)out, outlen, in, inlen, - NGHTTP2_HTTP_1_1_ALPN, NGHTTP2_HTTP_1_1_ALPN_LEN) == 0) { - return 0; - } - return -1; -} - -int nghttp2_select_alpn(const unsigned char **out, unsigned char *outlen, - const unsigned char *in, unsigned int inlen) { - if (select_alpn(out, outlen, in, inlen, NGHTTP2_PROTO_ALPN, - NGHTTP2_PROTO_ALPN_LEN) == 0) { - return 1; - } - if (select_alpn(out, outlen, in, inlen, NGHTTP2_HTTP_1_1_ALPN, - NGHTTP2_HTTP_1_1_ALPN_LEN) == 0) { - return 0; - } - return -1; -} diff --git a/3rdparty/exported/nghttp2/nghttp2_alpn.h b/3rdparty/exported/nghttp2/nghttp2_alpn.h deleted file mode 100644 index 09810fd82149..000000000000 --- a/3rdparty/exported/nghttp2/nghttp2_alpn.h +++ /dev/null @@ -1,34 +0,0 @@ -/* - * nghttp2 - HTTP/2 C Library - * - * Copyright (c) 2012 Tatsuhiro Tsujikawa - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE - * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION - * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION - * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ -#ifndef NGHTTP2_ALPN_H -#define NGHTTP2_ALPN_H - -#ifdef HAVE_CONFIG_H -# include -#endif /* HAVE_CONFIG_H */ - -#include - -#endif /* NGHTTP2_ALPN_H */ diff --git a/3rdparty/exported/nghttp2/nghttp2_buf.c b/3rdparty/exported/nghttp2/nghttp2_buf.c deleted file mode 100644 index 15cd674a650f..000000000000 --- a/3rdparty/exported/nghttp2/nghttp2_buf.c +++ /dev/null @@ -1,527 +0,0 @@ -/* - * nghttp2 - HTTP/2 C Library - * - * Copyright (c) 2014 Tatsuhiro Tsujikawa - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE - * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION - * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION - * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ -#include "nghttp2_buf.h" - -#include - -#include "nghttp2_helper.h" -#include "nghttp2_debug.h" - -void nghttp2_buf_init(nghttp2_buf *buf) { - buf->begin = NULL; - buf->end = NULL; - buf->pos = NULL; - buf->last = NULL; - buf->mark = NULL; -} - -int nghttp2_buf_init2(nghttp2_buf *buf, size_t initial, nghttp2_mem *mem) { - nghttp2_buf_init(buf); - return nghttp2_buf_reserve(buf, initial, mem); -} - -void nghttp2_buf_free(nghttp2_buf *buf, nghttp2_mem *mem) { - if (buf == NULL) { - return; - } - - nghttp2_mem_free(mem, buf->begin); - buf->begin = NULL; -} - -int nghttp2_buf_reserve(nghttp2_buf *buf, size_t new_cap, nghttp2_mem *mem) { - uint8_t *ptr; - size_t cap; - - cap = nghttp2_buf_cap(buf); - - if (cap >= new_cap) { - return 0; - } - - new_cap = nghttp2_max_size(new_cap, cap * 2); - - ptr = nghttp2_mem_realloc(mem, buf->begin, new_cap); - if (ptr == NULL) { - return NGHTTP2_ERR_NOMEM; - } - - buf->pos = ptr + (buf->pos - buf->begin); - buf->last = ptr + (buf->last - buf->begin); - buf->mark = ptr + (buf->mark - buf->begin); - buf->begin = ptr; - buf->end = ptr + new_cap; - - return 0; -} - -void nghttp2_buf_reset(nghttp2_buf *buf) { - buf->pos = buf->last = buf->mark = buf->begin; -} - -void nghttp2_buf_wrap_init(nghttp2_buf *buf, uint8_t *begin, size_t len) { - buf->begin = buf->pos = buf->last = buf->mark = buf->end = begin; - if (len) { - buf->end += len; - } -} - -static int buf_chain_new(nghttp2_buf_chain **chain, size_t chunk_length, - nghttp2_mem *mem) { - int rv; - - *chain = nghttp2_mem_malloc(mem, sizeof(nghttp2_buf_chain)); - if (*chain == NULL) { - return NGHTTP2_ERR_NOMEM; - } - - (*chain)->next = NULL; - - rv = nghttp2_buf_init2(&(*chain)->buf, chunk_length, mem); - if (rv != 0) { - nghttp2_mem_free(mem, *chain); - return NGHTTP2_ERR_NOMEM; - } - - return 0; -} - -static void buf_chain_del(nghttp2_buf_chain *chain, nghttp2_mem *mem) { - nghttp2_buf_free(&chain->buf, mem); - nghttp2_mem_free(mem, chain); -} - -int nghttp2_bufs_init(nghttp2_bufs *bufs, size_t chunk_length, size_t max_chunk, - nghttp2_mem *mem) { - return nghttp2_bufs_init2(bufs, chunk_length, max_chunk, 0, mem); -} - -int nghttp2_bufs_init2(nghttp2_bufs *bufs, size_t chunk_length, - size_t max_chunk, size_t offset, nghttp2_mem *mem) { - return nghttp2_bufs_init3(bufs, chunk_length, max_chunk, max_chunk, offset, - mem); -} - -int nghttp2_bufs_init3(nghttp2_bufs *bufs, size_t chunk_length, - size_t max_chunk, size_t chunk_keep, size_t offset, - nghttp2_mem *mem) { - int rv; - nghttp2_buf_chain *chain; - - if (chunk_keep == 0 || max_chunk < chunk_keep || chunk_length < offset) { - return NGHTTP2_ERR_INVALID_ARGUMENT; - } - - rv = buf_chain_new(&chain, chunk_length, mem); - if (rv != 0) { - return rv; - } - - bufs->mem = mem; - bufs->offset = offset; - - bufs->head = chain; - bufs->cur = bufs->head; - - nghttp2_buf_shift_right(&bufs->cur->buf, offset); - - bufs->chunk_length = chunk_length; - bufs->chunk_used = 1; - bufs->max_chunk = max_chunk; - bufs->chunk_keep = chunk_keep; - - return 0; -} - -int nghttp2_bufs_realloc(nghttp2_bufs *bufs, size_t chunk_length) { - int rv; - nghttp2_buf_chain *chain; - - if (chunk_length < bufs->offset) { - return NGHTTP2_ERR_INVALID_ARGUMENT; - } - - rv = buf_chain_new(&chain, chunk_length, bufs->mem); - if (rv != 0) { - return rv; - } - - nghttp2_bufs_free(bufs); - - bufs->head = chain; - bufs->cur = bufs->head; - - nghttp2_buf_shift_right(&bufs->cur->buf, bufs->offset); - - bufs->chunk_length = chunk_length; - bufs->chunk_used = 1; - - return 0; -} - -void nghttp2_bufs_free(nghttp2_bufs *bufs) { - nghttp2_buf_chain *chain, *next_chain; - - if (bufs == NULL) { - return; - } - - for (chain = bufs->head; chain;) { - next_chain = chain->next; - - buf_chain_del(chain, bufs->mem); - - chain = next_chain; - } - - bufs->head = NULL; -} - -int nghttp2_bufs_wrap_init(nghttp2_bufs *bufs, uint8_t *begin, size_t len, - nghttp2_mem *mem) { - nghttp2_buf_chain *chain; - - chain = nghttp2_mem_malloc(mem, sizeof(nghttp2_buf_chain)); - if (chain == NULL) { - return NGHTTP2_ERR_NOMEM; - } - - chain->next = NULL; - - nghttp2_buf_wrap_init(&chain->buf, begin, len); - - bufs->mem = mem; - bufs->offset = 0; - - bufs->head = chain; - bufs->cur = bufs->head; - - bufs->chunk_length = len; - bufs->chunk_used = 1; - bufs->max_chunk = 1; - bufs->chunk_keep = 1; - - return 0; -} - -int nghttp2_bufs_wrap_init2(nghttp2_bufs *bufs, const nghttp2_vec *vec, - size_t veclen, nghttp2_mem *mem) { - size_t i = 0; - nghttp2_buf_chain *cur_chain; - nghttp2_buf_chain *head_chain; - nghttp2_buf_chain **dst_chain = &head_chain; - - if (veclen == 0) { - return nghttp2_bufs_wrap_init(bufs, NULL, 0, mem); - } - - head_chain = nghttp2_mem_malloc(mem, sizeof(nghttp2_buf_chain) * veclen); - if (head_chain == NULL) { - return NGHTTP2_ERR_NOMEM; - } - - for (i = 0; i < veclen; ++i) { - cur_chain = &head_chain[i]; - cur_chain->next = NULL; - nghttp2_buf_wrap_init(&cur_chain->buf, vec[i].base, vec[i].len); - - *dst_chain = cur_chain; - dst_chain = &cur_chain->next; - } - - bufs->mem = mem; - bufs->offset = 0; - - bufs->head = head_chain; - bufs->cur = bufs->head; - - /* We don't use chunk_length since no allocation is expected. */ - bufs->chunk_length = 0; - bufs->chunk_used = veclen; - bufs->max_chunk = veclen; - bufs->chunk_keep = veclen; - - return 0; -} - -void nghttp2_bufs_wrap_free(nghttp2_bufs *bufs) { - if (bufs == NULL) { - return; - } - - if (bufs->head) { - nghttp2_mem_free(bufs->mem, bufs->head); - } -} - -void nghttp2_bufs_seek_last_present(nghttp2_bufs *bufs) { - nghttp2_buf_chain *ci; - - for (ci = bufs->cur; ci; ci = ci->next) { - if (nghttp2_buf_len(&ci->buf) == 0) { - return; - } else { - bufs->cur = ci; - } - } -} - -size_t nghttp2_bufs_len(nghttp2_bufs *bufs) { - nghttp2_buf_chain *ci; - size_t len; - - len = 0; - for (ci = bufs->head; ci; ci = ci->next) { - len += nghttp2_buf_len(&ci->buf); - } - - return len; -} - -static int bufs_alloc_chain(nghttp2_bufs *bufs) { - int rv; - nghttp2_buf_chain *chain; - - if (bufs->cur->next) { - bufs->cur = bufs->cur->next; - - return 0; - } - - if (bufs->max_chunk == bufs->chunk_used) { - return NGHTTP2_ERR_BUFFER_ERROR; - } - - rv = buf_chain_new(&chain, bufs->chunk_length, bufs->mem); - if (rv != 0) { - return rv; - } - - DEBUGF("new buffer %zu bytes allocated for bufs %p, used %zu\n", - bufs->chunk_length, bufs, bufs->chunk_used); - - ++bufs->chunk_used; - - bufs->cur->next = chain; - bufs->cur = chain; - - nghttp2_buf_shift_right(&bufs->cur->buf, bufs->offset); - - return 0; -} - -int nghttp2_bufs_add(nghttp2_bufs *bufs, const void *data, size_t len) { - int rv; - size_t nwrite; - nghttp2_buf *buf; - const uint8_t *p; - - p = data; - - while (len) { - buf = &bufs->cur->buf; - - nwrite = nghttp2_min_size(nghttp2_buf_avail(buf), len); - if (nwrite == 0) { - rv = bufs_alloc_chain(bufs); - if (rv != 0) { - return rv; - } - continue; - } - - buf->last = nghttp2_cpymem(buf->last, p, nwrite); - p += nwrite; - len -= nwrite; - } - - return 0; -} - -static int bufs_ensure_addb(nghttp2_bufs *bufs) { - int rv; - nghttp2_buf *buf; - - buf = &bufs->cur->buf; - - if (nghttp2_buf_avail(buf) > 0) { - return 0; - } - - rv = bufs_alloc_chain(bufs); - if (rv != 0) { - return rv; - } - - return 0; -} - -int nghttp2_bufs_addb(nghttp2_bufs *bufs, uint8_t b) { - int rv; - - rv = bufs_ensure_addb(bufs); - if (rv != 0) { - return rv; - } - - *bufs->cur->buf.last++ = b; - - return 0; -} - -int nghttp2_bufs_addb_hold(nghttp2_bufs *bufs, uint8_t b) { - int rv; - - rv = bufs_ensure_addb(bufs); - if (rv != 0) { - return rv; - } - - *bufs->cur->buf.last = b; - - return 0; -} - -int nghttp2_bufs_orb(nghttp2_bufs *bufs, uint8_t b) { - int rv; - - rv = bufs_ensure_addb(bufs); - if (rv != 0) { - return rv; - } - - *bufs->cur->buf.last++ |= b; - - return 0; -} - -int nghttp2_bufs_orb_hold(nghttp2_bufs *bufs, uint8_t b) { - int rv; - - rv = bufs_ensure_addb(bufs); - if (rv != 0) { - return rv; - } - - *bufs->cur->buf.last |= b; - - return 0; -} - -nghttp2_ssize nghttp2_bufs_remove(nghttp2_bufs *bufs, uint8_t **out) { - size_t len; - nghttp2_buf_chain *chain; - nghttp2_buf *buf; - uint8_t *res; - nghttp2_buf resbuf; - - len = 0; - - for (chain = bufs->head; chain; chain = chain->next) { - len += nghttp2_buf_len(&chain->buf); - } - - if (len == 0) { - res = NULL; - return 0; - } - - res = nghttp2_mem_malloc(bufs->mem, len); - if (res == NULL) { - return NGHTTP2_ERR_NOMEM; - } - - nghttp2_buf_wrap_init(&resbuf, res, len); - - for (chain = bufs->head; chain; chain = chain->next) { - buf = &chain->buf; - resbuf.last = nghttp2_cpymem(resbuf.last, buf->pos, nghttp2_buf_len(buf)); - } - - *out = res; - - return (nghttp2_ssize)len; -} - -size_t nghttp2_bufs_remove_copy(nghttp2_bufs *bufs, uint8_t *out) { - size_t len; - nghttp2_buf_chain *chain; - nghttp2_buf *buf; - nghttp2_buf resbuf; - - len = nghttp2_bufs_len(bufs); - - nghttp2_buf_wrap_init(&resbuf, out, len); - - for (chain = bufs->head; chain; chain = chain->next) { - buf = &chain->buf; - resbuf.last = nghttp2_cpymem(resbuf.last, buf->pos, nghttp2_buf_len(buf)); - } - - return len; -} - -void nghttp2_bufs_reset(nghttp2_bufs *bufs) { - nghttp2_buf_chain *chain, *ci; - size_t k; - - k = bufs->chunk_keep; - - for (ci = bufs->head; ci; ci = ci->next) { - nghttp2_buf_reset(&ci->buf); - nghttp2_buf_shift_right(&ci->buf, bufs->offset); - - if (--k == 0) { - break; - } - } - - if (ci) { - chain = ci->next; - ci->next = NULL; - - for (ci = chain; ci;) { - chain = ci->next; - - buf_chain_del(ci, bufs->mem); - - ci = chain; - } - - bufs->chunk_used = bufs->chunk_keep; - } - - bufs->cur = bufs->head; -} - -int nghttp2_bufs_advance(nghttp2_bufs *bufs) { return bufs_alloc_chain(bufs); } - -int nghttp2_bufs_next_present(nghttp2_bufs *bufs) { - nghttp2_buf_chain *chain; - - chain = bufs->cur->next; - - return chain && nghttp2_buf_len(&chain->buf); -} diff --git a/3rdparty/exported/nghttp2/nghttp2_buf.h b/3rdparty/exported/nghttp2/nghttp2_buf.h deleted file mode 100644 index 95ff3706a232..000000000000 --- a/3rdparty/exported/nghttp2/nghttp2_buf.h +++ /dev/null @@ -1,412 +0,0 @@ -/* - * nghttp2 - HTTP/2 C Library - * - * Copyright (c) 2014 Tatsuhiro Tsujikawa - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE - * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION - * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION - * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ -#ifndef NGHTTP2_BUF_H -#define NGHTTP2_BUF_H - -#ifdef HAVE_CONFIG_H -# include -#endif /* HAVE_CONFIG_H */ - -#include - -#include "nghttp2_int.h" -#include "nghttp2_mem.h" - -typedef struct { - /* This points to the beginning of the buffer. The effective range - of buffer is [begin, end). */ - uint8_t *begin; - /* This points to the memory one byte beyond the end of the - buffer. */ - uint8_t *end; - /* The position indicator for effective start of the buffer. pos <= - last must be hold. */ - uint8_t *pos; - /* The position indicator for effective one beyond of the end of the - buffer. last <= end must be hold. */ - uint8_t *last; - /* Mark arbitrary position in buffer [begin, end) */ - uint8_t *mark; -} nghttp2_buf; - -#define nghttp2_buf_len(BUF) ((size_t)((BUF)->last - (BUF)->pos)) -#define nghttp2_buf_avail(BUF) ((size_t)((BUF)->end - (BUF)->last)) -#define nghttp2_buf_mark_avail(BUF) ((size_t)((BUF)->mark - (BUF)->last)) -#define nghttp2_buf_cap(BUF) ((size_t)((BUF)->end - (BUF)->begin)) - -#define nghttp2_buf_pos_offset(BUF) ((size_t)((BUF)->pos - (BUF)->begin)) -#define nghttp2_buf_last_offset(BUF) ((size_t)((BUF)->last - (BUF)->begin)) - -#define nghttp2_buf_shift_right(BUF, AMT) \ - do { \ - (BUF)->pos += AMT; \ - (BUF)->last += AMT; \ - } while (0) - -#define nghttp2_buf_shift_left(BUF, AMT) \ - do { \ - (BUF)->pos -= AMT; \ - (BUF)->last -= AMT; \ - } while (0) - -/* - * Initializes the |buf|. No memory is allocated in this function. Use - * nghttp2_buf_reserve() to allocate memory. - */ -void nghttp2_buf_init(nghttp2_buf *buf); - -/* - * Initializes the |buf| and allocates at least |initial| bytes of - * memory. - * - * This function returns 0 if it succeeds, or one of the following - * negative error codes: - * - * NGHTTP2_ERR_NOMEM - * Out of memory - */ -int nghttp2_buf_init2(nghttp2_buf *buf, size_t initial, nghttp2_mem *mem); - -/* - * Frees buffer in |buf|. - */ -void nghttp2_buf_free(nghttp2_buf *buf, nghttp2_mem *mem); - -/* - * Extends buffer so that nghttp2_buf_cap() returns at least - * |new_cap|. If extensions took place, buffer pointers in |buf| will - * change. - * - * This function returns 0 if it succeeds, or one of the following - * negative error codes: - * - * NGHTTP2_ERR_NOMEM - * Out of memory - */ -int nghttp2_buf_reserve(nghttp2_buf *buf, size_t new_cap, nghttp2_mem *mem); - -/* - * Resets pos, last, mark member of |buf| to buf->begin. - */ -void nghttp2_buf_reset(nghttp2_buf *buf); - -/* - * Initializes |buf| using supplied buffer |begin| of length - * |len|. Semantically, the application should not call *_reserve() or - * nghttp2_free() functions for |buf|. - */ -void nghttp2_buf_wrap_init(nghttp2_buf *buf, uint8_t *begin, size_t len); - -struct nghttp2_buf_chain; - -typedef struct nghttp2_buf_chain nghttp2_buf_chain; - -/* Chains 2 buffers */ -struct nghttp2_buf_chain { - /* Points to the subsequent buffer. NULL if there is no such - buffer. */ - nghttp2_buf_chain *next; - nghttp2_buf buf; -}; - -typedef struct { - /* Points to the first buffer */ - nghttp2_buf_chain *head; - /* Buffer pointer where write occurs. */ - nghttp2_buf_chain *cur; - /* Memory allocator */ - nghttp2_mem *mem; - /* The buffer capacity of each buf. This field may be 0 if - nghttp2_bufs is initialized by nghttp2_bufs_wrap_init* family - functions. */ - size_t chunk_length; - /* The maximum number of nghttp2_buf_chain */ - size_t max_chunk; - /* The number of nghttp2_buf_chain allocated */ - size_t chunk_used; - /* The number of nghttp2_buf_chain to keep on reset */ - size_t chunk_keep; - /* pos offset from begin in each buffers. On initialization and - reset, buf->pos and buf->last are positioned at buf->begin + - offset. */ - size_t offset; -} nghttp2_bufs; - -/* - * This is the same as calling nghttp2_bufs_init2 with the given - * arguments and offset = 0. - */ -int nghttp2_bufs_init(nghttp2_bufs *bufs, size_t chunk_length, size_t max_chunk, - nghttp2_mem *mem); - -/* - * This is the same as calling nghttp2_bufs_init3 with the given - * arguments and chunk_keep = max_chunk. - */ -int nghttp2_bufs_init2(nghttp2_bufs *bufs, size_t chunk_length, - size_t max_chunk, size_t offset, nghttp2_mem *mem); - -/* - * Initializes |bufs|. Each buffer size is given in the - * |chunk_length|. The maximum number of buffers is given in the - * |max_chunk|. On reset, first |chunk_keep| buffers are kept and - * remaining buffers are deleted. Each buffer will have bufs->pos and - * bufs->last shifted to left by |offset| bytes on creation and reset. - * - * This function allocates first buffer. bufs->head and bufs->cur - * will point to the first buffer after this call. - * - * This function returns 0 if it succeeds, or one of the following - * negative error codes: - * - * NGHTTP2_ERR_NOMEM - * Out of memory. - * NGHTTP2_ERR_INVALID_ARGUMENT - * chunk_keep is 0; or max_chunk < chunk_keep; or offset is too - * long. - */ -int nghttp2_bufs_init3(nghttp2_bufs *bufs, size_t chunk_length, - size_t max_chunk, size_t chunk_keep, size_t offset, - nghttp2_mem *mem); - -/* - * Frees any related resources to the |bufs|. - */ -void nghttp2_bufs_free(nghttp2_bufs *bufs); - -/* - * Initializes |bufs| using supplied buffer |begin| of length |len|. - * The first buffer bufs->head uses buffer |begin|. The buffer size - * is fixed and no extra chunk buffer is allocated. In other - * words, max_chunk = chunk_keep = 1. To free the resource allocated - * for |bufs|, use nghttp2_bufs_wrap_free(). - * - * Don't use the function which performs allocation, such as - * nghttp2_bufs_realloc(). - * - * This function returns 0 if it succeeds, or one of the following - * negative error codes: - * - * NGHTTP2_ERR_NOMEM - * Out of memory. - */ -int nghttp2_bufs_wrap_init(nghttp2_bufs *bufs, uint8_t *begin, size_t len, - nghttp2_mem *mem); - -/* - * Initializes |bufs| using supplied |veclen| size of buf vector - * |vec|. The number of buffers is fixed and no extra chunk buffer is - * allocated. In other words, max_chunk = chunk_keep = |in_len|. To - * free the resource allocated for |bufs|, use - * nghttp2_bufs_wrap_free(). - * - * Don't use the function which performs allocation, such as - * nghttp2_bufs_realloc(). - * - * This function returns 0 if it succeeds, or one of the following - * negative error codes: - * - * NGHTTP2_ERR_NOMEM - * Out of memory. - */ -int nghttp2_bufs_wrap_init2(nghttp2_bufs *bufs, const nghttp2_vec *vec, - size_t veclen, nghttp2_mem *mem); - -/* - * Frees any related resource to the |bufs|. This function does not - * free supplied buffer provided in nghttp2_bufs_wrap_init(). - */ -void nghttp2_bufs_wrap_free(nghttp2_bufs *bufs); - -/* - * Reallocates internal buffer using |chunk_length|. The max_chunk, - * chunk_keep and offset do not change. After successful allocation - * of new buffer, previous buffers are deallocated without copying - * anything into new buffers. chunk_used is reset to 1. - * - * This function returns 0 if it succeeds, or one of the following - * negative error codes: - * - * NGHTTP2_ERR_NOMEM - * Out of memory. - * NGHTTP2_ERR_INVALID_ARGUMENT - * chunk_length < offset - */ -int nghttp2_bufs_realloc(nghttp2_bufs *bufs, size_t chunk_length); - -/* - * Appends the |data| of length |len| to the |bufs|. The write starts - * at bufs->cur->buf.last. A new buffers will be allocated to store - * all data. - * - * This function returns 0 if it succeeds, or one of the following - * negative error codes: - * - * NGHTTP2_ERR_NOMEM - * Out of memory. - * NGHTTP2_ERR_BUFFER_ERROR - * Out of buffer space. - */ -int nghttp2_bufs_add(nghttp2_bufs *bufs, const void *data, size_t len); - -/* - * Appends a single byte |b| to the |bufs|. The write starts at - * bufs->cur->buf.last. A new buffers will be allocated to store all - * data. - * - * This function returns 0 if it succeeds, or one of the following - * negative error codes: - * - * NGHTTP2_ERR_NOMEM - * Out of memory. - * NGHTTP2_ERR_BUFFER_ERROR - * Out of buffer space. - */ -int nghttp2_bufs_addb(nghttp2_bufs *bufs, uint8_t b); - -/* - * Behaves like nghttp2_bufs_addb(), but this does not update - * buf->last pointer. - */ -int nghttp2_bufs_addb_hold(nghttp2_bufs *bufs, uint8_t b); - -#define nghttp2_bufs_fast_addb(BUFS, B) \ - do { \ - *(BUFS)->cur->buf.last++ = B; \ - } while (0) - -#define nghttp2_bufs_fast_addb_hold(BUFS, B) \ - do { \ - *(BUFS)->cur->buf.last = B; \ - } while (0) - -/* - * Performs bitwise-OR of |b| at bufs->cur->buf.last. A new buffers - * will be allocated if necessary. - * - * This function returns 0 if it succeeds, or one of the following - * negative error codes: - * - * NGHTTP2_ERR_NOMEM - * Out of memory. - * NGHTTP2_ERR_BUFFER_ERROR - * Out of buffer space. - */ -int nghttp2_bufs_orb(nghttp2_bufs *bufs, uint8_t b); - -/* - * Behaves like nghttp2_bufs_orb(), but does not update buf->last - * pointer. - */ -int nghttp2_bufs_orb_hold(nghttp2_bufs *bufs, uint8_t b); - -#define nghttp2_bufs_fast_orb(BUFS, B) \ - do { \ - uint8_t **p = &(BUFS)->cur->buf.last; \ - **p = (uint8_t)(**p | (B)); \ - ++(*p); \ - } while (0) - -#define nghttp2_bufs_fast_orb_hold(BUFS, B) \ - do { \ - uint8_t *p = (BUFS)->cur->buf.last; \ - *p = (uint8_t)(*p | (B)); \ - } while (0) - -/* - * Copies all data stored in |bufs| to the contiguous buffer. This - * function allocates the contiguous memory to store all data in - * |bufs| and assigns it to |*out|. - * - * The contents of |bufs| is left unchanged. - * - * This function returns the length of copied data and assigns the - * pointer to copied data to |*out| if it succeeds, or one of the - * following negative error codes: - * - * NGHTTP2_ERR_NOMEM - * Out of memory - */ -nghttp2_ssize nghttp2_bufs_remove(nghttp2_bufs *bufs, uint8_t **out); - -/* - * Copies all data stored in |bufs| to |out|. This function assumes - * that the buffer space pointed by |out| has at least - * nghttp2_bufs(bufs) bytes. - * - * The contents of |bufs| is left unchanged. - * - * This function returns the length of copied data. - */ -size_t nghttp2_bufs_remove_copy(nghttp2_bufs *bufs, uint8_t *out); - -/* - * Resets |bufs| and makes the buffers empty. - */ -void nghttp2_bufs_reset(nghttp2_bufs *bufs); - -/* - * Moves bufs->cur to bufs->cur->next. If resulting bufs->cur is - * NULL, this function allocates new buffers and bufs->cur points to - * it. - * - * This function returns 0 if it succeeds, or one of the following - * negative error codes: - * - * NGHTTP2_ERR_NOMEM - * Out of memory - * NGHTTP2_ERR_BUFFER_ERROR - * Out of buffer space. - */ -int nghttp2_bufs_advance(nghttp2_bufs *bufs); - -/* Sets bufs->cur to bufs->head */ -#define nghttp2_bufs_rewind(BUFS) \ - do { \ - (BUFS)->cur = (BUFS)->head; \ - } while (0) - -/* - * Move bufs->cur, from the current position, using next member, to - * the last buf which has nghttp2_buf_len(buf) > 0 without seeing buf - * which satisfies nghttp2_buf_len(buf) == 0. If - * nghttp2_buf_len(&bufs->cur->buf) == 0 or bufs->cur->next is NULL, - * bufs->cur is unchanged. - */ -void nghttp2_bufs_seek_last_present(nghttp2_bufs *bufs); - -/* - * Returns nonzero if bufs->cur->next is not empty. - */ -int nghttp2_bufs_next_present(nghttp2_bufs *bufs); - -#define nghttp2_bufs_cur_avail(BUFS) nghttp2_buf_avail(&(BUFS)->cur->buf) - -/* - * Returns the total buffer length of |bufs|. - */ -size_t nghttp2_bufs_len(nghttp2_bufs *bufs); - -#endif /* NGHTTP2_BUF_H */ diff --git a/3rdparty/exported/nghttp2/nghttp2_callbacks.c b/3rdparty/exported/nghttp2/nghttp2_callbacks.c deleted file mode 100644 index 32fedd52d85a..000000000000 --- a/3rdparty/exported/nghttp2/nghttp2_callbacks.c +++ /dev/null @@ -1,203 +0,0 @@ -/* - * nghttp2 - HTTP/2 C Library - * - * Copyright (c) 2014 Tatsuhiro Tsujikawa - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE - * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION - * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION - * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ -#include "nghttp2_callbacks.h" - -#include - -int nghttp2_session_callbacks_new(nghttp2_session_callbacks **callbacks_ptr) { - *callbacks_ptr = calloc(1, sizeof(nghttp2_session_callbacks)); - - if (*callbacks_ptr == NULL) { - return NGHTTP2_ERR_NOMEM; - } - - return 0; -} - -void nghttp2_session_callbacks_del(nghttp2_session_callbacks *callbacks) { - free(callbacks); -} - -void nghttp2_session_callbacks_set_send_callback( - nghttp2_session_callbacks *cbs, nghttp2_send_callback send_callback) { - cbs->send_callback = send_callback; -} - -void nghttp2_session_callbacks_set_send_callback2( - nghttp2_session_callbacks *cbs, nghttp2_send_callback2 send_callback) { - cbs->send_callback2 = send_callback; -} - -void nghttp2_session_callbacks_set_recv_callback( - nghttp2_session_callbacks *cbs, nghttp2_recv_callback recv_callback) { - cbs->recv_callback = recv_callback; -} - -void nghttp2_session_callbacks_set_recv_callback2( - nghttp2_session_callbacks *cbs, nghttp2_recv_callback2 recv_callback) { - cbs->recv_callback2 = recv_callback; -} - -void nghttp2_session_callbacks_set_on_frame_recv_callback( - nghttp2_session_callbacks *cbs, - nghttp2_on_frame_recv_callback on_frame_recv_callback) { - cbs->on_frame_recv_callback = on_frame_recv_callback; -} - -void nghttp2_session_callbacks_set_on_invalid_frame_recv_callback( - nghttp2_session_callbacks *cbs, - nghttp2_on_invalid_frame_recv_callback on_invalid_frame_recv_callback) { - cbs->on_invalid_frame_recv_callback = on_invalid_frame_recv_callback; -} - -void nghttp2_session_callbacks_set_on_data_chunk_recv_callback( - nghttp2_session_callbacks *cbs, - nghttp2_on_data_chunk_recv_callback on_data_chunk_recv_callback) { - cbs->on_data_chunk_recv_callback = on_data_chunk_recv_callback; -} - -void nghttp2_session_callbacks_set_before_frame_send_callback( - nghttp2_session_callbacks *cbs, - nghttp2_before_frame_send_callback before_frame_send_callback) { - cbs->before_frame_send_callback = before_frame_send_callback; -} - -void nghttp2_session_callbacks_set_on_frame_send_callback( - nghttp2_session_callbacks *cbs, - nghttp2_on_frame_send_callback on_frame_send_callback) { - cbs->on_frame_send_callback = on_frame_send_callback; -} - -void nghttp2_session_callbacks_set_on_frame_not_send_callback( - nghttp2_session_callbacks *cbs, - nghttp2_on_frame_not_send_callback on_frame_not_send_callback) { - cbs->on_frame_not_send_callback = on_frame_not_send_callback; -} - -void nghttp2_session_callbacks_set_on_stream_close_callback( - nghttp2_session_callbacks *cbs, - nghttp2_on_stream_close_callback on_stream_close_callback) { - cbs->on_stream_close_callback = on_stream_close_callback; -} - -void nghttp2_session_callbacks_set_on_begin_headers_callback( - nghttp2_session_callbacks *cbs, - nghttp2_on_begin_headers_callback on_begin_headers_callback) { - cbs->on_begin_headers_callback = on_begin_headers_callback; -} - -void nghttp2_session_callbacks_set_on_header_callback( - nghttp2_session_callbacks *cbs, - nghttp2_on_header_callback on_header_callback) { - cbs->on_header_callback = on_header_callback; -} - -void nghttp2_session_callbacks_set_on_header_callback2( - nghttp2_session_callbacks *cbs, - nghttp2_on_header_callback2 on_header_callback2) { - cbs->on_header_callback2 = on_header_callback2; -} - -void nghttp2_session_callbacks_set_on_invalid_header_callback( - nghttp2_session_callbacks *cbs, - nghttp2_on_invalid_header_callback on_invalid_header_callback) { - cbs->on_invalid_header_callback = on_invalid_header_callback; -} - -void nghttp2_session_callbacks_set_on_invalid_header_callback2( - nghttp2_session_callbacks *cbs, - nghttp2_on_invalid_header_callback2 on_invalid_header_callback2) { - cbs->on_invalid_header_callback2 = on_invalid_header_callback2; -} - -void nghttp2_session_callbacks_set_select_padding_callback( - nghttp2_session_callbacks *cbs, - nghttp2_select_padding_callback select_padding_callback) { - cbs->select_padding_callback = select_padding_callback; -} - -void nghttp2_session_callbacks_set_select_padding_callback2( - nghttp2_session_callbacks *cbs, - nghttp2_select_padding_callback2 select_padding_callback) { - cbs->select_padding_callback2 = select_padding_callback; -} - -void nghttp2_session_callbacks_set_data_source_read_length_callback( - nghttp2_session_callbacks *cbs, - nghttp2_data_source_read_length_callback data_source_read_length_callback) { - cbs->read_length_callback = data_source_read_length_callback; -} - -void nghttp2_session_callbacks_set_data_source_read_length_callback2( - nghttp2_session_callbacks *cbs, - nghttp2_data_source_read_length_callback2 data_source_read_length_callback) { - cbs->read_length_callback2 = data_source_read_length_callback; -} - -void nghttp2_session_callbacks_set_on_begin_frame_callback( - nghttp2_session_callbacks *cbs, - nghttp2_on_begin_frame_callback on_begin_frame_callback) { - cbs->on_begin_frame_callback = on_begin_frame_callback; -} - -void nghttp2_session_callbacks_set_send_data_callback( - nghttp2_session_callbacks *cbs, - nghttp2_send_data_callback send_data_callback) { - cbs->send_data_callback = send_data_callback; -} - -void nghttp2_session_callbacks_set_pack_extension_callback( - nghttp2_session_callbacks *cbs, - nghttp2_pack_extension_callback pack_extension_callback) { - cbs->pack_extension_callback = pack_extension_callback; -} - -void nghttp2_session_callbacks_set_pack_extension_callback2( - nghttp2_session_callbacks *cbs, - nghttp2_pack_extension_callback2 pack_extension_callback) { - cbs->pack_extension_callback2 = pack_extension_callback; -} - -void nghttp2_session_callbacks_set_unpack_extension_callback( - nghttp2_session_callbacks *cbs, - nghttp2_unpack_extension_callback unpack_extension_callback) { - cbs->unpack_extension_callback = unpack_extension_callback; -} - -void nghttp2_session_callbacks_set_on_extension_chunk_recv_callback( - nghttp2_session_callbacks *cbs, - nghttp2_on_extension_chunk_recv_callback on_extension_chunk_recv_callback) { - cbs->on_extension_chunk_recv_callback = on_extension_chunk_recv_callback; -} - -void nghttp2_session_callbacks_set_error_callback( - nghttp2_session_callbacks *cbs, nghttp2_error_callback error_callback) { - cbs->error_callback = error_callback; -} - -void nghttp2_session_callbacks_set_error_callback2( - nghttp2_session_callbacks *cbs, nghttp2_error_callback2 error_callback2) { - cbs->error_callback2 = error_callback2; -} diff --git a/3rdparty/exported/nghttp2/nghttp2_callbacks.h b/3rdparty/exported/nghttp2/nghttp2_callbacks.h deleted file mode 100644 index a611f485481e..000000000000 --- a/3rdparty/exported/nghttp2/nghttp2_callbacks.h +++ /dev/null @@ -1,156 +0,0 @@ -/* - * nghttp2 - HTTP/2 C Library - * - * Copyright (c) 2014 Tatsuhiro Tsujikawa - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE - * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION - * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION - * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ -#ifndef NGHTTP2_CALLBACKS_H -#define NGHTTP2_CALLBACKS_H - -#ifdef HAVE_CONFIG_H -# include -#endif /* HAVE_CONFIG_H */ - -#include - -/* - * Callback functions. - */ -struct nghttp2_session_callbacks { - /** - * Deprecated. Use send_callback2 instead. Callback function - * invoked when the session wants to send data to the remote peer. - * This callback is not necessary if the application uses solely - * `nghttp2_session_mem_send()` to serialize data to transmit. - */ - nghttp2_send_callback send_callback; - /** - * Callback function invoked when the session wants to send data to - * the remote peer. This callback is not necessary if the - * application uses solely `nghttp2_session_mem_send2()` to - * serialize data to transmit. - */ - nghttp2_send_callback2 send_callback2; - /** - * Deprecated. Use recv_callback2 instead. Callback function - * invoked when the session wants to receive data from the remote - * peer. This callback is not necessary if the application uses - * solely `nghttp2_session_mem_recv()` to process received data. - */ - nghttp2_recv_callback recv_callback; - /** - * Callback function invoked when the session wants to receive data - * from the remote peer. This callback is not necessary if the - * application uses solely `nghttp2_session_mem_recv2()` to process - * received data. - */ - nghttp2_recv_callback2 recv_callback2; - /** - * Callback function invoked by `nghttp2_session_recv()` when a - * frame is received. - */ - nghttp2_on_frame_recv_callback on_frame_recv_callback; - /** - * Callback function invoked by `nghttp2_session_recv()` when an - * invalid non-DATA frame is received. - */ - nghttp2_on_invalid_frame_recv_callback on_invalid_frame_recv_callback; - /** - * Callback function invoked when a chunk of data in DATA frame is - * received. - */ - nghttp2_on_data_chunk_recv_callback on_data_chunk_recv_callback; - /** - * Callback function invoked before a non-DATA frame is sent. - */ - nghttp2_before_frame_send_callback before_frame_send_callback; - /** - * Callback function invoked after a frame is sent. - */ - nghttp2_on_frame_send_callback on_frame_send_callback; - /** - * The callback function invoked when a non-DATA frame is not sent - * because of an error. - */ - nghttp2_on_frame_not_send_callback on_frame_not_send_callback; - /** - * Callback function invoked when the stream is closed. - */ - nghttp2_on_stream_close_callback on_stream_close_callback; - /** - * Callback function invoked when the reception of header block in - * HEADERS or PUSH_PROMISE is started. - */ - nghttp2_on_begin_headers_callback on_begin_headers_callback; - /** - * Callback function invoked when a header name/value pair is - * received. - */ - nghttp2_on_header_callback on_header_callback; - nghttp2_on_header_callback2 on_header_callback2; - /** - * Callback function invoked when a invalid header name/value pair - * is received which is silently ignored if these callbacks are not - * set. - */ - nghttp2_on_invalid_header_callback on_invalid_header_callback; - nghttp2_on_invalid_header_callback2 on_invalid_header_callback2; - /** - * Deprecated. Use select_padding_callback2 instead. Callback - * function invoked when the library asks application how many - * padding bytes are required for the transmission of the given - * frame. - */ - nghttp2_select_padding_callback select_padding_callback; - /** - * Callback function invoked when the library asks application how - * many padding bytes are required for the transmission of the given - * frame. - */ - nghttp2_select_padding_callback2 select_padding_callback2; - /** - * Deprecated. Use read_length_callback2 instead. The callback - * function used to determine the length allowed in - * `nghttp2_data_source_read_callback()` - */ - nghttp2_data_source_read_length_callback read_length_callback; - /** - * The callback function used to determine the length allowed in - * `nghttp2_data_source_read_callback2()` - */ - nghttp2_data_source_read_length_callback2 read_length_callback2; - /** - * Sets callback function invoked when a frame header is received. - */ - nghttp2_on_begin_frame_callback on_begin_frame_callback; - nghttp2_send_data_callback send_data_callback; - /** - * Deprecated. Use pack_extension_callback2 instead. - */ - nghttp2_pack_extension_callback pack_extension_callback; - nghttp2_pack_extension_callback2 pack_extension_callback2; - nghttp2_unpack_extension_callback unpack_extension_callback; - nghttp2_on_extension_chunk_recv_callback on_extension_chunk_recv_callback; - nghttp2_error_callback error_callback; - nghttp2_error_callback2 error_callback2; -}; - -#endif /* NGHTTP2_CALLBACKS_H */ diff --git a/3rdparty/exported/nghttp2/nghttp2_debug.c b/3rdparty/exported/nghttp2/nghttp2_debug.c deleted file mode 100644 index 09dd2b28587a..000000000000 --- a/3rdparty/exported/nghttp2/nghttp2_debug.c +++ /dev/null @@ -1,60 +0,0 @@ -/* - * nghttp2 - HTTP/2 C Library - * - * Copyright (c) 2016 Tatsuhiro Tsujikawa - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE - * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION - * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION - * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ -#include "nghttp2_debug.h" - -#include - -#ifdef DEBUGBUILD - -static void nghttp2_default_debug_vfprintf_callback(const char *fmt, - va_list args) { - vfprintf(stderr, fmt, args); -} - -static nghttp2_debug_vprintf_callback static_debug_vprintf_callback = - nghttp2_default_debug_vfprintf_callback; - -void nghttp2_debug_vprintf(const char *format, ...) { - if (static_debug_vprintf_callback) { - va_list args; - va_start(args, format); - static_debug_vprintf_callback(format, args); - va_end(args); - } -} - -void nghttp2_set_debug_vprintf_callback( - nghttp2_debug_vprintf_callback debug_vprintf_callback) { - static_debug_vprintf_callback = debug_vprintf_callback; -} - -#else /* !DEBUGBUILD */ - -void nghttp2_set_debug_vprintf_callback( - nghttp2_debug_vprintf_callback debug_vprintf_callback) { - (void)debug_vprintf_callback; -} - -#endif /* !DEBUGBUILD */ diff --git a/3rdparty/exported/nghttp2/nghttp2_debug.h b/3rdparty/exported/nghttp2/nghttp2_debug.h deleted file mode 100644 index cbb4dd575472..000000000000 --- a/3rdparty/exported/nghttp2/nghttp2_debug.h +++ /dev/null @@ -1,43 +0,0 @@ -/* - * nghttp2 - HTTP/2 C Library - * - * Copyright (c) 2016 Tatsuhiro Tsujikawa - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE - * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION - * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION - * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ -#ifndef NGHTTP2_DEBUG_H -#define NGHTTP2_DEBUG_H - -#ifdef HAVE_CONFIG_H -# include -#endif /* HAVE_CONFIG_H */ - -#include - -#ifdef DEBUGBUILD -# define DEBUGF(...) nghttp2_debug_vprintf(__VA_ARGS__) -void nghttp2_debug_vprintf(const char *format, ...); -#else -# define DEBUGF(...) \ - do { \ - } while (0) -#endif - -#endif /* NGHTTP2_DEBUG_H */ diff --git a/3rdparty/exported/nghttp2/nghttp2_extpri.c b/3rdparty/exported/nghttp2/nghttp2_extpri.c deleted file mode 100644 index ba0263e7c8eb..000000000000 --- a/3rdparty/exported/nghttp2/nghttp2_extpri.c +++ /dev/null @@ -1,41 +0,0 @@ -/* - * nghttp2 - HTTP/2 C Library - * - * Copyright (c) 2022 nghttp3 contributors - * Copyright (c) 2022 nghttp2 contributors - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE - * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION - * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION - * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ -#include "nghttp2_extpri.h" -#include "nghttp2_http.h" - -uint8_t nghttp2_extpri_to_uint8(const nghttp2_extpri *extpri) { - return (uint8_t)((uint32_t)extpri->inc << 7 | extpri->urgency); -} - -void nghttp2_extpri_from_uint8(nghttp2_extpri *extpri, uint8_t u8extpri) { - extpri->urgency = nghttp2_extpri_uint8_urgency(u8extpri); - extpri->inc = nghttp2_extpri_uint8_inc(u8extpri); -} - -int nghttp2_extpri_parse_priority(nghttp2_extpri *extpri, const uint8_t *value, - size_t len) { - return nghttp2_http_parse_priority(extpri, value, len); -} diff --git a/3rdparty/exported/nghttp2/nghttp2_extpri.h b/3rdparty/exported/nghttp2/nghttp2_extpri.h deleted file mode 100644 index db911972084c..000000000000 --- a/3rdparty/exported/nghttp2/nghttp2_extpri.h +++ /dev/null @@ -1,65 +0,0 @@ -/* - * nghttp2 - HTTP/2 C Library - * - * Copyright (c) 2022 nghttp3 contributors - * Copyright (c) 2022 nghttp2 contributors - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE - * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION - * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION - * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ -#ifndef NGHTTP2_EXTPRI_H -#define NGHTTP2_EXTPRI_H - -#ifdef HAVE_CONFIG_H -# include -#endif /* HAVE_CONFIG_H */ - -#include - -/* - * NGHTTP2_EXTPRI_INC_MASK is a bit mask to retrieve incremental bit - * from a value produced by nghttp2_extpri_to_uint8. - */ -#define NGHTTP2_EXTPRI_INC_MASK (1 << 7) - -/* - * nghttp2_extpri_to_uint8 encodes |pri| into uint8_t variable. - */ -uint8_t nghttp2_extpri_to_uint8(const nghttp2_extpri *extpri); - -/* - * nghttp2_extpri_from_uint8 decodes |u8extpri|, which is produced by - * nghttp2_extpri_to_uint8, intto |extpri|. - */ -void nghttp2_extpri_from_uint8(nghttp2_extpri *extpri, uint8_t u8extpri); - -/* - * nghttp2_extpri_uint8_urgency extracts urgency from |PRI| which is - * supposed to be constructed by nghttp2_extpri_to_uint8. - */ -#define nghttp2_extpri_uint8_urgency(PRI) \ - ((uint32_t)((PRI) & ~NGHTTP2_EXTPRI_INC_MASK)) - -/* - * nghttp2_extpri_uint8_inc extracts inc from |PRI| which is supposed to - * be constructed by nghttp2_extpri_to_uint8. - */ -#define nghttp2_extpri_uint8_inc(PRI) (((PRI) & NGHTTP2_EXTPRI_INC_MASK) != 0) - -#endif /* NGHTTP2_EXTPRI_H */ diff --git a/3rdparty/exported/nghttp2/nghttp2_frame.c b/3rdparty/exported/nghttp2/nghttp2_frame.c deleted file mode 100644 index edc2aaaae9ed..000000000000 --- a/3rdparty/exported/nghttp2/nghttp2_frame.c +++ /dev/null @@ -1,1214 +0,0 @@ -/* - * nghttp2 - HTTP/2 C Library - * - * Copyright (c) 2013 Tatsuhiro Tsujikawa - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE - * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION - * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION - * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ -#include "nghttp2_frame.h" - -#include -#include -#include -#include - -#include "nghttp2_helper.h" -#include "nghttp2_net.h" -#include "nghttp2_priority_spec.h" -#include "nghttp2_debug.h" - -void nghttp2_frame_pack_frame_hd(uint8_t *buf, const nghttp2_frame_hd *hd) { - nghttp2_put_uint32be(&buf[0], (uint32_t)(hd->length << 8)); - buf[3] = hd->type; - buf[4] = hd->flags; - nghttp2_put_uint32be(&buf[5], (uint32_t)hd->stream_id); - /* ignore hd->reserved for now */ -} - -void nghttp2_frame_unpack_frame_hd(nghttp2_frame_hd *hd, const uint8_t *buf) { - hd->length = nghttp2_get_uint32(&buf[0]) >> 8; - hd->type = buf[3]; - hd->flags = buf[4]; - hd->stream_id = nghttp2_get_uint32(&buf[5]) & NGHTTP2_STREAM_ID_MASK; - hd->reserved = 0; -} - -void nghttp2_frame_hd_init(nghttp2_frame_hd *hd, size_t length, uint8_t type, - uint8_t flags, int32_t stream_id) { - hd->length = length; - hd->type = type; - hd->flags = flags; - hd->stream_id = stream_id; - hd->reserved = 0; -} - -void nghttp2_frame_headers_init(nghttp2_headers *frame, uint8_t flags, - int32_t stream_id, nghttp2_headers_category cat, - const nghttp2_priority_spec *pri_spec, - nghttp2_nv *nva, size_t nvlen) { - nghttp2_frame_hd_init(&frame->hd, 0, NGHTTP2_HEADERS, flags, stream_id); - frame->padlen = 0; - frame->nva = nva; - frame->nvlen = nvlen; - frame->cat = cat; - - if (pri_spec) { - frame->pri_spec = *pri_spec; - } else { - nghttp2_priority_spec_default_init(&frame->pri_spec); - } -} - -void nghttp2_frame_headers_free(nghttp2_headers *frame, nghttp2_mem *mem) { - nghttp2_nv_array_del(frame->nva, mem); -} - -void nghttp2_frame_priority_init(nghttp2_priority *frame, int32_t stream_id, - const nghttp2_priority_spec *pri_spec) { - nghttp2_frame_hd_init(&frame->hd, NGHTTP2_PRIORITY_SPECLEN, NGHTTP2_PRIORITY, - NGHTTP2_FLAG_NONE, stream_id); - frame->pri_spec = *pri_spec; -} - -void nghttp2_frame_priority_free(nghttp2_priority *frame) { (void)frame; } - -void nghttp2_frame_rst_stream_init(nghttp2_rst_stream *frame, int32_t stream_id, - uint32_t error_code) { - nghttp2_frame_hd_init(&frame->hd, 4, NGHTTP2_RST_STREAM, NGHTTP2_FLAG_NONE, - stream_id); - frame->error_code = error_code; -} - -void nghttp2_frame_rst_stream_free(nghttp2_rst_stream *frame) { (void)frame; } - -void nghttp2_frame_settings_init(nghttp2_settings *frame, uint8_t flags, - nghttp2_settings_entry *iv, size_t niv) { - nghttp2_frame_hd_init(&frame->hd, niv * NGHTTP2_FRAME_SETTINGS_ENTRY_LENGTH, - NGHTTP2_SETTINGS, flags, 0); - frame->niv = niv; - frame->iv = iv; -} - -void nghttp2_frame_settings_free(nghttp2_settings *frame, nghttp2_mem *mem) { - nghttp2_mem_free(mem, frame->iv); -} - -void nghttp2_frame_push_promise_init(nghttp2_push_promise *frame, uint8_t flags, - int32_t stream_id, - int32_t promised_stream_id, - nghttp2_nv *nva, size_t nvlen) { - nghttp2_frame_hd_init(&frame->hd, 0, NGHTTP2_PUSH_PROMISE, flags, stream_id); - frame->padlen = 0; - frame->nva = nva; - frame->nvlen = nvlen; - frame->promised_stream_id = promised_stream_id; - frame->reserved = 0; -} - -void nghttp2_frame_push_promise_free(nghttp2_push_promise *frame, - nghttp2_mem *mem) { - nghttp2_nv_array_del(frame->nva, mem); -} - -void nghttp2_frame_ping_init(nghttp2_ping *frame, uint8_t flags, - const uint8_t *opaque_data) { - nghttp2_frame_hd_init(&frame->hd, 8, NGHTTP2_PING, flags, 0); - if (opaque_data) { - memcpy(frame->opaque_data, opaque_data, sizeof(frame->opaque_data)); - } else { - memset(frame->opaque_data, 0, sizeof(frame->opaque_data)); - } -} - -void nghttp2_frame_ping_free(nghttp2_ping *frame) { (void)frame; } - -void nghttp2_frame_goaway_init(nghttp2_goaway *frame, int32_t last_stream_id, - uint32_t error_code, uint8_t *opaque_data, - size_t opaque_data_len) { - nghttp2_frame_hd_init(&frame->hd, 8 + opaque_data_len, NGHTTP2_GOAWAY, - NGHTTP2_FLAG_NONE, 0); - frame->last_stream_id = last_stream_id; - frame->error_code = error_code; - frame->opaque_data = opaque_data; - frame->opaque_data_len = opaque_data_len; - frame->reserved = 0; -} - -void nghttp2_frame_goaway_free(nghttp2_goaway *frame, nghttp2_mem *mem) { - nghttp2_mem_free(mem, frame->opaque_data); -} - -void nghttp2_frame_window_update_init(nghttp2_window_update *frame, - uint8_t flags, int32_t stream_id, - int32_t window_size_increment) { - nghttp2_frame_hd_init(&frame->hd, 4, NGHTTP2_WINDOW_UPDATE, flags, stream_id); - frame->window_size_increment = window_size_increment; - frame->reserved = 0; -} - -void nghttp2_frame_window_update_free(nghttp2_window_update *frame) { - (void)frame; -} - -size_t nghttp2_frame_trail_padlen(nghttp2_frame *frame, size_t padlen) { - /* We have iframe->padlen == 0, but iframe->frame.hd.flags may have - NGHTTP2_FLAG_PADDED set. This happens when receiving - CONTINUATION frame, since we don't reset flags after HEADERS was - received. */ - if (padlen == 0) { - return 0; - } - return padlen - ((frame->hd.flags & NGHTTP2_FLAG_PADDED) > 0); -} - -void nghttp2_frame_data_init(nghttp2_data *frame, uint8_t flags, - int32_t stream_id) { - /* At this moment, the length of DATA frame is unknown */ - nghttp2_frame_hd_init(&frame->hd, 0, NGHTTP2_DATA, flags, stream_id); - frame->padlen = 0; -} - -void nghttp2_frame_data_free(nghttp2_data *frame) { (void)frame; } - -void nghttp2_frame_extension_init(nghttp2_extension *frame, uint8_t type, - uint8_t flags, int32_t stream_id, - void *payload) { - nghttp2_frame_hd_init(&frame->hd, 0, type, flags, stream_id); - frame->payload = payload; -} - -void nghttp2_frame_extension_free(nghttp2_extension *frame) { (void)frame; } - -void nghttp2_frame_altsvc_init(nghttp2_extension *frame, int32_t stream_id, - uint8_t *origin, size_t origin_len, - uint8_t *field_value, size_t field_value_len) { - nghttp2_ext_altsvc *altsvc; - - nghttp2_frame_hd_init(&frame->hd, 2 + origin_len + field_value_len, - NGHTTP2_ALTSVC, NGHTTP2_FLAG_NONE, stream_id); - - altsvc = frame->payload; - altsvc->origin = origin; - altsvc->origin_len = origin_len; - altsvc->field_value = field_value; - altsvc->field_value_len = field_value_len; -} - -void nghttp2_frame_altsvc_free(nghttp2_extension *frame, nghttp2_mem *mem) { - nghttp2_ext_altsvc *altsvc; - - altsvc = frame->payload; - if (altsvc == NULL) { - return; - } - /* We use the same buffer for altsvc->origin and - altsvc->field_value. */ - nghttp2_mem_free(mem, altsvc->origin); -} - -void nghttp2_frame_origin_init(nghttp2_extension *frame, - nghttp2_origin_entry *ov, size_t nov) { - nghttp2_ext_origin *origin; - size_t payloadlen = 0; - size_t i; - - for (i = 0; i < nov; ++i) { - payloadlen += 2 + ov[i].origin_len; - } - - nghttp2_frame_hd_init(&frame->hd, payloadlen, NGHTTP2_ORIGIN, - NGHTTP2_FLAG_NONE, 0); - - origin = frame->payload; - origin->ov = ov; - origin->nov = nov; -} - -void nghttp2_frame_origin_free(nghttp2_extension *frame, nghttp2_mem *mem) { - nghttp2_ext_origin *origin; - - origin = frame->payload; - if (origin == NULL) { - return; - } - /* We use the same buffer for all resources pointed by the field of - origin directly or indirectly. */ - nghttp2_mem_free(mem, origin->ov); -} - -void nghttp2_frame_priority_update_init(nghttp2_extension *frame, - int32_t stream_id, uint8_t *field_value, - size_t field_value_len) { - nghttp2_ext_priority_update *priority_update; - - nghttp2_frame_hd_init(&frame->hd, 4 + field_value_len, - NGHTTP2_PRIORITY_UPDATE, NGHTTP2_FLAG_NONE, 0); - - priority_update = frame->payload; - priority_update->stream_id = stream_id; - priority_update->field_value = field_value; - priority_update->field_value_len = field_value_len; -} - -void nghttp2_frame_priority_update_free(nghttp2_extension *frame, - nghttp2_mem *mem) { - nghttp2_ext_priority_update *priority_update; - - priority_update = frame->payload; - if (priority_update == NULL) { - return; - } - nghttp2_mem_free(mem, priority_update->field_value); -} - -size_t nghttp2_frame_priority_len(uint8_t flags) { - if (flags & NGHTTP2_FLAG_PRIORITY) { - return NGHTTP2_PRIORITY_SPECLEN; - } - - return 0; -} - -size_t nghttp2_frame_headers_payload_nv_offset(nghttp2_headers *frame) { - return nghttp2_frame_priority_len(frame->hd.flags); -} - -/* - * Call this function after payload was serialized, but not before - * changing buf->pos and serializing frame header. - * - * This function assumes bufs->cur points to the last buf chain of the - * frame(s). - * - * This function serializes frame header for HEADERS/PUSH_PROMISE and - * handles their successive CONTINUATION frames. - * - * We don't process any padding here. - */ -static int frame_pack_headers_shared(nghttp2_bufs *bufs, - nghttp2_frame_hd *frame_hd) { - nghttp2_buf *buf; - nghttp2_buf_chain *ci, *ce; - nghttp2_frame_hd hd; - - buf = &bufs->head->buf; - - hd = *frame_hd; - hd.length = nghttp2_buf_len(buf); - - DEBUGF("send: HEADERS/PUSH_PROMISE, payloadlen=%zu\n", hd.length); - - /* We have multiple frame buffers, which means one or more - CONTINUATION frame is involved. Remove END_HEADERS flag from the - first frame. */ - if (bufs->head != bufs->cur) { - hd.flags = (uint8_t)(hd.flags & ~NGHTTP2_FLAG_END_HEADERS); - } - - buf->pos -= NGHTTP2_FRAME_HDLEN; - nghttp2_frame_pack_frame_hd(buf->pos, &hd); - - if (bufs->head != bufs->cur) { - /* 2nd and later frames are CONTINUATION frames. */ - hd.type = NGHTTP2_CONTINUATION; - /* We don't have no flags except for last CONTINUATION */ - hd.flags = NGHTTP2_FLAG_NONE; - - ce = bufs->cur; - - for (ci = bufs->head->next; ci != ce; ci = ci->next) { - buf = &ci->buf; - - hd.length = nghttp2_buf_len(buf); - - DEBUGF("send: int CONTINUATION, payloadlen=%zu\n", hd.length); - - buf->pos -= NGHTTP2_FRAME_HDLEN; - nghttp2_frame_pack_frame_hd(buf->pos, &hd); - } - - buf = &ci->buf; - hd.length = nghttp2_buf_len(buf); - /* Set END_HEADERS flag for last CONTINUATION */ - hd.flags = NGHTTP2_FLAG_END_HEADERS; - - DEBUGF("send: last CONTINUATION, payloadlen=%zu\n", hd.length); - - buf->pos -= NGHTTP2_FRAME_HDLEN; - nghttp2_frame_pack_frame_hd(buf->pos, &hd); - } - - return 0; -} - -int nghttp2_frame_pack_headers(nghttp2_bufs *bufs, nghttp2_headers *frame, - nghttp2_hd_deflater *deflater) { - size_t nv_offset; - int rv; - nghttp2_buf *buf; - - assert(bufs->head == bufs->cur); - - nv_offset = nghttp2_frame_headers_payload_nv_offset(frame); - - buf = &bufs->cur->buf; - - buf->pos += nv_offset; - buf->last = buf->pos; - - /* This call will adjust buf->last to the correct position */ - rv = nghttp2_hd_deflate_hd_bufs(deflater, bufs, frame->nva, frame->nvlen); - - if (rv == NGHTTP2_ERR_BUFFER_ERROR) { - rv = NGHTTP2_ERR_HEADER_COMP; - } - - buf->pos -= nv_offset; - - if (rv != 0) { - return rv; - } - - if (frame->hd.flags & NGHTTP2_FLAG_PRIORITY) { - nghttp2_frame_pack_priority_spec(buf->pos, &frame->pri_spec); - } - - frame->padlen = 0; - frame->hd.length = nghttp2_bufs_len(bufs); - - return frame_pack_headers_shared(bufs, &frame->hd); -} - -void nghttp2_frame_pack_priority_spec(uint8_t *buf, - const nghttp2_priority_spec *pri_spec) { - nghttp2_put_uint32be(buf, (uint32_t)pri_spec->stream_id); - if (pri_spec->exclusive) { - buf[0] |= 0x80; - } - buf[4] = (uint8_t)(pri_spec->weight - 1); -} - -void nghttp2_frame_unpack_priority_spec(nghttp2_priority_spec *pri_spec, - const uint8_t *payload) { - int32_t dep_stream_id; - uint8_t exclusive; - int32_t weight; - - dep_stream_id = nghttp2_get_uint32(payload) & NGHTTP2_STREAM_ID_MASK; - exclusive = (payload[0] & 0x80) > 0; - weight = payload[4] + 1; - - nghttp2_priority_spec_init(pri_spec, dep_stream_id, weight, exclusive); -} - -void nghttp2_frame_unpack_headers_payload(nghttp2_headers *frame, - const uint8_t *payload) { - if (frame->hd.flags & NGHTTP2_FLAG_PRIORITY) { - nghttp2_frame_unpack_priority_spec(&frame->pri_spec, payload); - } else { - nghttp2_priority_spec_default_init(&frame->pri_spec); - } - - frame->nva = NULL; - frame->nvlen = 0; -} - -void nghttp2_frame_pack_priority(nghttp2_bufs *bufs, nghttp2_priority *frame) { - nghttp2_buf *buf; - - assert(bufs->head == bufs->cur); - - buf = &bufs->head->buf; - - assert(nghttp2_buf_avail(buf) >= NGHTTP2_PRIORITY_SPECLEN); - - buf->pos -= NGHTTP2_FRAME_HDLEN; - - nghttp2_frame_pack_frame_hd(buf->pos, &frame->hd); - - nghttp2_frame_pack_priority_spec(buf->last, &frame->pri_spec); - - buf->last += NGHTTP2_PRIORITY_SPECLEN; -} - -void nghttp2_frame_unpack_priority_payload(nghttp2_priority *frame, - const uint8_t *payload) { - nghttp2_frame_unpack_priority_spec(&frame->pri_spec, payload); -} - -void nghttp2_frame_pack_rst_stream(nghttp2_bufs *bufs, - nghttp2_rst_stream *frame) { - nghttp2_buf *buf; - - assert(bufs->head == bufs->cur); - - buf = &bufs->head->buf; - - assert(nghttp2_buf_avail(buf) >= 4); - - buf->pos -= NGHTTP2_FRAME_HDLEN; - - nghttp2_frame_pack_frame_hd(buf->pos, &frame->hd); - - nghttp2_put_uint32be(buf->last, frame->error_code); - buf->last += 4; -} - -void nghttp2_frame_unpack_rst_stream_payload(nghttp2_rst_stream *frame, - const uint8_t *payload) { - frame->error_code = nghttp2_get_uint32(payload); -} - -int nghttp2_frame_pack_settings(nghttp2_bufs *bufs, nghttp2_settings *frame) { - nghttp2_buf *buf; - - assert(bufs->head == bufs->cur); - - buf = &bufs->head->buf; - - if (nghttp2_buf_avail(buf) < frame->hd.length) { - return NGHTTP2_ERR_FRAME_SIZE_ERROR; - } - - buf->pos -= NGHTTP2_FRAME_HDLEN; - - nghttp2_frame_pack_frame_hd(buf->pos, &frame->hd); - - buf->last += - nghttp2_frame_pack_settings_payload(buf->last, frame->iv, frame->niv); - - return 0; -} - -size_t nghttp2_frame_pack_settings_payload(uint8_t *buf, - const nghttp2_settings_entry *iv, - size_t niv) { - size_t i; - for (i = 0; i < niv; ++i, buf += NGHTTP2_FRAME_SETTINGS_ENTRY_LENGTH) { - nghttp2_put_uint16be(buf, (uint16_t)iv[i].settings_id); - nghttp2_put_uint32be(buf + 2, iv[i].value); - } - return NGHTTP2_FRAME_SETTINGS_ENTRY_LENGTH * niv; -} - -void nghttp2_frame_unpack_settings_payload(nghttp2_settings *frame, - nghttp2_settings_entry *iv, - size_t niv) { - frame->iv = iv; - frame->niv = niv; -} - -void nghttp2_frame_unpack_settings_entry(nghttp2_settings_entry *iv, - const uint8_t *payload) { - iv->settings_id = nghttp2_get_uint16(&payload[0]); - iv->value = nghttp2_get_uint32(&payload[2]); -} - -int nghttp2_frame_unpack_settings_payload2(nghttp2_settings_entry **iv_ptr, - size_t *niv_ptr, - const uint8_t *payload, - size_t payloadlen, - nghttp2_mem *mem) { - size_t i; - - *niv_ptr = payloadlen / NGHTTP2_FRAME_SETTINGS_ENTRY_LENGTH; - - if (*niv_ptr == 0) { - *iv_ptr = NULL; - - return 0; - } - - *iv_ptr = - nghttp2_mem_malloc(mem, (*niv_ptr) * sizeof(nghttp2_settings_entry)); - - if (*iv_ptr == NULL) { - return NGHTTP2_ERR_NOMEM; - } - - for (i = 0; i < *niv_ptr; ++i) { - size_t off = i * NGHTTP2_FRAME_SETTINGS_ENTRY_LENGTH; - nghttp2_frame_unpack_settings_entry(&(*iv_ptr)[i], &payload[off]); - } - - return 0; -} - -int nghttp2_frame_pack_push_promise(nghttp2_bufs *bufs, - nghttp2_push_promise *frame, - nghttp2_hd_deflater *deflater) { - size_t nv_offset = 4; - int rv; - nghttp2_buf *buf; - - assert(bufs->head == bufs->cur); - - buf = &bufs->cur->buf; - - buf->pos += nv_offset; - buf->last = buf->pos; - - /* This call will adjust buf->last to the correct position */ - rv = nghttp2_hd_deflate_hd_bufs(deflater, bufs, frame->nva, frame->nvlen); - - if (rv == NGHTTP2_ERR_BUFFER_ERROR) { - rv = NGHTTP2_ERR_HEADER_COMP; - } - - buf->pos -= nv_offset; - - if (rv != 0) { - return rv; - } - - nghttp2_put_uint32be(buf->pos, (uint32_t)frame->promised_stream_id); - - frame->padlen = 0; - frame->hd.length = nghttp2_bufs_len(bufs); - - return frame_pack_headers_shared(bufs, &frame->hd); -} - -void nghttp2_frame_unpack_push_promise_payload(nghttp2_push_promise *frame, - const uint8_t *payload) { - frame->promised_stream_id = - nghttp2_get_uint32(payload) & NGHTTP2_STREAM_ID_MASK; - frame->nva = NULL; - frame->nvlen = 0; -} - -void nghttp2_frame_pack_ping(nghttp2_bufs *bufs, nghttp2_ping *frame) { - nghttp2_buf *buf; - - assert(bufs->head == bufs->cur); - - buf = &bufs->head->buf; - - assert(nghttp2_buf_avail(buf) >= 8); - - buf->pos -= NGHTTP2_FRAME_HDLEN; - - nghttp2_frame_pack_frame_hd(buf->pos, &frame->hd); - - buf->last = - nghttp2_cpymem(buf->last, frame->opaque_data, sizeof(frame->opaque_data)); -} - -void nghttp2_frame_unpack_ping_payload(nghttp2_ping *frame, - const uint8_t *payload) { - memcpy(frame->opaque_data, payload, sizeof(frame->opaque_data)); -} - -int nghttp2_frame_pack_goaway(nghttp2_bufs *bufs, nghttp2_goaway *frame) { - int rv; - nghttp2_buf *buf; - - assert(bufs->head == bufs->cur); - - buf = &bufs->head->buf; - - buf->pos -= NGHTTP2_FRAME_HDLEN; - - nghttp2_frame_pack_frame_hd(buf->pos, &frame->hd); - - nghttp2_put_uint32be(buf->last, (uint32_t)frame->last_stream_id); - buf->last += 4; - - nghttp2_put_uint32be(buf->last, frame->error_code); - buf->last += 4; - - rv = nghttp2_bufs_add(bufs, frame->opaque_data, frame->opaque_data_len); - - if (rv == NGHTTP2_ERR_BUFFER_ERROR) { - return NGHTTP2_ERR_FRAME_SIZE_ERROR; - } - - if (rv != 0) { - return rv; - } - - return 0; -} - -void nghttp2_frame_unpack_goaway_payload(nghttp2_goaway *frame, - const uint8_t *payload, - uint8_t *var_gift_payload, - size_t var_gift_payloadlen) { - frame->last_stream_id = nghttp2_get_uint32(payload) & NGHTTP2_STREAM_ID_MASK; - frame->error_code = nghttp2_get_uint32(payload + 4); - - frame->opaque_data = var_gift_payload; - frame->opaque_data_len = var_gift_payloadlen; -} - -int nghttp2_frame_unpack_goaway_payload2(nghttp2_goaway *frame, - const uint8_t *payload, - size_t payloadlen, nghttp2_mem *mem) { - uint8_t *var_gift_payload; - size_t var_gift_payloadlen; - - if (payloadlen > 8) { - var_gift_payloadlen = payloadlen - 8; - } else { - var_gift_payloadlen = 0; - } - - if (!var_gift_payloadlen) { - var_gift_payload = NULL; - } else { - var_gift_payload = nghttp2_mem_malloc(mem, var_gift_payloadlen); - - if (var_gift_payload == NULL) { - return NGHTTP2_ERR_NOMEM; - } - - memcpy(var_gift_payload, payload + 8, var_gift_payloadlen); - } - - nghttp2_frame_unpack_goaway_payload(frame, payload, var_gift_payload, - var_gift_payloadlen); - - return 0; -} - -void nghttp2_frame_pack_window_update(nghttp2_bufs *bufs, - nghttp2_window_update *frame) { - nghttp2_buf *buf; - - assert(bufs->head == bufs->cur); - - buf = &bufs->head->buf; - - assert(nghttp2_buf_avail(buf) >= 4); - - buf->pos -= NGHTTP2_FRAME_HDLEN; - - nghttp2_frame_pack_frame_hd(buf->pos, &frame->hd); - - nghttp2_put_uint32be(buf->last, (uint32_t)frame->window_size_increment); - buf->last += 4; -} - -void nghttp2_frame_unpack_window_update_payload(nghttp2_window_update *frame, - const uint8_t *payload) { - frame->window_size_increment = - nghttp2_get_uint32(payload) & NGHTTP2_WINDOW_SIZE_INCREMENT_MASK; -} - -void nghttp2_frame_pack_altsvc(nghttp2_bufs *bufs, nghttp2_extension *frame) { - int rv; - nghttp2_buf *buf; - nghttp2_ext_altsvc *altsvc; - - /* This is required with --disable-assert. */ - (void)rv; - - altsvc = frame->payload; - - buf = &bufs->head->buf; - - assert(nghttp2_buf_avail(buf) >= - 2 + altsvc->origin_len + altsvc->field_value_len); - - buf->pos -= NGHTTP2_FRAME_HDLEN; - - nghttp2_frame_pack_frame_hd(buf->pos, &frame->hd); - - nghttp2_put_uint16be(buf->last, (uint16_t)altsvc->origin_len); - buf->last += 2; - - rv = nghttp2_bufs_add(bufs, altsvc->origin, altsvc->origin_len); - - assert(rv == 0); - - rv = nghttp2_bufs_add(bufs, altsvc->field_value, altsvc->field_value_len); - - assert(rv == 0); -} - -void nghttp2_frame_unpack_altsvc_payload(nghttp2_extension *frame, - size_t origin_len, uint8_t *payload, - size_t payloadlen) { - nghttp2_ext_altsvc *altsvc; - uint8_t *p; - - altsvc = frame->payload; - p = payload; - - altsvc->origin = p; - - p += origin_len; - - altsvc->origin_len = origin_len; - - altsvc->field_value = p; - altsvc->field_value_len = (size_t)(payload + payloadlen - p); -} - -int nghttp2_frame_unpack_altsvc_payload2(nghttp2_extension *frame, - const uint8_t *payload, - size_t payloadlen, nghttp2_mem *mem) { - uint8_t *buf; - size_t origin_len; - - if (payloadlen < 2) { - return NGHTTP2_FRAME_SIZE_ERROR; - } - - origin_len = nghttp2_get_uint16(payload); - - buf = nghttp2_mem_malloc(mem, payloadlen - 2); - if (!buf) { - return NGHTTP2_ERR_NOMEM; - } - - nghttp2_cpymem(buf, payload + 2, payloadlen - 2); - - nghttp2_frame_unpack_altsvc_payload(frame, origin_len, buf, payloadlen - 2); - - return 0; -} - -int nghttp2_frame_pack_origin(nghttp2_bufs *bufs, nghttp2_extension *frame) { - nghttp2_buf *buf; - nghttp2_ext_origin *origin; - nghttp2_origin_entry *orig; - size_t i; - - origin = frame->payload; - - buf = &bufs->head->buf; - - if (nghttp2_buf_avail(buf) < frame->hd.length) { - return NGHTTP2_ERR_FRAME_SIZE_ERROR; - } - - buf->pos -= NGHTTP2_FRAME_HDLEN; - - nghttp2_frame_pack_frame_hd(buf->pos, &frame->hd); - - for (i = 0; i < origin->nov; ++i) { - orig = &origin->ov[i]; - nghttp2_put_uint16be(buf->last, (uint16_t)orig->origin_len); - buf->last += 2; - buf->last = nghttp2_cpymem(buf->last, orig->origin, orig->origin_len); - } - - assert(nghttp2_buf_len(buf) == NGHTTP2_FRAME_HDLEN + frame->hd.length); - - return 0; -} - -int nghttp2_frame_unpack_origin_payload(nghttp2_extension *frame, - const uint8_t *payload, - size_t payloadlen, nghttp2_mem *mem) { - nghttp2_ext_origin *origin; - const uint8_t *p, *end; - uint8_t *dst; - size_t originlen; - nghttp2_origin_entry *ov; - size_t nov = 0; - size_t len = 0; - - origin = frame->payload; - p = end = payload; - if (payloadlen) { - end += payloadlen; - } - - for (; p != end;) { - if (end - p < 2) { - return NGHTTP2_ERR_FRAME_SIZE_ERROR; - } - originlen = nghttp2_get_uint16(p); - p += 2; - if (originlen == 0) { - continue; - } - if (originlen > (size_t)(end - p)) { - return NGHTTP2_ERR_FRAME_SIZE_ERROR; - } - p += originlen; - /* 1 for terminal NULL */ - len += originlen + 1; - ++nov; - } - - if (nov == 0) { - origin->ov = NULL; - origin->nov = 0; - - return 0; - } - - len += nov * sizeof(nghttp2_origin_entry); - - ov = nghttp2_mem_malloc(mem, len); - if (ov == NULL) { - return NGHTTP2_ERR_NOMEM; - } - - origin->ov = ov; - origin->nov = nov; - - dst = (uint8_t *)ov + nov * sizeof(nghttp2_origin_entry); - p = payload; - - for (; p != end;) { - originlen = nghttp2_get_uint16(p); - p += 2; - if (originlen == 0) { - continue; - } - ov->origin = dst; - ov->origin_len = originlen; - dst = nghttp2_cpymem(dst, p, originlen); - *dst++ = '\0'; - p += originlen; - ++ov; - } - - return 0; -} - -void nghttp2_frame_pack_priority_update(nghttp2_bufs *bufs, - nghttp2_extension *frame) { - int rv; - nghttp2_buf *buf; - nghttp2_ext_priority_update *priority_update; - - /* This is required with --disable-assert. */ - (void)rv; - - priority_update = frame->payload; - - buf = &bufs->head->buf; - - assert(nghttp2_buf_avail(buf) >= 4 + priority_update->field_value_len); - - buf->pos -= NGHTTP2_FRAME_HDLEN; - - nghttp2_frame_pack_frame_hd(buf->pos, &frame->hd); - - nghttp2_put_uint32be(buf->last, (uint32_t)priority_update->stream_id); - buf->last += 4; - - rv = nghttp2_bufs_add(bufs, priority_update->field_value, - priority_update->field_value_len); - - assert(rv == 0); -} - -void nghttp2_frame_unpack_priority_update_payload(nghttp2_extension *frame, - uint8_t *payload, - size_t payloadlen) { - nghttp2_ext_priority_update *priority_update; - - assert(payloadlen >= 4); - - priority_update = frame->payload; - - priority_update->stream_id = - nghttp2_get_uint32(payload) & NGHTTP2_STREAM_ID_MASK; - - if (payloadlen > 4) { - priority_update->field_value = payload + 4; - priority_update->field_value_len = payloadlen - 4; - } else { - priority_update->field_value = NULL; - priority_update->field_value_len = 0; - } -} - -nghttp2_settings_entry *nghttp2_frame_iv_copy(const nghttp2_settings_entry *iv, - size_t niv, nghttp2_mem *mem) { - nghttp2_settings_entry *iv_copy; - size_t len = niv * sizeof(nghttp2_settings_entry); - - if (len == 0) { - return NULL; - } - - iv_copy = nghttp2_mem_malloc(mem, len); - - if (iv_copy == NULL) { - return NULL; - } - - memcpy(iv_copy, iv, len); - - return iv_copy; -} - -int nghttp2_nv_equal(const nghttp2_nv *a, const nghttp2_nv *b) { - if (a->namelen != b->namelen || a->valuelen != b->valuelen) { - return 0; - } - - if (a->name == NULL || b->name == NULL) { - assert(a->namelen == 0); - assert(b->namelen == 0); - } else if (memcmp(a->name, b->name, a->namelen) != 0) { - return 0; - } - - if (a->value == NULL || b->value == NULL) { - assert(a->valuelen == 0); - assert(b->valuelen == 0); - } else if (memcmp(a->value, b->value, a->valuelen) != 0) { - return 0; - } - - return 1; -} - -void nghttp2_nv_array_del(nghttp2_nv *nva, nghttp2_mem *mem) { - nghttp2_mem_free(mem, nva); -} - -static int bytes_compar(const uint8_t *a, size_t alen, const uint8_t *b, - size_t blen) { - int rv; - - if (alen == blen) { - return memcmp(a, b, alen); - } - - if (alen < blen) { - rv = memcmp(a, b, alen); - - if (rv == 0) { - return -1; - } - - return rv; - } - - rv = memcmp(a, b, blen); - - if (rv == 0) { - return 1; - } - - return rv; -} - -int nghttp2_nv_compare_name(const nghttp2_nv *lhs, const nghttp2_nv *rhs) { - return bytes_compar(lhs->name, lhs->namelen, rhs->name, rhs->namelen); -} - -static int nv_compar(const void *lhs, const void *rhs) { - const nghttp2_nv *a = (const nghttp2_nv *)lhs; - const nghttp2_nv *b = (const nghttp2_nv *)rhs; - int rv; - - rv = bytes_compar(a->name, a->namelen, b->name, b->namelen); - - if (rv == 0) { - return bytes_compar(a->value, a->valuelen, b->value, b->valuelen); - } - - return rv; -} - -void nghttp2_nv_array_sort(nghttp2_nv *nva, size_t nvlen) { - qsort(nva, nvlen, sizeof(nghttp2_nv), nv_compar); -} - -int nghttp2_nv_array_copy(nghttp2_nv **nva_ptr, const nghttp2_nv *nva, - size_t nvlen, nghttp2_mem *mem) { - size_t i; - uint8_t *data = NULL; - size_t buflen = 0; - nghttp2_nv *p; - - if (nvlen == 0) { - *nva_ptr = NULL; - - return 0; - } - - for (i = 0; i < nvlen; ++i) { - /* + 1 for null-termination */ - if ((nva[i].flags & NGHTTP2_NV_FLAG_NO_COPY_NAME) == 0) { - buflen += nva[i].namelen + 1; - } - if ((nva[i].flags & NGHTTP2_NV_FLAG_NO_COPY_VALUE) == 0) { - buflen += nva[i].valuelen + 1; - } - } - - buflen += sizeof(nghttp2_nv) * nvlen; - - *nva_ptr = nghttp2_mem_malloc(mem, buflen); - - if (*nva_ptr == NULL) { - return NGHTTP2_ERR_NOMEM; - } - - p = *nva_ptr; - data = (uint8_t *)(*nva_ptr) + sizeof(nghttp2_nv) * nvlen; - - for (i = 0; i < nvlen; ++i) { - p->flags = nva[i].flags; - - if (nva[i].flags & NGHTTP2_NV_FLAG_NO_COPY_NAME) { - p->name = nva[i].name; - p->namelen = nva[i].namelen; - } else { - if (nva[i].namelen) { - memcpy(data, nva[i].name, nva[i].namelen); - } - p->name = data; - p->namelen = nva[i].namelen; - data[p->namelen] = '\0'; - nghttp2_downcase(p->name, p->namelen); - data += nva[i].namelen + 1; - } - - if (nva[i].flags & NGHTTP2_NV_FLAG_NO_COPY_VALUE) { - p->value = nva[i].value; - p->valuelen = nva[i].valuelen; - } else { - if (nva[i].valuelen) { - memcpy(data, nva[i].value, nva[i].valuelen); - } - p->value = data; - p->valuelen = nva[i].valuelen; - data[p->valuelen] = '\0'; - data += nva[i].valuelen + 1; - } - - ++p; - } - return 0; -} - -int nghttp2_iv_check(const nghttp2_settings_entry *iv, size_t niv) { - size_t i; - for (i = 0; i < niv; ++i) { - switch (iv[i].settings_id) { - case NGHTTP2_SETTINGS_HEADER_TABLE_SIZE: - break; - case NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS: - break; - case NGHTTP2_SETTINGS_ENABLE_PUSH: - if (iv[i].value != 0 && iv[i].value != 1) { - return 0; - } - break; - case NGHTTP2_SETTINGS_INITIAL_WINDOW_SIZE: - if (iv[i].value > (uint32_t)NGHTTP2_MAX_WINDOW_SIZE) { - return 0; - } - break; - case NGHTTP2_SETTINGS_MAX_FRAME_SIZE: - if (iv[i].value < NGHTTP2_MAX_FRAME_SIZE_MIN || - iv[i].value > NGHTTP2_MAX_FRAME_SIZE_MAX) { - return 0; - } - break; - case NGHTTP2_SETTINGS_MAX_HEADER_LIST_SIZE: - break; - case NGHTTP2_SETTINGS_ENABLE_CONNECT_PROTOCOL: - if (iv[i].value != 0 && iv[i].value != 1) { - return 0; - } - break; - case NGHTTP2_SETTINGS_NO_RFC7540_PRIORITIES: - if (iv[i].value != 0 && iv[i].value != 1) { - return 0; - } - break; - } - } - return 1; -} - -static void frame_set_pad(nghttp2_buf *buf, size_t padlen, int framehd_only) { - size_t trail_padlen; - size_t newlen; - - DEBUGF("send: padlen=%zu, shift left 1 bytes\n", padlen); - - memmove(buf->pos - 1, buf->pos, NGHTTP2_FRAME_HDLEN); - - --buf->pos; - - buf->pos[4] |= NGHTTP2_FLAG_PADDED; - - newlen = (nghttp2_get_uint32(buf->pos) >> 8) + padlen; - nghttp2_put_uint32be(buf->pos, (uint32_t)((newlen << 8) + buf->pos[3])); - - if (framehd_only) { - return; - } - - trail_padlen = padlen - 1; - buf->pos[NGHTTP2_FRAME_HDLEN] = (uint8_t)trail_padlen; - - /* zero out padding */ - memset(buf->last, 0, trail_padlen); - /* extend buffers trail_padlen bytes, since we ate previous padlen - - trail_padlen byte(s) */ - buf->last += trail_padlen; -} - -void nghttp2_frame_add_pad(nghttp2_bufs *bufs, nghttp2_frame_hd *hd, - size_t padlen, int framehd_only) { - nghttp2_buf *buf; - - if (padlen == 0) { - DEBUGF("send: padlen = 0, nothing to do\n"); - - return; - } - - /* - * We have arranged bufs like this: - * - * 0 1 2 3 - * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | |Frame header | Frame payload... : - * +-+-----------------+-------------------------------------------+ - * | |Frame header | Frame payload... : - * +-+-----------------+-------------------------------------------+ - * | |Frame header | Frame payload... : - * +-+-----------------+-------------------------------------------+ - * - * We arranged padding so that it is included in the first frame - * completely. For padded frame, we are going to adjust buf->pos of - * frame which includes padding and serialize (memmove) frame header - * in the correct position. Also extends buf->last to include - * padding. - */ - - buf = &bufs->head->buf; - - assert(nghttp2_buf_avail(buf) >= padlen - 1); - - frame_set_pad(buf, padlen, framehd_only); - - hd->length += padlen; - hd->flags |= NGHTTP2_FLAG_PADDED; - - DEBUGF("send: final payloadlen=%zu, padlen=%zu\n", hd->length, padlen); -} diff --git a/3rdparty/exported/nghttp2/nghttp2_frame.h b/3rdparty/exported/nghttp2/nghttp2_frame.h deleted file mode 100644 index d58668806c43..000000000000 --- a/3rdparty/exported/nghttp2/nghttp2_frame.h +++ /dev/null @@ -1,637 +0,0 @@ -/* - * nghttp2 - HTTP/2 C Library - * - * Copyright (c) 2012 Tatsuhiro Tsujikawa - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE - * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION - * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION - * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ -#ifndef NGHTTP2_FRAME_H -#define NGHTTP2_FRAME_H - -#ifdef HAVE_CONFIG_H -# include -#endif /* HAVE_CONFIG_H */ - -#include -#include "nghttp2_hd.h" -#include "nghttp2_buf.h" - -#define NGHTTP2_STREAM_ID_MASK ((1u << 31) - 1) -#define NGHTTP2_PRI_GROUP_ID_MASK ((1u << 31) - 1) -#define NGHTTP2_PRIORITY_MASK ((1u << 31) - 1) -#define NGHTTP2_WINDOW_SIZE_INCREMENT_MASK ((1u << 31) - 1) -#define NGHTTP2_SETTINGS_ID_MASK ((1 << 24) - 1) - -/* The number of bytes of frame header. */ -#define NGHTTP2_FRAME_HDLEN 9 - -#define NGHTTP2_MAX_FRAME_SIZE_MAX ((1 << 24) - 1) -#define NGHTTP2_MAX_FRAME_SIZE_MIN (1 << 14) - -#define NGHTTP2_MAX_PAYLOADLEN 16384 -/* The one frame buffer length for transmission. We may use several of - them to support CONTINUATION. To account for Pad Length field, we - allocate extra 1 byte, which saves extra large memcopying. */ -#define NGHTTP2_FRAMEBUF_CHUNKLEN \ - (NGHTTP2_FRAME_HDLEN + 1 + NGHTTP2_MAX_PAYLOADLEN) - -/* The default length of DATA frame payload. */ -#define NGHTTP2_DATA_PAYLOADLEN NGHTTP2_MAX_FRAME_SIZE_MIN - -/* Maximum headers block size to send, calculated using - nghttp2_hd_deflate_bound(). This is the default value, and can be - overridden by nghttp2_option_set_max_send_header_block_length(). */ -#define NGHTTP2_MAX_HEADERSLEN 65536 - -/* The number of bytes for each SETTINGS entry */ -#define NGHTTP2_FRAME_SETTINGS_ENTRY_LENGTH 6 - -/* Length of priority related fields in HEADERS/PRIORITY frames */ -#define NGHTTP2_PRIORITY_SPECLEN 5 - -/* Maximum length of padding in bytes. */ -#define NGHTTP2_MAX_PADLEN 256 - -/* Union of extension frame payload */ -typedef union { - nghttp2_ext_altsvc altsvc; - nghttp2_ext_origin origin; - nghttp2_ext_priority_update priority_update; -} nghttp2_ext_frame_payload; - -void nghttp2_frame_pack_frame_hd(uint8_t *buf, const nghttp2_frame_hd *hd); - -void nghttp2_frame_unpack_frame_hd(nghttp2_frame_hd *hd, const uint8_t *buf); - -/** - * Initializes frame header |hd| with given parameters. Reserved bit - * is set to 0. - */ -void nghttp2_frame_hd_init(nghttp2_frame_hd *hd, size_t length, uint8_t type, - uint8_t flags, int32_t stream_id); - -/** - * Returns the number of priority field depending on the |flags|. If - * |flags| has neither NGHTTP2_FLAG_PRIORITY_GROUP nor - * NGHTTP2_FLAG_PRIORITY_DEPENDENCY set, return 0. - */ -size_t nghttp2_frame_priority_len(uint8_t flags); - -/** - * Packs the |pri_spec| in |buf|. This function assumes |buf| has - * enough space for serialization. - */ -void nghttp2_frame_pack_priority_spec(uint8_t *buf, - const nghttp2_priority_spec *pri_spec); - -/** - * Unpacks the priority specification from payload |payload| of length - * |payloadlen| to |pri_spec|. The |flags| is used to determine what - * kind of priority specification is in |payload|. This function - * assumes the |payload| contains whole priority specification. - */ -void nghttp2_frame_unpack_priority_spec(nghttp2_priority_spec *pri_spec, - const uint8_t *payload); - -/* - * Returns the offset from the HEADERS frame payload where the - * compressed header block starts. The frame payload does not include - * frame header. - */ -size_t nghttp2_frame_headers_payload_nv_offset(nghttp2_headers *frame); - -/* - * Packs HEADERS frame |frame| in wire format and store it in |bufs|. - * This function expands |bufs| as necessary to store frame. - * - * The caller must make sure that nghttp2_bufs_reset(bufs) is called - * before calling this function. - * - * frame->hd.length is assigned after length is determined during - * packing process. CONTINUATION frames are also serialized in this - * function. This function does not handle padding. - * - * This function returns 0 if it succeeds, or returns one of the - * following negative error codes: - * - * NGHTTP2_ERR_HEADER_COMP - * The deflate operation failed. - * NGHTTP2_ERR_NOMEM - * Out of memory. - */ -int nghttp2_frame_pack_headers(nghttp2_bufs *bufs, nghttp2_headers *frame, - nghttp2_hd_deflater *deflater); - -/* - * Unpacks HEADERS frame byte sequence into |frame|. This function - * only unapcks bytes that come before name/value header block and - * after possible Pad Length field. - */ -void nghttp2_frame_unpack_headers_payload(nghttp2_headers *frame, - const uint8_t *payload); - -/* - * Packs PRIORITY frame |frame| in wire format and store it in - * |bufs|. - * - * The caller must make sure that nghttp2_bufs_reset(bufs) is called - * before calling this function. - */ -void nghttp2_frame_pack_priority(nghttp2_bufs *bufs, nghttp2_priority *frame); - -/* - * Unpacks PRIORITY wire format into |frame|. - */ -void nghttp2_frame_unpack_priority_payload(nghttp2_priority *frame, - const uint8_t *payload); - -/* - * Packs RST_STREAM frame |frame| in wire frame format and store it in - * |bufs|. - * - * The caller must make sure that nghttp2_bufs_reset(bufs) is called - * before calling this function. - */ -void nghttp2_frame_pack_rst_stream(nghttp2_bufs *bufs, - nghttp2_rst_stream *frame); - -/* - * Unpacks RST_STREAM frame byte sequence into |frame|. - */ -void nghttp2_frame_unpack_rst_stream_payload(nghttp2_rst_stream *frame, - const uint8_t *payload); - -/* - * Packs SETTINGS frame |frame| in wire format and store it in - * |bufs|. - * - * The caller must make sure that nghttp2_bufs_reset(bufs) is called - * before calling this function. - * - * This function returns 0 if it succeeds, or returns one of the - * following negative error codes: - * - * NGHTTP2_ERR_FRAME_SIZE_ERROR - * The length of the frame is too large. - */ -int nghttp2_frame_pack_settings(nghttp2_bufs *bufs, nghttp2_settings *frame); - -/* - * Packs the |iv|, which includes |niv| entries, in the |buf|, - * assuming the |buf| has at least 8 * |niv| bytes. - * - * Returns the number of bytes written into the |buf|. - */ -size_t nghttp2_frame_pack_settings_payload(uint8_t *buf, - const nghttp2_settings_entry *iv, - size_t niv); - -void nghttp2_frame_unpack_settings_entry(nghttp2_settings_entry *iv, - const uint8_t *payload); - -/* - * Initializes payload of frame->settings. The |frame| takes - * ownership of |iv|. - */ -void nghttp2_frame_unpack_settings_payload(nghttp2_settings *frame, - nghttp2_settings_entry *iv, - size_t niv); - -/* - * Unpacks SETTINGS payload into |*iv_ptr|. The number of entries are - * assigned to the |*niv_ptr|. This function allocates enough memory - * to store the result in |*iv_ptr|. The caller is responsible to free - * |*iv_ptr| after its use. - * - * This function returns 0 if it succeeds or one of the following - * negative error codes: - * - * NGHTTP2_ERR_NOMEM - * Out of memory. - */ -int nghttp2_frame_unpack_settings_payload2(nghttp2_settings_entry **iv_ptr, - size_t *niv_ptr, - const uint8_t *payload, - size_t payloadlen, nghttp2_mem *mem); - -/* - * Packs PUSH_PROMISE frame |frame| in wire format and store it in - * |bufs|. This function expands |bufs| as necessary to store - * frame. - * - * The caller must make sure that nghttp2_bufs_reset(bufs) is called - * before calling this function. - * - * frame->hd.length is assigned after length is determined during - * packing process. CONTINUATION frames are also serialized in this - * function. This function does not handle padding. - * - * This function returns 0 if it succeeds, or returns one of the - * following negative error codes: - * - * NGHTTP2_ERR_HEADER_COMP - * The deflate operation failed. - * NGHTTP2_ERR_NOMEM - * Out of memory. - */ -int nghttp2_frame_pack_push_promise(nghttp2_bufs *bufs, - nghttp2_push_promise *frame, - nghttp2_hd_deflater *deflater); - -/* - * Unpacks PUSH_PROMISE frame byte sequence into |frame|. This - * function only unapcks bytes that come before name/value header - * block and after possible Pad Length field. - */ -void nghttp2_frame_unpack_push_promise_payload(nghttp2_push_promise *frame, - const uint8_t *payload); - -/* - * Packs PING frame |frame| in wire format and store it in - * |bufs|. - * - * The caller must make sure that nghttp2_bufs_reset(bufs) is called - * before calling this function. - */ -void nghttp2_frame_pack_ping(nghttp2_bufs *bufs, nghttp2_ping *frame); - -/* - * Unpacks PING wire format into |frame|. - */ -void nghttp2_frame_unpack_ping_payload(nghttp2_ping *frame, - const uint8_t *payload); - -/* - * Packs GOAWAY frame |frame| in wire format and store it in |bufs|. - * This function expands |bufs| as necessary to store frame. - * - * The caller must make sure that nghttp2_bufs_reset(bufs) is called - * before calling this function. - * - * This function returns 0 if it succeeds or one of the following - * negative error codes: - * - * NGHTTP2_ERR_NOMEM - * Out of memory. - * NGHTTP2_ERR_FRAME_SIZE_ERROR - * The length of the frame is too large. - */ -int nghttp2_frame_pack_goaway(nghttp2_bufs *bufs, nghttp2_goaway *frame); - -/* - * Unpacks GOAWAY wire format into |frame|. The |payload| of length - * |payloadlen| contains first 8 bytes of payload. The - * |var_gift_payload| of length |var_gift_payloadlen| contains - * remaining payload and its buffer is gifted to the function and then - * |frame|. The |var_gift_payloadlen| must be freed by - * nghttp2_frame_goaway_free(). - */ -void nghttp2_frame_unpack_goaway_payload(nghttp2_goaway *frame, - const uint8_t *payload, - uint8_t *var_gift_payload, - size_t var_gift_payloadlen); - -/* - * Unpacks GOAWAY wire format into |frame|. This function only exists - * for unit test. After allocating buffer for debug data, this - * function internally calls nghttp2_frame_unpack_goaway_payload(). - * - * This function returns 0 if it succeeds, or one of the following - * negative error codes: - * - * NGHTTP2_ERR_NOMEM - * Out of memory. - */ -int nghttp2_frame_unpack_goaway_payload2(nghttp2_goaway *frame, - const uint8_t *payload, - size_t payloadlen, nghttp2_mem *mem); - -/* - * Packs WINDOW_UPDATE frame |frame| in wire frame format and store it - * in |bufs|. - * - * The caller must make sure that nghttp2_bufs_reset(bufs) is called - * before calling this function. - */ -void nghttp2_frame_pack_window_update(nghttp2_bufs *bufs, - nghttp2_window_update *frame); - -/* - * Unpacks WINDOW_UPDATE frame byte sequence into |frame|. - */ -void nghttp2_frame_unpack_window_update_payload(nghttp2_window_update *frame, - const uint8_t *payload); - -/* - * Packs ALTSVC frame |frame| in wire frame format and store it in - * |bufs|. - * - * The caller must make sure that nghttp2_bufs_reset(bufs) is called - * before calling this function. - */ -void nghttp2_frame_pack_altsvc(nghttp2_bufs *bufs, nghttp2_extension *ext); - -/* - * Unpacks ALTSVC wire format into |frame|. The |payload| of - * |payloadlen| bytes contains frame payload. This function assumes - * that frame->payload points to the nghttp2_ext_altsvc object. - */ -void nghttp2_frame_unpack_altsvc_payload(nghttp2_extension *frame, - size_t origin_len, uint8_t *payload, - size_t payloadlen); - -/* - * Unpacks ALTSVC wire format into |frame|. This function only exists - * for unit test. After allocating buffer for fields, this function - * internally calls nghttp2_frame_unpack_altsvc_payload(). - * - * This function returns 0 if it succeeds, or one of the following - * negative error codes: - * - * NGHTTP2_ERR_NOMEM - * Out of memory. - * NGHTTP2_ERR_FRAME_SIZE_ERROR - * The payload is too small. - */ -int nghttp2_frame_unpack_altsvc_payload2(nghttp2_extension *frame, - const uint8_t *payload, - size_t payloadlen, nghttp2_mem *mem); - -/* - * Packs ORIGIN frame |frame| in wire frame format and store it in - * |bufs|. - * - * The caller must make sure that nghttp2_bufs_reset(bufs) is called - * before calling this function. - * - * This function returns 0 if it succeeds, or one of the following - * negative error codes: - * - * NGHTTP2_ERR_FRAME_SIZE_ERROR - * The length of the frame is too large. - */ -int nghttp2_frame_pack_origin(nghttp2_bufs *bufs, nghttp2_extension *ext); - -/* - * Unpacks ORIGIN wire format into |frame|. The |payload| of length - * |payloadlen| contains the frame payload. - * - * This function returns 0 if it succeeds, or one of the following - * negative error codes: - * - * NGHTTP2_ERR_NOMEM - * Out of memory. - * NGHTTP2_ERR_FRAME_SIZE_ERROR - * The payload is too small. - */ -int nghttp2_frame_unpack_origin_payload(nghttp2_extension *frame, - const uint8_t *payload, - size_t payloadlen, nghttp2_mem *mem); - -/* - * Packs PRIORITY_UPDATE frame |frame| in wire frame format and store - * it in |bufs|. - * - * The caller must make sure that nghttp2_bufs_reset(bufs) is called - * before calling this function. - */ -void nghttp2_frame_pack_priority_update(nghttp2_bufs *bufs, - nghttp2_extension *ext); - -/* - * Unpacks PRIORITY_UPDATE wire format into |frame|. The |payload| of - * |payloadlen| bytes contains frame payload. This function assumes - * that frame->payload points to the nghttp2_ext_priority_update - * object. - */ -void nghttp2_frame_unpack_priority_update_payload(nghttp2_extension *frame, - uint8_t *payload, - size_t payloadlen); - -/* - * Initializes HEADERS frame |frame| with given values. |frame| takes - * ownership of |nva|, so caller must not free it. If |stream_id| is - * not assigned yet, it must be -1. - */ -void nghttp2_frame_headers_init(nghttp2_headers *frame, uint8_t flags, - int32_t stream_id, nghttp2_headers_category cat, - const nghttp2_priority_spec *pri_spec, - nghttp2_nv *nva, size_t nvlen); - -void nghttp2_frame_headers_free(nghttp2_headers *frame, nghttp2_mem *mem); - -void nghttp2_frame_priority_init(nghttp2_priority *frame, int32_t stream_id, - const nghttp2_priority_spec *pri_spec); - -void nghttp2_frame_priority_free(nghttp2_priority *frame); - -void nghttp2_frame_rst_stream_init(nghttp2_rst_stream *frame, int32_t stream_id, - uint32_t error_code); - -void nghttp2_frame_rst_stream_free(nghttp2_rst_stream *frame); - -/* - * Initializes PUSH_PROMISE frame |frame| with given values. |frame| - * takes ownership of |nva|, so caller must not free it. - */ -void nghttp2_frame_push_promise_init(nghttp2_push_promise *frame, uint8_t flags, - int32_t stream_id, - int32_t promised_stream_id, - nghttp2_nv *nva, size_t nvlen); - -void nghttp2_frame_push_promise_free(nghttp2_push_promise *frame, - nghttp2_mem *mem); - -/* - * Initializes SETTINGS frame |frame| with given values. |frame| takes - * ownership of |iv|, so caller must not free it. The |flags| are - * bitwise-OR of one or more of nghttp2_settings_flag. - */ -void nghttp2_frame_settings_init(nghttp2_settings *frame, uint8_t flags, - nghttp2_settings_entry *iv, size_t niv); - -void nghttp2_frame_settings_free(nghttp2_settings *frame, nghttp2_mem *mem); - -/* - * Initializes PING frame |frame| with given values. If the - * |opqeue_data| is not NULL, it must point to 8 bytes memory region - * of data. The data pointed by |opaque_data| is copied. It can be - * NULL. In this case, 8 bytes NULL is used. - */ -void nghttp2_frame_ping_init(nghttp2_ping *frame, uint8_t flags, - const uint8_t *opque_data); - -void nghttp2_frame_ping_free(nghttp2_ping *frame); - -/* - * Initializes GOAWAY frame |frame| with given values. On success, - * this function takes ownership of |opaque_data|, so caller must not - * free it. If the |opaque_data_len| is 0, opaque_data could be NULL. - */ -void nghttp2_frame_goaway_init(nghttp2_goaway *frame, int32_t last_stream_id, - uint32_t error_code, uint8_t *opaque_data, - size_t opaque_data_len); - -void nghttp2_frame_goaway_free(nghttp2_goaway *frame, nghttp2_mem *mem); - -void nghttp2_frame_window_update_init(nghttp2_window_update *frame, - uint8_t flags, int32_t stream_id, - int32_t window_size_increment); - -void nghttp2_frame_window_update_free(nghttp2_window_update *frame); - -void nghttp2_frame_extension_init(nghttp2_extension *frame, uint8_t type, - uint8_t flags, int32_t stream_id, - void *payload); - -void nghttp2_frame_extension_free(nghttp2_extension *frame); - -/* - * Initializes ALTSVC frame |frame| with given values. This function - * assumes that frame->payload points to nghttp2_ext_altsvc object. - * Also |origin| and |field_value| are allocated in single buffer, - * starting |origin|. On success, this function takes ownership of - * |origin|, so caller must not free it. - */ -void nghttp2_frame_altsvc_init(nghttp2_extension *frame, int32_t stream_id, - uint8_t *origin, size_t origin_len, - uint8_t *field_value, size_t field_value_len); - -/* - * Frees up resources under |frame|. This function does not free - * nghttp2_ext_altsvc object pointed by frame->payload. This function - * only frees origin pointed by nghttp2_ext_altsvc.origin. Therefore, - * other fields must be allocated in the same buffer with origin. - */ -void nghttp2_frame_altsvc_free(nghttp2_extension *frame, nghttp2_mem *mem); - -/* - * Initializes ORIGIN frame |frame| with given values. This function - * assumes that frame->payload points to nghttp2_ext_origin object. - * Also |ov| and the memory pointed by the field of its elements are - * allocated in single buffer, starting with |ov|. On success, this - * function takes ownership of |ov|, so caller must not free it. - */ -void nghttp2_frame_origin_init(nghttp2_extension *frame, - nghttp2_origin_entry *ov, size_t nov); - -/* - * Frees up resources under |frame|. This function does not free - * nghttp2_ext_origin object pointed by frame->payload. This function - * only frees nghttp2_ext_origin.ov. Therefore, other fields must be - * allocated in the same buffer with ov. - */ -void nghttp2_frame_origin_free(nghttp2_extension *frame, nghttp2_mem *mem); - -/* - * Initializes PRIORITY_UPDATE frame |frame| with given values. This - * function assumes that frame->payload points to - * nghttp2_ext_priority_update object. On success, this function - * takes ownership of |field_value|, so caller must not free it. - */ -void nghttp2_frame_priority_update_init(nghttp2_extension *frame, - int32_t stream_id, uint8_t *field_value, - size_t field_value_len); - -/* - * Frees up resources under |frame|. This function does not free - * nghttp2_ext_priority_update object pointed by frame->payload. This - * function only frees field_value pointed by - * nghttp2_ext_priority_update.field_value. - */ -void nghttp2_frame_priority_update_free(nghttp2_extension *frame, - nghttp2_mem *mem); - -/* - * Returns the number of padding bytes after payload. The total - * padding length is given in the |padlen|. The returned value does - * not include the Pad Length field. If |padlen| is 0, this function - * returns 0, regardless of frame->hd.flags. - */ -size_t nghttp2_frame_trail_padlen(nghttp2_frame *frame, size_t padlen); - -void nghttp2_frame_data_init(nghttp2_data *frame, uint8_t flags, - int32_t stream_id); - -void nghttp2_frame_data_free(nghttp2_data *frame); - -/* - * Makes copy of |iv| and return the copy. The |niv| is the number of - * entries in |iv|. This function returns the pointer to the copy if - * it succeeds, or NULL. - */ -nghttp2_settings_entry *nghttp2_frame_iv_copy(const nghttp2_settings_entry *iv, - size_t niv, nghttp2_mem *mem); - -/* - * Sorts the |nva| in ascending order of name and value. If names are - * equivalent, sort them by value. - */ -void nghttp2_nv_array_sort(nghttp2_nv *nva, size_t nvlen); - -/* - * Copies name/value pairs from |nva|, which contains |nvlen| pairs, - * to |*nva_ptr|, which is dynamically allocated so that all items can - * be stored. The resultant name and value in nghttp2_nv are - * guaranteed to be NULL-terminated even if the input is not - * null-terminated. - * - * The |*nva_ptr| must be freed using nghttp2_nv_array_del(). - * - * This function returns 0 if it succeeds or one of the following - * negative error codes: - * - * NGHTTP2_ERR_NOMEM - * Out of memory. - */ -int nghttp2_nv_array_copy(nghttp2_nv **nva_ptr, const nghttp2_nv *nva, - size_t nvlen, nghttp2_mem *mem); - -/* - * Returns nonzero if the name/value pair |a| equals to |b|. The name - * is compared in case-sensitive, because we ensure that this function - * is called after the name is lower-cased. - */ -int nghttp2_nv_equal(const nghttp2_nv *a, const nghttp2_nv *b); - -/* - * Frees |nva|. - */ -void nghttp2_nv_array_del(nghttp2_nv *nva, nghttp2_mem *mem); - -/* - * Checks that the |iv|, which includes |niv| entries, does not have - * invalid values. - * - * This function returns nonzero if it succeeds, or 0. - */ -int nghttp2_iv_check(const nghttp2_settings_entry *iv, size_t niv); - -/* - * Sets Pad Length field and flags and adjusts frame header position - * of each buffers in |bufs|. The number of padding is given in the - * |padlen| including Pad Length field. The |hd| is the frame header - * for the serialized data. This function fills zeros padding region - * unless framehd_only is nonzero. - */ -void nghttp2_frame_add_pad(nghttp2_bufs *bufs, nghttp2_frame_hd *hd, - size_t padlen, int framehd_only); - -#endif /* NGHTTP2_FRAME_H */ diff --git a/3rdparty/exported/nghttp2/nghttp2_hd.c b/3rdparty/exported/nghttp2/nghttp2_hd.c deleted file mode 100644 index 55fc2cc6bfea..000000000000 --- a/3rdparty/exported/nghttp2/nghttp2_hd.c +++ /dev/null @@ -1,2377 +0,0 @@ -/* - * nghttp2 - HTTP/2 C Library - * - * Copyright (c) 2013 Tatsuhiro Tsujikawa - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE - * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION - * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION - * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ -#include "nghttp2_hd.h" - -#include -#include -#include - -#include "nghttp2_helper.h" -#include "nghttp2_int.h" -#include "nghttp2_debug.h" - -/* Make scalar initialization form of nghttp2_hd_entry */ -#define MAKE_STATIC_ENT(N, V, T, H) \ - { \ - {NULL, NULL, (uint8_t *)(N), sizeof((N)) - 1, -1}, \ - {NULL, NULL, (uint8_t *)(V), sizeof((V)) - 1, -1}, \ - {(uint8_t *)(N), (uint8_t *)(V), sizeof((N)) - 1, sizeof((V)) - 1, 0}, \ - T, \ - H, \ - } - -/* Generated by mkstatictbl.py */ -/* 3rd parameter is nghttp2_token value for header field name. We use - first enum value if same header names are repeated (e.g., - :status). */ -static const nghttp2_hd_static_entry static_table[] = { - MAKE_STATIC_ENT(":authority", "", 0, 3153725150u), - MAKE_STATIC_ENT(":method", "GET", 1, 695666056u), - MAKE_STATIC_ENT(":method", "POST", 1, 695666056u), - MAKE_STATIC_ENT(":path", "/", 3, 3292848686u), - MAKE_STATIC_ENT(":path", "/index.html", 3, 3292848686u), - MAKE_STATIC_ENT(":scheme", "http", 5, 2510477674u), - MAKE_STATIC_ENT(":scheme", "https", 5, 2510477674u), - MAKE_STATIC_ENT(":status", "200", 7, 4000288983u), - MAKE_STATIC_ENT(":status", "204", 7, 4000288983u), - MAKE_STATIC_ENT(":status", "206", 7, 4000288983u), - MAKE_STATIC_ENT(":status", "304", 7, 4000288983u), - MAKE_STATIC_ENT(":status", "400", 7, 4000288983u), - MAKE_STATIC_ENT(":status", "404", 7, 4000288983u), - MAKE_STATIC_ENT(":status", "500", 7, 4000288983u), - MAKE_STATIC_ENT("accept-charset", "", 14, 3664010344u), - MAKE_STATIC_ENT("accept-encoding", "gzip, deflate", 15, 3379649177u), - MAKE_STATIC_ENT("accept-language", "", 16, 1979086614u), - MAKE_STATIC_ENT("accept-ranges", "", 17, 1713753958u), - MAKE_STATIC_ENT("accept", "", 18, 136609321u), - MAKE_STATIC_ENT("access-control-allow-origin", "", 19, 2710797292u), - MAKE_STATIC_ENT("age", "", 20, 742476188u), - MAKE_STATIC_ENT("allow", "", 21, 2930878514u), - MAKE_STATIC_ENT("authorization", "", 22, 2436257726u), - MAKE_STATIC_ENT("cache-control", "", 23, 1355326669u), - MAKE_STATIC_ENT("content-disposition", "", 24, 3889184348u), - MAKE_STATIC_ENT("content-encoding", "", 25, 65203592u), - MAKE_STATIC_ENT("content-language", "", 26, 24973587u), - MAKE_STATIC_ENT("content-length", "", 27, 1308181789u), - MAKE_STATIC_ENT("content-location", "", 28, 2302364718u), - MAKE_STATIC_ENT("content-range", "", 29, 3555523146u), - MAKE_STATIC_ENT("content-type", "", 30, 4244048277u), - MAKE_STATIC_ENT("cookie", "", 31, 2007449791u), - MAKE_STATIC_ENT("date", "", 32, 3564297305u), - MAKE_STATIC_ENT("etag", "", 33, 113792960u), - MAKE_STATIC_ENT("expect", "", 34, 2530896728u), - MAKE_STATIC_ENT("expires", "", 35, 1049544579u), - MAKE_STATIC_ENT("from", "", 36, 2513272949u), - MAKE_STATIC_ENT("host", "", 37, 2952701295u), - MAKE_STATIC_ENT("if-match", "", 38, 3597694698u), - MAKE_STATIC_ENT("if-modified-since", "", 39, 2213050793u), - MAKE_STATIC_ENT("if-none-match", "", 40, 2536202615u), - MAKE_STATIC_ENT("if-range", "", 41, 2340978238u), - MAKE_STATIC_ENT("if-unmodified-since", "", 42, 3794814858u), - MAKE_STATIC_ENT("last-modified", "", 43, 3226950251u), - MAKE_STATIC_ENT("link", "", 44, 232457833u), - MAKE_STATIC_ENT("location", "", 45, 200649126u), - MAKE_STATIC_ENT("max-forwards", "", 46, 1826162134u), - MAKE_STATIC_ENT("proxy-authenticate", "", 47, 2709445359u), - MAKE_STATIC_ENT("proxy-authorization", "", 48, 2686392507u), - MAKE_STATIC_ENT("range", "", 49, 4208725202u), - MAKE_STATIC_ENT("referer", "", 50, 3969579366u), - MAKE_STATIC_ENT("refresh", "", 51, 3572655668u), - MAKE_STATIC_ENT("retry-after", "", 52, 3336180598u), - MAKE_STATIC_ENT("server", "", 53, 1085029842u), - MAKE_STATIC_ENT("set-cookie", "", 54, 1848371000u), - MAKE_STATIC_ENT("strict-transport-security", "", 55, 4138147361u), - MAKE_STATIC_ENT("transfer-encoding", "", 56, 3719590988u), - MAKE_STATIC_ENT("user-agent", "", 57, 606444526u), - MAKE_STATIC_ENT("vary", "", 58, 1085005381u), - MAKE_STATIC_ENT("via", "", 59, 1762798611u), - MAKE_STATIC_ENT("www-authenticate", "", 60, 779865858u), -}; - -static int memeq(const void *s1, const void *s2, size_t n) { - return memcmp(s1, s2, n) == 0; -} - -/* - * This function was generated by genlibtokenlookup.py. Inspired by - * h2o header lookup. https://github.com/h2o/h2o - */ -static int32_t lookup_token(const uint8_t *name, size_t namelen) { - switch (namelen) { - case 2: - switch (name[1]) { - case 'e': - if (memeq("t", name, 1)) { - return NGHTTP2_TOKEN_TE; - } - break; - } - break; - case 3: - switch (name[2]) { - case 'a': - if (memeq("vi", name, 2)) { - return NGHTTP2_TOKEN_VIA; - } - break; - case 'e': - if (memeq("ag", name, 2)) { - return NGHTTP2_TOKEN_AGE; - } - break; - } - break; - case 4: - switch (name[3]) { - case 'e': - if (memeq("dat", name, 3)) { - return NGHTTP2_TOKEN_DATE; - } - break; - case 'g': - if (memeq("eta", name, 3)) { - return NGHTTP2_TOKEN_ETAG; - } - break; - case 'k': - if (memeq("lin", name, 3)) { - return NGHTTP2_TOKEN_LINK; - } - break; - case 'm': - if (memeq("fro", name, 3)) { - return NGHTTP2_TOKEN_FROM; - } - break; - case 't': - if (memeq("hos", name, 3)) { - return NGHTTP2_TOKEN_HOST; - } - break; - case 'y': - if (memeq("var", name, 3)) { - return NGHTTP2_TOKEN_VARY; - } - break; - } - break; - case 5: - switch (name[4]) { - case 'e': - if (memeq("rang", name, 4)) { - return NGHTTP2_TOKEN_RANGE; - } - break; - case 'h': - if (memeq(":pat", name, 4)) { - return NGHTTP2_TOKEN__PATH; - } - break; - case 'w': - if (memeq("allo", name, 4)) { - return NGHTTP2_TOKEN_ALLOW; - } - break; - } - break; - case 6: - switch (name[5]) { - case 'e': - if (memeq("cooki", name, 5)) { - return NGHTTP2_TOKEN_COOKIE; - } - break; - case 'r': - if (memeq("serve", name, 5)) { - return NGHTTP2_TOKEN_SERVER; - } - break; - case 't': - if (memeq("accep", name, 5)) { - return NGHTTP2_TOKEN_ACCEPT; - } - if (memeq("expec", name, 5)) { - return NGHTTP2_TOKEN_EXPECT; - } - break; - } - break; - case 7: - switch (name[6]) { - case 'd': - if (memeq(":metho", name, 6)) { - return NGHTTP2_TOKEN__METHOD; - } - break; - case 'e': - if (memeq(":schem", name, 6)) { - return NGHTTP2_TOKEN__SCHEME; - } - if (memeq("upgrad", name, 6)) { - return NGHTTP2_TOKEN_UPGRADE; - } - break; - case 'h': - if (memeq("refres", name, 6)) { - return NGHTTP2_TOKEN_REFRESH; - } - break; - case 'r': - if (memeq("refere", name, 6)) { - return NGHTTP2_TOKEN_REFERER; - } - break; - case 's': - if (memeq(":statu", name, 6)) { - return NGHTTP2_TOKEN__STATUS; - } - if (memeq("expire", name, 6)) { - return NGHTTP2_TOKEN_EXPIRES; - } - break; - } - break; - case 8: - switch (name[7]) { - case 'e': - if (memeq("if-rang", name, 7)) { - return NGHTTP2_TOKEN_IF_RANGE; - } - break; - case 'h': - if (memeq("if-matc", name, 7)) { - return NGHTTP2_TOKEN_IF_MATCH; - } - break; - case 'n': - if (memeq("locatio", name, 7)) { - return NGHTTP2_TOKEN_LOCATION; - } - break; - case 'y': - if (memeq("priorit", name, 7)) { - return NGHTTP2_TOKEN_PRIORITY; - } - break; - } - break; - case 9: - switch (name[8]) { - case 'l': - if (memeq(":protoco", name, 8)) { - return NGHTTP2_TOKEN__PROTOCOL; - } - break; - } - break; - case 10: - switch (name[9]) { - case 'e': - if (memeq("keep-aliv", name, 9)) { - return NGHTTP2_TOKEN_KEEP_ALIVE; - } - if (memeq("set-cooki", name, 9)) { - return NGHTTP2_TOKEN_SET_COOKIE; - } - break; - case 'n': - if (memeq("connectio", name, 9)) { - return NGHTTP2_TOKEN_CONNECTION; - } - break; - case 't': - if (memeq("user-agen", name, 9)) { - return NGHTTP2_TOKEN_USER_AGENT; - } - break; - case 'y': - if (memeq(":authorit", name, 9)) { - return NGHTTP2_TOKEN__AUTHORITY; - } - break; - } - break; - case 11: - switch (name[10]) { - case 'r': - if (memeq("retry-afte", name, 10)) { - return NGHTTP2_TOKEN_RETRY_AFTER; - } - break; - } - break; - case 12: - switch (name[11]) { - case 'e': - if (memeq("content-typ", name, 11)) { - return NGHTTP2_TOKEN_CONTENT_TYPE; - } - break; - case 's': - if (memeq("max-forward", name, 11)) { - return NGHTTP2_TOKEN_MAX_FORWARDS; - } - break; - } - break; - case 13: - switch (name[12]) { - case 'd': - if (memeq("last-modifie", name, 12)) { - return NGHTTP2_TOKEN_LAST_MODIFIED; - } - break; - case 'e': - if (memeq("content-rang", name, 12)) { - return NGHTTP2_TOKEN_CONTENT_RANGE; - } - break; - case 'h': - if (memeq("if-none-matc", name, 12)) { - return NGHTTP2_TOKEN_IF_NONE_MATCH; - } - break; - case 'l': - if (memeq("cache-contro", name, 12)) { - return NGHTTP2_TOKEN_CACHE_CONTROL; - } - break; - case 'n': - if (memeq("authorizatio", name, 12)) { - return NGHTTP2_TOKEN_AUTHORIZATION; - } - break; - case 's': - if (memeq("accept-range", name, 12)) { - return NGHTTP2_TOKEN_ACCEPT_RANGES; - } - break; - } - break; - case 14: - switch (name[13]) { - case 'h': - if (memeq("content-lengt", name, 13)) { - return NGHTTP2_TOKEN_CONTENT_LENGTH; - } - break; - case 't': - if (memeq("accept-charse", name, 13)) { - return NGHTTP2_TOKEN_ACCEPT_CHARSET; - } - break; - } - break; - case 15: - switch (name[14]) { - case 'e': - if (memeq("accept-languag", name, 14)) { - return NGHTTP2_TOKEN_ACCEPT_LANGUAGE; - } - break; - case 'g': - if (memeq("accept-encodin", name, 14)) { - return NGHTTP2_TOKEN_ACCEPT_ENCODING; - } - break; - } - break; - case 16: - switch (name[15]) { - case 'e': - if (memeq("content-languag", name, 15)) { - return NGHTTP2_TOKEN_CONTENT_LANGUAGE; - } - if (memeq("www-authenticat", name, 15)) { - return NGHTTP2_TOKEN_WWW_AUTHENTICATE; - } - break; - case 'g': - if (memeq("content-encodin", name, 15)) { - return NGHTTP2_TOKEN_CONTENT_ENCODING; - } - break; - case 'n': - if (memeq("content-locatio", name, 15)) { - return NGHTTP2_TOKEN_CONTENT_LOCATION; - } - if (memeq("proxy-connectio", name, 15)) { - return NGHTTP2_TOKEN_PROXY_CONNECTION; - } - break; - } - break; - case 17: - switch (name[16]) { - case 'e': - if (memeq("if-modified-sinc", name, 16)) { - return NGHTTP2_TOKEN_IF_MODIFIED_SINCE; - } - break; - case 'g': - if (memeq("transfer-encodin", name, 16)) { - return NGHTTP2_TOKEN_TRANSFER_ENCODING; - } - break; - } - break; - case 18: - switch (name[17]) { - case 'e': - if (memeq("proxy-authenticat", name, 17)) { - return NGHTTP2_TOKEN_PROXY_AUTHENTICATE; - } - break; - } - break; - case 19: - switch (name[18]) { - case 'e': - if (memeq("if-unmodified-sinc", name, 18)) { - return NGHTTP2_TOKEN_IF_UNMODIFIED_SINCE; - } - break; - case 'n': - if (memeq("content-dispositio", name, 18)) { - return NGHTTP2_TOKEN_CONTENT_DISPOSITION; - } - if (memeq("proxy-authorizatio", name, 18)) { - return NGHTTP2_TOKEN_PROXY_AUTHORIZATION; - } - break; - } - break; - case 25: - switch (name[24]) { - case 'y': - if (memeq("strict-transport-securit", name, 24)) { - return NGHTTP2_TOKEN_STRICT_TRANSPORT_SECURITY; - } - break; - } - break; - case 27: - switch (name[26]) { - case 'n': - if (memeq("access-control-allow-origi", name, 26)) { - return NGHTTP2_TOKEN_ACCESS_CONTROL_ALLOW_ORIGIN; - } - break; - } - break; - } - return -1; -} - -void nghttp2_hd_entry_init(nghttp2_hd_entry *ent, nghttp2_hd_nv *nv) { - ent->nv = *nv; - ent->cnv.name = nv->name->base; - ent->cnv.namelen = nv->name->len; - ent->cnv.value = nv->value->base; - ent->cnv.valuelen = nv->value->len; - ent->cnv.flags = nv->flags; - ent->next = NULL; - ent->hash = 0; - - nghttp2_rcbuf_incref(ent->nv.name); - nghttp2_rcbuf_incref(ent->nv.value); -} - -void nghttp2_hd_entry_free(nghttp2_hd_entry *ent) { - nghttp2_rcbuf_decref(ent->nv.value); - nghttp2_rcbuf_decref(ent->nv.name); -} - -static int name_eq(const nghttp2_hd_nv *a, const nghttp2_nv *b) { - return a->name->len == b->namelen && - memeq(a->name->base, b->name, b->namelen); -} - -static int value_eq(const nghttp2_hd_nv *a, const nghttp2_nv *b) { - return a->value->len == b->valuelen && - memeq(a->value->base, b->value, b->valuelen); -} - -static uint32_t name_hash(const nghttp2_nv *nv) { - /* 32 bit FNV-1a: http://isthe.com/chongo/tech/comp/fnv/ */ - uint32_t h = 2166136261u; - size_t i; - - for (i = 0; i < nv->namelen; ++i) { - h ^= nv->name[i]; - h += (h << 1) + (h << 4) + (h << 7) + (h << 8) + (h << 24); - } - - return h; -} - -static void hd_map_init(nghttp2_hd_map *map) { - memset(map, 0, sizeof(nghttp2_hd_map)); -} - -static void hd_map_insert(nghttp2_hd_map *map, nghttp2_hd_entry *ent) { - nghttp2_hd_entry **bucket; - - bucket = &map->table[ent->hash & (HD_MAP_SIZE - 1)]; - - if (*bucket == NULL) { - *bucket = ent; - return; - } - - /* lower index is linked near the root */ - ent->next = *bucket; - *bucket = ent; -} - -static nghttp2_hd_entry *hd_map_find(nghttp2_hd_map *map, int *exact_match, - const nghttp2_nv *nv, int32_t token, - uint32_t hash, int name_only) { - nghttp2_hd_entry *p; - nghttp2_hd_entry *res = NULL; - - *exact_match = 0; - - for (p = map->table[hash & (HD_MAP_SIZE - 1)]; p; p = p->next) { - if (token != p->nv.token || - (token == -1 && (hash != p->hash || !name_eq(&p->nv, nv)))) { - continue; - } - if (!res) { - res = p; - if (name_only) { - break; - } - } - if (value_eq(&p->nv, nv)) { - res = p; - *exact_match = 1; - break; - } - } - - return res; -} - -static void hd_map_remove(nghttp2_hd_map *map, nghttp2_hd_entry *ent) { - nghttp2_hd_entry **dst; - - dst = &map->table[ent->hash & (HD_MAP_SIZE - 1)]; - - for (; *dst; dst = &(*dst)->next) { - if (*dst != ent) { - continue; - } - - *dst = ent->next; - ent->next = NULL; - return; - } -} - -static int hd_ringbuf_init(nghttp2_hd_ringbuf *ringbuf, size_t bufsize, - nghttp2_mem *mem) { - size_t size; - for (size = 1; size < bufsize; size <<= 1) - ; - ringbuf->buffer = nghttp2_mem_malloc(mem, sizeof(nghttp2_hd_entry *) * size); - if (ringbuf->buffer == NULL) { - return NGHTTP2_ERR_NOMEM; - } - ringbuf->mask = size - 1; - ringbuf->first = 0; - ringbuf->len = 0; - return 0; -} - -static nghttp2_hd_entry *hd_ringbuf_get(nghttp2_hd_ringbuf *ringbuf, - size_t idx) { - assert(idx < ringbuf->len); - return ringbuf->buffer[(ringbuf->first + idx) & ringbuf->mask]; -} - -static int hd_ringbuf_reserve(nghttp2_hd_ringbuf *ringbuf, size_t bufsize, - nghttp2_mem *mem) { - size_t i; - size_t size; - nghttp2_hd_entry **buffer; - - if (ringbuf->mask + 1 >= bufsize) { - return 0; - } - for (size = 1; size < bufsize; size <<= 1) - ; - buffer = nghttp2_mem_malloc(mem, sizeof(nghttp2_hd_entry *) * size); - if (buffer == NULL) { - return NGHTTP2_ERR_NOMEM; - } - for (i = 0; i < ringbuf->len; ++i) { - buffer[i] = hd_ringbuf_get(ringbuf, i); - } - nghttp2_mem_free(mem, ringbuf->buffer); - ringbuf->buffer = buffer; - ringbuf->mask = size - 1; - ringbuf->first = 0; - return 0; -} - -static void hd_ringbuf_free(nghttp2_hd_ringbuf *ringbuf, nghttp2_mem *mem) { - size_t i; - if (ringbuf == NULL) { - return; - } - for (i = 0; i < ringbuf->len; ++i) { - nghttp2_hd_entry *ent = hd_ringbuf_get(ringbuf, i); - - nghttp2_hd_entry_free(ent); - nghttp2_mem_free(mem, ent); - } - nghttp2_mem_free(mem, ringbuf->buffer); -} - -static int hd_ringbuf_push_front(nghttp2_hd_ringbuf *ringbuf, - nghttp2_hd_entry *ent, nghttp2_mem *mem) { - int rv; - - rv = hd_ringbuf_reserve(ringbuf, ringbuf->len + 1, mem); - - if (rv != 0) { - return rv; - } - - ringbuf->buffer[--ringbuf->first & ringbuf->mask] = ent; - ++ringbuf->len; - - return 0; -} - -static void hd_ringbuf_pop_back(nghttp2_hd_ringbuf *ringbuf) { - assert(ringbuf->len > 0); - --ringbuf->len; -} - -static int hd_context_init(nghttp2_hd_context *context, nghttp2_mem *mem) { - int rv; - context->mem = mem; - context->bad = 0; - context->hd_table_bufsize_max = NGHTTP2_HD_DEFAULT_MAX_BUFFER_SIZE; - rv = hd_ringbuf_init( - &context->hd_table, - context->hd_table_bufsize_max / NGHTTP2_HD_ENTRY_OVERHEAD, mem); - if (rv != 0) { - return rv; - } - - context->hd_table_bufsize = 0; - context->next_seq = 0; - - return 0; -} - -static void hd_context_free(nghttp2_hd_context *context) { - hd_ringbuf_free(&context->hd_table, context->mem); -} - -int nghttp2_hd_deflate_init(nghttp2_hd_deflater *deflater, nghttp2_mem *mem) { - return nghttp2_hd_deflate_init2( - deflater, NGHTTP2_HD_DEFAULT_MAX_DEFLATE_BUFFER_SIZE, mem); -} - -int nghttp2_hd_deflate_init2(nghttp2_hd_deflater *deflater, - size_t max_deflate_dynamic_table_size, - nghttp2_mem *mem) { - int rv; - rv = hd_context_init(&deflater->ctx, mem); - if (rv != 0) { - return rv; - } - - hd_map_init(&deflater->map); - - if (max_deflate_dynamic_table_size < NGHTTP2_HD_DEFAULT_MAX_BUFFER_SIZE) { - deflater->notify_table_size_change = 1; - deflater->ctx.hd_table_bufsize_max = max_deflate_dynamic_table_size; - } else { - deflater->notify_table_size_change = 0; - } - - deflater->deflate_hd_table_bufsize_max = max_deflate_dynamic_table_size; - deflater->min_hd_table_bufsize_max = UINT32_MAX; - - return 0; -} - -int nghttp2_hd_inflate_init(nghttp2_hd_inflater *inflater, nghttp2_mem *mem) { - int rv; - - rv = hd_context_init(&inflater->ctx, mem); - if (rv != 0) { - goto fail; - } - - inflater->settings_hd_table_bufsize_max = NGHTTP2_HD_DEFAULT_MAX_BUFFER_SIZE; - inflater->min_hd_table_bufsize_max = UINT32_MAX; - - inflater->nv_name_keep = NULL; - inflater->nv_value_keep = NULL; - - inflater->opcode = NGHTTP2_HD_OPCODE_NONE; - inflater->state = NGHTTP2_HD_STATE_INFLATE_START; - - nghttp2_buf_init(&inflater->namebuf); - nghttp2_buf_init(&inflater->valuebuf); - - inflater->namercbuf = NULL; - inflater->valuercbuf = NULL; - - inflater->huffman_encoded = 0; - inflater->index = 0; - inflater->left = 0; - inflater->shift = 0; - inflater->index_required = 0; - inflater->no_index = 0; - - return 0; - -fail: - return rv; -} - -static void hd_inflate_keep_free(nghttp2_hd_inflater *inflater) { - nghttp2_rcbuf_decref(inflater->nv_value_keep); - nghttp2_rcbuf_decref(inflater->nv_name_keep); - - inflater->nv_value_keep = NULL; - inflater->nv_name_keep = NULL; -} - -void nghttp2_hd_deflate_free(nghttp2_hd_deflater *deflater) { - hd_context_free(&deflater->ctx); -} - -void nghttp2_hd_inflate_free(nghttp2_hd_inflater *inflater) { - hd_inflate_keep_free(inflater); - - nghttp2_rcbuf_decref(inflater->valuercbuf); - nghttp2_rcbuf_decref(inflater->namercbuf); - - hd_context_free(&inflater->ctx); -} - -static size_t entry_room(size_t namelen, size_t valuelen) { - return NGHTTP2_HD_ENTRY_OVERHEAD + namelen + valuelen; -} - -static void emit_header(nghttp2_hd_nv *nv_out, nghttp2_hd_nv *nv) { - DEBUGF("inflatehd: header emission: %s: %s\n", nv->name->base, - nv->value->base); - /* ent->ref may be 0. This happens if the encoder emits literal - block larger than header table capacity with indexing. */ - *nv_out = *nv; -} - -static size_t count_encoded_length(size_t n, size_t prefix) { - size_t k = (size_t)((1 << prefix) - 1); - size_t len = 0; - - if (n < k) { - return 1; - } - - n -= k; - ++len; - - for (; n >= 128; n >>= 7, ++len) - ; - - return len + 1; -} - -static size_t encode_length(uint8_t *buf, size_t n, size_t prefix) { - size_t k = (size_t)((1 << prefix) - 1); - uint8_t *begin = buf; - - *buf = (uint8_t)(*buf & ~k); - - if (n < k) { - *buf = (uint8_t)(*buf | n); - return 1; - } - - *buf = (uint8_t)(*buf | k); - ++buf; - - n -= k; - - for (; n >= 128; n >>= 7) { - *buf++ = (uint8_t)((1 << 7) | (n & 0x7f)); - } - - *buf++ = (uint8_t)n; - - return (size_t)(buf - begin); -} - -/* - * Decodes |prefix| prefixed integer stored from |in|. The |last| - * represents the 1 beyond the last of the valid contiguous memory - * region from |in|. The decoded integer must be less than or equal - * to UINT32_MAX. - * - * If the |initial| is nonzero, it is used as a initial value, this - * function assumes the |in| starts with intermediate data. - * - * An entire integer is decoded successfully, decoded, the |*fin| is - * set to nonzero. - * - * This function stores the decoded integer in |*res| if it succeed, - * including partial decoding (in this case, number of shift to make - * in the next call will be stored in |*shift_ptr|) and returns number - * of bytes processed, or returns -1, indicating decoding error. - */ -static nghttp2_ssize decode_length(uint32_t *res, size_t *shift_ptr, int *fin, - uint32_t initial, size_t shift, - const uint8_t *in, const uint8_t *last, - size_t prefix) { - uint32_t k = (uint8_t)((1 << prefix) - 1); - uint32_t n = initial; - const uint8_t *start = in; - - *shift_ptr = 0; - *fin = 0; - - if (n == 0) { - if ((*in & k) != k) { - *res = (*in) & k; - *fin = 1; - return 1; - } - - n = k; - - if (++in == last) { - *res = n; - return (nghttp2_ssize)(in - start); - } - } - - for (; in != last; ++in, shift += 7) { - uint32_t add = *in & 0x7f; - - if (shift >= 32) { - DEBUGF("inflate: shift exponent overflow\n"); - return -1; - } - - if ((UINT32_MAX >> shift) < add) { - DEBUGF("inflate: integer overflow on shift\n"); - return -1; - } - - add <<= shift; - - if (UINT32_MAX - add < n) { - DEBUGF("inflate: integer overflow on addition\n"); - return -1; - } - - n += add; - - if ((*in & (1 << 7)) == 0) { - break; - } - } - - *shift_ptr = shift; - - if (in == last) { - *res = n; - return (nghttp2_ssize)(in - start); - } - - *res = n; - *fin = 1; - return (nghttp2_ssize)(in + 1 - start); -} - -static int emit_table_size(nghttp2_bufs *bufs, size_t table_size) { - int rv; - uint8_t *bufp; - size_t blocklen; - uint8_t sb[16]; - - DEBUGF("deflatehd: emit table_size=%zu\n", table_size); - - blocklen = count_encoded_length(table_size, 5); - - if (sizeof(sb) < blocklen) { - return NGHTTP2_ERR_HEADER_COMP; - } - - bufp = sb; - - *bufp = 0x20u; - - encode_length(bufp, table_size, 5); - - rv = nghttp2_bufs_add(bufs, sb, blocklen); - if (rv != 0) { - return rv; - } - - return 0; -} - -static int emit_indexed_block(nghttp2_bufs *bufs, size_t idx) { - int rv; - size_t blocklen; - uint8_t sb[16]; - uint8_t *bufp; - - blocklen = count_encoded_length(idx + 1, 7); - - DEBUGF("deflatehd: emit indexed index=%zu, %zu bytes\n", idx, blocklen); - - if (sizeof(sb) < blocklen) { - return NGHTTP2_ERR_HEADER_COMP; - } - - bufp = sb; - *bufp = 0x80u; - encode_length(bufp, idx + 1, 7); - - rv = nghttp2_bufs_add(bufs, sb, blocklen); - if (rv != 0) { - return rv; - } - - return 0; -} - -static int emit_string(nghttp2_bufs *bufs, const uint8_t *str, size_t len) { - int rv; - uint8_t sb[16]; - uint8_t *bufp; - size_t blocklen; - size_t enclen; - int huffman = 0; - - enclen = nghttp2_hd_huff_encode_count(str, len); - - if (enclen < len) { - huffman = 1; - } else { - enclen = len; - } - - blocklen = count_encoded_length(enclen, 7); - - DEBUGF("deflatehd: emit string str=%.*s, length=%zu, huffman=%d, " - "encoded_length=%zu\n", - (int)len, (const char *)str, len, huffman, enclen); - - if (sizeof(sb) < blocklen) { - return NGHTTP2_ERR_HEADER_COMP; - } - - bufp = sb; - *bufp = huffman ? 1 << 7 : 0; - encode_length(bufp, enclen, 7); - - rv = nghttp2_bufs_add(bufs, sb, blocklen); - if (rv != 0) { - return rv; - } - - if (huffman) { - rv = nghttp2_hd_huff_encode(bufs, str, len); - } else { - assert(enclen == len); - rv = nghttp2_bufs_add(bufs, str, len); - } - - return rv; -} - -static uint8_t pack_first_byte(int indexing_mode) { - switch (indexing_mode) { - case NGHTTP2_HD_WITH_INDEXING: - return 0x40u; - case NGHTTP2_HD_WITHOUT_INDEXING: - return 0; - case NGHTTP2_HD_NEVER_INDEXING: - return 0x10u; - default: - assert(0); - } - /* This is required to compile with android NDK r10d + - --enable-werror */ - return 0; -} - -static int emit_indname_block(nghttp2_bufs *bufs, size_t idx, - const nghttp2_nv *nv, int indexing_mode) { - int rv; - uint8_t *bufp; - size_t blocklen; - uint8_t sb[16]; - size_t prefixlen; - - if (indexing_mode == NGHTTP2_HD_WITH_INDEXING) { - prefixlen = 6; - } else { - prefixlen = 4; - } - - DEBUGF("deflatehd: emit indname index=%zu, valuelen=%zu, indexing_mode=%d\n", - idx, nv->valuelen, indexing_mode); - - blocklen = count_encoded_length(idx + 1, prefixlen); - - if (sizeof(sb) < blocklen) { - return NGHTTP2_ERR_HEADER_COMP; - } - - bufp = sb; - - *bufp = pack_first_byte(indexing_mode); - - encode_length(bufp, idx + 1, prefixlen); - - rv = nghttp2_bufs_add(bufs, sb, blocklen); - if (rv != 0) { - return rv; - } - - rv = emit_string(bufs, nv->value, nv->valuelen); - if (rv != 0) { - return rv; - } - - return 0; -} - -static int emit_newname_block(nghttp2_bufs *bufs, const nghttp2_nv *nv, - int indexing_mode) { - int rv; - - DEBUGF( - "deflatehd: emit newname namelen=%zu, valuelen=%zu, indexing_mode=%d\n", - nv->namelen, nv->valuelen, indexing_mode); - - rv = nghttp2_bufs_addb(bufs, pack_first_byte(indexing_mode)); - if (rv != 0) { - return rv; - } - - rv = emit_string(bufs, nv->name, nv->namelen); - if (rv != 0) { - return rv; - } - - rv = emit_string(bufs, nv->value, nv->valuelen); - if (rv != 0) { - return rv; - } - - return 0; -} - -static int add_hd_table_incremental(nghttp2_hd_context *context, - nghttp2_hd_nv *nv, nghttp2_hd_map *map, - uint32_t hash) { - int rv; - nghttp2_hd_entry *new_ent; - size_t room; - nghttp2_mem *mem; - - mem = context->mem; - room = entry_room(nv->name->len, nv->value->len); - - while (context->hd_table_bufsize + room > context->hd_table_bufsize_max && - context->hd_table.len > 0) { - size_t idx = context->hd_table.len - 1; - nghttp2_hd_entry *ent = hd_ringbuf_get(&context->hd_table, idx); - - context->hd_table_bufsize -= - entry_room(ent->nv.name->len, ent->nv.value->len); - - DEBUGF("hpack: remove item from header table: %s: %s\n", - (char *)ent->nv.name->base, (char *)ent->nv.value->base); - - hd_ringbuf_pop_back(&context->hd_table); - if (map) { - hd_map_remove(map, ent); - } - - nghttp2_hd_entry_free(ent); - nghttp2_mem_free(mem, ent); - } - - if (room > context->hd_table_bufsize_max) { - /* The entry taking more than NGHTTP2_HD_MAX_BUFFER_SIZE is - immediately evicted. So we don't allocate memory for it. */ - return 0; - } - - new_ent = nghttp2_mem_malloc(mem, sizeof(nghttp2_hd_entry)); - if (new_ent == NULL) { - return NGHTTP2_ERR_NOMEM; - } - - nghttp2_hd_entry_init(new_ent, nv); - - rv = hd_ringbuf_push_front(&context->hd_table, new_ent, mem); - - if (rv != 0) { - nghttp2_hd_entry_free(new_ent); - nghttp2_mem_free(mem, new_ent); - - return rv; - } - - new_ent->seq = context->next_seq++; - new_ent->hash = hash; - - if (map) { - hd_map_insert(map, new_ent); - } - - context->hd_table_bufsize += room; - - return 0; -} - -typedef struct { - nghttp2_ssize index; - /* Nonzero if both name and value are matched. */ - int name_value_match; -} search_result; - -static search_result search_static_table(const nghttp2_nv *nv, int32_t token, - int name_only) { - search_result res = {token, 0}; - int i; - const nghttp2_hd_static_entry *ent; - - if (name_only) { - return res; - } - - for (i = token; - i <= NGHTTP2_TOKEN_WWW_AUTHENTICATE && static_table[i].token == token; - ++i) { - ent = &static_table[i]; - if (ent->value.len == nv->valuelen && - memcmp(ent->value.base, nv->value, nv->valuelen) == 0) { - res.index = i; - res.name_value_match = 1; - return res; - } - } - return res; -} - -static search_result search_hd_table(nghttp2_hd_context *context, - const nghttp2_nv *nv, int32_t token, - int indexing_mode, nghttp2_hd_map *map, - uint32_t hash) { - search_result res = {-1, 0}; - const nghttp2_hd_entry *ent; - int exact_match; - int name_only = indexing_mode == NGHTTP2_HD_NEVER_INDEXING; - - exact_match = 0; - ent = hd_map_find(map, &exact_match, nv, token, hash, name_only); - - if (!exact_match && token >= 0 && token <= NGHTTP2_TOKEN_WWW_AUTHENTICATE) { - return search_static_table(nv, token, name_only); - } - - if (ent == NULL) { - return res; - } - - res.index = (nghttp2_ssize)(context->next_seq - 1 - ent->seq + - NGHTTP2_STATIC_TABLE_LENGTH); - res.name_value_match = exact_match; - - return res; -} - -static void hd_context_shrink_table_size(nghttp2_hd_context *context, - nghttp2_hd_map *map) { - nghttp2_mem *mem; - - mem = context->mem; - - while (context->hd_table_bufsize > context->hd_table_bufsize_max && - context->hd_table.len > 0) { - size_t idx = context->hd_table.len - 1; - nghttp2_hd_entry *ent = hd_ringbuf_get(&context->hd_table, idx); - context->hd_table_bufsize -= - entry_room(ent->nv.name->len, ent->nv.value->len); - hd_ringbuf_pop_back(&context->hd_table); - if (map) { - hd_map_remove(map, ent); - } - - nghttp2_hd_entry_free(ent); - nghttp2_mem_free(mem, ent); - } -} - -int nghttp2_hd_deflate_change_table_size( - nghttp2_hd_deflater *deflater, size_t settings_max_dynamic_table_size) { - size_t next_bufsize = nghttp2_min_size( - settings_max_dynamic_table_size, deflater->deflate_hd_table_bufsize_max); - - deflater->ctx.hd_table_bufsize_max = next_bufsize; - - deflater->min_hd_table_bufsize_max = - nghttp2_min_size(deflater->min_hd_table_bufsize_max, next_bufsize); - - deflater->notify_table_size_change = 1; - - hd_context_shrink_table_size(&deflater->ctx, &deflater->map); - return 0; -} - -int nghttp2_hd_inflate_change_table_size( - nghttp2_hd_inflater *inflater, size_t settings_max_dynamic_table_size) { - switch (inflater->state) { - case NGHTTP2_HD_STATE_EXPECT_TABLE_SIZE: - case NGHTTP2_HD_STATE_INFLATE_START: - break; - default: - return NGHTTP2_ERR_INVALID_STATE; - } - - inflater->settings_hd_table_bufsize_max = settings_max_dynamic_table_size; - - /* It seems that encoder is not required to send dynamic table size - update if the table size is not changed after applying - SETTINGS_HEADER_TABLE_SIZE. RFC 7541 is ambiguous here, but this - is the intention of the editor. If new maximum table size is - strictly smaller than the current negotiated maximum size, - encoder must send dynamic table size update. In other cases, we - cannot expect it to do so. */ - if (inflater->ctx.hd_table_bufsize_max > settings_max_dynamic_table_size) { - inflater->state = NGHTTP2_HD_STATE_EXPECT_TABLE_SIZE; - /* Remember minimum value, and validate that encoder sends the - value less than or equal to this. */ - inflater->min_hd_table_bufsize_max = settings_max_dynamic_table_size; - - inflater->ctx.hd_table_bufsize_max = settings_max_dynamic_table_size; - - hd_context_shrink_table_size(&inflater->ctx, NULL); - } - - return 0; -} - -#define INDEX_RANGE_VALID(context, idx) \ - ((idx) < (context)->hd_table.len + NGHTTP2_STATIC_TABLE_LENGTH) - -static size_t get_max_index(nghttp2_hd_context *context) { - return context->hd_table.len + NGHTTP2_STATIC_TABLE_LENGTH; -} - -nghttp2_hd_nv nghttp2_hd_table_get(nghttp2_hd_context *context, size_t idx) { - assert(INDEX_RANGE_VALID(context, idx)); - if (idx >= NGHTTP2_STATIC_TABLE_LENGTH) { - return hd_ringbuf_get(&context->hd_table, idx - NGHTTP2_STATIC_TABLE_LENGTH) - ->nv; - } else { - const nghttp2_hd_static_entry *ent = &static_table[idx]; - nghttp2_hd_nv nv = {(nghttp2_rcbuf *)&ent->name, - (nghttp2_rcbuf *)&ent->value, ent->token, - NGHTTP2_NV_FLAG_NONE}; - return nv; - } -} - -static const nghttp2_nv *nghttp2_hd_table_get2(nghttp2_hd_context *context, - size_t idx) { - assert(INDEX_RANGE_VALID(context, idx)); - if (idx >= NGHTTP2_STATIC_TABLE_LENGTH) { - return &hd_ringbuf_get(&context->hd_table, - idx - NGHTTP2_STATIC_TABLE_LENGTH) - ->cnv; - } - - return &static_table[idx].cnv; -} - -static int hd_deflate_decide_indexing(nghttp2_hd_deflater *deflater, - const nghttp2_nv *nv, int32_t token) { - if (token == NGHTTP2_TOKEN__PATH || token == NGHTTP2_TOKEN_AGE || - token == NGHTTP2_TOKEN_CONTENT_LENGTH || token == NGHTTP2_TOKEN_ETAG || - token == NGHTTP2_TOKEN_IF_MODIFIED_SINCE || - token == NGHTTP2_TOKEN_IF_NONE_MATCH || token == NGHTTP2_TOKEN_LOCATION || - token == NGHTTP2_TOKEN_SET_COOKIE || - entry_room(nv->namelen, nv->valuelen) > - deflater->ctx.hd_table_bufsize_max * 3 / 4) { - return NGHTTP2_HD_WITHOUT_INDEXING; - } - - return NGHTTP2_HD_WITH_INDEXING; -} - -static int deflate_nv(nghttp2_hd_deflater *deflater, nghttp2_bufs *bufs, - const nghttp2_nv *nv) { - int rv; - search_result res; - nghttp2_ssize idx; - int indexing_mode; - int32_t token; - nghttp2_mem *mem; - uint32_t hash = 0; - - DEBUGF("deflatehd: deflating %.*s: %.*s\n", (int)nv->namelen, nv->name, - (int)nv->valuelen, nv->value); - - mem = deflater->ctx.mem; - - token = lookup_token(nv->name, nv->namelen); - if (token == -1) { - hash = name_hash(nv); - } else if (token <= NGHTTP2_TOKEN_WWW_AUTHENTICATE) { - hash = static_table[token].hash; - } - - /* Don't index authorization header field since it may contain low - entropy secret data (e.g., id/password). Also cookie header - field with less than 20 bytes value is also never indexed. This - is the same criteria used in Firefox codebase. */ - indexing_mode = token == NGHTTP2_TOKEN_AUTHORIZATION || - (token == NGHTTP2_TOKEN_COOKIE && nv->valuelen < 20) || - (nv->flags & NGHTTP2_NV_FLAG_NO_INDEX) - ? NGHTTP2_HD_NEVER_INDEXING - : hd_deflate_decide_indexing(deflater, nv, token); - - res = search_hd_table(&deflater->ctx, nv, token, indexing_mode, - &deflater->map, hash); - - idx = res.index; - - if (res.name_value_match) { - DEBUGF("deflatehd: name/value match index=%td\n", idx); - - rv = emit_indexed_block(bufs, (size_t)idx); - if (rv != 0) { - return rv; - } - - return 0; - } - - if (res.index != -1) { - DEBUGF("deflatehd: name match index=%td\n", res.index); - } - - if (indexing_mode == NGHTTP2_HD_WITH_INDEXING) { - nghttp2_hd_nv hd_nv; - - if (idx != -1) { - hd_nv.name = nghttp2_hd_table_get(&deflater->ctx, (size_t)idx).name; - nghttp2_rcbuf_incref(hd_nv.name); - } else { - rv = nghttp2_rcbuf_new2(&hd_nv.name, nv->name, nv->namelen, mem); - if (rv != 0) { - return rv; - } - } - - rv = nghttp2_rcbuf_new2(&hd_nv.value, nv->value, nv->valuelen, mem); - - if (rv != 0) { - nghttp2_rcbuf_decref(hd_nv.name); - return rv; - } - - hd_nv.token = token; - hd_nv.flags = NGHTTP2_NV_FLAG_NONE; - - rv = add_hd_table_incremental(&deflater->ctx, &hd_nv, &deflater->map, hash); - - nghttp2_rcbuf_decref(hd_nv.value); - nghttp2_rcbuf_decref(hd_nv.name); - - if (rv != 0) { - return NGHTTP2_ERR_HEADER_COMP; - } - } - if (idx == -1) { - rv = emit_newname_block(bufs, nv, indexing_mode); - } else { - rv = emit_indname_block(bufs, (size_t)idx, nv, indexing_mode); - } - if (rv != 0) { - return rv; - } - - return 0; -} - -int nghttp2_hd_deflate_hd_bufs(nghttp2_hd_deflater *deflater, - nghttp2_bufs *bufs, const nghttp2_nv *nv, - size_t nvlen) { - size_t i; - int rv = 0; - - if (deflater->ctx.bad) { - return NGHTTP2_ERR_HEADER_COMP; - } - - if (deflater->notify_table_size_change) { - size_t min_hd_table_bufsize_max; - - min_hd_table_bufsize_max = deflater->min_hd_table_bufsize_max; - - deflater->notify_table_size_change = 0; - deflater->min_hd_table_bufsize_max = UINT32_MAX; - - if (deflater->ctx.hd_table_bufsize_max > min_hd_table_bufsize_max) { - rv = emit_table_size(bufs, min_hd_table_bufsize_max); - - if (rv != 0) { - goto fail; - } - } - - rv = emit_table_size(bufs, deflater->ctx.hd_table_bufsize_max); - - if (rv != 0) { - goto fail; - } - } - - for (i = 0; i < nvlen; ++i) { - rv = deflate_nv(deflater, bufs, &nv[i]); - if (rv != 0) { - goto fail; - } - } - - DEBUGF("deflatehd: all input name/value pairs were deflated\n"); - - return 0; -fail: - DEBUGF("deflatehd: error return %d\n", rv); - - deflater->ctx.bad = 1; - return rv; -} - -ssize_t nghttp2_hd_deflate_hd(nghttp2_hd_deflater *deflater, uint8_t *buf, - size_t buflen, const nghttp2_nv *nv, - size_t nvlen) { - return (ssize_t)nghttp2_hd_deflate_hd2(deflater, buf, buflen, nv, nvlen); -} - -nghttp2_ssize nghttp2_hd_deflate_hd2(nghttp2_hd_deflater *deflater, - uint8_t *buf, size_t buflen, - const nghttp2_nv *nv, size_t nvlen) { - nghttp2_bufs bufs; - int rv; - nghttp2_mem *mem; - - mem = deflater->ctx.mem; - - rv = nghttp2_bufs_wrap_init(&bufs, buf, buflen, mem); - - if (rv != 0) { - return rv; - } - - rv = nghttp2_hd_deflate_hd_bufs(deflater, &bufs, nv, nvlen); - - buflen = nghttp2_bufs_len(&bufs); - - nghttp2_bufs_wrap_free(&bufs); - - if (rv == NGHTTP2_ERR_BUFFER_ERROR) { - return NGHTTP2_ERR_INSUFF_BUFSIZE; - } - - if (rv != 0) { - return rv; - } - - return (nghttp2_ssize)buflen; -} - -ssize_t nghttp2_hd_deflate_hd_vec(nghttp2_hd_deflater *deflater, - const nghttp2_vec *vec, size_t veclen, - const nghttp2_nv *nv, size_t nvlen) { - return (ssize_t)nghttp2_hd_deflate_hd_vec2(deflater, vec, veclen, nv, nvlen); -} - -nghttp2_ssize nghttp2_hd_deflate_hd_vec2(nghttp2_hd_deflater *deflater, - const nghttp2_vec *vec, size_t veclen, - const nghttp2_nv *nv, size_t nvlen) { - nghttp2_bufs bufs; - int rv; - nghttp2_mem *mem; - size_t buflen; - - mem = deflater->ctx.mem; - - rv = nghttp2_bufs_wrap_init2(&bufs, vec, veclen, mem); - - if (rv != 0) { - return rv; - } - - rv = nghttp2_hd_deflate_hd_bufs(deflater, &bufs, nv, nvlen); - - buflen = nghttp2_bufs_len(&bufs); - - nghttp2_bufs_wrap_free(&bufs); - - if (rv == NGHTTP2_ERR_BUFFER_ERROR) { - return NGHTTP2_ERR_INSUFF_BUFSIZE; - } - - if (rv != 0) { - return rv; - } - - return (nghttp2_ssize)buflen; -} - -size_t nghttp2_hd_deflate_bound(nghttp2_hd_deflater *deflater, - const nghttp2_nv *nva, size_t nvlen) { - size_t n = 0; - size_t i; - (void)deflater; - - /* Possible Maximum Header Table Size Change. Encoding (1u << 31) - - 1 using 4 bit prefix requires 6 bytes. We may emit this at most - twice. */ - n += 12; - - /* Use Literal Header Field without indexing - New Name, since it is - most space consuming format. Also we choose the less one between - non-huffman and huffman, so using literal byte count is - sufficient for upper bound. - - Encoding (1u << 31) - 1 using 7 bit prefix requires 6 bytes. We - need 2 of this for |nvlen| header fields. */ - n += 6 * 2 * nvlen; - - for (i = 0; i < nvlen; ++i) { - n += nva[i].namelen + nva[i].valuelen; - } - - return n; -} - -int nghttp2_hd_deflate_new(nghttp2_hd_deflater **deflater_ptr, - size_t deflate_hd_table_bufsize_max) { - return nghttp2_hd_deflate_new2(deflater_ptr, deflate_hd_table_bufsize_max, - NULL); -} - -int nghttp2_hd_deflate_new2(nghttp2_hd_deflater **deflater_ptr, - size_t deflate_hd_table_bufsize_max, - nghttp2_mem *mem) { - int rv; - nghttp2_hd_deflater *deflater; - - if (mem == NULL) { - mem = nghttp2_mem_default(); - } - - deflater = nghttp2_mem_malloc(mem, sizeof(nghttp2_hd_deflater)); - - if (deflater == NULL) { - return NGHTTP2_ERR_NOMEM; - } - - rv = nghttp2_hd_deflate_init2(deflater, deflate_hd_table_bufsize_max, mem); - - if (rv != 0) { - nghttp2_mem_free(mem, deflater); - - return rv; - } - - *deflater_ptr = deflater; - - return 0; -} - -void nghttp2_hd_deflate_del(nghttp2_hd_deflater *deflater) { - nghttp2_mem *mem; - - mem = deflater->ctx.mem; - - nghttp2_hd_deflate_free(deflater); - - nghttp2_mem_free(mem, deflater); -} - -static void hd_inflate_set_huffman_encoded(nghttp2_hd_inflater *inflater, - const uint8_t *in) { - inflater->huffman_encoded = (*in & (1 << 7)) != 0; -} - -/* - * Decodes the integer from the range [in, last). The result is - * assigned to |inflater->left|. If the |inflater->left| is 0, then - * it performs variable integer decoding from scratch. Otherwise, it - * uses the |inflater->left| as the initial value and continues to - * decode assuming that [in, last) begins with intermediary sequence. - * - * This function returns the number of bytes read if it succeeds, or - * one of the following negative error codes: - * - * NGHTTP2_ERR_HEADER_COMP - * Integer decoding failed - */ -static nghttp2_ssize hd_inflate_read_len(nghttp2_hd_inflater *inflater, - int *rfin, const uint8_t *in, - const uint8_t *last, size_t prefix, - size_t maxlen) { - nghttp2_ssize rv; - uint32_t out; - - *rfin = 0; - - rv = decode_length(&out, &inflater->shift, rfin, (uint32_t)inflater->left, - inflater->shift, in, last, prefix); - - if (rv == -1) { - DEBUGF("inflatehd: integer decoding failed\n"); - return NGHTTP2_ERR_HEADER_COMP; - } - - if (out > maxlen) { - DEBUGF("inflatehd: integer exceeded the maximum value %zu\n", maxlen); - return NGHTTP2_ERR_HEADER_COMP; - } - - inflater->left = out; - - DEBUGF("inflatehd: decoded integer is %u\n", out); - - return rv; -} - -/* - * Reads |inflater->left| bytes from the range [in, last) and performs - * huffman decoding against them and pushes the result into the - * |buffer|. - * - * This function returns the number of bytes read if it succeeds, or - * one of the following negative error codes: - * - * NGHTTP2_ERR_NOMEM - * Out of memory - * NGHTTP2_ERR_HEADER_COMP - * Huffman decoding failed - */ -static nghttp2_ssize hd_inflate_read_huff(nghttp2_hd_inflater *inflater, - nghttp2_buf *buf, const uint8_t *in, - const uint8_t *last) { - nghttp2_ssize readlen; - int fin = 0; - if ((size_t)(last - in) >= inflater->left) { - last = in + inflater->left; - fin = 1; - } - readlen = nghttp2_hd_huff_decode(&inflater->huff_decode_ctx, buf, in, - (size_t)(last - in), fin); - - if (readlen < 0) { - DEBUGF("inflatehd: huffman decoding failed\n"); - return readlen; - } - if (nghttp2_hd_huff_decode_failure_state(&inflater->huff_decode_ctx)) { - DEBUGF("inflatehd: huffman decoding failed\n"); - return NGHTTP2_ERR_HEADER_COMP; - } - - inflater->left -= (size_t)readlen; - return readlen; -} - -/* - * Reads |inflater->left| bytes from the range [in, last) and copies - * them into the |buffer|. - * - * This function returns the number of bytes read if it succeeds, or - * one of the following negative error codes: - * - * NGHTTP2_ERR_NOMEM - * Out of memory - * NGHTTP2_ERR_HEADER_COMP - * Header decompression failed - */ -static nghttp2_ssize hd_inflate_read(nghttp2_hd_inflater *inflater, - nghttp2_buf *buf, const uint8_t *in, - const uint8_t *last) { - size_t len = nghttp2_min_size((size_t)(last - in), inflater->left); - - buf->last = nghttp2_cpymem(buf->last, in, len); - - inflater->left -= len; - return (nghttp2_ssize)len; -} - -/* - * Finalize indexed header representation reception. The referenced - * header is always emitted, and |*nv_out| is filled with that value. - */ -static void hd_inflate_commit_indexed(nghttp2_hd_inflater *inflater, - nghttp2_hd_nv *nv_out) { - nghttp2_hd_nv nv = nghttp2_hd_table_get(&inflater->ctx, inflater->index); - - emit_header(nv_out, &nv); -} - -/* - * Finalize literal header representation - new name- reception. If - * header is emitted, |*nv_out| is filled with that value and 0 is - * returned. - * - * This function returns 0 if it succeeds, or one of the following - * negative error codes: - * - * NGHTTP2_ERR_NOMEM - * Out of memory - */ -static int hd_inflate_commit_newname(nghttp2_hd_inflater *inflater, - nghttp2_hd_nv *nv_out) { - nghttp2_hd_nv nv; - int rv; - - if (inflater->no_index) { - nv.flags = NGHTTP2_NV_FLAG_NO_INDEX; - } else { - nv.flags = NGHTTP2_NV_FLAG_NONE; - } - - nv.name = inflater->namercbuf; - nv.value = inflater->valuercbuf; - nv.token = lookup_token(inflater->namercbuf->base, inflater->namercbuf->len); - - if (inflater->index_required) { - rv = add_hd_table_incremental(&inflater->ctx, &nv, NULL, 0); - - if (rv != 0) { - return rv; - } - } - - emit_header(nv_out, &nv); - - inflater->nv_name_keep = nv.name; - inflater->nv_value_keep = nv.value; - - inflater->namercbuf = NULL; - inflater->valuercbuf = NULL; - - return 0; -} - -/* - * Finalize literal header representation - indexed name- - * reception. If header is emitted, |*nv_out| is filled with that - * value and 0 is returned. - * - * This function returns 0 if it succeeds, or one of the following - * negative error codes: - * - * NGHTTP2_ERR_NOMEM - * Out of memory - */ -static int hd_inflate_commit_indname(nghttp2_hd_inflater *inflater, - nghttp2_hd_nv *nv_out) { - nghttp2_hd_nv nv; - int rv; - - nv = nghttp2_hd_table_get(&inflater->ctx, inflater->index); - - if (inflater->no_index) { - nv.flags = NGHTTP2_NV_FLAG_NO_INDEX; - } else { - nv.flags = NGHTTP2_NV_FLAG_NONE; - } - - nghttp2_rcbuf_incref(nv.name); - - nv.value = inflater->valuercbuf; - - if (inflater->index_required) { - rv = add_hd_table_incremental(&inflater->ctx, &nv, NULL, 0); - if (rv != 0) { - nghttp2_rcbuf_decref(nv.name); - return NGHTTP2_ERR_NOMEM; - } - } - - emit_header(nv_out, &nv); - - inflater->nv_name_keep = nv.name; - inflater->nv_value_keep = nv.value; - - inflater->valuercbuf = NULL; - - return 0; -} - -ssize_t nghttp2_hd_inflate_hd(nghttp2_hd_inflater *inflater, nghttp2_nv *nv_out, - int *inflate_flags, uint8_t *in, size_t inlen, - int in_final) { - return nghttp2_hd_inflate_hd2(inflater, nv_out, inflate_flags, in, inlen, - in_final); -} - -ssize_t nghttp2_hd_inflate_hd2(nghttp2_hd_inflater *inflater, - nghttp2_nv *nv_out, int *inflate_flags, - const uint8_t *in, size_t inlen, int in_final) { - return (nghttp2_ssize)nghttp2_hd_inflate_hd3(inflater, nv_out, inflate_flags, - in, inlen, in_final); -} - -nghttp2_ssize nghttp2_hd_inflate_hd3(nghttp2_hd_inflater *inflater, - nghttp2_nv *nv_out, int *inflate_flags, - const uint8_t *in, size_t inlen, - int in_final) { - nghttp2_ssize rv; - nghttp2_hd_nv hd_nv; - - rv = nghttp2_hd_inflate_hd_nv(inflater, &hd_nv, inflate_flags, in, inlen, - in_final); - - if (rv < 0) { - return rv; - } - - if (*inflate_flags & NGHTTP2_HD_INFLATE_EMIT) { - nv_out->name = hd_nv.name->base; - nv_out->namelen = hd_nv.name->len; - - nv_out->value = hd_nv.value->base; - nv_out->valuelen = hd_nv.value->len; - - nv_out->flags = hd_nv.flags; - } - - return rv; -} - -nghttp2_ssize nghttp2_hd_inflate_hd_nv(nghttp2_hd_inflater *inflater, - nghttp2_hd_nv *nv_out, - int *inflate_flags, const uint8_t *in, - size_t inlen, int in_final) { - nghttp2_ssize rv = 0; - const uint8_t *first = in; - const uint8_t *last = in + inlen; - int rfin = 0; - int busy = 0; - nghttp2_mem *mem; - - mem = inflater->ctx.mem; - - if (inflater->ctx.bad) { - return NGHTTP2_ERR_HEADER_COMP; - } - - DEBUGF("inflatehd: start state=%d\n", inflater->state); - hd_inflate_keep_free(inflater); - *inflate_flags = NGHTTP2_HD_INFLATE_NONE; - for (; in != last || busy;) { - busy = 0; - switch (inflater->state) { - case NGHTTP2_HD_STATE_EXPECT_TABLE_SIZE: - if ((*in & 0xe0u) != 0x20u) { - DEBUGF("inflatehd: header table size change was expected, but saw " - "0x%02x as first byte", - *in); - rv = NGHTTP2_ERR_HEADER_COMP; - goto fail; - } - /* fall through */ - case NGHTTP2_HD_STATE_INFLATE_START: - case NGHTTP2_HD_STATE_OPCODE: - if ((*in & 0xe0u) == 0x20u) { - DEBUGF("inflatehd: header table size change\n"); - if (inflater->state == NGHTTP2_HD_STATE_OPCODE) { - DEBUGF("inflatehd: header table size change must appear at the head " - "of header block\n"); - rv = NGHTTP2_ERR_HEADER_COMP; - goto fail; - } - inflater->opcode = NGHTTP2_HD_OPCODE_INDEXED; - inflater->state = NGHTTP2_HD_STATE_READ_TABLE_SIZE; - } else if (*in & 0x80u) { - DEBUGF("inflatehd: indexed repr\n"); - inflater->opcode = NGHTTP2_HD_OPCODE_INDEXED; - inflater->state = NGHTTP2_HD_STATE_READ_INDEX; - } else { - if (*in == 0x40u || *in == 0 || *in == 0x10u) { - DEBUGF("inflatehd: literal header repr - new name\n"); - inflater->opcode = NGHTTP2_HD_OPCODE_NEWNAME; - inflater->state = NGHTTP2_HD_STATE_NEWNAME_CHECK_NAMELEN; - } else { - DEBUGF("inflatehd: literal header repr - indexed name\n"); - inflater->opcode = NGHTTP2_HD_OPCODE_INDNAME; - inflater->state = NGHTTP2_HD_STATE_READ_INDEX; - } - inflater->index_required = (*in & 0x40) != 0; - inflater->no_index = (*in & 0xf0u) == 0x10u; - DEBUGF("inflatehd: indexing required=%d, no_index=%d\n", - inflater->index_required, inflater->no_index); - if (inflater->opcode == NGHTTP2_HD_OPCODE_NEWNAME) { - ++in; - } - } - inflater->left = 0; - inflater->shift = 0; - break; - case NGHTTP2_HD_STATE_READ_TABLE_SIZE: - rfin = 0; - rv = hd_inflate_read_len( - inflater, &rfin, in, last, 5, - nghttp2_min_size(inflater->min_hd_table_bufsize_max, - inflater->settings_hd_table_bufsize_max)); - if (rv < 0) { - goto fail; - } - in += rv; - if (!rfin) { - goto almost_ok; - } - DEBUGF("inflatehd: table_size=%zu\n", inflater->left); - inflater->min_hd_table_bufsize_max = UINT32_MAX; - inflater->ctx.hd_table_bufsize_max = inflater->left; - hd_context_shrink_table_size(&inflater->ctx, NULL); - inflater->state = NGHTTP2_HD_STATE_INFLATE_START; - break; - case NGHTTP2_HD_STATE_READ_INDEX: { - size_t prefixlen; - - if (inflater->opcode == NGHTTP2_HD_OPCODE_INDEXED) { - prefixlen = 7; - } else if (inflater->index_required) { - prefixlen = 6; - } else { - prefixlen = 4; - } - - rfin = 0; - rv = hd_inflate_read_len(inflater, &rfin, in, last, prefixlen, - get_max_index(&inflater->ctx)); - if (rv < 0) { - goto fail; - } - - in += rv; - - if (!rfin) { - goto almost_ok; - } - - if (inflater->left == 0) { - rv = NGHTTP2_ERR_HEADER_COMP; - goto fail; - } - - DEBUGF("inflatehd: index=%zu\n", inflater->left); - if (inflater->opcode == NGHTTP2_HD_OPCODE_INDEXED) { - inflater->index = inflater->left; - --inflater->index; - - hd_inflate_commit_indexed(inflater, nv_out); - - inflater->state = NGHTTP2_HD_STATE_OPCODE; - *inflate_flags |= NGHTTP2_HD_INFLATE_EMIT; - return (nghttp2_ssize)(in - first); - } else { - inflater->index = inflater->left; - --inflater->index; - - inflater->state = NGHTTP2_HD_STATE_CHECK_VALUELEN; - } - break; - } - case NGHTTP2_HD_STATE_NEWNAME_CHECK_NAMELEN: - hd_inflate_set_huffman_encoded(inflater, in); - inflater->state = NGHTTP2_HD_STATE_NEWNAME_READ_NAMELEN; - inflater->left = 0; - inflater->shift = 0; - DEBUGF("inflatehd: huffman encoded=%d\n", inflater->huffman_encoded != 0); - /* Fall through */ - case NGHTTP2_HD_STATE_NEWNAME_READ_NAMELEN: - rfin = 0; - rv = hd_inflate_read_len(inflater, &rfin, in, last, 7, NGHTTP2_HD_MAX_NV); - if (rv < 0) { - goto fail; - } - in += rv; - if (!rfin) { - DEBUGF("inflatehd: integer not fully decoded. current=%zu\n", - inflater->left); - - goto almost_ok; - } - - if (inflater->huffman_encoded) { - nghttp2_hd_huff_decode_context_init(&inflater->huff_decode_ctx); - - inflater->state = NGHTTP2_HD_STATE_NEWNAME_READ_NAMEHUFF; - - rv = - nghttp2_rcbuf_new(&inflater->namercbuf, inflater->left * 2 + 1, mem); - } else { - inflater->state = NGHTTP2_HD_STATE_NEWNAME_READ_NAME; - rv = nghttp2_rcbuf_new(&inflater->namercbuf, inflater->left + 1, mem); - } - - if (rv != 0) { - goto fail; - } - - nghttp2_buf_wrap_init(&inflater->namebuf, inflater->namercbuf->base, - inflater->namercbuf->len); - - break; - case NGHTTP2_HD_STATE_NEWNAME_READ_NAMEHUFF: - rv = hd_inflate_read_huff(inflater, &inflater->namebuf, in, last); - if (rv < 0) { - goto fail; - } - - in += rv; - - DEBUGF("inflatehd: %td bytes read\n", rv); - - if (inflater->left) { - DEBUGF("inflatehd: still %zu bytes to go\n", inflater->left); - - goto almost_ok; - } - - *inflater->namebuf.last = '\0'; - inflater->namercbuf->len = nghttp2_buf_len(&inflater->namebuf); - - inflater->state = NGHTTP2_HD_STATE_CHECK_VALUELEN; - - break; - case NGHTTP2_HD_STATE_NEWNAME_READ_NAME: - rv = hd_inflate_read(inflater, &inflater->namebuf, in, last); - if (rv < 0) { - goto fail; - } - - in += rv; - - DEBUGF("inflatehd: %td bytes read\n", rv); - if (inflater->left) { - DEBUGF("inflatehd: still %zu bytes to go\n", inflater->left); - - goto almost_ok; - } - - *inflater->namebuf.last = '\0'; - inflater->namercbuf->len = nghttp2_buf_len(&inflater->namebuf); - - inflater->state = NGHTTP2_HD_STATE_CHECK_VALUELEN; - - break; - case NGHTTP2_HD_STATE_CHECK_VALUELEN: - hd_inflate_set_huffman_encoded(inflater, in); - inflater->state = NGHTTP2_HD_STATE_READ_VALUELEN; - inflater->left = 0; - inflater->shift = 0; - DEBUGF("inflatehd: huffman encoded=%d\n", inflater->huffman_encoded != 0); - /* Fall through */ - case NGHTTP2_HD_STATE_READ_VALUELEN: - rfin = 0; - rv = hd_inflate_read_len(inflater, &rfin, in, last, 7, NGHTTP2_HD_MAX_NV); - if (rv < 0) { - goto fail; - } - - in += rv; - - if (!rfin) { - goto almost_ok; - } - - DEBUGF("inflatehd: valuelen=%zu\n", inflater->left); - - if (inflater->huffman_encoded) { - nghttp2_hd_huff_decode_context_init(&inflater->huff_decode_ctx); - - inflater->state = NGHTTP2_HD_STATE_READ_VALUEHUFF; - - rv = - nghttp2_rcbuf_new(&inflater->valuercbuf, inflater->left * 2 + 1, mem); - } else { - inflater->state = NGHTTP2_HD_STATE_READ_VALUE; - - rv = nghttp2_rcbuf_new(&inflater->valuercbuf, inflater->left + 1, mem); - } - - if (rv != 0) { - goto fail; - } - - nghttp2_buf_wrap_init(&inflater->valuebuf, inflater->valuercbuf->base, - inflater->valuercbuf->len); - - busy = 1; - - break; - case NGHTTP2_HD_STATE_READ_VALUEHUFF: - rv = hd_inflate_read_huff(inflater, &inflater->valuebuf, in, last); - if (rv < 0) { - goto fail; - } - - in += rv; - - DEBUGF("inflatehd: %td bytes read\n", rv); - - if (inflater->left) { - DEBUGF("inflatehd: still %zu bytes to go\n", inflater->left); - - goto almost_ok; - } - - *inflater->valuebuf.last = '\0'; - inflater->valuercbuf->len = nghttp2_buf_len(&inflater->valuebuf); - - if (inflater->opcode == NGHTTP2_HD_OPCODE_NEWNAME) { - rv = hd_inflate_commit_newname(inflater, nv_out); - } else { - rv = hd_inflate_commit_indname(inflater, nv_out); - } - - if (rv != 0) { - goto fail; - } - - inflater->state = NGHTTP2_HD_STATE_OPCODE; - *inflate_flags |= NGHTTP2_HD_INFLATE_EMIT; - - return (nghttp2_ssize)(in - first); - case NGHTTP2_HD_STATE_READ_VALUE: - rv = hd_inflate_read(inflater, &inflater->valuebuf, in, last); - if (rv < 0) { - DEBUGF("inflatehd: value read failure %td: %s\n", rv, - nghttp2_strerror((int)rv)); - goto fail; - } - - in += rv; - - DEBUGF("inflatehd: %td bytes read\n", rv); - - if (inflater->left) { - DEBUGF("inflatehd: still %zu bytes to go\n", inflater->left); - goto almost_ok; - } - - *inflater->valuebuf.last = '\0'; - inflater->valuercbuf->len = nghttp2_buf_len(&inflater->valuebuf); - - if (inflater->opcode == NGHTTP2_HD_OPCODE_NEWNAME) { - rv = hd_inflate_commit_newname(inflater, nv_out); - } else { - rv = hd_inflate_commit_indname(inflater, nv_out); - } - - if (rv != 0) { - goto fail; - } - - inflater->state = NGHTTP2_HD_STATE_OPCODE; - *inflate_flags |= NGHTTP2_HD_INFLATE_EMIT; - - return (nghttp2_ssize)(in - first); - } - } - - assert(in == last); - - DEBUGF("inflatehd: all input bytes were processed\n"); - - if (in_final) { - DEBUGF("inflatehd: in_final set\n"); - - if (inflater->state != NGHTTP2_HD_STATE_OPCODE && - inflater->state != NGHTTP2_HD_STATE_INFLATE_START) { - DEBUGF("inflatehd: unacceptable state=%d\n", inflater->state); - rv = NGHTTP2_ERR_HEADER_COMP; - - goto fail; - } - *inflate_flags |= NGHTTP2_HD_INFLATE_FINAL; - } - return (nghttp2_ssize)(in - first); - -almost_ok: - if (in_final) { - DEBUGF("inflatehd: input ended prematurely\n"); - - rv = NGHTTP2_ERR_HEADER_COMP; - - goto fail; - } - return (nghttp2_ssize)(in - first); - -fail: - DEBUGF("inflatehd: error return %td\n", rv); - - inflater->ctx.bad = 1; - return rv; -} - -int nghttp2_hd_inflate_end_headers(nghttp2_hd_inflater *inflater) { - hd_inflate_keep_free(inflater); - inflater->state = NGHTTP2_HD_STATE_INFLATE_START; - return 0; -} - -int nghttp2_hd_inflate_new(nghttp2_hd_inflater **inflater_ptr) { - return nghttp2_hd_inflate_new2(inflater_ptr, NULL); -} - -int nghttp2_hd_inflate_new2(nghttp2_hd_inflater **inflater_ptr, - nghttp2_mem *mem) { - int rv; - nghttp2_hd_inflater *inflater; - - if (mem == NULL) { - mem = nghttp2_mem_default(); - } - - inflater = nghttp2_mem_malloc(mem, sizeof(nghttp2_hd_inflater)); - - if (inflater == NULL) { - return NGHTTP2_ERR_NOMEM; - } - - rv = nghttp2_hd_inflate_init(inflater, mem); - - if (rv != 0) { - nghttp2_mem_free(mem, inflater); - - return rv; - } - - *inflater_ptr = inflater; - - return 0; -} - -void nghttp2_hd_inflate_del(nghttp2_hd_inflater *inflater) { - nghttp2_mem *mem; - - mem = inflater->ctx.mem; - nghttp2_hd_inflate_free(inflater); - - nghttp2_mem_free(mem, inflater); -} - -int nghttp2_hd_emit_indname_block(nghttp2_bufs *bufs, size_t idx, - nghttp2_nv *nv, int indexing_mode) { - return emit_indname_block(bufs, idx, nv, indexing_mode); -} - -int nghttp2_hd_emit_newname_block(nghttp2_bufs *bufs, nghttp2_nv *nv, - int indexing_mode) { - return emit_newname_block(bufs, nv, indexing_mode); -} - -int nghttp2_hd_emit_table_size(nghttp2_bufs *bufs, size_t table_size) { - return emit_table_size(bufs, table_size); -} - -nghttp2_ssize nghttp2_hd_decode_length(uint32_t *res, size_t *shift_ptr, - int *fin, uint32_t initial, size_t shift, - uint8_t *in, uint8_t *last, - size_t prefix) { - return decode_length(res, shift_ptr, fin, initial, shift, in, last, prefix); -} - -static const nghttp2_nv *hd_get_table_entry(nghttp2_hd_context *context, - size_t idx) { - if (idx == 0) { - return NULL; - } - - --idx; - - if (!INDEX_RANGE_VALID(context, idx)) { - return NULL; - } - - return nghttp2_hd_table_get2(context, idx); -} - -size_t nghttp2_hd_deflate_get_num_table_entries(nghttp2_hd_deflater *deflater) { - return get_max_index(&deflater->ctx); -} - -const nghttp2_nv * -nghttp2_hd_deflate_get_table_entry(nghttp2_hd_deflater *deflater, size_t idx) { - return hd_get_table_entry(&deflater->ctx, idx); -} - -size_t -nghttp2_hd_deflate_get_dynamic_table_size(nghttp2_hd_deflater *deflater) { - return deflater->ctx.hd_table_bufsize; -} - -size_t -nghttp2_hd_deflate_get_max_dynamic_table_size(nghttp2_hd_deflater *deflater) { - return deflater->ctx.hd_table_bufsize_max; -} - -size_t nghttp2_hd_inflate_get_num_table_entries(nghttp2_hd_inflater *inflater) { - return get_max_index(&inflater->ctx); -} - -const nghttp2_nv * -nghttp2_hd_inflate_get_table_entry(nghttp2_hd_inflater *inflater, size_t idx) { - return hd_get_table_entry(&inflater->ctx, idx); -} - -size_t -nghttp2_hd_inflate_get_dynamic_table_size(nghttp2_hd_inflater *inflater) { - return inflater->ctx.hd_table_bufsize; -} - -size_t -nghttp2_hd_inflate_get_max_dynamic_table_size(nghttp2_hd_inflater *inflater) { - return inflater->ctx.hd_table_bufsize_max; -} diff --git a/3rdparty/exported/nghttp2/nghttp2_hd.h b/3rdparty/exported/nghttp2/nghttp2_hd.h deleted file mode 100644 index 38a31a83c389..000000000000 --- a/3rdparty/exported/nghttp2/nghttp2_hd.h +++ /dev/null @@ -1,442 +0,0 @@ -/* - * nghttp2 - HTTP/2 C Library - * - * Copyright (c) 2013 Tatsuhiro Tsujikawa - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE - * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION - * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION - * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ -#ifndef NGHTTP2_HD_H -#define NGHTTP2_HD_H - -#ifdef HAVE_CONFIG_H -# include -#endif /* HAVE_CONFIG_H */ - -#include - -#include "nghttp2_hd_huffman.h" -#include "nghttp2_buf.h" -#include "nghttp2_mem.h" -#include "nghttp2_rcbuf.h" - -#define NGHTTP2_HD_DEFAULT_MAX_BUFFER_SIZE NGHTTP2_DEFAULT_HEADER_TABLE_SIZE -#define NGHTTP2_HD_ENTRY_OVERHEAD 32 - -/* The maximum length of one name/value pair. This is the sum of the - length of name and value. This is not specified by the spec. We - just chose the arbitrary size */ -#define NGHTTP2_HD_MAX_NV 65536 - -/* Default size of maximum table buffer size for encoder. Even if - remote decoder notifies larger buffer size for its decoding, - encoder only uses the memory up to this value. */ -#define NGHTTP2_HD_DEFAULT_MAX_DEFLATE_BUFFER_SIZE (1 << 12) - -/* Exported for unit test */ -#define NGHTTP2_STATIC_TABLE_LENGTH 61 - -/* Generated by genlibtokenlookup.py */ -typedef enum { - NGHTTP2_TOKEN__AUTHORITY = 0, - NGHTTP2_TOKEN__METHOD = 1, - NGHTTP2_TOKEN__PATH = 3, - NGHTTP2_TOKEN__SCHEME = 5, - NGHTTP2_TOKEN__STATUS = 7, - NGHTTP2_TOKEN_ACCEPT_CHARSET = 14, - NGHTTP2_TOKEN_ACCEPT_ENCODING = 15, - NGHTTP2_TOKEN_ACCEPT_LANGUAGE = 16, - NGHTTP2_TOKEN_ACCEPT_RANGES = 17, - NGHTTP2_TOKEN_ACCEPT = 18, - NGHTTP2_TOKEN_ACCESS_CONTROL_ALLOW_ORIGIN = 19, - NGHTTP2_TOKEN_AGE = 20, - NGHTTP2_TOKEN_ALLOW = 21, - NGHTTP2_TOKEN_AUTHORIZATION = 22, - NGHTTP2_TOKEN_CACHE_CONTROL = 23, - NGHTTP2_TOKEN_CONTENT_DISPOSITION = 24, - NGHTTP2_TOKEN_CONTENT_ENCODING = 25, - NGHTTP2_TOKEN_CONTENT_LANGUAGE = 26, - NGHTTP2_TOKEN_CONTENT_LENGTH = 27, - NGHTTP2_TOKEN_CONTENT_LOCATION = 28, - NGHTTP2_TOKEN_CONTENT_RANGE = 29, - NGHTTP2_TOKEN_CONTENT_TYPE = 30, - NGHTTP2_TOKEN_COOKIE = 31, - NGHTTP2_TOKEN_DATE = 32, - NGHTTP2_TOKEN_ETAG = 33, - NGHTTP2_TOKEN_EXPECT = 34, - NGHTTP2_TOKEN_EXPIRES = 35, - NGHTTP2_TOKEN_FROM = 36, - NGHTTP2_TOKEN_HOST = 37, - NGHTTP2_TOKEN_IF_MATCH = 38, - NGHTTP2_TOKEN_IF_MODIFIED_SINCE = 39, - NGHTTP2_TOKEN_IF_NONE_MATCH = 40, - NGHTTP2_TOKEN_IF_RANGE = 41, - NGHTTP2_TOKEN_IF_UNMODIFIED_SINCE = 42, - NGHTTP2_TOKEN_LAST_MODIFIED = 43, - NGHTTP2_TOKEN_LINK = 44, - NGHTTP2_TOKEN_LOCATION = 45, - NGHTTP2_TOKEN_MAX_FORWARDS = 46, - NGHTTP2_TOKEN_PROXY_AUTHENTICATE = 47, - NGHTTP2_TOKEN_PROXY_AUTHORIZATION = 48, - NGHTTP2_TOKEN_RANGE = 49, - NGHTTP2_TOKEN_REFERER = 50, - NGHTTP2_TOKEN_REFRESH = 51, - NGHTTP2_TOKEN_RETRY_AFTER = 52, - NGHTTP2_TOKEN_SERVER = 53, - NGHTTP2_TOKEN_SET_COOKIE = 54, - NGHTTP2_TOKEN_STRICT_TRANSPORT_SECURITY = 55, - NGHTTP2_TOKEN_TRANSFER_ENCODING = 56, - NGHTTP2_TOKEN_USER_AGENT = 57, - NGHTTP2_TOKEN_VARY = 58, - NGHTTP2_TOKEN_VIA = 59, - NGHTTP2_TOKEN_WWW_AUTHENTICATE = 60, - NGHTTP2_TOKEN_TE, - NGHTTP2_TOKEN_CONNECTION, - NGHTTP2_TOKEN_KEEP_ALIVE, - NGHTTP2_TOKEN_PROXY_CONNECTION, - NGHTTP2_TOKEN_UPGRADE, - NGHTTP2_TOKEN__PROTOCOL, - NGHTTP2_TOKEN_PRIORITY, -} nghttp2_token; - -struct nghttp2_hd_entry; -typedef struct nghttp2_hd_entry nghttp2_hd_entry; - -typedef struct { - /* The buffer containing header field name. NULL-termination is - guaranteed. */ - nghttp2_rcbuf *name; - /* The buffer containing header field value. NULL-termination is - guaranteed. */ - nghttp2_rcbuf *value; - /* nghttp2_token value for name. It could be -1 if we have no token - for that header field name. */ - int32_t token; - /* Bitwise OR of one or more of nghttp2_nv_flag. */ - uint8_t flags; -} nghttp2_hd_nv; - -struct nghttp2_hd_entry { - /* The header field name/value pair */ - nghttp2_hd_nv nv; - /* This is solely for nghttp2_hd_{deflate,inflate}_get_table_entry - APIs to keep backward compatibility. */ - nghttp2_nv cnv; - /* The next entry which shares same bucket in hash table. */ - nghttp2_hd_entry *next; - /* The sequence number. We will increment it by one whenever we - store nghttp2_hd_entry to dynamic header table. */ - uint32_t seq; - /* The hash value for header name (nv.name). */ - uint32_t hash; -}; - -/* The entry used for static header table. */ -typedef struct { - nghttp2_rcbuf name; - nghttp2_rcbuf value; - nghttp2_nv cnv; - int32_t token; - uint32_t hash; -} nghttp2_hd_static_entry; - -typedef struct { - nghttp2_hd_entry **buffer; - size_t mask; - size_t first; - size_t len; -} nghttp2_hd_ringbuf; - -typedef enum { - NGHTTP2_HD_OPCODE_NONE, - NGHTTP2_HD_OPCODE_INDEXED, - NGHTTP2_HD_OPCODE_NEWNAME, - NGHTTP2_HD_OPCODE_INDNAME -} nghttp2_hd_opcode; - -typedef enum { - NGHTTP2_HD_STATE_EXPECT_TABLE_SIZE, - NGHTTP2_HD_STATE_INFLATE_START, - NGHTTP2_HD_STATE_OPCODE, - NGHTTP2_HD_STATE_READ_TABLE_SIZE, - NGHTTP2_HD_STATE_READ_INDEX, - NGHTTP2_HD_STATE_NEWNAME_CHECK_NAMELEN, - NGHTTP2_HD_STATE_NEWNAME_READ_NAMELEN, - NGHTTP2_HD_STATE_NEWNAME_READ_NAMEHUFF, - NGHTTP2_HD_STATE_NEWNAME_READ_NAME, - NGHTTP2_HD_STATE_CHECK_VALUELEN, - NGHTTP2_HD_STATE_READ_VALUELEN, - NGHTTP2_HD_STATE_READ_VALUEHUFF, - NGHTTP2_HD_STATE_READ_VALUE -} nghttp2_hd_inflate_state; - -typedef enum { - NGHTTP2_HD_WITH_INDEXING, - NGHTTP2_HD_WITHOUT_INDEXING, - NGHTTP2_HD_NEVER_INDEXING -} nghttp2_hd_indexing_mode; - -typedef struct { - /* dynamic header table */ - nghttp2_hd_ringbuf hd_table; - /* Memory allocator */ - nghttp2_mem *mem; - /* Abstract buffer size of hd_table as described in the spec. This - is the sum of length of name/value in hd_table + - NGHTTP2_HD_ENTRY_OVERHEAD bytes overhead per each entry. */ - size_t hd_table_bufsize; - /* The effective header table size. */ - size_t hd_table_bufsize_max; - /* Next sequence number for nghttp2_hd_entry */ - uint32_t next_seq; - /* If inflate/deflate error occurred, this value is set to 1 and - further invocation of inflate/deflate will fail with - NGHTTP2_ERR_HEADER_COMP. */ - uint8_t bad; -} nghttp2_hd_context; - -#define HD_MAP_SIZE 128 - -typedef struct { - nghttp2_hd_entry *table[HD_MAP_SIZE]; -} nghttp2_hd_map; - -struct nghttp2_hd_deflater { - nghttp2_hd_context ctx; - nghttp2_hd_map map; - /* The upper limit of the header table size the deflater accepts. */ - size_t deflate_hd_table_bufsize_max; - /* Minimum header table size notified in the next context update */ - size_t min_hd_table_bufsize_max; - /* If nonzero, send header table size using encoding context update - in the next deflate process */ - uint8_t notify_table_size_change; -}; - -struct nghttp2_hd_inflater { - nghttp2_hd_context ctx; - /* Stores current state of huffman decoding */ - nghttp2_hd_huff_decode_context huff_decode_ctx; - /* header buffer */ - nghttp2_buf namebuf, valuebuf; - nghttp2_rcbuf *namercbuf, *valuercbuf; - /* Pointer to the name/value pair which are used in the current - header emission. */ - nghttp2_rcbuf *nv_name_keep, *nv_value_keep; - /* The number of bytes to read */ - size_t left; - /* The index in indexed repr or indexed name */ - size_t index; - /* The maximum header table size the inflater supports. This is the - same value transmitted in SETTINGS_HEADER_TABLE_SIZE */ - size_t settings_hd_table_bufsize_max; - /* Minimum header table size set by nghttp2_hd_inflate_change_table_size */ - size_t min_hd_table_bufsize_max; - /* The number of next shift to decode integer */ - size_t shift; - nghttp2_hd_opcode opcode; - nghttp2_hd_inflate_state state; - /* nonzero if string is huffman encoded */ - uint8_t huffman_encoded; - /* nonzero if deflater requires that current entry is indexed */ - uint8_t index_required; - /* nonzero if deflater requires that current entry must not be - indexed */ - uint8_t no_index; -}; - -/* - * Initializes the |ent| members. The reference counts of nv->name - * and nv->value are increased by one for each. - */ -void nghttp2_hd_entry_init(nghttp2_hd_entry *ent, nghttp2_hd_nv *nv); - -/* - * This function decreases the reference counts of nv->name and - * nv->value. - */ -void nghttp2_hd_entry_free(nghttp2_hd_entry *ent); - -/* - * Initializes |deflater| for deflating name/values pairs. - * - * The encoder only uses up to - * NGHTTP2_HD_DEFAULT_MAX_DEFLATE_BUFFER_SIZE bytes for header table - * even if the larger value is specified later in - * nghttp2_hd_change_table_size(). - * - * This function returns 0 if it succeeds, or one of the following - * negative error codes: - * - * NGHTTP2_ERR_NOMEM - * Out of memory. - */ -int nghttp2_hd_deflate_init(nghttp2_hd_deflater *deflater, nghttp2_mem *mem); - -/* - * Initializes |deflater| for deflating name/values pairs. - * - * The encoder only uses up to |max_deflate_dynamic_table_size| bytes - * for header table even if the larger value is specified later in - * nghttp2_hd_change_table_size(). - * - * This function returns 0 if it succeeds, or one of the following - * negative error codes: - * - * NGHTTP2_ERR_NOMEM - * Out of memory. - */ -int nghttp2_hd_deflate_init2(nghttp2_hd_deflater *deflater, - size_t max_deflate_dynamic_table_size, - nghttp2_mem *mem); - -/* - * Deallocates any resources allocated for |deflater|. - */ -void nghttp2_hd_deflate_free(nghttp2_hd_deflater *deflater); - -/* - * Deflates the |nva|, which has the |nvlen| name/value pairs, into - * the |bufs|. - * - * This function expands |bufs| as necessary to store the result. If - * buffers is full and the process still requires more space, this - * function fails and returns NGHTTP2_ERR_HEADER_COMP. - * - * After this function returns, it is safe to delete the |nva|. - * - * This function returns 0 if it succeeds, or one of the following - * negative error codes: - * - * NGHTTP2_ERR_NOMEM - * Out of memory. - * NGHTTP2_ERR_HEADER_COMP - * Deflation process has failed. - * NGHTTP2_ERR_BUFFER_ERROR - * Out of buffer space. - */ -int nghttp2_hd_deflate_hd_bufs(nghttp2_hd_deflater *deflater, - nghttp2_bufs *bufs, const nghttp2_nv *nva, - size_t nvlen); - -/* - * Initializes |inflater| for inflating name/values pairs. - * - * This function returns 0 if it succeeds, or one of the following - * negative error codes: - * - * :enum:`NGHTTP2_ERR_NOMEM` - * Out of memory. - */ -int nghttp2_hd_inflate_init(nghttp2_hd_inflater *inflater, nghttp2_mem *mem); - -/* - * Deallocates any resources allocated for |inflater|. - */ -void nghttp2_hd_inflate_free(nghttp2_hd_inflater *inflater); - -/* - * Similar to nghttp2_hd_inflate_hd(), but this takes nghttp2_hd_nv - * instead of nghttp2_nv as output parameter |nv_out|. Other than - * that return values and semantics are the same as - * nghttp2_hd_inflate_hd(). - */ -nghttp2_ssize nghttp2_hd_inflate_hd_nv(nghttp2_hd_inflater *inflater, - nghttp2_hd_nv *nv_out, - int *inflate_flags, const uint8_t *in, - size_t inlen, int in_final); - -/* For unittesting purpose */ -int nghttp2_hd_emit_indname_block(nghttp2_bufs *bufs, size_t index, - nghttp2_nv *nv, int indexing_mode); - -/* For unittesting purpose */ -int nghttp2_hd_emit_newname_block(nghttp2_bufs *bufs, nghttp2_nv *nv, - int indexing_mode); - -/* For unittesting purpose */ -int nghttp2_hd_emit_table_size(nghttp2_bufs *bufs, size_t table_size); - -/* For unittesting purpose */ -nghttp2_hd_nv nghttp2_hd_table_get(nghttp2_hd_context *context, size_t index); - -/* For unittesting purpose */ -nghttp2_ssize nghttp2_hd_decode_length(uint32_t *res, size_t *shift_ptr, - int *fin, uint32_t initial, size_t shift, - uint8_t *in, uint8_t *last, - size_t prefix); - -/* Huffman encoding/decoding functions */ - -/* - * Counts the required bytes to encode |src| with length |len|. - * - * This function returns the number of required bytes to encode given - * data, including padding of prefix of terminal symbol code. This - * function always succeeds. - */ -size_t nghttp2_hd_huff_encode_count(const uint8_t *src, size_t len); - -/* - * Encodes the given data |src| with length |srclen| to the |bufs|. - * This function expands extra buffers in |bufs| if necessary. - * - * This function returns 0 if it succeeds, or one of the following - * negative error codes: - * - * NGHTTP2_ERR_NOMEM - * Out of memory. - * NGHTTP2_ERR_BUFFER_ERROR - * Out of buffer space. - */ -int nghttp2_hd_huff_encode(nghttp2_bufs *bufs, const uint8_t *src, - size_t srclen); - -void nghttp2_hd_huff_decode_context_init(nghttp2_hd_huff_decode_context *ctx); - -/* - * Decodes the given data |src| with length |srclen|. The |ctx| must - * be initialized by nghttp2_hd_huff_decode_context_init(). The result - * will be written to |buf|. This function assumes that |buf| has the - * enough room to store the decoded byte string. - * - * The caller must set the |fin| to nonzero if the given input is the - * final block. - * - * This function returns the number of read bytes from the |in|. - * - * If this function fails, it returns one of the following negative - * return codes: - * - * NGHTTP2_ERR_NOMEM - * Out of memory. - * NGHTTP2_ERR_HEADER_COMP - * Decoding process has failed. - */ -nghttp2_ssize nghttp2_hd_huff_decode(nghttp2_hd_huff_decode_context *ctx, - nghttp2_buf *buf, const uint8_t *src, - size_t srclen, int fin); - -/* - * nghttp2_hd_huff_decode_failure_state returns nonzero if |ctx| - * indicates that huffman decoding context is in failure state. - */ -int nghttp2_hd_huff_decode_failure_state(nghttp2_hd_huff_decode_context *ctx); - -#endif /* NGHTTP2_HD_H */ diff --git a/3rdparty/exported/nghttp2/nghttp2_hd_huffman.c b/3rdparty/exported/nghttp2/nghttp2_hd_huffman.c deleted file mode 100644 index de2620076a6e..000000000000 --- a/3rdparty/exported/nghttp2/nghttp2_hd_huffman.c +++ /dev/null @@ -1,146 +0,0 @@ -/* - * nghttp2 - HTTP/2 C Library - * - * Copyright (c) 2013 Tatsuhiro Tsujikawa - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE - * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION - * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION - * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ -#include "nghttp2_hd_huffman.h" - -#include -#include -#include - -#include "nghttp2_hd.h" -#include "nghttp2_net.h" - -size_t nghttp2_hd_huff_encode_count(const uint8_t *src, size_t len) { - size_t i; - size_t nbits = 0; - - for (i = 0; i < len; ++i) { - nbits += huff_sym_table[src[i]].nbits; - } - /* pad the prefix of EOS (256) */ - return (nbits + 7) / 8; -} - -int nghttp2_hd_huff_encode(nghttp2_bufs *bufs, const uint8_t *src, - size_t srclen) { - const nghttp2_huff_sym *sym; - const uint8_t *end = src + srclen; - uint64_t code = 0; - uint32_t x; - size_t nbits = 0; - size_t avail; - int rv; - - avail = nghttp2_bufs_cur_avail(bufs); - - for (; src != end;) { - sym = &huff_sym_table[*src++]; - code |= (uint64_t)sym->code << (32 - nbits); - nbits += sym->nbits; - if (nbits < 32) { - continue; - } - if (avail >= 4) { - x = htonl((uint32_t)(code >> 32)); - memcpy(bufs->cur->buf.last, &x, 4); - bufs->cur->buf.last += 4; - avail -= 4; - code <<= 32; - nbits -= 32; - continue; - } - - for (; nbits >= 8;) { - rv = nghttp2_bufs_addb(bufs, (uint8_t)(code >> 56)); - if (rv != 0) { - return rv; - } - code <<= 8; - nbits -= 8; - } - - avail = nghttp2_bufs_cur_avail(bufs); - } - - for (; nbits >= 8;) { - rv = nghttp2_bufs_addb(bufs, (uint8_t)(code >> 56)); - if (rv != 0) { - return rv; - } - code <<= 8; - nbits -= 8; - } - - if (nbits) { - rv = nghttp2_bufs_addb( - bufs, (uint8_t)((uint8_t)(code >> 56) | ((1 << (8 - nbits)) - 1))); - if (rv != 0) { - return rv; - } - } - - return 0; -} - -void nghttp2_hd_huff_decode_context_init(nghttp2_hd_huff_decode_context *ctx) { - ctx->fstate = NGHTTP2_HUFF_ACCEPTED; -} - -nghttp2_ssize nghttp2_hd_huff_decode(nghttp2_hd_huff_decode_context *ctx, - nghttp2_buf *buf, const uint8_t *src, - size_t srclen, int final) { - const uint8_t *end = src + srclen; - nghttp2_huff_decode node = {ctx->fstate, 0}; - const nghttp2_huff_decode *t = &node; - uint8_t c; - - /* We use the decoding algorithm described in - - http://graphics.ics.uci.edu/pub/Prefix.pdf [!!! NO LONGER VALID !!!] - - https://ics.uci.edu/~dan/pubs/Prefix.pdf - - https://github.com/nghttp2/nghttp2/files/15141264/Prefix.pdf */ - for (; src != end;) { - c = *src++; - t = &huff_decode_table[t->fstate & 0x1ff][c >> 4]; - if (t->fstate & NGHTTP2_HUFF_SYM) { - *buf->last++ = t->sym; - } - - t = &huff_decode_table[t->fstate & 0x1ff][c & 0xf]; - if (t->fstate & NGHTTP2_HUFF_SYM) { - *buf->last++ = t->sym; - } - } - - ctx->fstate = t->fstate; - - if (final && !(ctx->fstate & NGHTTP2_HUFF_ACCEPTED)) { - return NGHTTP2_ERR_HEADER_COMP; - } - - return (nghttp2_ssize)srclen; -} - -int nghttp2_hd_huff_decode_failure_state(nghttp2_hd_huff_decode_context *ctx) { - return ctx->fstate == 0x100; -} diff --git a/3rdparty/exported/nghttp2/nghttp2_hd_huffman.h b/3rdparty/exported/nghttp2/nghttp2_hd_huffman.h deleted file mode 100644 index 2bfd5318165f..000000000000 --- a/3rdparty/exported/nghttp2/nghttp2_hd_huffman.h +++ /dev/null @@ -1,72 +0,0 @@ -/* - * nghttp2 - HTTP/2 C Library - * - * Copyright (c) 2013 Tatsuhiro Tsujikawa - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE - * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION - * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION - * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ -#ifndef NGHTTP2_HD_HUFFMAN_H -#define NGHTTP2_HD_HUFFMAN_H - -#ifdef HAVE_CONFIG_H -# include -#endif /* HAVE_CONFIG_H */ - -#include - -typedef enum { - /* FSA accepts this state as the end of huffman encoding - sequence. */ - NGHTTP2_HUFF_ACCEPTED = 1 << 14, - /* This state emits symbol */ - NGHTTP2_HUFF_SYM = 1 << 15, -} nghttp2_huff_decode_flag; - -typedef struct { - /* fstate is the current huffman decoding state, which is actually - the node ID of internal huffman tree with - nghttp2_huff_decode_flag OR-ed. We have 257 leaf nodes, but they - are identical to root node other than emitting a symbol, so we - have 256 internal nodes [1..255], inclusive. The node ID 256 is - a special node and it is a terminal state that means decoding - failed. */ - uint16_t fstate; - /* symbol if NGHTTP2_HUFF_SYM flag set */ - uint8_t sym; -} nghttp2_huff_decode; - -typedef nghttp2_huff_decode huff_decode_table_type[16]; - -typedef struct { - /* fstate is the current huffman decoding state. */ - uint16_t fstate; -} nghttp2_hd_huff_decode_context; - -typedef struct { - /* The number of bits in this code */ - uint32_t nbits; - /* Huffman code aligned to LSB */ - uint32_t code; -} nghttp2_huff_sym; - -extern const nghttp2_huff_sym huff_sym_table[]; -extern const nghttp2_huff_decode huff_decode_table[][16]; - -#endif /* NGHTTP2_HD_HUFFMAN_H */ diff --git a/3rdparty/exported/nghttp2/nghttp2_hd_huffman_data.c b/3rdparty/exported/nghttp2/nghttp2_hd_huffman_data.c deleted file mode 100644 index c8f4a6fa2667..000000000000 --- a/3rdparty/exported/nghttp2/nghttp2_hd_huffman_data.c +++ /dev/null @@ -1,4980 +0,0 @@ -/* - * nghttp2 - HTTP/2 C Library - * - * Copyright (c) 2013 Tatsuhiro Tsujikawa - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE - * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION - * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION - * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ -#include "nghttp2_hd_huffman.h" - -/* Generated by mkhufftbl.py */ - -const nghttp2_huff_sym huff_sym_table[] = { - {13, 0xffc00000u}, {23, 0xffffb000u}, {28, 0xfffffe20u}, {28, 0xfffffe30u}, - {28, 0xfffffe40u}, {28, 0xfffffe50u}, {28, 0xfffffe60u}, {28, 0xfffffe70u}, - {28, 0xfffffe80u}, {24, 0xffffea00u}, {30, 0xfffffff0u}, {28, 0xfffffe90u}, - {28, 0xfffffea0u}, {30, 0xfffffff4u}, {28, 0xfffffeb0u}, {28, 0xfffffec0u}, - {28, 0xfffffed0u}, {28, 0xfffffee0u}, {28, 0xfffffef0u}, {28, 0xffffff00u}, - {28, 0xffffff10u}, {28, 0xffffff20u}, {30, 0xfffffff8u}, {28, 0xffffff30u}, - {28, 0xffffff40u}, {28, 0xffffff50u}, {28, 0xffffff60u}, {28, 0xffffff70u}, - {28, 0xffffff80u}, {28, 0xffffff90u}, {28, 0xffffffa0u}, {28, 0xffffffb0u}, - {6, 0x50000000u}, {10, 0xfe000000u}, {10, 0xfe400000u}, {12, 0xffa00000u}, - {13, 0xffc80000u}, {6, 0x54000000u}, {8, 0xf8000000u}, {11, 0xff400000u}, - {10, 0xfe800000u}, {10, 0xfec00000u}, {8, 0xf9000000u}, {11, 0xff600000u}, - {8, 0xfa000000u}, {6, 0x58000000u}, {6, 0x5c000000u}, {6, 0x60000000u}, - {5, 0x0u}, {5, 0x8000000u}, {5, 0x10000000u}, {6, 0x64000000u}, - {6, 0x68000000u}, {6, 0x6c000000u}, {6, 0x70000000u}, {6, 0x74000000u}, - {6, 0x78000000u}, {6, 0x7c000000u}, {7, 0xb8000000u}, {8, 0xfb000000u}, - {15, 0xfff80000u}, {6, 0x80000000u}, {12, 0xffb00000u}, {10, 0xff000000u}, - {13, 0xffd00000u}, {6, 0x84000000u}, {7, 0xba000000u}, {7, 0xbc000000u}, - {7, 0xbe000000u}, {7, 0xc0000000u}, {7, 0xc2000000u}, {7, 0xc4000000u}, - {7, 0xc6000000u}, {7, 0xc8000000u}, {7, 0xca000000u}, {7, 0xcc000000u}, - {7, 0xce000000u}, {7, 0xd0000000u}, {7, 0xd2000000u}, {7, 0xd4000000u}, - {7, 0xd6000000u}, {7, 0xd8000000u}, {7, 0xda000000u}, {7, 0xdc000000u}, - {7, 0xde000000u}, {7, 0xe0000000u}, {7, 0xe2000000u}, {7, 0xe4000000u}, - {8, 0xfc000000u}, {7, 0xe6000000u}, {8, 0xfd000000u}, {13, 0xffd80000u}, - {19, 0xfffe0000u}, {13, 0xffe00000u}, {14, 0xfff00000u}, {6, 0x88000000u}, - {15, 0xfffa0000u}, {5, 0x18000000u}, {6, 0x8c000000u}, {5, 0x20000000u}, - {6, 0x90000000u}, {5, 0x28000000u}, {6, 0x94000000u}, {6, 0x98000000u}, - {6, 0x9c000000u}, {5, 0x30000000u}, {7, 0xe8000000u}, {7, 0xea000000u}, - {6, 0xa0000000u}, {6, 0xa4000000u}, {6, 0xa8000000u}, {5, 0x38000000u}, - {6, 0xac000000u}, {7, 0xec000000u}, {6, 0xb0000000u}, {5, 0x40000000u}, - {5, 0x48000000u}, {6, 0xb4000000u}, {7, 0xee000000u}, {7, 0xf0000000u}, - {7, 0xf2000000u}, {7, 0xf4000000u}, {7, 0xf6000000u}, {15, 0xfffc0000u}, - {11, 0xff800000u}, {14, 0xfff40000u}, {13, 0xffe80000u}, {28, 0xffffffc0u}, - {20, 0xfffe6000u}, {22, 0xffff4800u}, {20, 0xfffe7000u}, {20, 0xfffe8000u}, - {22, 0xffff4c00u}, {22, 0xffff5000u}, {22, 0xffff5400u}, {23, 0xffffb200u}, - {22, 0xffff5800u}, {23, 0xffffb400u}, {23, 0xffffb600u}, {23, 0xffffb800u}, - {23, 0xffffba00u}, {23, 0xffffbc00u}, {24, 0xffffeb00u}, {23, 0xffffbe00u}, - {24, 0xffffec00u}, {24, 0xffffed00u}, {22, 0xffff5c00u}, {23, 0xffffc000u}, - {24, 0xffffee00u}, {23, 0xffffc200u}, {23, 0xffffc400u}, {23, 0xffffc600u}, - {23, 0xffffc800u}, {21, 0xfffee000u}, {22, 0xffff6000u}, {23, 0xffffca00u}, - {22, 0xffff6400u}, {23, 0xffffcc00u}, {23, 0xffffce00u}, {24, 0xffffef00u}, - {22, 0xffff6800u}, {21, 0xfffee800u}, {20, 0xfffe9000u}, {22, 0xffff6c00u}, - {22, 0xffff7000u}, {23, 0xffffd000u}, {23, 0xffffd200u}, {21, 0xfffef000u}, - {23, 0xffffd400u}, {22, 0xffff7400u}, {22, 0xffff7800u}, {24, 0xfffff000u}, - {21, 0xfffef800u}, {22, 0xffff7c00u}, {23, 0xffffd600u}, {23, 0xffffd800u}, - {21, 0xffff0000u}, {21, 0xffff0800u}, {22, 0xffff8000u}, {21, 0xffff1000u}, - {23, 0xffffda00u}, {22, 0xffff8400u}, {23, 0xffffdc00u}, {23, 0xffffde00u}, - {20, 0xfffea000u}, {22, 0xffff8800u}, {22, 0xffff8c00u}, {22, 0xffff9000u}, - {23, 0xffffe000u}, {22, 0xffff9400u}, {22, 0xffff9800u}, {23, 0xffffe200u}, - {26, 0xfffff800u}, {26, 0xfffff840u}, {20, 0xfffeb000u}, {19, 0xfffe2000u}, - {22, 0xffff9c00u}, {23, 0xffffe400u}, {22, 0xffffa000u}, {25, 0xfffff600u}, - {26, 0xfffff880u}, {26, 0xfffff8c0u}, {26, 0xfffff900u}, {27, 0xfffffbc0u}, - {27, 0xfffffbe0u}, {26, 0xfffff940u}, {24, 0xfffff100u}, {25, 0xfffff680u}, - {19, 0xfffe4000u}, {21, 0xffff1800u}, {26, 0xfffff980u}, {27, 0xfffffc00u}, - {27, 0xfffffc20u}, {26, 0xfffff9c0u}, {27, 0xfffffc40u}, {24, 0xfffff200u}, - {21, 0xffff2000u}, {21, 0xffff2800u}, {26, 0xfffffa00u}, {26, 0xfffffa40u}, - {28, 0xffffffd0u}, {27, 0xfffffc60u}, {27, 0xfffffc80u}, {27, 0xfffffca0u}, - {20, 0xfffec000u}, {24, 0xfffff300u}, {20, 0xfffed000u}, {21, 0xffff3000u}, - {22, 0xffffa400u}, {21, 0xffff3800u}, {21, 0xffff4000u}, {23, 0xffffe600u}, - {22, 0xffffa800u}, {22, 0xffffac00u}, {25, 0xfffff700u}, {25, 0xfffff780u}, - {24, 0xfffff400u}, {24, 0xfffff500u}, {26, 0xfffffa80u}, {23, 0xffffe800u}, - {26, 0xfffffac0u}, {27, 0xfffffcc0u}, {26, 0xfffffb00u}, {26, 0xfffffb40u}, - {27, 0xfffffce0u}, {27, 0xfffffd00u}, {27, 0xfffffd20u}, {27, 0xfffffd40u}, - {27, 0xfffffd60u}, {28, 0xffffffe0u}, {27, 0xfffffd80u}, {27, 0xfffffda0u}, - {27, 0xfffffdc0u}, {27, 0xfffffde0u}, {27, 0xfffffe00u}, {26, 0xfffffb80u}, - {30, 0xfffffffcu}}; - -const nghttp2_huff_decode huff_decode_table[][16] = { - /* 0 */ - { - {0x04, 0}, - {0x05, 0}, - {0x07, 0}, - {0x08, 0}, - {0x0b, 0}, - {0x0c, 0}, - {0x10, 0}, - {0x13, 0}, - {0x19, 0}, - {0x1c, 0}, - {0x20, 0}, - {0x23, 0}, - {0x2a, 0}, - {0x31, 0}, - {0x39, 0}, - {0x4040, 0}, - }, - /* 1 */ - { - {0xc000, 48}, - {0xc000, 49}, - {0xc000, 50}, - {0xc000, 97}, - {0xc000, 99}, - {0xc000, 101}, - {0xc000, 105}, - {0xc000, 111}, - {0xc000, 115}, - {0xc000, 116}, - {0x0d, 0}, - {0x0e, 0}, - {0x11, 0}, - {0x12, 0}, - {0x14, 0}, - {0x15, 0}, - }, - /* 2 */ - { - {0x8001, 48}, - {0xc016, 48}, - {0x8001, 49}, - {0xc016, 49}, - {0x8001, 50}, - {0xc016, 50}, - {0x8001, 97}, - {0xc016, 97}, - {0x8001, 99}, - {0xc016, 99}, - {0x8001, 101}, - {0xc016, 101}, - {0x8001, 105}, - {0xc016, 105}, - {0x8001, 111}, - {0xc016, 111}, - }, - /* 3 */ - { - {0x8002, 48}, - {0x8009, 48}, - {0x8017, 48}, - {0xc028, 48}, - {0x8002, 49}, - {0x8009, 49}, - {0x8017, 49}, - {0xc028, 49}, - {0x8002, 50}, - {0x8009, 50}, - {0x8017, 50}, - {0xc028, 50}, - {0x8002, 97}, - {0x8009, 97}, - {0x8017, 97}, - {0xc028, 97}, - }, - /* 4 */ - { - {0x8003, 48}, - {0x8006, 48}, - {0x800a, 48}, - {0x800f, 48}, - {0x8018, 48}, - {0x801f, 48}, - {0x8029, 48}, - {0xc038, 48}, - {0x8003, 49}, - {0x8006, 49}, - {0x800a, 49}, - {0x800f, 49}, - {0x8018, 49}, - {0x801f, 49}, - {0x8029, 49}, - {0xc038, 49}, - }, - /* 5 */ - { - {0x8003, 50}, - {0x8006, 50}, - {0x800a, 50}, - {0x800f, 50}, - {0x8018, 50}, - {0x801f, 50}, - {0x8029, 50}, - {0xc038, 50}, - {0x8003, 97}, - {0x8006, 97}, - {0x800a, 97}, - {0x800f, 97}, - {0x8018, 97}, - {0x801f, 97}, - {0x8029, 97}, - {0xc038, 97}, - }, - /* 6 */ - { - {0x8002, 99}, - {0x8009, 99}, - {0x8017, 99}, - {0xc028, 99}, - {0x8002, 101}, - {0x8009, 101}, - {0x8017, 101}, - {0xc028, 101}, - {0x8002, 105}, - {0x8009, 105}, - {0x8017, 105}, - {0xc028, 105}, - {0x8002, 111}, - {0x8009, 111}, - {0x8017, 111}, - {0xc028, 111}, - }, - /* 7 */ - { - {0x8003, 99}, - {0x8006, 99}, - {0x800a, 99}, - {0x800f, 99}, - {0x8018, 99}, - {0x801f, 99}, - {0x8029, 99}, - {0xc038, 99}, - {0x8003, 101}, - {0x8006, 101}, - {0x800a, 101}, - {0x800f, 101}, - {0x8018, 101}, - {0x801f, 101}, - {0x8029, 101}, - {0xc038, 101}, - }, - /* 8 */ - { - {0x8003, 105}, - {0x8006, 105}, - {0x800a, 105}, - {0x800f, 105}, - {0x8018, 105}, - {0x801f, 105}, - {0x8029, 105}, - {0xc038, 105}, - {0x8003, 111}, - {0x8006, 111}, - {0x800a, 111}, - {0x800f, 111}, - {0x8018, 111}, - {0x801f, 111}, - {0x8029, 111}, - {0xc038, 111}, - }, - /* 9 */ - { - {0x8001, 115}, - {0xc016, 115}, - {0x8001, 116}, - {0xc016, 116}, - {0xc000, 32}, - {0xc000, 37}, - {0xc000, 45}, - {0xc000, 46}, - {0xc000, 47}, - {0xc000, 51}, - {0xc000, 52}, - {0xc000, 53}, - {0xc000, 54}, - {0xc000, 55}, - {0xc000, 56}, - {0xc000, 57}, - }, - /* 10 */ - { - {0x8002, 115}, - {0x8009, 115}, - {0x8017, 115}, - {0xc028, 115}, - {0x8002, 116}, - {0x8009, 116}, - {0x8017, 116}, - {0xc028, 116}, - {0x8001, 32}, - {0xc016, 32}, - {0x8001, 37}, - {0xc016, 37}, - {0x8001, 45}, - {0xc016, 45}, - {0x8001, 46}, - {0xc016, 46}, - }, - /* 11 */ - { - {0x8003, 115}, - {0x8006, 115}, - {0x800a, 115}, - {0x800f, 115}, - {0x8018, 115}, - {0x801f, 115}, - {0x8029, 115}, - {0xc038, 115}, - {0x8003, 116}, - {0x8006, 116}, - {0x800a, 116}, - {0x800f, 116}, - {0x8018, 116}, - {0x801f, 116}, - {0x8029, 116}, - {0xc038, 116}, - }, - /* 12 */ - { - {0x8002, 32}, - {0x8009, 32}, - {0x8017, 32}, - {0xc028, 32}, - {0x8002, 37}, - {0x8009, 37}, - {0x8017, 37}, - {0xc028, 37}, - {0x8002, 45}, - {0x8009, 45}, - {0x8017, 45}, - {0xc028, 45}, - {0x8002, 46}, - {0x8009, 46}, - {0x8017, 46}, - {0xc028, 46}, - }, - /* 13 */ - { - {0x8003, 32}, - {0x8006, 32}, - {0x800a, 32}, - {0x800f, 32}, - {0x8018, 32}, - {0x801f, 32}, - {0x8029, 32}, - {0xc038, 32}, - {0x8003, 37}, - {0x8006, 37}, - {0x800a, 37}, - {0x800f, 37}, - {0x8018, 37}, - {0x801f, 37}, - {0x8029, 37}, - {0xc038, 37}, - }, - /* 14 */ - { - {0x8003, 45}, - {0x8006, 45}, - {0x800a, 45}, - {0x800f, 45}, - {0x8018, 45}, - {0x801f, 45}, - {0x8029, 45}, - {0xc038, 45}, - {0x8003, 46}, - {0x8006, 46}, - {0x800a, 46}, - {0x800f, 46}, - {0x8018, 46}, - {0x801f, 46}, - {0x8029, 46}, - {0xc038, 46}, - }, - /* 15 */ - { - {0x8001, 47}, - {0xc016, 47}, - {0x8001, 51}, - {0xc016, 51}, - {0x8001, 52}, - {0xc016, 52}, - {0x8001, 53}, - {0xc016, 53}, - {0x8001, 54}, - {0xc016, 54}, - {0x8001, 55}, - {0xc016, 55}, - {0x8001, 56}, - {0xc016, 56}, - {0x8001, 57}, - {0xc016, 57}, - }, - /* 16 */ - { - {0x8002, 47}, - {0x8009, 47}, - {0x8017, 47}, - {0xc028, 47}, - {0x8002, 51}, - {0x8009, 51}, - {0x8017, 51}, - {0xc028, 51}, - {0x8002, 52}, - {0x8009, 52}, - {0x8017, 52}, - {0xc028, 52}, - {0x8002, 53}, - {0x8009, 53}, - {0x8017, 53}, - {0xc028, 53}, - }, - /* 17 */ - { - {0x8003, 47}, - {0x8006, 47}, - {0x800a, 47}, - {0x800f, 47}, - {0x8018, 47}, - {0x801f, 47}, - {0x8029, 47}, - {0xc038, 47}, - {0x8003, 51}, - {0x8006, 51}, - {0x800a, 51}, - {0x800f, 51}, - {0x8018, 51}, - {0x801f, 51}, - {0x8029, 51}, - {0xc038, 51}, - }, - /* 18 */ - { - {0x8003, 52}, - {0x8006, 52}, - {0x800a, 52}, - {0x800f, 52}, - {0x8018, 52}, - {0x801f, 52}, - {0x8029, 52}, - {0xc038, 52}, - {0x8003, 53}, - {0x8006, 53}, - {0x800a, 53}, - {0x800f, 53}, - {0x8018, 53}, - {0x801f, 53}, - {0x8029, 53}, - {0xc038, 53}, - }, - /* 19 */ - { - {0x8002, 54}, - {0x8009, 54}, - {0x8017, 54}, - {0xc028, 54}, - {0x8002, 55}, - {0x8009, 55}, - {0x8017, 55}, - {0xc028, 55}, - {0x8002, 56}, - {0x8009, 56}, - {0x8017, 56}, - {0xc028, 56}, - {0x8002, 57}, - {0x8009, 57}, - {0x8017, 57}, - {0xc028, 57}, - }, - /* 20 */ - { - {0x8003, 54}, - {0x8006, 54}, - {0x800a, 54}, - {0x800f, 54}, - {0x8018, 54}, - {0x801f, 54}, - {0x8029, 54}, - {0xc038, 54}, - {0x8003, 55}, - {0x8006, 55}, - {0x800a, 55}, - {0x800f, 55}, - {0x8018, 55}, - {0x801f, 55}, - {0x8029, 55}, - {0xc038, 55}, - }, - /* 21 */ - { - {0x8003, 56}, - {0x8006, 56}, - {0x800a, 56}, - {0x800f, 56}, - {0x8018, 56}, - {0x801f, 56}, - {0x8029, 56}, - {0xc038, 56}, - {0x8003, 57}, - {0x8006, 57}, - {0x800a, 57}, - {0x800f, 57}, - {0x8018, 57}, - {0x801f, 57}, - {0x8029, 57}, - {0xc038, 57}, - }, - /* 22 */ - { - {0x1a, 0}, - {0x1b, 0}, - {0x1d, 0}, - {0x1e, 0}, - {0x21, 0}, - {0x22, 0}, - {0x24, 0}, - {0x25, 0}, - {0x2b, 0}, - {0x2e, 0}, - {0x32, 0}, - {0x35, 0}, - {0x3a, 0}, - {0x3d, 0}, - {0x41, 0}, - {0x4044, 0}, - }, - /* 23 */ - { - {0xc000, 61}, - {0xc000, 65}, - {0xc000, 95}, - {0xc000, 98}, - {0xc000, 100}, - {0xc000, 102}, - {0xc000, 103}, - {0xc000, 104}, - {0xc000, 108}, - {0xc000, 109}, - {0xc000, 110}, - {0xc000, 112}, - {0xc000, 114}, - {0xc000, 117}, - {0x26, 0}, - {0x27, 0}, - }, - /* 24 */ - { - {0x8001, 61}, - {0xc016, 61}, - {0x8001, 65}, - {0xc016, 65}, - {0x8001, 95}, - {0xc016, 95}, - {0x8001, 98}, - {0xc016, 98}, - {0x8001, 100}, - {0xc016, 100}, - {0x8001, 102}, - {0xc016, 102}, - {0x8001, 103}, - {0xc016, 103}, - {0x8001, 104}, - {0xc016, 104}, - }, - /* 25 */ - { - {0x8002, 61}, - {0x8009, 61}, - {0x8017, 61}, - {0xc028, 61}, - {0x8002, 65}, - {0x8009, 65}, - {0x8017, 65}, - {0xc028, 65}, - {0x8002, 95}, - {0x8009, 95}, - {0x8017, 95}, - {0xc028, 95}, - {0x8002, 98}, - {0x8009, 98}, - {0x8017, 98}, - {0xc028, 98}, - }, - /* 26 */ - { - {0x8003, 61}, - {0x8006, 61}, - {0x800a, 61}, - {0x800f, 61}, - {0x8018, 61}, - {0x801f, 61}, - {0x8029, 61}, - {0xc038, 61}, - {0x8003, 65}, - {0x8006, 65}, - {0x800a, 65}, - {0x800f, 65}, - {0x8018, 65}, - {0x801f, 65}, - {0x8029, 65}, - {0xc038, 65}, - }, - /* 27 */ - { - {0x8003, 95}, - {0x8006, 95}, - {0x800a, 95}, - {0x800f, 95}, - {0x8018, 95}, - {0x801f, 95}, - {0x8029, 95}, - {0xc038, 95}, - {0x8003, 98}, - {0x8006, 98}, - {0x800a, 98}, - {0x800f, 98}, - {0x8018, 98}, - {0x801f, 98}, - {0x8029, 98}, - {0xc038, 98}, - }, - /* 28 */ - { - {0x8002, 100}, - {0x8009, 100}, - {0x8017, 100}, - {0xc028, 100}, - {0x8002, 102}, - {0x8009, 102}, - {0x8017, 102}, - {0xc028, 102}, - {0x8002, 103}, - {0x8009, 103}, - {0x8017, 103}, - {0xc028, 103}, - {0x8002, 104}, - {0x8009, 104}, - {0x8017, 104}, - {0xc028, 104}, - }, - /* 29 */ - { - {0x8003, 100}, - {0x8006, 100}, - {0x800a, 100}, - {0x800f, 100}, - {0x8018, 100}, - {0x801f, 100}, - {0x8029, 100}, - {0xc038, 100}, - {0x8003, 102}, - {0x8006, 102}, - {0x800a, 102}, - {0x800f, 102}, - {0x8018, 102}, - {0x801f, 102}, - {0x8029, 102}, - {0xc038, 102}, - }, - /* 30 */ - { - {0x8003, 103}, - {0x8006, 103}, - {0x800a, 103}, - {0x800f, 103}, - {0x8018, 103}, - {0x801f, 103}, - {0x8029, 103}, - {0xc038, 103}, - {0x8003, 104}, - {0x8006, 104}, - {0x800a, 104}, - {0x800f, 104}, - {0x8018, 104}, - {0x801f, 104}, - {0x8029, 104}, - {0xc038, 104}, - }, - /* 31 */ - { - {0x8001, 108}, - {0xc016, 108}, - {0x8001, 109}, - {0xc016, 109}, - {0x8001, 110}, - {0xc016, 110}, - {0x8001, 112}, - {0xc016, 112}, - {0x8001, 114}, - {0xc016, 114}, - {0x8001, 117}, - {0xc016, 117}, - {0xc000, 58}, - {0xc000, 66}, - {0xc000, 67}, - {0xc000, 68}, - }, - /* 32 */ - { - {0x8002, 108}, - {0x8009, 108}, - {0x8017, 108}, - {0xc028, 108}, - {0x8002, 109}, - {0x8009, 109}, - {0x8017, 109}, - {0xc028, 109}, - {0x8002, 110}, - {0x8009, 110}, - {0x8017, 110}, - {0xc028, 110}, - {0x8002, 112}, - {0x8009, 112}, - {0x8017, 112}, - {0xc028, 112}, - }, - /* 33 */ - { - {0x8003, 108}, - {0x8006, 108}, - {0x800a, 108}, - {0x800f, 108}, - {0x8018, 108}, - {0x801f, 108}, - {0x8029, 108}, - {0xc038, 108}, - {0x8003, 109}, - {0x8006, 109}, - {0x800a, 109}, - {0x800f, 109}, - {0x8018, 109}, - {0x801f, 109}, - {0x8029, 109}, - {0xc038, 109}, - }, - /* 34 */ - { - {0x8003, 110}, - {0x8006, 110}, - {0x800a, 110}, - {0x800f, 110}, - {0x8018, 110}, - {0x801f, 110}, - {0x8029, 110}, - {0xc038, 110}, - {0x8003, 112}, - {0x8006, 112}, - {0x800a, 112}, - {0x800f, 112}, - {0x8018, 112}, - {0x801f, 112}, - {0x8029, 112}, - {0xc038, 112}, - }, - /* 35 */ - { - {0x8002, 114}, - {0x8009, 114}, - {0x8017, 114}, - {0xc028, 114}, - {0x8002, 117}, - {0x8009, 117}, - {0x8017, 117}, - {0xc028, 117}, - {0x8001, 58}, - {0xc016, 58}, - {0x8001, 66}, - {0xc016, 66}, - {0x8001, 67}, - {0xc016, 67}, - {0x8001, 68}, - {0xc016, 68}, - }, - /* 36 */ - { - {0x8003, 114}, - {0x8006, 114}, - {0x800a, 114}, - {0x800f, 114}, - {0x8018, 114}, - {0x801f, 114}, - {0x8029, 114}, - {0xc038, 114}, - {0x8003, 117}, - {0x8006, 117}, - {0x800a, 117}, - {0x800f, 117}, - {0x8018, 117}, - {0x801f, 117}, - {0x8029, 117}, - {0xc038, 117}, - }, - /* 37 */ - { - {0x8002, 58}, - {0x8009, 58}, - {0x8017, 58}, - {0xc028, 58}, - {0x8002, 66}, - {0x8009, 66}, - {0x8017, 66}, - {0xc028, 66}, - {0x8002, 67}, - {0x8009, 67}, - {0x8017, 67}, - {0xc028, 67}, - {0x8002, 68}, - {0x8009, 68}, - {0x8017, 68}, - {0xc028, 68}, - }, - /* 38 */ - { - {0x8003, 58}, - {0x8006, 58}, - {0x800a, 58}, - {0x800f, 58}, - {0x8018, 58}, - {0x801f, 58}, - {0x8029, 58}, - {0xc038, 58}, - {0x8003, 66}, - {0x8006, 66}, - {0x800a, 66}, - {0x800f, 66}, - {0x8018, 66}, - {0x801f, 66}, - {0x8029, 66}, - {0xc038, 66}, - }, - /* 39 */ - { - {0x8003, 67}, - {0x8006, 67}, - {0x800a, 67}, - {0x800f, 67}, - {0x8018, 67}, - {0x801f, 67}, - {0x8029, 67}, - {0xc038, 67}, - {0x8003, 68}, - {0x8006, 68}, - {0x800a, 68}, - {0x800f, 68}, - {0x8018, 68}, - {0x801f, 68}, - {0x8029, 68}, - {0xc038, 68}, - }, - /* 40 */ - { - {0x2c, 0}, - {0x2d, 0}, - {0x2f, 0}, - {0x30, 0}, - {0x33, 0}, - {0x34, 0}, - {0x36, 0}, - {0x37, 0}, - {0x3b, 0}, - {0x3c, 0}, - {0x3e, 0}, - {0x3f, 0}, - {0x42, 0}, - {0x43, 0}, - {0x45, 0}, - {0x4048, 0}, - }, - /* 41 */ - { - {0xc000, 69}, - {0xc000, 70}, - {0xc000, 71}, - {0xc000, 72}, - {0xc000, 73}, - {0xc000, 74}, - {0xc000, 75}, - {0xc000, 76}, - {0xc000, 77}, - {0xc000, 78}, - {0xc000, 79}, - {0xc000, 80}, - {0xc000, 81}, - {0xc000, 82}, - {0xc000, 83}, - {0xc000, 84}, - }, - /* 42 */ - { - {0x8001, 69}, - {0xc016, 69}, - {0x8001, 70}, - {0xc016, 70}, - {0x8001, 71}, - {0xc016, 71}, - {0x8001, 72}, - {0xc016, 72}, - {0x8001, 73}, - {0xc016, 73}, - {0x8001, 74}, - {0xc016, 74}, - {0x8001, 75}, - {0xc016, 75}, - {0x8001, 76}, - {0xc016, 76}, - }, - /* 43 */ - { - {0x8002, 69}, - {0x8009, 69}, - {0x8017, 69}, - {0xc028, 69}, - {0x8002, 70}, - {0x8009, 70}, - {0x8017, 70}, - {0xc028, 70}, - {0x8002, 71}, - {0x8009, 71}, - {0x8017, 71}, - {0xc028, 71}, - {0x8002, 72}, - {0x8009, 72}, - {0x8017, 72}, - {0xc028, 72}, - }, - /* 44 */ - { - {0x8003, 69}, - {0x8006, 69}, - {0x800a, 69}, - {0x800f, 69}, - {0x8018, 69}, - {0x801f, 69}, - {0x8029, 69}, - {0xc038, 69}, - {0x8003, 70}, - {0x8006, 70}, - {0x800a, 70}, - {0x800f, 70}, - {0x8018, 70}, - {0x801f, 70}, - {0x8029, 70}, - {0xc038, 70}, - }, - /* 45 */ - { - {0x8003, 71}, - {0x8006, 71}, - {0x800a, 71}, - {0x800f, 71}, - {0x8018, 71}, - {0x801f, 71}, - {0x8029, 71}, - {0xc038, 71}, - {0x8003, 72}, - {0x8006, 72}, - {0x800a, 72}, - {0x800f, 72}, - {0x8018, 72}, - {0x801f, 72}, - {0x8029, 72}, - {0xc038, 72}, - }, - /* 46 */ - { - {0x8002, 73}, - {0x8009, 73}, - {0x8017, 73}, - {0xc028, 73}, - {0x8002, 74}, - {0x8009, 74}, - {0x8017, 74}, - {0xc028, 74}, - {0x8002, 75}, - {0x8009, 75}, - {0x8017, 75}, - {0xc028, 75}, - {0x8002, 76}, - {0x8009, 76}, - {0x8017, 76}, - {0xc028, 76}, - }, - /* 47 */ - { - {0x8003, 73}, - {0x8006, 73}, - {0x800a, 73}, - {0x800f, 73}, - {0x8018, 73}, - {0x801f, 73}, - {0x8029, 73}, - {0xc038, 73}, - {0x8003, 74}, - {0x8006, 74}, - {0x800a, 74}, - {0x800f, 74}, - {0x8018, 74}, - {0x801f, 74}, - {0x8029, 74}, - {0xc038, 74}, - }, - /* 48 */ - { - {0x8003, 75}, - {0x8006, 75}, - {0x800a, 75}, - {0x800f, 75}, - {0x8018, 75}, - {0x801f, 75}, - {0x8029, 75}, - {0xc038, 75}, - {0x8003, 76}, - {0x8006, 76}, - {0x800a, 76}, - {0x800f, 76}, - {0x8018, 76}, - {0x801f, 76}, - {0x8029, 76}, - {0xc038, 76}, - }, - /* 49 */ - { - {0x8001, 77}, - {0xc016, 77}, - {0x8001, 78}, - {0xc016, 78}, - {0x8001, 79}, - {0xc016, 79}, - {0x8001, 80}, - {0xc016, 80}, - {0x8001, 81}, - {0xc016, 81}, - {0x8001, 82}, - {0xc016, 82}, - {0x8001, 83}, - {0xc016, 83}, - {0x8001, 84}, - {0xc016, 84}, - }, - /* 50 */ - { - {0x8002, 77}, - {0x8009, 77}, - {0x8017, 77}, - {0xc028, 77}, - {0x8002, 78}, - {0x8009, 78}, - {0x8017, 78}, - {0xc028, 78}, - {0x8002, 79}, - {0x8009, 79}, - {0x8017, 79}, - {0xc028, 79}, - {0x8002, 80}, - {0x8009, 80}, - {0x8017, 80}, - {0xc028, 80}, - }, - /* 51 */ - { - {0x8003, 77}, - {0x8006, 77}, - {0x800a, 77}, - {0x800f, 77}, - {0x8018, 77}, - {0x801f, 77}, - {0x8029, 77}, - {0xc038, 77}, - {0x8003, 78}, - {0x8006, 78}, - {0x800a, 78}, - {0x800f, 78}, - {0x8018, 78}, - {0x801f, 78}, - {0x8029, 78}, - {0xc038, 78}, - }, - /* 52 */ - { - {0x8003, 79}, - {0x8006, 79}, - {0x800a, 79}, - {0x800f, 79}, - {0x8018, 79}, - {0x801f, 79}, - {0x8029, 79}, - {0xc038, 79}, - {0x8003, 80}, - {0x8006, 80}, - {0x800a, 80}, - {0x800f, 80}, - {0x8018, 80}, - {0x801f, 80}, - {0x8029, 80}, - {0xc038, 80}, - }, - /* 53 */ - { - {0x8002, 81}, - {0x8009, 81}, - {0x8017, 81}, - {0xc028, 81}, - {0x8002, 82}, - {0x8009, 82}, - {0x8017, 82}, - {0xc028, 82}, - {0x8002, 83}, - {0x8009, 83}, - {0x8017, 83}, - {0xc028, 83}, - {0x8002, 84}, - {0x8009, 84}, - {0x8017, 84}, - {0xc028, 84}, - }, - /* 54 */ - { - {0x8003, 81}, - {0x8006, 81}, - {0x800a, 81}, - {0x800f, 81}, - {0x8018, 81}, - {0x801f, 81}, - {0x8029, 81}, - {0xc038, 81}, - {0x8003, 82}, - {0x8006, 82}, - {0x800a, 82}, - {0x800f, 82}, - {0x8018, 82}, - {0x801f, 82}, - {0x8029, 82}, - {0xc038, 82}, - }, - /* 55 */ - { - {0x8003, 83}, - {0x8006, 83}, - {0x800a, 83}, - {0x800f, 83}, - {0x8018, 83}, - {0x801f, 83}, - {0x8029, 83}, - {0xc038, 83}, - {0x8003, 84}, - {0x8006, 84}, - {0x800a, 84}, - {0x800f, 84}, - {0x8018, 84}, - {0x801f, 84}, - {0x8029, 84}, - {0xc038, 84}, - }, - /* 56 */ - { - {0xc000, 85}, - {0xc000, 86}, - {0xc000, 87}, - {0xc000, 89}, - {0xc000, 106}, - {0xc000, 107}, - {0xc000, 113}, - {0xc000, 118}, - {0xc000, 119}, - {0xc000, 120}, - {0xc000, 121}, - {0xc000, 122}, - {0x46, 0}, - {0x47, 0}, - {0x49, 0}, - {0x404a, 0}, - }, - /* 57 */ - { - {0x8001, 85}, - {0xc016, 85}, - {0x8001, 86}, - {0xc016, 86}, - {0x8001, 87}, - {0xc016, 87}, - {0x8001, 89}, - {0xc016, 89}, - {0x8001, 106}, - {0xc016, 106}, - {0x8001, 107}, - {0xc016, 107}, - {0x8001, 113}, - {0xc016, 113}, - {0x8001, 118}, - {0xc016, 118}, - }, - /* 58 */ - { - {0x8002, 85}, - {0x8009, 85}, - {0x8017, 85}, - {0xc028, 85}, - {0x8002, 86}, - {0x8009, 86}, - {0x8017, 86}, - {0xc028, 86}, - {0x8002, 87}, - {0x8009, 87}, - {0x8017, 87}, - {0xc028, 87}, - {0x8002, 89}, - {0x8009, 89}, - {0x8017, 89}, - {0xc028, 89}, - }, - /* 59 */ - { - {0x8003, 85}, - {0x8006, 85}, - {0x800a, 85}, - {0x800f, 85}, - {0x8018, 85}, - {0x801f, 85}, - {0x8029, 85}, - {0xc038, 85}, - {0x8003, 86}, - {0x8006, 86}, - {0x800a, 86}, - {0x800f, 86}, - {0x8018, 86}, - {0x801f, 86}, - {0x8029, 86}, - {0xc038, 86}, - }, - /* 60 */ - { - {0x8003, 87}, - {0x8006, 87}, - {0x800a, 87}, - {0x800f, 87}, - {0x8018, 87}, - {0x801f, 87}, - {0x8029, 87}, - {0xc038, 87}, - {0x8003, 89}, - {0x8006, 89}, - {0x800a, 89}, - {0x800f, 89}, - {0x8018, 89}, - {0x801f, 89}, - {0x8029, 89}, - {0xc038, 89}, - }, - /* 61 */ - { - {0x8002, 106}, - {0x8009, 106}, - {0x8017, 106}, - {0xc028, 106}, - {0x8002, 107}, - {0x8009, 107}, - {0x8017, 107}, - {0xc028, 107}, - {0x8002, 113}, - {0x8009, 113}, - {0x8017, 113}, - {0xc028, 113}, - {0x8002, 118}, - {0x8009, 118}, - {0x8017, 118}, - {0xc028, 118}, - }, - /* 62 */ - { - {0x8003, 106}, - {0x8006, 106}, - {0x800a, 106}, - {0x800f, 106}, - {0x8018, 106}, - {0x801f, 106}, - {0x8029, 106}, - {0xc038, 106}, - {0x8003, 107}, - {0x8006, 107}, - {0x800a, 107}, - {0x800f, 107}, - {0x8018, 107}, - {0x801f, 107}, - {0x8029, 107}, - {0xc038, 107}, - }, - /* 63 */ - { - {0x8003, 113}, - {0x8006, 113}, - {0x800a, 113}, - {0x800f, 113}, - {0x8018, 113}, - {0x801f, 113}, - {0x8029, 113}, - {0xc038, 113}, - {0x8003, 118}, - {0x8006, 118}, - {0x800a, 118}, - {0x800f, 118}, - {0x8018, 118}, - {0x801f, 118}, - {0x8029, 118}, - {0xc038, 118}, - }, - /* 64 */ - { - {0x8001, 119}, - {0xc016, 119}, - {0x8001, 120}, - {0xc016, 120}, - {0x8001, 121}, - {0xc016, 121}, - {0x8001, 122}, - {0xc016, 122}, - {0xc000, 38}, - {0xc000, 42}, - {0xc000, 44}, - {0xc000, 59}, - {0xc000, 88}, - {0xc000, 90}, - {0x4b, 0}, - {0x4e, 0}, - }, - /* 65 */ - { - {0x8002, 119}, - {0x8009, 119}, - {0x8017, 119}, - {0xc028, 119}, - {0x8002, 120}, - {0x8009, 120}, - {0x8017, 120}, - {0xc028, 120}, - {0x8002, 121}, - {0x8009, 121}, - {0x8017, 121}, - {0xc028, 121}, - {0x8002, 122}, - {0x8009, 122}, - {0x8017, 122}, - {0xc028, 122}, - }, - /* 66 */ - { - {0x8003, 119}, - {0x8006, 119}, - {0x800a, 119}, - {0x800f, 119}, - {0x8018, 119}, - {0x801f, 119}, - {0x8029, 119}, - {0xc038, 119}, - {0x8003, 120}, - {0x8006, 120}, - {0x800a, 120}, - {0x800f, 120}, - {0x8018, 120}, - {0x801f, 120}, - {0x8029, 120}, - {0xc038, 120}, - }, - /* 67 */ - { - {0x8003, 121}, - {0x8006, 121}, - {0x800a, 121}, - {0x800f, 121}, - {0x8018, 121}, - {0x801f, 121}, - {0x8029, 121}, - {0xc038, 121}, - {0x8003, 122}, - {0x8006, 122}, - {0x800a, 122}, - {0x800f, 122}, - {0x8018, 122}, - {0x801f, 122}, - {0x8029, 122}, - {0xc038, 122}, - }, - /* 68 */ - { - {0x8001, 38}, - {0xc016, 38}, - {0x8001, 42}, - {0xc016, 42}, - {0x8001, 44}, - {0xc016, 44}, - {0x8001, 59}, - {0xc016, 59}, - {0x8001, 88}, - {0xc016, 88}, - {0x8001, 90}, - {0xc016, 90}, - {0x4c, 0}, - {0x4d, 0}, - {0x4f, 0}, - {0x51, 0}, - }, - /* 69 */ - { - {0x8002, 38}, - {0x8009, 38}, - {0x8017, 38}, - {0xc028, 38}, - {0x8002, 42}, - {0x8009, 42}, - {0x8017, 42}, - {0xc028, 42}, - {0x8002, 44}, - {0x8009, 44}, - {0x8017, 44}, - {0xc028, 44}, - {0x8002, 59}, - {0x8009, 59}, - {0x8017, 59}, - {0xc028, 59}, - }, - /* 70 */ - { - {0x8003, 38}, - {0x8006, 38}, - {0x800a, 38}, - {0x800f, 38}, - {0x8018, 38}, - {0x801f, 38}, - {0x8029, 38}, - {0xc038, 38}, - {0x8003, 42}, - {0x8006, 42}, - {0x800a, 42}, - {0x800f, 42}, - {0x8018, 42}, - {0x801f, 42}, - {0x8029, 42}, - {0xc038, 42}, - }, - /* 71 */ - { - {0x8003, 44}, - {0x8006, 44}, - {0x800a, 44}, - {0x800f, 44}, - {0x8018, 44}, - {0x801f, 44}, - {0x8029, 44}, - {0xc038, 44}, - {0x8003, 59}, - {0x8006, 59}, - {0x800a, 59}, - {0x800f, 59}, - {0x8018, 59}, - {0x801f, 59}, - {0x8029, 59}, - {0xc038, 59}, - }, - /* 72 */ - { - {0x8002, 88}, - {0x8009, 88}, - {0x8017, 88}, - {0xc028, 88}, - {0x8002, 90}, - {0x8009, 90}, - {0x8017, 90}, - {0xc028, 90}, - {0xc000, 33}, - {0xc000, 34}, - {0xc000, 40}, - {0xc000, 41}, - {0xc000, 63}, - {0x50, 0}, - {0x52, 0}, - {0x54, 0}, - }, - /* 73 */ - { - {0x8003, 88}, - {0x8006, 88}, - {0x800a, 88}, - {0x800f, 88}, - {0x8018, 88}, - {0x801f, 88}, - {0x8029, 88}, - {0xc038, 88}, - {0x8003, 90}, - {0x8006, 90}, - {0x800a, 90}, - {0x800f, 90}, - {0x8018, 90}, - {0x801f, 90}, - {0x8029, 90}, - {0xc038, 90}, - }, - /* 74 */ - { - {0x8001, 33}, - {0xc016, 33}, - {0x8001, 34}, - {0xc016, 34}, - {0x8001, 40}, - {0xc016, 40}, - {0x8001, 41}, - {0xc016, 41}, - {0x8001, 63}, - {0xc016, 63}, - {0xc000, 39}, - {0xc000, 43}, - {0xc000, 124}, - {0x53, 0}, - {0x55, 0}, - {0x58, 0}, - }, - /* 75 */ - { - {0x8002, 33}, - {0x8009, 33}, - {0x8017, 33}, - {0xc028, 33}, - {0x8002, 34}, - {0x8009, 34}, - {0x8017, 34}, - {0xc028, 34}, - {0x8002, 40}, - {0x8009, 40}, - {0x8017, 40}, - {0xc028, 40}, - {0x8002, 41}, - {0x8009, 41}, - {0x8017, 41}, - {0xc028, 41}, - }, - /* 76 */ - { - {0x8003, 33}, - {0x8006, 33}, - {0x800a, 33}, - {0x800f, 33}, - {0x8018, 33}, - {0x801f, 33}, - {0x8029, 33}, - {0xc038, 33}, - {0x8003, 34}, - {0x8006, 34}, - {0x800a, 34}, - {0x800f, 34}, - {0x8018, 34}, - {0x801f, 34}, - {0x8029, 34}, - {0xc038, 34}, - }, - /* 77 */ - { - {0x8003, 40}, - {0x8006, 40}, - {0x800a, 40}, - {0x800f, 40}, - {0x8018, 40}, - {0x801f, 40}, - {0x8029, 40}, - {0xc038, 40}, - {0x8003, 41}, - {0x8006, 41}, - {0x800a, 41}, - {0x800f, 41}, - {0x8018, 41}, - {0x801f, 41}, - {0x8029, 41}, - {0xc038, 41}, - }, - /* 78 */ - { - {0x8002, 63}, - {0x8009, 63}, - {0x8017, 63}, - {0xc028, 63}, - {0x8001, 39}, - {0xc016, 39}, - {0x8001, 43}, - {0xc016, 43}, - {0x8001, 124}, - {0xc016, 124}, - {0xc000, 35}, - {0xc000, 62}, - {0x56, 0}, - {0x57, 0}, - {0x59, 0}, - {0x5a, 0}, - }, - /* 79 */ - { - {0x8003, 63}, - {0x8006, 63}, - {0x800a, 63}, - {0x800f, 63}, - {0x8018, 63}, - {0x801f, 63}, - {0x8029, 63}, - {0xc038, 63}, - {0x8002, 39}, - {0x8009, 39}, - {0x8017, 39}, - {0xc028, 39}, - {0x8002, 43}, - {0x8009, 43}, - {0x8017, 43}, - {0xc028, 43}, - }, - /* 80 */ - { - {0x8003, 39}, - {0x8006, 39}, - {0x800a, 39}, - {0x800f, 39}, - {0x8018, 39}, - {0x801f, 39}, - {0x8029, 39}, - {0xc038, 39}, - {0x8003, 43}, - {0x8006, 43}, - {0x800a, 43}, - {0x800f, 43}, - {0x8018, 43}, - {0x801f, 43}, - {0x8029, 43}, - {0xc038, 43}, - }, - /* 81 */ - { - {0x8002, 124}, - {0x8009, 124}, - {0x8017, 124}, - {0xc028, 124}, - {0x8001, 35}, - {0xc016, 35}, - {0x8001, 62}, - {0xc016, 62}, - {0xc000, 0}, - {0xc000, 36}, - {0xc000, 64}, - {0xc000, 91}, - {0xc000, 93}, - {0xc000, 126}, - {0x5b, 0}, - {0x5c, 0}, - }, - /* 82 */ - { - {0x8003, 124}, - {0x8006, 124}, - {0x800a, 124}, - {0x800f, 124}, - {0x8018, 124}, - {0x801f, 124}, - {0x8029, 124}, - {0xc038, 124}, - {0x8002, 35}, - {0x8009, 35}, - {0x8017, 35}, - {0xc028, 35}, - {0x8002, 62}, - {0x8009, 62}, - {0x8017, 62}, - {0xc028, 62}, - }, - /* 83 */ - { - {0x8003, 35}, - {0x8006, 35}, - {0x800a, 35}, - {0x800f, 35}, - {0x8018, 35}, - {0x801f, 35}, - {0x8029, 35}, - {0xc038, 35}, - {0x8003, 62}, - {0x8006, 62}, - {0x800a, 62}, - {0x800f, 62}, - {0x8018, 62}, - {0x801f, 62}, - {0x8029, 62}, - {0xc038, 62}, - }, - /* 84 */ - { - {0x8001, 0}, - {0xc016, 0}, - {0x8001, 36}, - {0xc016, 36}, - {0x8001, 64}, - {0xc016, 64}, - {0x8001, 91}, - {0xc016, 91}, - {0x8001, 93}, - {0xc016, 93}, - {0x8001, 126}, - {0xc016, 126}, - {0xc000, 94}, - {0xc000, 125}, - {0x5d, 0}, - {0x5e, 0}, - }, - /* 85 */ - { - {0x8002, 0}, - {0x8009, 0}, - {0x8017, 0}, - {0xc028, 0}, - {0x8002, 36}, - {0x8009, 36}, - {0x8017, 36}, - {0xc028, 36}, - {0x8002, 64}, - {0x8009, 64}, - {0x8017, 64}, - {0xc028, 64}, - {0x8002, 91}, - {0x8009, 91}, - {0x8017, 91}, - {0xc028, 91}, - }, - /* 86 */ - { - {0x8003, 0}, - {0x8006, 0}, - {0x800a, 0}, - {0x800f, 0}, - {0x8018, 0}, - {0x801f, 0}, - {0x8029, 0}, - {0xc038, 0}, - {0x8003, 36}, - {0x8006, 36}, - {0x800a, 36}, - {0x800f, 36}, - {0x8018, 36}, - {0x801f, 36}, - {0x8029, 36}, - {0xc038, 36}, - }, - /* 87 */ - { - {0x8003, 64}, - {0x8006, 64}, - {0x800a, 64}, - {0x800f, 64}, - {0x8018, 64}, - {0x801f, 64}, - {0x8029, 64}, - {0xc038, 64}, - {0x8003, 91}, - {0x8006, 91}, - {0x800a, 91}, - {0x800f, 91}, - {0x8018, 91}, - {0x801f, 91}, - {0x8029, 91}, - {0xc038, 91}, - }, - /* 88 */ - { - {0x8002, 93}, - {0x8009, 93}, - {0x8017, 93}, - {0xc028, 93}, - {0x8002, 126}, - {0x8009, 126}, - {0x8017, 126}, - {0xc028, 126}, - {0x8001, 94}, - {0xc016, 94}, - {0x8001, 125}, - {0xc016, 125}, - {0xc000, 60}, - {0xc000, 96}, - {0xc000, 123}, - {0x5f, 0}, - }, - /* 89 */ - { - {0x8003, 93}, - {0x8006, 93}, - {0x800a, 93}, - {0x800f, 93}, - {0x8018, 93}, - {0x801f, 93}, - {0x8029, 93}, - {0xc038, 93}, - {0x8003, 126}, - {0x8006, 126}, - {0x800a, 126}, - {0x800f, 126}, - {0x8018, 126}, - {0x801f, 126}, - {0x8029, 126}, - {0xc038, 126}, - }, - /* 90 */ - { - {0x8002, 94}, - {0x8009, 94}, - {0x8017, 94}, - {0xc028, 94}, - {0x8002, 125}, - {0x8009, 125}, - {0x8017, 125}, - {0xc028, 125}, - {0x8001, 60}, - {0xc016, 60}, - {0x8001, 96}, - {0xc016, 96}, - {0x8001, 123}, - {0xc016, 123}, - {0x60, 0}, - {0x6e, 0}, - }, - /* 91 */ - { - {0x8003, 94}, - {0x8006, 94}, - {0x800a, 94}, - {0x800f, 94}, - {0x8018, 94}, - {0x801f, 94}, - {0x8029, 94}, - {0xc038, 94}, - {0x8003, 125}, - {0x8006, 125}, - {0x800a, 125}, - {0x800f, 125}, - {0x8018, 125}, - {0x801f, 125}, - {0x8029, 125}, - {0xc038, 125}, - }, - /* 92 */ - { - {0x8002, 60}, - {0x8009, 60}, - {0x8017, 60}, - {0xc028, 60}, - {0x8002, 96}, - {0x8009, 96}, - {0x8017, 96}, - {0xc028, 96}, - {0x8002, 123}, - {0x8009, 123}, - {0x8017, 123}, - {0xc028, 123}, - {0x61, 0}, - {0x65, 0}, - {0x6f, 0}, - {0x85, 0}, - }, - /* 93 */ - { - {0x8003, 60}, - {0x8006, 60}, - {0x800a, 60}, - {0x800f, 60}, - {0x8018, 60}, - {0x801f, 60}, - {0x8029, 60}, - {0xc038, 60}, - {0x8003, 96}, - {0x8006, 96}, - {0x800a, 96}, - {0x800f, 96}, - {0x8018, 96}, - {0x801f, 96}, - {0x8029, 96}, - {0xc038, 96}, - }, - /* 94 */ - { - {0x8003, 123}, - {0x8006, 123}, - {0x800a, 123}, - {0x800f, 123}, - {0x8018, 123}, - {0x801f, 123}, - {0x8029, 123}, - {0xc038, 123}, - {0x62, 0}, - {0x63, 0}, - {0x66, 0}, - {0x69, 0}, - {0x70, 0}, - {0x77, 0}, - {0x86, 0}, - {0x99, 0}, - }, - /* 95 */ - { - {0xc000, 92}, - {0xc000, 195}, - {0xc000, 208}, - {0x64, 0}, - {0x67, 0}, - {0x68, 0}, - {0x6a, 0}, - {0x6b, 0}, - {0x71, 0}, - {0x74, 0}, - {0x78, 0}, - {0x7e, 0}, - {0x87, 0}, - {0x8e, 0}, - {0x9a, 0}, - {0xa9, 0}, - }, - /* 96 */ - { - {0x8001, 92}, - {0xc016, 92}, - {0x8001, 195}, - {0xc016, 195}, - {0x8001, 208}, - {0xc016, 208}, - {0xc000, 128}, - {0xc000, 130}, - {0xc000, 131}, - {0xc000, 162}, - {0xc000, 184}, - {0xc000, 194}, - {0xc000, 224}, - {0xc000, 226}, - {0x6c, 0}, - {0x6d, 0}, - }, - /* 97 */ - { - {0x8002, 92}, - {0x8009, 92}, - {0x8017, 92}, - {0xc028, 92}, - {0x8002, 195}, - {0x8009, 195}, - {0x8017, 195}, - {0xc028, 195}, - {0x8002, 208}, - {0x8009, 208}, - {0x8017, 208}, - {0xc028, 208}, - {0x8001, 128}, - {0xc016, 128}, - {0x8001, 130}, - {0xc016, 130}, - }, - /* 98 */ - { - {0x8003, 92}, - {0x8006, 92}, - {0x800a, 92}, - {0x800f, 92}, - {0x8018, 92}, - {0x801f, 92}, - {0x8029, 92}, - {0xc038, 92}, - {0x8003, 195}, - {0x8006, 195}, - {0x800a, 195}, - {0x800f, 195}, - {0x8018, 195}, - {0x801f, 195}, - {0x8029, 195}, - {0xc038, 195}, - }, - /* 99 */ - { - {0x8003, 208}, - {0x8006, 208}, - {0x800a, 208}, - {0x800f, 208}, - {0x8018, 208}, - {0x801f, 208}, - {0x8029, 208}, - {0xc038, 208}, - {0x8002, 128}, - {0x8009, 128}, - {0x8017, 128}, - {0xc028, 128}, - {0x8002, 130}, - {0x8009, 130}, - {0x8017, 130}, - {0xc028, 130}, - }, - /* 100 */ - { - {0x8003, 128}, - {0x8006, 128}, - {0x800a, 128}, - {0x800f, 128}, - {0x8018, 128}, - {0x801f, 128}, - {0x8029, 128}, - {0xc038, 128}, - {0x8003, 130}, - {0x8006, 130}, - {0x800a, 130}, - {0x800f, 130}, - {0x8018, 130}, - {0x801f, 130}, - {0x8029, 130}, - {0xc038, 130}, - }, - /* 101 */ - { - {0x8001, 131}, - {0xc016, 131}, - {0x8001, 162}, - {0xc016, 162}, - {0x8001, 184}, - {0xc016, 184}, - {0x8001, 194}, - {0xc016, 194}, - {0x8001, 224}, - {0xc016, 224}, - {0x8001, 226}, - {0xc016, 226}, - {0xc000, 153}, - {0xc000, 161}, - {0xc000, 167}, - {0xc000, 172}, - }, - /* 102 */ - { - {0x8002, 131}, - {0x8009, 131}, - {0x8017, 131}, - {0xc028, 131}, - {0x8002, 162}, - {0x8009, 162}, - {0x8017, 162}, - {0xc028, 162}, - {0x8002, 184}, - {0x8009, 184}, - {0x8017, 184}, - {0xc028, 184}, - {0x8002, 194}, - {0x8009, 194}, - {0x8017, 194}, - {0xc028, 194}, - }, - /* 103 */ - { - {0x8003, 131}, - {0x8006, 131}, - {0x800a, 131}, - {0x800f, 131}, - {0x8018, 131}, - {0x801f, 131}, - {0x8029, 131}, - {0xc038, 131}, - {0x8003, 162}, - {0x8006, 162}, - {0x800a, 162}, - {0x800f, 162}, - {0x8018, 162}, - {0x801f, 162}, - {0x8029, 162}, - {0xc038, 162}, - }, - /* 104 */ - { - {0x8003, 184}, - {0x8006, 184}, - {0x800a, 184}, - {0x800f, 184}, - {0x8018, 184}, - {0x801f, 184}, - {0x8029, 184}, - {0xc038, 184}, - {0x8003, 194}, - {0x8006, 194}, - {0x800a, 194}, - {0x800f, 194}, - {0x8018, 194}, - {0x801f, 194}, - {0x8029, 194}, - {0xc038, 194}, - }, - /* 105 */ - { - {0x8002, 224}, - {0x8009, 224}, - {0x8017, 224}, - {0xc028, 224}, - {0x8002, 226}, - {0x8009, 226}, - {0x8017, 226}, - {0xc028, 226}, - {0x8001, 153}, - {0xc016, 153}, - {0x8001, 161}, - {0xc016, 161}, - {0x8001, 167}, - {0xc016, 167}, - {0x8001, 172}, - {0xc016, 172}, - }, - /* 106 */ - { - {0x8003, 224}, - {0x8006, 224}, - {0x800a, 224}, - {0x800f, 224}, - {0x8018, 224}, - {0x801f, 224}, - {0x8029, 224}, - {0xc038, 224}, - {0x8003, 226}, - {0x8006, 226}, - {0x800a, 226}, - {0x800f, 226}, - {0x8018, 226}, - {0x801f, 226}, - {0x8029, 226}, - {0xc038, 226}, - }, - /* 107 */ - { - {0x8002, 153}, - {0x8009, 153}, - {0x8017, 153}, - {0xc028, 153}, - {0x8002, 161}, - {0x8009, 161}, - {0x8017, 161}, - {0xc028, 161}, - {0x8002, 167}, - {0x8009, 167}, - {0x8017, 167}, - {0xc028, 167}, - {0x8002, 172}, - {0x8009, 172}, - {0x8017, 172}, - {0xc028, 172}, - }, - /* 108 */ - { - {0x8003, 153}, - {0x8006, 153}, - {0x800a, 153}, - {0x800f, 153}, - {0x8018, 153}, - {0x801f, 153}, - {0x8029, 153}, - {0xc038, 153}, - {0x8003, 161}, - {0x8006, 161}, - {0x800a, 161}, - {0x800f, 161}, - {0x8018, 161}, - {0x801f, 161}, - {0x8029, 161}, - {0xc038, 161}, - }, - /* 109 */ - { - {0x8003, 167}, - {0x8006, 167}, - {0x800a, 167}, - {0x800f, 167}, - {0x8018, 167}, - {0x801f, 167}, - {0x8029, 167}, - {0xc038, 167}, - {0x8003, 172}, - {0x8006, 172}, - {0x800a, 172}, - {0x800f, 172}, - {0x8018, 172}, - {0x801f, 172}, - {0x8029, 172}, - {0xc038, 172}, - }, - /* 110 */ - { - {0x72, 0}, - {0x73, 0}, - {0x75, 0}, - {0x76, 0}, - {0x79, 0}, - {0x7b, 0}, - {0x7f, 0}, - {0x82, 0}, - {0x88, 0}, - {0x8b, 0}, - {0x8f, 0}, - {0x92, 0}, - {0x9b, 0}, - {0xa2, 0}, - {0xaa, 0}, - {0xb4, 0}, - }, - /* 111 */ - { - {0xc000, 176}, - {0xc000, 177}, - {0xc000, 179}, - {0xc000, 209}, - {0xc000, 216}, - {0xc000, 217}, - {0xc000, 227}, - {0xc000, 229}, - {0xc000, 230}, - {0x7a, 0}, - {0x7c, 0}, - {0x7d, 0}, - {0x80, 0}, - {0x81, 0}, - {0x83, 0}, - {0x84, 0}, - }, - /* 112 */ - { - {0x8001, 176}, - {0xc016, 176}, - {0x8001, 177}, - {0xc016, 177}, - {0x8001, 179}, - {0xc016, 179}, - {0x8001, 209}, - {0xc016, 209}, - {0x8001, 216}, - {0xc016, 216}, - {0x8001, 217}, - {0xc016, 217}, - {0x8001, 227}, - {0xc016, 227}, - {0x8001, 229}, - {0xc016, 229}, - }, - /* 113 */ - { - {0x8002, 176}, - {0x8009, 176}, - {0x8017, 176}, - {0xc028, 176}, - {0x8002, 177}, - {0x8009, 177}, - {0x8017, 177}, - {0xc028, 177}, - {0x8002, 179}, - {0x8009, 179}, - {0x8017, 179}, - {0xc028, 179}, - {0x8002, 209}, - {0x8009, 209}, - {0x8017, 209}, - {0xc028, 209}, - }, - /* 114 */ - { - {0x8003, 176}, - {0x8006, 176}, - {0x800a, 176}, - {0x800f, 176}, - {0x8018, 176}, - {0x801f, 176}, - {0x8029, 176}, - {0xc038, 176}, - {0x8003, 177}, - {0x8006, 177}, - {0x800a, 177}, - {0x800f, 177}, - {0x8018, 177}, - {0x801f, 177}, - {0x8029, 177}, - {0xc038, 177}, - }, - /* 115 */ - { - {0x8003, 179}, - {0x8006, 179}, - {0x800a, 179}, - {0x800f, 179}, - {0x8018, 179}, - {0x801f, 179}, - {0x8029, 179}, - {0xc038, 179}, - {0x8003, 209}, - {0x8006, 209}, - {0x800a, 209}, - {0x800f, 209}, - {0x8018, 209}, - {0x801f, 209}, - {0x8029, 209}, - {0xc038, 209}, - }, - /* 116 */ - { - {0x8002, 216}, - {0x8009, 216}, - {0x8017, 216}, - {0xc028, 216}, - {0x8002, 217}, - {0x8009, 217}, - {0x8017, 217}, - {0xc028, 217}, - {0x8002, 227}, - {0x8009, 227}, - {0x8017, 227}, - {0xc028, 227}, - {0x8002, 229}, - {0x8009, 229}, - {0x8017, 229}, - {0xc028, 229}, - }, - /* 117 */ - { - {0x8003, 216}, - {0x8006, 216}, - {0x800a, 216}, - {0x800f, 216}, - {0x8018, 216}, - {0x801f, 216}, - {0x8029, 216}, - {0xc038, 216}, - {0x8003, 217}, - {0x8006, 217}, - {0x800a, 217}, - {0x800f, 217}, - {0x8018, 217}, - {0x801f, 217}, - {0x8029, 217}, - {0xc038, 217}, - }, - /* 118 */ - { - {0x8003, 227}, - {0x8006, 227}, - {0x800a, 227}, - {0x800f, 227}, - {0x8018, 227}, - {0x801f, 227}, - {0x8029, 227}, - {0xc038, 227}, - {0x8003, 229}, - {0x8006, 229}, - {0x800a, 229}, - {0x800f, 229}, - {0x8018, 229}, - {0x801f, 229}, - {0x8029, 229}, - {0xc038, 229}, - }, - /* 119 */ - { - {0x8001, 230}, - {0xc016, 230}, - {0xc000, 129}, - {0xc000, 132}, - {0xc000, 133}, - {0xc000, 134}, - {0xc000, 136}, - {0xc000, 146}, - {0xc000, 154}, - {0xc000, 156}, - {0xc000, 160}, - {0xc000, 163}, - {0xc000, 164}, - {0xc000, 169}, - {0xc000, 170}, - {0xc000, 173}, - }, - /* 120 */ - { - {0x8002, 230}, - {0x8009, 230}, - {0x8017, 230}, - {0xc028, 230}, - {0x8001, 129}, - {0xc016, 129}, - {0x8001, 132}, - {0xc016, 132}, - {0x8001, 133}, - {0xc016, 133}, - {0x8001, 134}, - {0xc016, 134}, - {0x8001, 136}, - {0xc016, 136}, - {0x8001, 146}, - {0xc016, 146}, - }, - /* 121 */ - { - {0x8003, 230}, - {0x8006, 230}, - {0x800a, 230}, - {0x800f, 230}, - {0x8018, 230}, - {0x801f, 230}, - {0x8029, 230}, - {0xc038, 230}, - {0x8002, 129}, - {0x8009, 129}, - {0x8017, 129}, - {0xc028, 129}, - {0x8002, 132}, - {0x8009, 132}, - {0x8017, 132}, - {0xc028, 132}, - }, - /* 122 */ - { - {0x8003, 129}, - {0x8006, 129}, - {0x800a, 129}, - {0x800f, 129}, - {0x8018, 129}, - {0x801f, 129}, - {0x8029, 129}, - {0xc038, 129}, - {0x8003, 132}, - {0x8006, 132}, - {0x800a, 132}, - {0x800f, 132}, - {0x8018, 132}, - {0x801f, 132}, - {0x8029, 132}, - {0xc038, 132}, - }, - /* 123 */ - { - {0x8002, 133}, - {0x8009, 133}, - {0x8017, 133}, - {0xc028, 133}, - {0x8002, 134}, - {0x8009, 134}, - {0x8017, 134}, - {0xc028, 134}, - {0x8002, 136}, - {0x8009, 136}, - {0x8017, 136}, - {0xc028, 136}, - {0x8002, 146}, - {0x8009, 146}, - {0x8017, 146}, - {0xc028, 146}, - }, - /* 124 */ - { - {0x8003, 133}, - {0x8006, 133}, - {0x800a, 133}, - {0x800f, 133}, - {0x8018, 133}, - {0x801f, 133}, - {0x8029, 133}, - {0xc038, 133}, - {0x8003, 134}, - {0x8006, 134}, - {0x800a, 134}, - {0x800f, 134}, - {0x8018, 134}, - {0x801f, 134}, - {0x8029, 134}, - {0xc038, 134}, - }, - /* 125 */ - { - {0x8003, 136}, - {0x8006, 136}, - {0x800a, 136}, - {0x800f, 136}, - {0x8018, 136}, - {0x801f, 136}, - {0x8029, 136}, - {0xc038, 136}, - {0x8003, 146}, - {0x8006, 146}, - {0x800a, 146}, - {0x800f, 146}, - {0x8018, 146}, - {0x801f, 146}, - {0x8029, 146}, - {0xc038, 146}, - }, - /* 126 */ - { - {0x8001, 154}, - {0xc016, 154}, - {0x8001, 156}, - {0xc016, 156}, - {0x8001, 160}, - {0xc016, 160}, - {0x8001, 163}, - {0xc016, 163}, - {0x8001, 164}, - {0xc016, 164}, - {0x8001, 169}, - {0xc016, 169}, - {0x8001, 170}, - {0xc016, 170}, - {0x8001, 173}, - {0xc016, 173}, - }, - /* 127 */ - { - {0x8002, 154}, - {0x8009, 154}, - {0x8017, 154}, - {0xc028, 154}, - {0x8002, 156}, - {0x8009, 156}, - {0x8017, 156}, - {0xc028, 156}, - {0x8002, 160}, - {0x8009, 160}, - {0x8017, 160}, - {0xc028, 160}, - {0x8002, 163}, - {0x8009, 163}, - {0x8017, 163}, - {0xc028, 163}, - }, - /* 128 */ - { - {0x8003, 154}, - {0x8006, 154}, - {0x800a, 154}, - {0x800f, 154}, - {0x8018, 154}, - {0x801f, 154}, - {0x8029, 154}, - {0xc038, 154}, - {0x8003, 156}, - {0x8006, 156}, - {0x800a, 156}, - {0x800f, 156}, - {0x8018, 156}, - {0x801f, 156}, - {0x8029, 156}, - {0xc038, 156}, - }, - /* 129 */ - { - {0x8003, 160}, - {0x8006, 160}, - {0x800a, 160}, - {0x800f, 160}, - {0x8018, 160}, - {0x801f, 160}, - {0x8029, 160}, - {0xc038, 160}, - {0x8003, 163}, - {0x8006, 163}, - {0x800a, 163}, - {0x800f, 163}, - {0x8018, 163}, - {0x801f, 163}, - {0x8029, 163}, - {0xc038, 163}, - }, - /* 130 */ - { - {0x8002, 164}, - {0x8009, 164}, - {0x8017, 164}, - {0xc028, 164}, - {0x8002, 169}, - {0x8009, 169}, - {0x8017, 169}, - {0xc028, 169}, - {0x8002, 170}, - {0x8009, 170}, - {0x8017, 170}, - {0xc028, 170}, - {0x8002, 173}, - {0x8009, 173}, - {0x8017, 173}, - {0xc028, 173}, - }, - /* 131 */ - { - {0x8003, 164}, - {0x8006, 164}, - {0x800a, 164}, - {0x800f, 164}, - {0x8018, 164}, - {0x801f, 164}, - {0x8029, 164}, - {0xc038, 164}, - {0x8003, 169}, - {0x8006, 169}, - {0x800a, 169}, - {0x800f, 169}, - {0x8018, 169}, - {0x801f, 169}, - {0x8029, 169}, - {0xc038, 169}, - }, - /* 132 */ - { - {0x8003, 170}, - {0x8006, 170}, - {0x800a, 170}, - {0x800f, 170}, - {0x8018, 170}, - {0x801f, 170}, - {0x8029, 170}, - {0xc038, 170}, - {0x8003, 173}, - {0x8006, 173}, - {0x800a, 173}, - {0x800f, 173}, - {0x8018, 173}, - {0x801f, 173}, - {0x8029, 173}, - {0xc038, 173}, - }, - /* 133 */ - { - {0x89, 0}, - {0x8a, 0}, - {0x8c, 0}, - {0x8d, 0}, - {0x90, 0}, - {0x91, 0}, - {0x93, 0}, - {0x96, 0}, - {0x9c, 0}, - {0x9f, 0}, - {0xa3, 0}, - {0xa6, 0}, - {0xab, 0}, - {0xae, 0}, - {0xb5, 0}, - {0xbe, 0}, - }, - /* 134 */ - { - {0xc000, 178}, - {0xc000, 181}, - {0xc000, 185}, - {0xc000, 186}, - {0xc000, 187}, - {0xc000, 189}, - {0xc000, 190}, - {0xc000, 196}, - {0xc000, 198}, - {0xc000, 228}, - {0xc000, 232}, - {0xc000, 233}, - {0x94, 0}, - {0x95, 0}, - {0x97, 0}, - {0x98, 0}, - }, - /* 135 */ - { - {0x8001, 178}, - {0xc016, 178}, - {0x8001, 181}, - {0xc016, 181}, - {0x8001, 185}, - {0xc016, 185}, - {0x8001, 186}, - {0xc016, 186}, - {0x8001, 187}, - {0xc016, 187}, - {0x8001, 189}, - {0xc016, 189}, - {0x8001, 190}, - {0xc016, 190}, - {0x8001, 196}, - {0xc016, 196}, - }, - /* 136 */ - { - {0x8002, 178}, - {0x8009, 178}, - {0x8017, 178}, - {0xc028, 178}, - {0x8002, 181}, - {0x8009, 181}, - {0x8017, 181}, - {0xc028, 181}, - {0x8002, 185}, - {0x8009, 185}, - {0x8017, 185}, - {0xc028, 185}, - {0x8002, 186}, - {0x8009, 186}, - {0x8017, 186}, - {0xc028, 186}, - }, - /* 137 */ - { - {0x8003, 178}, - {0x8006, 178}, - {0x800a, 178}, - {0x800f, 178}, - {0x8018, 178}, - {0x801f, 178}, - {0x8029, 178}, - {0xc038, 178}, - {0x8003, 181}, - {0x8006, 181}, - {0x800a, 181}, - {0x800f, 181}, - {0x8018, 181}, - {0x801f, 181}, - {0x8029, 181}, - {0xc038, 181}, - }, - /* 138 */ - { - {0x8003, 185}, - {0x8006, 185}, - {0x800a, 185}, - {0x800f, 185}, - {0x8018, 185}, - {0x801f, 185}, - {0x8029, 185}, - {0xc038, 185}, - {0x8003, 186}, - {0x8006, 186}, - {0x800a, 186}, - {0x800f, 186}, - {0x8018, 186}, - {0x801f, 186}, - {0x8029, 186}, - {0xc038, 186}, - }, - /* 139 */ - { - {0x8002, 187}, - {0x8009, 187}, - {0x8017, 187}, - {0xc028, 187}, - {0x8002, 189}, - {0x8009, 189}, - {0x8017, 189}, - {0xc028, 189}, - {0x8002, 190}, - {0x8009, 190}, - {0x8017, 190}, - {0xc028, 190}, - {0x8002, 196}, - {0x8009, 196}, - {0x8017, 196}, - {0xc028, 196}, - }, - /* 140 */ - { - {0x8003, 187}, - {0x8006, 187}, - {0x800a, 187}, - {0x800f, 187}, - {0x8018, 187}, - {0x801f, 187}, - {0x8029, 187}, - {0xc038, 187}, - {0x8003, 189}, - {0x8006, 189}, - {0x800a, 189}, - {0x800f, 189}, - {0x8018, 189}, - {0x801f, 189}, - {0x8029, 189}, - {0xc038, 189}, - }, - /* 141 */ - { - {0x8003, 190}, - {0x8006, 190}, - {0x800a, 190}, - {0x800f, 190}, - {0x8018, 190}, - {0x801f, 190}, - {0x8029, 190}, - {0xc038, 190}, - {0x8003, 196}, - {0x8006, 196}, - {0x800a, 196}, - {0x800f, 196}, - {0x8018, 196}, - {0x801f, 196}, - {0x8029, 196}, - {0xc038, 196}, - }, - /* 142 */ - { - {0x8001, 198}, - {0xc016, 198}, - {0x8001, 228}, - {0xc016, 228}, - {0x8001, 232}, - {0xc016, 232}, - {0x8001, 233}, - {0xc016, 233}, - {0xc000, 1}, - {0xc000, 135}, - {0xc000, 137}, - {0xc000, 138}, - {0xc000, 139}, - {0xc000, 140}, - {0xc000, 141}, - {0xc000, 143}, - }, - /* 143 */ - { - {0x8002, 198}, - {0x8009, 198}, - {0x8017, 198}, - {0xc028, 198}, - {0x8002, 228}, - {0x8009, 228}, - {0x8017, 228}, - {0xc028, 228}, - {0x8002, 232}, - {0x8009, 232}, - {0x8017, 232}, - {0xc028, 232}, - {0x8002, 233}, - {0x8009, 233}, - {0x8017, 233}, - {0xc028, 233}, - }, - /* 144 */ - { - {0x8003, 198}, - {0x8006, 198}, - {0x800a, 198}, - {0x800f, 198}, - {0x8018, 198}, - {0x801f, 198}, - {0x8029, 198}, - {0xc038, 198}, - {0x8003, 228}, - {0x8006, 228}, - {0x800a, 228}, - {0x800f, 228}, - {0x8018, 228}, - {0x801f, 228}, - {0x8029, 228}, - {0xc038, 228}, - }, - /* 145 */ - { - {0x8003, 232}, - {0x8006, 232}, - {0x800a, 232}, - {0x800f, 232}, - {0x8018, 232}, - {0x801f, 232}, - {0x8029, 232}, - {0xc038, 232}, - {0x8003, 233}, - {0x8006, 233}, - {0x800a, 233}, - {0x800f, 233}, - {0x8018, 233}, - {0x801f, 233}, - {0x8029, 233}, - {0xc038, 233}, - }, - /* 146 */ - { - {0x8001, 1}, - {0xc016, 1}, - {0x8001, 135}, - {0xc016, 135}, - {0x8001, 137}, - {0xc016, 137}, - {0x8001, 138}, - {0xc016, 138}, - {0x8001, 139}, - {0xc016, 139}, - {0x8001, 140}, - {0xc016, 140}, - {0x8001, 141}, - {0xc016, 141}, - {0x8001, 143}, - {0xc016, 143}, - }, - /* 147 */ - { - {0x8002, 1}, - {0x8009, 1}, - {0x8017, 1}, - {0xc028, 1}, - {0x8002, 135}, - {0x8009, 135}, - {0x8017, 135}, - {0xc028, 135}, - {0x8002, 137}, - {0x8009, 137}, - {0x8017, 137}, - {0xc028, 137}, - {0x8002, 138}, - {0x8009, 138}, - {0x8017, 138}, - {0xc028, 138}, - }, - /* 148 */ - { - {0x8003, 1}, - {0x8006, 1}, - {0x800a, 1}, - {0x800f, 1}, - {0x8018, 1}, - {0x801f, 1}, - {0x8029, 1}, - {0xc038, 1}, - {0x8003, 135}, - {0x8006, 135}, - {0x800a, 135}, - {0x800f, 135}, - {0x8018, 135}, - {0x801f, 135}, - {0x8029, 135}, - {0xc038, 135}, - }, - /* 149 */ - { - {0x8003, 137}, - {0x8006, 137}, - {0x800a, 137}, - {0x800f, 137}, - {0x8018, 137}, - {0x801f, 137}, - {0x8029, 137}, - {0xc038, 137}, - {0x8003, 138}, - {0x8006, 138}, - {0x800a, 138}, - {0x800f, 138}, - {0x8018, 138}, - {0x801f, 138}, - {0x8029, 138}, - {0xc038, 138}, - }, - /* 150 */ - { - {0x8002, 139}, - {0x8009, 139}, - {0x8017, 139}, - {0xc028, 139}, - {0x8002, 140}, - {0x8009, 140}, - {0x8017, 140}, - {0xc028, 140}, - {0x8002, 141}, - {0x8009, 141}, - {0x8017, 141}, - {0xc028, 141}, - {0x8002, 143}, - {0x8009, 143}, - {0x8017, 143}, - {0xc028, 143}, - }, - /* 151 */ - { - {0x8003, 139}, - {0x8006, 139}, - {0x800a, 139}, - {0x800f, 139}, - {0x8018, 139}, - {0x801f, 139}, - {0x8029, 139}, - {0xc038, 139}, - {0x8003, 140}, - {0x8006, 140}, - {0x800a, 140}, - {0x800f, 140}, - {0x8018, 140}, - {0x801f, 140}, - {0x8029, 140}, - {0xc038, 140}, - }, - /* 152 */ - { - {0x8003, 141}, - {0x8006, 141}, - {0x800a, 141}, - {0x800f, 141}, - {0x8018, 141}, - {0x801f, 141}, - {0x8029, 141}, - {0xc038, 141}, - {0x8003, 143}, - {0x8006, 143}, - {0x800a, 143}, - {0x800f, 143}, - {0x8018, 143}, - {0x801f, 143}, - {0x8029, 143}, - {0xc038, 143}, - }, - /* 153 */ - { - {0x9d, 0}, - {0x9e, 0}, - {0xa0, 0}, - {0xa1, 0}, - {0xa4, 0}, - {0xa5, 0}, - {0xa7, 0}, - {0xa8, 0}, - {0xac, 0}, - {0xad, 0}, - {0xaf, 0}, - {0xb1, 0}, - {0xb6, 0}, - {0xb9, 0}, - {0xbf, 0}, - {0xcf, 0}, - }, - /* 154 */ - { - {0xc000, 147}, - {0xc000, 149}, - {0xc000, 150}, - {0xc000, 151}, - {0xc000, 152}, - {0xc000, 155}, - {0xc000, 157}, - {0xc000, 158}, - {0xc000, 165}, - {0xc000, 166}, - {0xc000, 168}, - {0xc000, 174}, - {0xc000, 175}, - {0xc000, 180}, - {0xc000, 182}, - {0xc000, 183}, - }, - /* 155 */ - { - {0x8001, 147}, - {0xc016, 147}, - {0x8001, 149}, - {0xc016, 149}, - {0x8001, 150}, - {0xc016, 150}, - {0x8001, 151}, - {0xc016, 151}, - {0x8001, 152}, - {0xc016, 152}, - {0x8001, 155}, - {0xc016, 155}, - {0x8001, 157}, - {0xc016, 157}, - {0x8001, 158}, - {0xc016, 158}, - }, - /* 156 */ - { - {0x8002, 147}, - {0x8009, 147}, - {0x8017, 147}, - {0xc028, 147}, - {0x8002, 149}, - {0x8009, 149}, - {0x8017, 149}, - {0xc028, 149}, - {0x8002, 150}, - {0x8009, 150}, - {0x8017, 150}, - {0xc028, 150}, - {0x8002, 151}, - {0x8009, 151}, - {0x8017, 151}, - {0xc028, 151}, - }, - /* 157 */ - { - {0x8003, 147}, - {0x8006, 147}, - {0x800a, 147}, - {0x800f, 147}, - {0x8018, 147}, - {0x801f, 147}, - {0x8029, 147}, - {0xc038, 147}, - {0x8003, 149}, - {0x8006, 149}, - {0x800a, 149}, - {0x800f, 149}, - {0x8018, 149}, - {0x801f, 149}, - {0x8029, 149}, - {0xc038, 149}, - }, - /* 158 */ - { - {0x8003, 150}, - {0x8006, 150}, - {0x800a, 150}, - {0x800f, 150}, - {0x8018, 150}, - {0x801f, 150}, - {0x8029, 150}, - {0xc038, 150}, - {0x8003, 151}, - {0x8006, 151}, - {0x800a, 151}, - {0x800f, 151}, - {0x8018, 151}, - {0x801f, 151}, - {0x8029, 151}, - {0xc038, 151}, - }, - /* 159 */ - { - {0x8002, 152}, - {0x8009, 152}, - {0x8017, 152}, - {0xc028, 152}, - {0x8002, 155}, - {0x8009, 155}, - {0x8017, 155}, - {0xc028, 155}, - {0x8002, 157}, - {0x8009, 157}, - {0x8017, 157}, - {0xc028, 157}, - {0x8002, 158}, - {0x8009, 158}, - {0x8017, 158}, - {0xc028, 158}, - }, - /* 160 */ - { - {0x8003, 152}, - {0x8006, 152}, - {0x800a, 152}, - {0x800f, 152}, - {0x8018, 152}, - {0x801f, 152}, - {0x8029, 152}, - {0xc038, 152}, - {0x8003, 155}, - {0x8006, 155}, - {0x800a, 155}, - {0x800f, 155}, - {0x8018, 155}, - {0x801f, 155}, - {0x8029, 155}, - {0xc038, 155}, - }, - /* 161 */ - { - {0x8003, 157}, - {0x8006, 157}, - {0x800a, 157}, - {0x800f, 157}, - {0x8018, 157}, - {0x801f, 157}, - {0x8029, 157}, - {0xc038, 157}, - {0x8003, 158}, - {0x8006, 158}, - {0x800a, 158}, - {0x800f, 158}, - {0x8018, 158}, - {0x801f, 158}, - {0x8029, 158}, - {0xc038, 158}, - }, - /* 162 */ - { - {0x8001, 165}, - {0xc016, 165}, - {0x8001, 166}, - {0xc016, 166}, - {0x8001, 168}, - {0xc016, 168}, - {0x8001, 174}, - {0xc016, 174}, - {0x8001, 175}, - {0xc016, 175}, - {0x8001, 180}, - {0xc016, 180}, - {0x8001, 182}, - {0xc016, 182}, - {0x8001, 183}, - {0xc016, 183}, - }, - /* 163 */ - { - {0x8002, 165}, - {0x8009, 165}, - {0x8017, 165}, - {0xc028, 165}, - {0x8002, 166}, - {0x8009, 166}, - {0x8017, 166}, - {0xc028, 166}, - {0x8002, 168}, - {0x8009, 168}, - {0x8017, 168}, - {0xc028, 168}, - {0x8002, 174}, - {0x8009, 174}, - {0x8017, 174}, - {0xc028, 174}, - }, - /* 164 */ - { - {0x8003, 165}, - {0x8006, 165}, - {0x800a, 165}, - {0x800f, 165}, - {0x8018, 165}, - {0x801f, 165}, - {0x8029, 165}, - {0xc038, 165}, - {0x8003, 166}, - {0x8006, 166}, - {0x800a, 166}, - {0x800f, 166}, - {0x8018, 166}, - {0x801f, 166}, - {0x8029, 166}, - {0xc038, 166}, - }, - /* 165 */ - { - {0x8003, 168}, - {0x8006, 168}, - {0x800a, 168}, - {0x800f, 168}, - {0x8018, 168}, - {0x801f, 168}, - {0x8029, 168}, - {0xc038, 168}, - {0x8003, 174}, - {0x8006, 174}, - {0x800a, 174}, - {0x800f, 174}, - {0x8018, 174}, - {0x801f, 174}, - {0x8029, 174}, - {0xc038, 174}, - }, - /* 166 */ - { - {0x8002, 175}, - {0x8009, 175}, - {0x8017, 175}, - {0xc028, 175}, - {0x8002, 180}, - {0x8009, 180}, - {0x8017, 180}, - {0xc028, 180}, - {0x8002, 182}, - {0x8009, 182}, - {0x8017, 182}, - {0xc028, 182}, - {0x8002, 183}, - {0x8009, 183}, - {0x8017, 183}, - {0xc028, 183}, - }, - /* 167 */ - { - {0x8003, 175}, - {0x8006, 175}, - {0x800a, 175}, - {0x800f, 175}, - {0x8018, 175}, - {0x801f, 175}, - {0x8029, 175}, - {0xc038, 175}, - {0x8003, 180}, - {0x8006, 180}, - {0x800a, 180}, - {0x800f, 180}, - {0x8018, 180}, - {0x801f, 180}, - {0x8029, 180}, - {0xc038, 180}, - }, - /* 168 */ - { - {0x8003, 182}, - {0x8006, 182}, - {0x800a, 182}, - {0x800f, 182}, - {0x8018, 182}, - {0x801f, 182}, - {0x8029, 182}, - {0xc038, 182}, - {0x8003, 183}, - {0x8006, 183}, - {0x800a, 183}, - {0x800f, 183}, - {0x8018, 183}, - {0x801f, 183}, - {0x8029, 183}, - {0xc038, 183}, - }, - /* 169 */ - { - {0xc000, 188}, - {0xc000, 191}, - {0xc000, 197}, - {0xc000, 231}, - {0xc000, 239}, - {0xb0, 0}, - {0xb2, 0}, - {0xb3, 0}, - {0xb7, 0}, - {0xb8, 0}, - {0xba, 0}, - {0xbb, 0}, - {0xc0, 0}, - {0xc7, 0}, - {0xd0, 0}, - {0xdf, 0}, - }, - /* 170 */ - { - {0x8001, 188}, - {0xc016, 188}, - {0x8001, 191}, - {0xc016, 191}, - {0x8001, 197}, - {0xc016, 197}, - {0x8001, 231}, - {0xc016, 231}, - {0x8001, 239}, - {0xc016, 239}, - {0xc000, 9}, - {0xc000, 142}, - {0xc000, 144}, - {0xc000, 145}, - {0xc000, 148}, - {0xc000, 159}, - }, - /* 171 */ - { - {0x8002, 188}, - {0x8009, 188}, - {0x8017, 188}, - {0xc028, 188}, - {0x8002, 191}, - {0x8009, 191}, - {0x8017, 191}, - {0xc028, 191}, - {0x8002, 197}, - {0x8009, 197}, - {0x8017, 197}, - {0xc028, 197}, - {0x8002, 231}, - {0x8009, 231}, - {0x8017, 231}, - {0xc028, 231}, - }, - /* 172 */ - { - {0x8003, 188}, - {0x8006, 188}, - {0x800a, 188}, - {0x800f, 188}, - {0x8018, 188}, - {0x801f, 188}, - {0x8029, 188}, - {0xc038, 188}, - {0x8003, 191}, - {0x8006, 191}, - {0x800a, 191}, - {0x800f, 191}, - {0x8018, 191}, - {0x801f, 191}, - {0x8029, 191}, - {0xc038, 191}, - }, - /* 173 */ - { - {0x8003, 197}, - {0x8006, 197}, - {0x800a, 197}, - {0x800f, 197}, - {0x8018, 197}, - {0x801f, 197}, - {0x8029, 197}, - {0xc038, 197}, - {0x8003, 231}, - {0x8006, 231}, - {0x800a, 231}, - {0x800f, 231}, - {0x8018, 231}, - {0x801f, 231}, - {0x8029, 231}, - {0xc038, 231}, - }, - /* 174 */ - { - {0x8002, 239}, - {0x8009, 239}, - {0x8017, 239}, - {0xc028, 239}, - {0x8001, 9}, - {0xc016, 9}, - {0x8001, 142}, - {0xc016, 142}, - {0x8001, 144}, - {0xc016, 144}, - {0x8001, 145}, - {0xc016, 145}, - {0x8001, 148}, - {0xc016, 148}, - {0x8001, 159}, - {0xc016, 159}, - }, - /* 175 */ - { - {0x8003, 239}, - {0x8006, 239}, - {0x800a, 239}, - {0x800f, 239}, - {0x8018, 239}, - {0x801f, 239}, - {0x8029, 239}, - {0xc038, 239}, - {0x8002, 9}, - {0x8009, 9}, - {0x8017, 9}, - {0xc028, 9}, - {0x8002, 142}, - {0x8009, 142}, - {0x8017, 142}, - {0xc028, 142}, - }, - /* 176 */ - { - {0x8003, 9}, - {0x8006, 9}, - {0x800a, 9}, - {0x800f, 9}, - {0x8018, 9}, - {0x801f, 9}, - {0x8029, 9}, - {0xc038, 9}, - {0x8003, 142}, - {0x8006, 142}, - {0x800a, 142}, - {0x800f, 142}, - {0x8018, 142}, - {0x801f, 142}, - {0x8029, 142}, - {0xc038, 142}, - }, - /* 177 */ - { - {0x8002, 144}, - {0x8009, 144}, - {0x8017, 144}, - {0xc028, 144}, - {0x8002, 145}, - {0x8009, 145}, - {0x8017, 145}, - {0xc028, 145}, - {0x8002, 148}, - {0x8009, 148}, - {0x8017, 148}, - {0xc028, 148}, - {0x8002, 159}, - {0x8009, 159}, - {0x8017, 159}, - {0xc028, 159}, - }, - /* 178 */ - { - {0x8003, 144}, - {0x8006, 144}, - {0x800a, 144}, - {0x800f, 144}, - {0x8018, 144}, - {0x801f, 144}, - {0x8029, 144}, - {0xc038, 144}, - {0x8003, 145}, - {0x8006, 145}, - {0x800a, 145}, - {0x800f, 145}, - {0x8018, 145}, - {0x801f, 145}, - {0x8029, 145}, - {0xc038, 145}, - }, - /* 179 */ - { - {0x8003, 148}, - {0x8006, 148}, - {0x800a, 148}, - {0x800f, 148}, - {0x8018, 148}, - {0x801f, 148}, - {0x8029, 148}, - {0xc038, 148}, - {0x8003, 159}, - {0x8006, 159}, - {0x800a, 159}, - {0x800f, 159}, - {0x8018, 159}, - {0x801f, 159}, - {0x8029, 159}, - {0xc038, 159}, - }, - /* 180 */ - { - {0xc000, 171}, - {0xc000, 206}, - {0xc000, 215}, - {0xc000, 225}, - {0xc000, 236}, - {0xc000, 237}, - {0xbc, 0}, - {0xbd, 0}, - {0xc1, 0}, - {0xc4, 0}, - {0xc8, 0}, - {0xcb, 0}, - {0xd1, 0}, - {0xd8, 0}, - {0xe0, 0}, - {0xee, 0}, - }, - /* 181 */ - { - {0x8001, 171}, - {0xc016, 171}, - {0x8001, 206}, - {0xc016, 206}, - {0x8001, 215}, - {0xc016, 215}, - {0x8001, 225}, - {0xc016, 225}, - {0x8001, 236}, - {0xc016, 236}, - {0x8001, 237}, - {0xc016, 237}, - {0xc000, 199}, - {0xc000, 207}, - {0xc000, 234}, - {0xc000, 235}, - }, - /* 182 */ - { - {0x8002, 171}, - {0x8009, 171}, - {0x8017, 171}, - {0xc028, 171}, - {0x8002, 206}, - {0x8009, 206}, - {0x8017, 206}, - {0xc028, 206}, - {0x8002, 215}, - {0x8009, 215}, - {0x8017, 215}, - {0xc028, 215}, - {0x8002, 225}, - {0x8009, 225}, - {0x8017, 225}, - {0xc028, 225}, - }, - /* 183 */ - { - {0x8003, 171}, - {0x8006, 171}, - {0x800a, 171}, - {0x800f, 171}, - {0x8018, 171}, - {0x801f, 171}, - {0x8029, 171}, - {0xc038, 171}, - {0x8003, 206}, - {0x8006, 206}, - {0x800a, 206}, - {0x800f, 206}, - {0x8018, 206}, - {0x801f, 206}, - {0x8029, 206}, - {0xc038, 206}, - }, - /* 184 */ - { - {0x8003, 215}, - {0x8006, 215}, - {0x800a, 215}, - {0x800f, 215}, - {0x8018, 215}, - {0x801f, 215}, - {0x8029, 215}, - {0xc038, 215}, - {0x8003, 225}, - {0x8006, 225}, - {0x800a, 225}, - {0x800f, 225}, - {0x8018, 225}, - {0x801f, 225}, - {0x8029, 225}, - {0xc038, 225}, - }, - /* 185 */ - { - {0x8002, 236}, - {0x8009, 236}, - {0x8017, 236}, - {0xc028, 236}, - {0x8002, 237}, - {0x8009, 237}, - {0x8017, 237}, - {0xc028, 237}, - {0x8001, 199}, - {0xc016, 199}, - {0x8001, 207}, - {0xc016, 207}, - {0x8001, 234}, - {0xc016, 234}, - {0x8001, 235}, - {0xc016, 235}, - }, - /* 186 */ - { - {0x8003, 236}, - {0x8006, 236}, - {0x800a, 236}, - {0x800f, 236}, - {0x8018, 236}, - {0x801f, 236}, - {0x8029, 236}, - {0xc038, 236}, - {0x8003, 237}, - {0x8006, 237}, - {0x800a, 237}, - {0x800f, 237}, - {0x8018, 237}, - {0x801f, 237}, - {0x8029, 237}, - {0xc038, 237}, - }, - /* 187 */ - { - {0x8002, 199}, - {0x8009, 199}, - {0x8017, 199}, - {0xc028, 199}, - {0x8002, 207}, - {0x8009, 207}, - {0x8017, 207}, - {0xc028, 207}, - {0x8002, 234}, - {0x8009, 234}, - {0x8017, 234}, - {0xc028, 234}, - {0x8002, 235}, - {0x8009, 235}, - {0x8017, 235}, - {0xc028, 235}, - }, - /* 188 */ - { - {0x8003, 199}, - {0x8006, 199}, - {0x800a, 199}, - {0x800f, 199}, - {0x8018, 199}, - {0x801f, 199}, - {0x8029, 199}, - {0xc038, 199}, - {0x8003, 207}, - {0x8006, 207}, - {0x800a, 207}, - {0x800f, 207}, - {0x8018, 207}, - {0x801f, 207}, - {0x8029, 207}, - {0xc038, 207}, - }, - /* 189 */ - { - {0x8003, 234}, - {0x8006, 234}, - {0x800a, 234}, - {0x800f, 234}, - {0x8018, 234}, - {0x801f, 234}, - {0x8029, 234}, - {0xc038, 234}, - {0x8003, 235}, - {0x8006, 235}, - {0x800a, 235}, - {0x800f, 235}, - {0x8018, 235}, - {0x801f, 235}, - {0x8029, 235}, - {0xc038, 235}, - }, - /* 190 */ - { - {0xc2, 0}, - {0xc3, 0}, - {0xc5, 0}, - {0xc6, 0}, - {0xc9, 0}, - {0xca, 0}, - {0xcc, 0}, - {0xcd, 0}, - {0xd2, 0}, - {0xd5, 0}, - {0xd9, 0}, - {0xdc, 0}, - {0xe1, 0}, - {0xe7, 0}, - {0xef, 0}, - {0xf6, 0}, - }, - /* 191 */ - { - {0xc000, 192}, - {0xc000, 193}, - {0xc000, 200}, - {0xc000, 201}, - {0xc000, 202}, - {0xc000, 205}, - {0xc000, 210}, - {0xc000, 213}, - {0xc000, 218}, - {0xc000, 219}, - {0xc000, 238}, - {0xc000, 240}, - {0xc000, 242}, - {0xc000, 243}, - {0xc000, 255}, - {0xce, 0}, - }, - /* 192 */ - { - {0x8001, 192}, - {0xc016, 192}, - {0x8001, 193}, - {0xc016, 193}, - {0x8001, 200}, - {0xc016, 200}, - {0x8001, 201}, - {0xc016, 201}, - {0x8001, 202}, - {0xc016, 202}, - {0x8001, 205}, - {0xc016, 205}, - {0x8001, 210}, - {0xc016, 210}, - {0x8001, 213}, - {0xc016, 213}, - }, - /* 193 */ - { - {0x8002, 192}, - {0x8009, 192}, - {0x8017, 192}, - {0xc028, 192}, - {0x8002, 193}, - {0x8009, 193}, - {0x8017, 193}, - {0xc028, 193}, - {0x8002, 200}, - {0x8009, 200}, - {0x8017, 200}, - {0xc028, 200}, - {0x8002, 201}, - {0x8009, 201}, - {0x8017, 201}, - {0xc028, 201}, - }, - /* 194 */ - { - {0x8003, 192}, - {0x8006, 192}, - {0x800a, 192}, - {0x800f, 192}, - {0x8018, 192}, - {0x801f, 192}, - {0x8029, 192}, - {0xc038, 192}, - {0x8003, 193}, - {0x8006, 193}, - {0x800a, 193}, - {0x800f, 193}, - {0x8018, 193}, - {0x801f, 193}, - {0x8029, 193}, - {0xc038, 193}, - }, - /* 195 */ - { - {0x8003, 200}, - {0x8006, 200}, - {0x800a, 200}, - {0x800f, 200}, - {0x8018, 200}, - {0x801f, 200}, - {0x8029, 200}, - {0xc038, 200}, - {0x8003, 201}, - {0x8006, 201}, - {0x800a, 201}, - {0x800f, 201}, - {0x8018, 201}, - {0x801f, 201}, - {0x8029, 201}, - {0xc038, 201}, - }, - /* 196 */ - { - {0x8002, 202}, - {0x8009, 202}, - {0x8017, 202}, - {0xc028, 202}, - {0x8002, 205}, - {0x8009, 205}, - {0x8017, 205}, - {0xc028, 205}, - {0x8002, 210}, - {0x8009, 210}, - {0x8017, 210}, - {0xc028, 210}, - {0x8002, 213}, - {0x8009, 213}, - {0x8017, 213}, - {0xc028, 213}, - }, - /* 197 */ - { - {0x8003, 202}, - {0x8006, 202}, - {0x800a, 202}, - {0x800f, 202}, - {0x8018, 202}, - {0x801f, 202}, - {0x8029, 202}, - {0xc038, 202}, - {0x8003, 205}, - {0x8006, 205}, - {0x800a, 205}, - {0x800f, 205}, - {0x8018, 205}, - {0x801f, 205}, - {0x8029, 205}, - {0xc038, 205}, - }, - /* 198 */ - { - {0x8003, 210}, - {0x8006, 210}, - {0x800a, 210}, - {0x800f, 210}, - {0x8018, 210}, - {0x801f, 210}, - {0x8029, 210}, - {0xc038, 210}, - {0x8003, 213}, - {0x8006, 213}, - {0x800a, 213}, - {0x800f, 213}, - {0x8018, 213}, - {0x801f, 213}, - {0x8029, 213}, - {0xc038, 213}, - }, - /* 199 */ - { - {0x8001, 218}, - {0xc016, 218}, - {0x8001, 219}, - {0xc016, 219}, - {0x8001, 238}, - {0xc016, 238}, - {0x8001, 240}, - {0xc016, 240}, - {0x8001, 242}, - {0xc016, 242}, - {0x8001, 243}, - {0xc016, 243}, - {0x8001, 255}, - {0xc016, 255}, - {0xc000, 203}, - {0xc000, 204}, - }, - /* 200 */ - { - {0x8002, 218}, - {0x8009, 218}, - {0x8017, 218}, - {0xc028, 218}, - {0x8002, 219}, - {0x8009, 219}, - {0x8017, 219}, - {0xc028, 219}, - {0x8002, 238}, - {0x8009, 238}, - {0x8017, 238}, - {0xc028, 238}, - {0x8002, 240}, - {0x8009, 240}, - {0x8017, 240}, - {0xc028, 240}, - }, - /* 201 */ - { - {0x8003, 218}, - {0x8006, 218}, - {0x800a, 218}, - {0x800f, 218}, - {0x8018, 218}, - {0x801f, 218}, - {0x8029, 218}, - {0xc038, 218}, - {0x8003, 219}, - {0x8006, 219}, - {0x800a, 219}, - {0x800f, 219}, - {0x8018, 219}, - {0x801f, 219}, - {0x8029, 219}, - {0xc038, 219}, - }, - /* 202 */ - { - {0x8003, 238}, - {0x8006, 238}, - {0x800a, 238}, - {0x800f, 238}, - {0x8018, 238}, - {0x801f, 238}, - {0x8029, 238}, - {0xc038, 238}, - {0x8003, 240}, - {0x8006, 240}, - {0x800a, 240}, - {0x800f, 240}, - {0x8018, 240}, - {0x801f, 240}, - {0x8029, 240}, - {0xc038, 240}, - }, - /* 203 */ - { - {0x8002, 242}, - {0x8009, 242}, - {0x8017, 242}, - {0xc028, 242}, - {0x8002, 243}, - {0x8009, 243}, - {0x8017, 243}, - {0xc028, 243}, - {0x8002, 255}, - {0x8009, 255}, - {0x8017, 255}, - {0xc028, 255}, - {0x8001, 203}, - {0xc016, 203}, - {0x8001, 204}, - {0xc016, 204}, - }, - /* 204 */ - { - {0x8003, 242}, - {0x8006, 242}, - {0x800a, 242}, - {0x800f, 242}, - {0x8018, 242}, - {0x801f, 242}, - {0x8029, 242}, - {0xc038, 242}, - {0x8003, 243}, - {0x8006, 243}, - {0x800a, 243}, - {0x800f, 243}, - {0x8018, 243}, - {0x801f, 243}, - {0x8029, 243}, - {0xc038, 243}, - }, - /* 205 */ - { - {0x8003, 255}, - {0x8006, 255}, - {0x800a, 255}, - {0x800f, 255}, - {0x8018, 255}, - {0x801f, 255}, - {0x8029, 255}, - {0xc038, 255}, - {0x8002, 203}, - {0x8009, 203}, - {0x8017, 203}, - {0xc028, 203}, - {0x8002, 204}, - {0x8009, 204}, - {0x8017, 204}, - {0xc028, 204}, - }, - /* 206 */ - { - {0x8003, 203}, - {0x8006, 203}, - {0x800a, 203}, - {0x800f, 203}, - {0x8018, 203}, - {0x801f, 203}, - {0x8029, 203}, - {0xc038, 203}, - {0x8003, 204}, - {0x8006, 204}, - {0x800a, 204}, - {0x800f, 204}, - {0x8018, 204}, - {0x801f, 204}, - {0x8029, 204}, - {0xc038, 204}, - }, - /* 207 */ - { - {0xd3, 0}, - {0xd4, 0}, - {0xd6, 0}, - {0xd7, 0}, - {0xda, 0}, - {0xdb, 0}, - {0xdd, 0}, - {0xde, 0}, - {0xe2, 0}, - {0xe4, 0}, - {0xe8, 0}, - {0xeb, 0}, - {0xf0, 0}, - {0xf3, 0}, - {0xf7, 0}, - {0xfa, 0}, - }, - /* 208 */ - { - {0xc000, 211}, - {0xc000, 212}, - {0xc000, 214}, - {0xc000, 221}, - {0xc000, 222}, - {0xc000, 223}, - {0xc000, 241}, - {0xc000, 244}, - {0xc000, 245}, - {0xc000, 246}, - {0xc000, 247}, - {0xc000, 248}, - {0xc000, 250}, - {0xc000, 251}, - {0xc000, 252}, - {0xc000, 253}, - }, - /* 209 */ - { - {0x8001, 211}, - {0xc016, 211}, - {0x8001, 212}, - {0xc016, 212}, - {0x8001, 214}, - {0xc016, 214}, - {0x8001, 221}, - {0xc016, 221}, - {0x8001, 222}, - {0xc016, 222}, - {0x8001, 223}, - {0xc016, 223}, - {0x8001, 241}, - {0xc016, 241}, - {0x8001, 244}, - {0xc016, 244}, - }, - /* 210 */ - { - {0x8002, 211}, - {0x8009, 211}, - {0x8017, 211}, - {0xc028, 211}, - {0x8002, 212}, - {0x8009, 212}, - {0x8017, 212}, - {0xc028, 212}, - {0x8002, 214}, - {0x8009, 214}, - {0x8017, 214}, - {0xc028, 214}, - {0x8002, 221}, - {0x8009, 221}, - {0x8017, 221}, - {0xc028, 221}, - }, - /* 211 */ - { - {0x8003, 211}, - {0x8006, 211}, - {0x800a, 211}, - {0x800f, 211}, - {0x8018, 211}, - {0x801f, 211}, - {0x8029, 211}, - {0xc038, 211}, - {0x8003, 212}, - {0x8006, 212}, - {0x800a, 212}, - {0x800f, 212}, - {0x8018, 212}, - {0x801f, 212}, - {0x8029, 212}, - {0xc038, 212}, - }, - /* 212 */ - { - {0x8003, 214}, - {0x8006, 214}, - {0x800a, 214}, - {0x800f, 214}, - {0x8018, 214}, - {0x801f, 214}, - {0x8029, 214}, - {0xc038, 214}, - {0x8003, 221}, - {0x8006, 221}, - {0x800a, 221}, - {0x800f, 221}, - {0x8018, 221}, - {0x801f, 221}, - {0x8029, 221}, - {0xc038, 221}, - }, - /* 213 */ - { - {0x8002, 222}, - {0x8009, 222}, - {0x8017, 222}, - {0xc028, 222}, - {0x8002, 223}, - {0x8009, 223}, - {0x8017, 223}, - {0xc028, 223}, - {0x8002, 241}, - {0x8009, 241}, - {0x8017, 241}, - {0xc028, 241}, - {0x8002, 244}, - {0x8009, 244}, - {0x8017, 244}, - {0xc028, 244}, - }, - /* 214 */ - { - {0x8003, 222}, - {0x8006, 222}, - {0x800a, 222}, - {0x800f, 222}, - {0x8018, 222}, - {0x801f, 222}, - {0x8029, 222}, - {0xc038, 222}, - {0x8003, 223}, - {0x8006, 223}, - {0x800a, 223}, - {0x800f, 223}, - {0x8018, 223}, - {0x801f, 223}, - {0x8029, 223}, - {0xc038, 223}, - }, - /* 215 */ - { - {0x8003, 241}, - {0x8006, 241}, - {0x800a, 241}, - {0x800f, 241}, - {0x8018, 241}, - {0x801f, 241}, - {0x8029, 241}, - {0xc038, 241}, - {0x8003, 244}, - {0x8006, 244}, - {0x800a, 244}, - {0x800f, 244}, - {0x8018, 244}, - {0x801f, 244}, - {0x8029, 244}, - {0xc038, 244}, - }, - /* 216 */ - { - {0x8001, 245}, - {0xc016, 245}, - {0x8001, 246}, - {0xc016, 246}, - {0x8001, 247}, - {0xc016, 247}, - {0x8001, 248}, - {0xc016, 248}, - {0x8001, 250}, - {0xc016, 250}, - {0x8001, 251}, - {0xc016, 251}, - {0x8001, 252}, - {0xc016, 252}, - {0x8001, 253}, - {0xc016, 253}, - }, - /* 217 */ - { - {0x8002, 245}, - {0x8009, 245}, - {0x8017, 245}, - {0xc028, 245}, - {0x8002, 246}, - {0x8009, 246}, - {0x8017, 246}, - {0xc028, 246}, - {0x8002, 247}, - {0x8009, 247}, - {0x8017, 247}, - {0xc028, 247}, - {0x8002, 248}, - {0x8009, 248}, - {0x8017, 248}, - {0xc028, 248}, - }, - /* 218 */ - { - {0x8003, 245}, - {0x8006, 245}, - {0x800a, 245}, - {0x800f, 245}, - {0x8018, 245}, - {0x801f, 245}, - {0x8029, 245}, - {0xc038, 245}, - {0x8003, 246}, - {0x8006, 246}, - {0x800a, 246}, - {0x800f, 246}, - {0x8018, 246}, - {0x801f, 246}, - {0x8029, 246}, - {0xc038, 246}, - }, - /* 219 */ - { - {0x8003, 247}, - {0x8006, 247}, - {0x800a, 247}, - {0x800f, 247}, - {0x8018, 247}, - {0x801f, 247}, - {0x8029, 247}, - {0xc038, 247}, - {0x8003, 248}, - {0x8006, 248}, - {0x800a, 248}, - {0x800f, 248}, - {0x8018, 248}, - {0x801f, 248}, - {0x8029, 248}, - {0xc038, 248}, - }, - /* 220 */ - { - {0x8002, 250}, - {0x8009, 250}, - {0x8017, 250}, - {0xc028, 250}, - {0x8002, 251}, - {0x8009, 251}, - {0x8017, 251}, - {0xc028, 251}, - {0x8002, 252}, - {0x8009, 252}, - {0x8017, 252}, - {0xc028, 252}, - {0x8002, 253}, - {0x8009, 253}, - {0x8017, 253}, - {0xc028, 253}, - }, - /* 221 */ - { - {0x8003, 250}, - {0x8006, 250}, - {0x800a, 250}, - {0x800f, 250}, - {0x8018, 250}, - {0x801f, 250}, - {0x8029, 250}, - {0xc038, 250}, - {0x8003, 251}, - {0x8006, 251}, - {0x800a, 251}, - {0x800f, 251}, - {0x8018, 251}, - {0x801f, 251}, - {0x8029, 251}, - {0xc038, 251}, - }, - /* 222 */ - { - {0x8003, 252}, - {0x8006, 252}, - {0x800a, 252}, - {0x800f, 252}, - {0x8018, 252}, - {0x801f, 252}, - {0x8029, 252}, - {0xc038, 252}, - {0x8003, 253}, - {0x8006, 253}, - {0x800a, 253}, - {0x800f, 253}, - {0x8018, 253}, - {0x801f, 253}, - {0x8029, 253}, - {0xc038, 253}, - }, - /* 223 */ - { - {0xc000, 254}, - {0xe3, 0}, - {0xe5, 0}, - {0xe6, 0}, - {0xe9, 0}, - {0xea, 0}, - {0xec, 0}, - {0xed, 0}, - {0xf1, 0}, - {0xf2, 0}, - {0xf4, 0}, - {0xf5, 0}, - {0xf8, 0}, - {0xf9, 0}, - {0xfb, 0}, - {0xfc, 0}, - }, - /* 224 */ - { - {0x8001, 254}, - {0xc016, 254}, - {0xc000, 2}, - {0xc000, 3}, - {0xc000, 4}, - {0xc000, 5}, - {0xc000, 6}, - {0xc000, 7}, - {0xc000, 8}, - {0xc000, 11}, - {0xc000, 12}, - {0xc000, 14}, - {0xc000, 15}, - {0xc000, 16}, - {0xc000, 17}, - {0xc000, 18}, - }, - /* 225 */ - { - {0x8002, 254}, - {0x8009, 254}, - {0x8017, 254}, - {0xc028, 254}, - {0x8001, 2}, - {0xc016, 2}, - {0x8001, 3}, - {0xc016, 3}, - {0x8001, 4}, - {0xc016, 4}, - {0x8001, 5}, - {0xc016, 5}, - {0x8001, 6}, - {0xc016, 6}, - {0x8001, 7}, - {0xc016, 7}, - }, - /* 226 */ - { - {0x8003, 254}, - {0x8006, 254}, - {0x800a, 254}, - {0x800f, 254}, - {0x8018, 254}, - {0x801f, 254}, - {0x8029, 254}, - {0xc038, 254}, - {0x8002, 2}, - {0x8009, 2}, - {0x8017, 2}, - {0xc028, 2}, - {0x8002, 3}, - {0x8009, 3}, - {0x8017, 3}, - {0xc028, 3}, - }, - /* 227 */ - { - {0x8003, 2}, - {0x8006, 2}, - {0x800a, 2}, - {0x800f, 2}, - {0x8018, 2}, - {0x801f, 2}, - {0x8029, 2}, - {0xc038, 2}, - {0x8003, 3}, - {0x8006, 3}, - {0x800a, 3}, - {0x800f, 3}, - {0x8018, 3}, - {0x801f, 3}, - {0x8029, 3}, - {0xc038, 3}, - }, - /* 228 */ - { - {0x8002, 4}, - {0x8009, 4}, - {0x8017, 4}, - {0xc028, 4}, - {0x8002, 5}, - {0x8009, 5}, - {0x8017, 5}, - {0xc028, 5}, - {0x8002, 6}, - {0x8009, 6}, - {0x8017, 6}, - {0xc028, 6}, - {0x8002, 7}, - {0x8009, 7}, - {0x8017, 7}, - {0xc028, 7}, - }, - /* 229 */ - { - {0x8003, 4}, - {0x8006, 4}, - {0x800a, 4}, - {0x800f, 4}, - {0x8018, 4}, - {0x801f, 4}, - {0x8029, 4}, - {0xc038, 4}, - {0x8003, 5}, - {0x8006, 5}, - {0x800a, 5}, - {0x800f, 5}, - {0x8018, 5}, - {0x801f, 5}, - {0x8029, 5}, - {0xc038, 5}, - }, - /* 230 */ - { - {0x8003, 6}, - {0x8006, 6}, - {0x800a, 6}, - {0x800f, 6}, - {0x8018, 6}, - {0x801f, 6}, - {0x8029, 6}, - {0xc038, 6}, - {0x8003, 7}, - {0x8006, 7}, - {0x800a, 7}, - {0x800f, 7}, - {0x8018, 7}, - {0x801f, 7}, - {0x8029, 7}, - {0xc038, 7}, - }, - /* 231 */ - { - {0x8001, 8}, - {0xc016, 8}, - {0x8001, 11}, - {0xc016, 11}, - {0x8001, 12}, - {0xc016, 12}, - {0x8001, 14}, - {0xc016, 14}, - {0x8001, 15}, - {0xc016, 15}, - {0x8001, 16}, - {0xc016, 16}, - {0x8001, 17}, - {0xc016, 17}, - {0x8001, 18}, - {0xc016, 18}, - }, - /* 232 */ - { - {0x8002, 8}, - {0x8009, 8}, - {0x8017, 8}, - {0xc028, 8}, - {0x8002, 11}, - {0x8009, 11}, - {0x8017, 11}, - {0xc028, 11}, - {0x8002, 12}, - {0x8009, 12}, - {0x8017, 12}, - {0xc028, 12}, - {0x8002, 14}, - {0x8009, 14}, - {0x8017, 14}, - {0xc028, 14}, - }, - /* 233 */ - { - {0x8003, 8}, - {0x8006, 8}, - {0x800a, 8}, - {0x800f, 8}, - {0x8018, 8}, - {0x801f, 8}, - {0x8029, 8}, - {0xc038, 8}, - {0x8003, 11}, - {0x8006, 11}, - {0x800a, 11}, - {0x800f, 11}, - {0x8018, 11}, - {0x801f, 11}, - {0x8029, 11}, - {0xc038, 11}, - }, - /* 234 */ - { - {0x8003, 12}, - {0x8006, 12}, - {0x800a, 12}, - {0x800f, 12}, - {0x8018, 12}, - {0x801f, 12}, - {0x8029, 12}, - {0xc038, 12}, - {0x8003, 14}, - {0x8006, 14}, - {0x800a, 14}, - {0x800f, 14}, - {0x8018, 14}, - {0x801f, 14}, - {0x8029, 14}, - {0xc038, 14}, - }, - /* 235 */ - { - {0x8002, 15}, - {0x8009, 15}, - {0x8017, 15}, - {0xc028, 15}, - {0x8002, 16}, - {0x8009, 16}, - {0x8017, 16}, - {0xc028, 16}, - {0x8002, 17}, - {0x8009, 17}, - {0x8017, 17}, - {0xc028, 17}, - {0x8002, 18}, - {0x8009, 18}, - {0x8017, 18}, - {0xc028, 18}, - }, - /* 236 */ - { - {0x8003, 15}, - {0x8006, 15}, - {0x800a, 15}, - {0x800f, 15}, - {0x8018, 15}, - {0x801f, 15}, - {0x8029, 15}, - {0xc038, 15}, - {0x8003, 16}, - {0x8006, 16}, - {0x800a, 16}, - {0x800f, 16}, - {0x8018, 16}, - {0x801f, 16}, - {0x8029, 16}, - {0xc038, 16}, - }, - /* 237 */ - { - {0x8003, 17}, - {0x8006, 17}, - {0x800a, 17}, - {0x800f, 17}, - {0x8018, 17}, - {0x801f, 17}, - {0x8029, 17}, - {0xc038, 17}, - {0x8003, 18}, - {0x8006, 18}, - {0x800a, 18}, - {0x800f, 18}, - {0x8018, 18}, - {0x801f, 18}, - {0x8029, 18}, - {0xc038, 18}, - }, - /* 238 */ - { - {0xc000, 19}, - {0xc000, 20}, - {0xc000, 21}, - {0xc000, 23}, - {0xc000, 24}, - {0xc000, 25}, - {0xc000, 26}, - {0xc000, 27}, - {0xc000, 28}, - {0xc000, 29}, - {0xc000, 30}, - {0xc000, 31}, - {0xc000, 127}, - {0xc000, 220}, - {0xc000, 249}, - {0xfd, 0}, - }, - /* 239 */ - { - {0x8001, 19}, - {0xc016, 19}, - {0x8001, 20}, - {0xc016, 20}, - {0x8001, 21}, - {0xc016, 21}, - {0x8001, 23}, - {0xc016, 23}, - {0x8001, 24}, - {0xc016, 24}, - {0x8001, 25}, - {0xc016, 25}, - {0x8001, 26}, - {0xc016, 26}, - {0x8001, 27}, - {0xc016, 27}, - }, - /* 240 */ - { - {0x8002, 19}, - {0x8009, 19}, - {0x8017, 19}, - {0xc028, 19}, - {0x8002, 20}, - {0x8009, 20}, - {0x8017, 20}, - {0xc028, 20}, - {0x8002, 21}, - {0x8009, 21}, - {0x8017, 21}, - {0xc028, 21}, - {0x8002, 23}, - {0x8009, 23}, - {0x8017, 23}, - {0xc028, 23}, - }, - /* 241 */ - { - {0x8003, 19}, - {0x8006, 19}, - {0x800a, 19}, - {0x800f, 19}, - {0x8018, 19}, - {0x801f, 19}, - {0x8029, 19}, - {0xc038, 19}, - {0x8003, 20}, - {0x8006, 20}, - {0x800a, 20}, - {0x800f, 20}, - {0x8018, 20}, - {0x801f, 20}, - {0x8029, 20}, - {0xc038, 20}, - }, - /* 242 */ - { - {0x8003, 21}, - {0x8006, 21}, - {0x800a, 21}, - {0x800f, 21}, - {0x8018, 21}, - {0x801f, 21}, - {0x8029, 21}, - {0xc038, 21}, - {0x8003, 23}, - {0x8006, 23}, - {0x800a, 23}, - {0x800f, 23}, - {0x8018, 23}, - {0x801f, 23}, - {0x8029, 23}, - {0xc038, 23}, - }, - /* 243 */ - { - {0x8002, 24}, - {0x8009, 24}, - {0x8017, 24}, - {0xc028, 24}, - {0x8002, 25}, - {0x8009, 25}, - {0x8017, 25}, - {0xc028, 25}, - {0x8002, 26}, - {0x8009, 26}, - {0x8017, 26}, - {0xc028, 26}, - {0x8002, 27}, - {0x8009, 27}, - {0x8017, 27}, - {0xc028, 27}, - }, - /* 244 */ - { - {0x8003, 24}, - {0x8006, 24}, - {0x800a, 24}, - {0x800f, 24}, - {0x8018, 24}, - {0x801f, 24}, - {0x8029, 24}, - {0xc038, 24}, - {0x8003, 25}, - {0x8006, 25}, - {0x800a, 25}, - {0x800f, 25}, - {0x8018, 25}, - {0x801f, 25}, - {0x8029, 25}, - {0xc038, 25}, - }, - /* 245 */ - { - {0x8003, 26}, - {0x8006, 26}, - {0x800a, 26}, - {0x800f, 26}, - {0x8018, 26}, - {0x801f, 26}, - {0x8029, 26}, - {0xc038, 26}, - {0x8003, 27}, - {0x8006, 27}, - {0x800a, 27}, - {0x800f, 27}, - {0x8018, 27}, - {0x801f, 27}, - {0x8029, 27}, - {0xc038, 27}, - }, - /* 246 */ - { - {0x8001, 28}, - {0xc016, 28}, - {0x8001, 29}, - {0xc016, 29}, - {0x8001, 30}, - {0xc016, 30}, - {0x8001, 31}, - {0xc016, 31}, - {0x8001, 127}, - {0xc016, 127}, - {0x8001, 220}, - {0xc016, 220}, - {0x8001, 249}, - {0xc016, 249}, - {0xfe, 0}, - {0xff, 0}, - }, - /* 247 */ - { - {0x8002, 28}, - {0x8009, 28}, - {0x8017, 28}, - {0xc028, 28}, - {0x8002, 29}, - {0x8009, 29}, - {0x8017, 29}, - {0xc028, 29}, - {0x8002, 30}, - {0x8009, 30}, - {0x8017, 30}, - {0xc028, 30}, - {0x8002, 31}, - {0x8009, 31}, - {0x8017, 31}, - {0xc028, 31}, - }, - /* 248 */ - { - {0x8003, 28}, - {0x8006, 28}, - {0x800a, 28}, - {0x800f, 28}, - {0x8018, 28}, - {0x801f, 28}, - {0x8029, 28}, - {0xc038, 28}, - {0x8003, 29}, - {0x8006, 29}, - {0x800a, 29}, - {0x800f, 29}, - {0x8018, 29}, - {0x801f, 29}, - {0x8029, 29}, - {0xc038, 29}, - }, - /* 249 */ - { - {0x8003, 30}, - {0x8006, 30}, - {0x800a, 30}, - {0x800f, 30}, - {0x8018, 30}, - {0x801f, 30}, - {0x8029, 30}, - {0xc038, 30}, - {0x8003, 31}, - {0x8006, 31}, - {0x800a, 31}, - {0x800f, 31}, - {0x8018, 31}, - {0x801f, 31}, - {0x8029, 31}, - {0xc038, 31}, - }, - /* 250 */ - { - {0x8002, 127}, - {0x8009, 127}, - {0x8017, 127}, - {0xc028, 127}, - {0x8002, 220}, - {0x8009, 220}, - {0x8017, 220}, - {0xc028, 220}, - {0x8002, 249}, - {0x8009, 249}, - {0x8017, 249}, - {0xc028, 249}, - {0xc000, 10}, - {0xc000, 13}, - {0xc000, 22}, - {0x100, 0}, - }, - /* 251 */ - { - {0x8003, 127}, - {0x8006, 127}, - {0x800a, 127}, - {0x800f, 127}, - {0x8018, 127}, - {0x801f, 127}, - {0x8029, 127}, - {0xc038, 127}, - {0x8003, 220}, - {0x8006, 220}, - {0x800a, 220}, - {0x800f, 220}, - {0x8018, 220}, - {0x801f, 220}, - {0x8029, 220}, - {0xc038, 220}, - }, - /* 252 */ - { - {0x8003, 249}, - {0x8006, 249}, - {0x800a, 249}, - {0x800f, 249}, - {0x8018, 249}, - {0x801f, 249}, - {0x8029, 249}, - {0xc038, 249}, - {0x8001, 10}, - {0xc016, 10}, - {0x8001, 13}, - {0xc016, 13}, - {0x8001, 22}, - {0xc016, 22}, - {0x100, 0}, - {0x100, 0}, - }, - /* 253 */ - { - {0x8002, 10}, - {0x8009, 10}, - {0x8017, 10}, - {0xc028, 10}, - {0x8002, 13}, - {0x8009, 13}, - {0x8017, 13}, - {0xc028, 13}, - {0x8002, 22}, - {0x8009, 22}, - {0x8017, 22}, - {0xc028, 22}, - {0x100, 0}, - {0x100, 0}, - {0x100, 0}, - {0x100, 0}, - }, - /* 254 */ - { - {0x8003, 10}, - {0x8006, 10}, - {0x800a, 10}, - {0x800f, 10}, - {0x8018, 10}, - {0x801f, 10}, - {0x8029, 10}, - {0xc038, 10}, - {0x8003, 13}, - {0x8006, 13}, - {0x800a, 13}, - {0x800f, 13}, - {0x8018, 13}, - {0x801f, 13}, - {0x8029, 13}, - {0xc038, 13}, - }, - /* 255 */ - { - {0x8003, 22}, - {0x8006, 22}, - {0x800a, 22}, - {0x800f, 22}, - {0x8018, 22}, - {0x801f, 22}, - {0x8029, 22}, - {0xc038, 22}, - {0x100, 0}, - {0x100, 0}, - {0x100, 0}, - {0x100, 0}, - {0x100, 0}, - {0x100, 0}, - {0x100, 0}, - {0x100, 0}, - }, - /* 256 */ - { - {0x100, 0}, - {0x100, 0}, - {0x100, 0}, - {0x100, 0}, - {0x100, 0}, - {0x100, 0}, - {0x100, 0}, - {0x100, 0}, - {0x100, 0}, - {0x100, 0}, - {0x100, 0}, - {0x100, 0}, - {0x100, 0}, - {0x100, 0}, - {0x100, 0}, - {0x100, 0}, - }, -}; diff --git a/3rdparty/exported/nghttp2/nghttp2_helper.c b/3rdparty/exported/nghttp2/nghttp2_helper.c deleted file mode 100644 index f54f37c13e27..000000000000 --- a/3rdparty/exported/nghttp2/nghttp2_helper.c +++ /dev/null @@ -1,805 +0,0 @@ -/* - * nghttp2 - HTTP/2 C Library - * - * Copyright (c) 2012 Tatsuhiro Tsujikawa - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE - * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION - * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION - * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ -#include "nghttp2_helper.h" - -#include -#include - -#include "nghttp2_net.h" - -void nghttp2_put_uint16be(uint8_t *buf, uint16_t n) { - uint16_t x = htons(n); - memcpy(buf, &x, sizeof(uint16_t)); -} - -void nghttp2_put_uint32be(uint8_t *buf, uint32_t n) { - uint32_t x = htonl(n); - memcpy(buf, &x, sizeof(uint32_t)); -} - -uint16_t nghttp2_get_uint16(const uint8_t *data) { - uint16_t n; - memcpy(&n, data, sizeof(uint16_t)); - return ntohs(n); -} - -uint32_t nghttp2_get_uint32(const uint8_t *data) { - uint32_t n; - memcpy(&n, data, sizeof(uint32_t)); - return ntohl(n); -} - -/* Generated by gendowncasetbl.py */ -static const uint8_t DOWNCASE_TBL[] = { - 0 /* NUL */, 1 /* SOH */, 2 /* STX */, 3 /* ETX */, - 4 /* EOT */, 5 /* ENQ */, 6 /* ACK */, 7 /* BEL */, - 8 /* BS */, 9 /* HT */, 10 /* LF */, 11 /* VT */, - 12 /* FF */, 13 /* CR */, 14 /* SO */, 15 /* SI */, - 16 /* DLE */, 17 /* DC1 */, 18 /* DC2 */, 19 /* DC3 */, - 20 /* DC4 */, 21 /* NAK */, 22 /* SYN */, 23 /* ETB */, - 24 /* CAN */, 25 /* EM */, 26 /* SUB */, 27 /* ESC */, - 28 /* FS */, 29 /* GS */, 30 /* RS */, 31 /* US */, - 32 /* SPC */, 33 /* ! */, 34 /* " */, 35 /* # */, - 36 /* $ */, 37 /* % */, 38 /* & */, 39 /* ' */, - 40 /* ( */, 41 /* ) */, 42 /* * */, 43 /* + */, - 44 /* , */, 45 /* - */, 46 /* . */, 47 /* / */, - 48 /* 0 */, 49 /* 1 */, 50 /* 2 */, 51 /* 3 */, - 52 /* 4 */, 53 /* 5 */, 54 /* 6 */, 55 /* 7 */, - 56 /* 8 */, 57 /* 9 */, 58 /* : */, 59 /* ; */, - 60 /* < */, 61 /* = */, 62 /* > */, 63 /* ? */, - 64 /* @ */, 97 /* A */, 98 /* B */, 99 /* C */, - 100 /* D */, 101 /* E */, 102 /* F */, 103 /* G */, - 104 /* H */, 105 /* I */, 106 /* J */, 107 /* K */, - 108 /* L */, 109 /* M */, 110 /* N */, 111 /* O */, - 112 /* P */, 113 /* Q */, 114 /* R */, 115 /* S */, - 116 /* T */, 117 /* U */, 118 /* V */, 119 /* W */, - 120 /* X */, 121 /* Y */, 122 /* Z */, 91 /* [ */, - 92 /* \ */, 93 /* ] */, 94 /* ^ */, 95 /* _ */, - 96 /* ` */, 97 /* a */, 98 /* b */, 99 /* c */, - 100 /* d */, 101 /* e */, 102 /* f */, 103 /* g */, - 104 /* h */, 105 /* i */, 106 /* j */, 107 /* k */, - 108 /* l */, 109 /* m */, 110 /* n */, 111 /* o */, - 112 /* p */, 113 /* q */, 114 /* r */, 115 /* s */, - 116 /* t */, 117 /* u */, 118 /* v */, 119 /* w */, - 120 /* x */, 121 /* y */, 122 /* z */, 123 /* { */, - 124 /* | */, 125 /* } */, 126 /* ~ */, 127 /* DEL */, - 128 /* 0x80 */, 129 /* 0x81 */, 130 /* 0x82 */, 131 /* 0x83 */, - 132 /* 0x84 */, 133 /* 0x85 */, 134 /* 0x86 */, 135 /* 0x87 */, - 136 /* 0x88 */, 137 /* 0x89 */, 138 /* 0x8a */, 139 /* 0x8b */, - 140 /* 0x8c */, 141 /* 0x8d */, 142 /* 0x8e */, 143 /* 0x8f */, - 144 /* 0x90 */, 145 /* 0x91 */, 146 /* 0x92 */, 147 /* 0x93 */, - 148 /* 0x94 */, 149 /* 0x95 */, 150 /* 0x96 */, 151 /* 0x97 */, - 152 /* 0x98 */, 153 /* 0x99 */, 154 /* 0x9a */, 155 /* 0x9b */, - 156 /* 0x9c */, 157 /* 0x9d */, 158 /* 0x9e */, 159 /* 0x9f */, - 160 /* 0xa0 */, 161 /* 0xa1 */, 162 /* 0xa2 */, 163 /* 0xa3 */, - 164 /* 0xa4 */, 165 /* 0xa5 */, 166 /* 0xa6 */, 167 /* 0xa7 */, - 168 /* 0xa8 */, 169 /* 0xa9 */, 170 /* 0xaa */, 171 /* 0xab */, - 172 /* 0xac */, 173 /* 0xad */, 174 /* 0xae */, 175 /* 0xaf */, - 176 /* 0xb0 */, 177 /* 0xb1 */, 178 /* 0xb2 */, 179 /* 0xb3 */, - 180 /* 0xb4 */, 181 /* 0xb5 */, 182 /* 0xb6 */, 183 /* 0xb7 */, - 184 /* 0xb8 */, 185 /* 0xb9 */, 186 /* 0xba */, 187 /* 0xbb */, - 188 /* 0xbc */, 189 /* 0xbd */, 190 /* 0xbe */, 191 /* 0xbf */, - 192 /* 0xc0 */, 193 /* 0xc1 */, 194 /* 0xc2 */, 195 /* 0xc3 */, - 196 /* 0xc4 */, 197 /* 0xc5 */, 198 /* 0xc6 */, 199 /* 0xc7 */, - 200 /* 0xc8 */, 201 /* 0xc9 */, 202 /* 0xca */, 203 /* 0xcb */, - 204 /* 0xcc */, 205 /* 0xcd */, 206 /* 0xce */, 207 /* 0xcf */, - 208 /* 0xd0 */, 209 /* 0xd1 */, 210 /* 0xd2 */, 211 /* 0xd3 */, - 212 /* 0xd4 */, 213 /* 0xd5 */, 214 /* 0xd6 */, 215 /* 0xd7 */, - 216 /* 0xd8 */, 217 /* 0xd9 */, 218 /* 0xda */, 219 /* 0xdb */, - 220 /* 0xdc */, 221 /* 0xdd */, 222 /* 0xde */, 223 /* 0xdf */, - 224 /* 0xe0 */, 225 /* 0xe1 */, 226 /* 0xe2 */, 227 /* 0xe3 */, - 228 /* 0xe4 */, 229 /* 0xe5 */, 230 /* 0xe6 */, 231 /* 0xe7 */, - 232 /* 0xe8 */, 233 /* 0xe9 */, 234 /* 0xea */, 235 /* 0xeb */, - 236 /* 0xec */, 237 /* 0xed */, 238 /* 0xee */, 239 /* 0xef */, - 240 /* 0xf0 */, 241 /* 0xf1 */, 242 /* 0xf2 */, 243 /* 0xf3 */, - 244 /* 0xf4 */, 245 /* 0xf5 */, 246 /* 0xf6 */, 247 /* 0xf7 */, - 248 /* 0xf8 */, 249 /* 0xf9 */, 250 /* 0xfa */, 251 /* 0xfb */, - 252 /* 0xfc */, 253 /* 0xfd */, 254 /* 0xfe */, 255 /* 0xff */, -}; - -void nghttp2_downcase(uint8_t *s, size_t len) { - size_t i; - for (i = 0; i < len; ++i) { - s[i] = DOWNCASE_TBL[s[i]]; - } -} - -/* - * local_window_size - * ^ * - * | * recv_window_size - * | * * ^ - * | * * | - * 0+++++++++ - * | * * \ - * | * * | This rage is hidden in flow control. But it must be - * v * * / kept in order to restore it when window size is enlarged. - * recv_reduction - * (+ for negative direction) - * - * recv_window_size could be negative if we decrease - * local_window_size more than recv_window_size: - * - * local_window_size - * ^ * - * | * - * | * - * 0++++++++ - * | * ^ recv_window_size (negative) - * | * | - * v * * - * recv_reduction - */ -int nghttp2_adjust_local_window_size(int32_t *local_window_size_ptr, - int32_t *recv_window_size_ptr, - int32_t *recv_reduction_ptr, - int32_t *delta_ptr) { - if (*delta_ptr > 0) { - int32_t recv_reduction_delta; - int32_t delta; - int32_t new_recv_window_size = - nghttp2_max_int32(0, *recv_window_size_ptr) - *delta_ptr; - - if (new_recv_window_size >= 0) { - *recv_window_size_ptr = new_recv_window_size; - return 0; - } - - delta = -new_recv_window_size; - - /* The delta size is strictly more than received bytes. Increase - local_window_size by that difference |delta|. */ - if (*local_window_size_ptr > NGHTTP2_MAX_WINDOW_SIZE - delta) { - return NGHTTP2_ERR_FLOW_CONTROL; - } - *local_window_size_ptr += delta; - /* If there is recv_reduction due to earlier window_size - reduction, we have to adjust it too. */ - recv_reduction_delta = nghttp2_min_int32(*recv_reduction_ptr, delta); - *recv_reduction_ptr -= recv_reduction_delta; - if (*recv_window_size_ptr < 0) { - *recv_window_size_ptr += recv_reduction_delta; - } else { - /* If *recv_window_size_ptr > 0, then those bytes are going to - be returned to the remote peer (by WINDOW_UPDATE with the - adjusted *delta_ptr), so it is effectively 0 now. We set to - *recv_reduction_delta, because caller does not take into - account it in *delta_ptr. */ - *recv_window_size_ptr = recv_reduction_delta; - } - /* recv_reduction_delta must be paid from *delta_ptr, since it was - added in window size reduction (see below). */ - *delta_ptr -= recv_reduction_delta; - - return 0; - } - - if (*local_window_size_ptr + *delta_ptr < 0 || - *recv_window_size_ptr < INT32_MIN - *delta_ptr || - *recv_reduction_ptr > INT32_MAX + *delta_ptr) { - return NGHTTP2_ERR_FLOW_CONTROL; - } - /* Decreasing local window size. Note that we achieve this without - noticing to the remote peer. To do this, we cut - recv_window_size by -delta. This means that we don't send - WINDOW_UPDATE for -delta bytes. */ - *local_window_size_ptr += *delta_ptr; - *recv_window_size_ptr += *delta_ptr; - *recv_reduction_ptr -= *delta_ptr; - *delta_ptr = 0; - - return 0; -} - -int nghttp2_increase_local_window_size(int32_t *local_window_size_ptr, - int32_t *recv_window_size_ptr, - int32_t *recv_reduction_ptr, - int32_t *delta_ptr) { - int32_t recv_reduction_delta; - int32_t delta; - - delta = *delta_ptr; - - assert(delta >= 0); - - /* The delta size is strictly more than received bytes. Increase - local_window_size by that difference |delta|. */ - if (*local_window_size_ptr > NGHTTP2_MAX_WINDOW_SIZE - delta) { - return NGHTTP2_ERR_FLOW_CONTROL; - } - - *local_window_size_ptr += delta; - /* If there is recv_reduction due to earlier window_size - reduction, we have to adjust it too. */ - recv_reduction_delta = nghttp2_min_int32(*recv_reduction_ptr, delta); - *recv_reduction_ptr -= recv_reduction_delta; - - *recv_window_size_ptr += recv_reduction_delta; - - /* recv_reduction_delta must be paid from *delta_ptr, since it was - added in window size reduction (see below). */ - *delta_ptr -= recv_reduction_delta; - - return 0; -} - -int nghttp2_should_send_window_update(int32_t local_window_size, - int32_t recv_window_size) { - return recv_window_size > 0 && recv_window_size >= local_window_size / 2; -} - -const char *nghttp2_strerror(int error_code) { - switch (error_code) { - case 0: - return "Success"; - case NGHTTP2_ERR_INVALID_ARGUMENT: - return "Invalid argument"; - case NGHTTP2_ERR_BUFFER_ERROR: - return "Out of buffer space"; - case NGHTTP2_ERR_UNSUPPORTED_VERSION: - return "Unsupported SPDY version"; - case NGHTTP2_ERR_WOULDBLOCK: - return "Operation would block"; - case NGHTTP2_ERR_PROTO: - return "Protocol error"; - case NGHTTP2_ERR_INVALID_FRAME: - return "Invalid frame octets"; - case NGHTTP2_ERR_EOF: - return "EOF"; - case NGHTTP2_ERR_DEFERRED: - return "Data transfer deferred"; - case NGHTTP2_ERR_STREAM_ID_NOT_AVAILABLE: - return "No more Stream ID available"; - case NGHTTP2_ERR_STREAM_CLOSED: - return "Stream was already closed or invalid"; - case NGHTTP2_ERR_STREAM_CLOSING: - return "Stream is closing"; - case NGHTTP2_ERR_STREAM_SHUT_WR: - return "The transmission is not allowed for this stream"; - case NGHTTP2_ERR_INVALID_STREAM_ID: - return "Stream ID is invalid"; - case NGHTTP2_ERR_INVALID_STREAM_STATE: - return "Invalid stream state"; - case NGHTTP2_ERR_DEFERRED_DATA_EXIST: - return "Another DATA frame has already been deferred"; - case NGHTTP2_ERR_START_STREAM_NOT_ALLOWED: - return "request HEADERS is not allowed"; - case NGHTTP2_ERR_GOAWAY_ALREADY_SENT: - return "GOAWAY has already been sent"; - case NGHTTP2_ERR_INVALID_HEADER_BLOCK: - return "Invalid header block"; - case NGHTTP2_ERR_INVALID_STATE: - return "Invalid state"; - case NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE: - return "The user callback function failed due to the temporal error"; - case NGHTTP2_ERR_FRAME_SIZE_ERROR: - return "The length of the frame is invalid"; - case NGHTTP2_ERR_HEADER_COMP: - return "Header compression/decompression error"; - case NGHTTP2_ERR_FLOW_CONTROL: - return "Flow control error"; - case NGHTTP2_ERR_INSUFF_BUFSIZE: - return "Insufficient buffer size given to function"; - case NGHTTP2_ERR_PAUSE: - return "Callback was paused by the application"; - case NGHTTP2_ERR_TOO_MANY_INFLIGHT_SETTINGS: - return "Too many inflight SETTINGS"; - case NGHTTP2_ERR_PUSH_DISABLED: - return "Server push is disabled by peer"; - case NGHTTP2_ERR_DATA_EXIST: - return "DATA or HEADERS frame has already been submitted for the stream"; - case NGHTTP2_ERR_SESSION_CLOSING: - return "The current session is closing"; - case NGHTTP2_ERR_HTTP_HEADER: - return "Invalid HTTP header field was received"; - case NGHTTP2_ERR_HTTP_MESSAGING: - return "Violation in HTTP messaging rule"; - case NGHTTP2_ERR_REFUSED_STREAM: - return "Stream was refused"; - case NGHTTP2_ERR_INTERNAL: - return "Internal error"; - case NGHTTP2_ERR_CANCEL: - return "Cancel"; - case NGHTTP2_ERR_SETTINGS_EXPECTED: - return "When a local endpoint expects to receive SETTINGS frame, it " - "receives an other type of frame"; - case NGHTTP2_ERR_NOMEM: - return "Out of memory"; - case NGHTTP2_ERR_CALLBACK_FAILURE: - return "The user callback function failed"; - case NGHTTP2_ERR_BAD_CLIENT_MAGIC: - return "Received bad client magic byte string"; - case NGHTTP2_ERR_FLOODED: - return "Flooding was detected in this HTTP/2 session, and it must be " - "closed"; - case NGHTTP2_ERR_TOO_MANY_SETTINGS: - return "SETTINGS frame contained more than the maximum allowed entries"; - case NGHTTP2_ERR_TOO_MANY_CONTINUATIONS: - return "Too many CONTINUATION frames following a HEADER frame"; - default: - return "Unknown error code"; - } -} - -/* Generated by gennmchartbl.py */ -static const int VALID_HD_NAME_CHARS[] = { - 0 /* NUL */, 0 /* SOH */, 0 /* STX */, 0 /* ETX */, - 0 /* EOT */, 0 /* ENQ */, 0 /* ACK */, 0 /* BEL */, - 0 /* BS */, 0 /* HT */, 0 /* LF */, 0 /* VT */, - 0 /* FF */, 0 /* CR */, 0 /* SO */, 0 /* SI */, - 0 /* DLE */, 0 /* DC1 */, 0 /* DC2 */, 0 /* DC3 */, - 0 /* DC4 */, 0 /* NAK */, 0 /* SYN */, 0 /* ETB */, - 0 /* CAN */, 0 /* EM */, 0 /* SUB */, 0 /* ESC */, - 0 /* FS */, 0 /* GS */, 0 /* RS */, 0 /* US */, - 0 /* SPC */, 1 /* ! */, 0 /* " */, 1 /* # */, - 1 /* $ */, 1 /* % */, 1 /* & */, 1 /* ' */, - 0 /* ( */, 0 /* ) */, 1 /* * */, 1 /* + */, - 0 /* , */, 1 /* - */, 1 /* . */, 0 /* / */, - 1 /* 0 */, 1 /* 1 */, 1 /* 2 */, 1 /* 3 */, - 1 /* 4 */, 1 /* 5 */, 1 /* 6 */, 1 /* 7 */, - 1 /* 8 */, 1 /* 9 */, 0 /* : */, 0 /* ; */, - 0 /* < */, 0 /* = */, 0 /* > */, 0 /* ? */, - 0 /* @ */, 0 /* A */, 0 /* B */, 0 /* C */, - 0 /* D */, 0 /* E */, 0 /* F */, 0 /* G */, - 0 /* H */, 0 /* I */, 0 /* J */, 0 /* K */, - 0 /* L */, 0 /* M */, 0 /* N */, 0 /* O */, - 0 /* P */, 0 /* Q */, 0 /* R */, 0 /* S */, - 0 /* T */, 0 /* U */, 0 /* V */, 0 /* W */, - 0 /* X */, 0 /* Y */, 0 /* Z */, 0 /* [ */, - 0 /* \ */, 0 /* ] */, 1 /* ^ */, 1 /* _ */, - 1 /* ` */, 1 /* a */, 1 /* b */, 1 /* c */, - 1 /* d */, 1 /* e */, 1 /* f */, 1 /* g */, - 1 /* h */, 1 /* i */, 1 /* j */, 1 /* k */, - 1 /* l */, 1 /* m */, 1 /* n */, 1 /* o */, - 1 /* p */, 1 /* q */, 1 /* r */, 1 /* s */, - 1 /* t */, 1 /* u */, 1 /* v */, 1 /* w */, - 1 /* x */, 1 /* y */, 1 /* z */, 0 /* { */, - 1 /* | */, 0 /* } */, 1 /* ~ */, 0 /* DEL */, - 0 /* 0x80 */, 0 /* 0x81 */, 0 /* 0x82 */, 0 /* 0x83 */, - 0 /* 0x84 */, 0 /* 0x85 */, 0 /* 0x86 */, 0 /* 0x87 */, - 0 /* 0x88 */, 0 /* 0x89 */, 0 /* 0x8a */, 0 /* 0x8b */, - 0 /* 0x8c */, 0 /* 0x8d */, 0 /* 0x8e */, 0 /* 0x8f */, - 0 /* 0x90 */, 0 /* 0x91 */, 0 /* 0x92 */, 0 /* 0x93 */, - 0 /* 0x94 */, 0 /* 0x95 */, 0 /* 0x96 */, 0 /* 0x97 */, - 0 /* 0x98 */, 0 /* 0x99 */, 0 /* 0x9a */, 0 /* 0x9b */, - 0 /* 0x9c */, 0 /* 0x9d */, 0 /* 0x9e */, 0 /* 0x9f */, - 0 /* 0xa0 */, 0 /* 0xa1 */, 0 /* 0xa2 */, 0 /* 0xa3 */, - 0 /* 0xa4 */, 0 /* 0xa5 */, 0 /* 0xa6 */, 0 /* 0xa7 */, - 0 /* 0xa8 */, 0 /* 0xa9 */, 0 /* 0xaa */, 0 /* 0xab */, - 0 /* 0xac */, 0 /* 0xad */, 0 /* 0xae */, 0 /* 0xaf */, - 0 /* 0xb0 */, 0 /* 0xb1 */, 0 /* 0xb2 */, 0 /* 0xb3 */, - 0 /* 0xb4 */, 0 /* 0xb5 */, 0 /* 0xb6 */, 0 /* 0xb7 */, - 0 /* 0xb8 */, 0 /* 0xb9 */, 0 /* 0xba */, 0 /* 0xbb */, - 0 /* 0xbc */, 0 /* 0xbd */, 0 /* 0xbe */, 0 /* 0xbf */, - 0 /* 0xc0 */, 0 /* 0xc1 */, 0 /* 0xc2 */, 0 /* 0xc3 */, - 0 /* 0xc4 */, 0 /* 0xc5 */, 0 /* 0xc6 */, 0 /* 0xc7 */, - 0 /* 0xc8 */, 0 /* 0xc9 */, 0 /* 0xca */, 0 /* 0xcb */, - 0 /* 0xcc */, 0 /* 0xcd */, 0 /* 0xce */, 0 /* 0xcf */, - 0 /* 0xd0 */, 0 /* 0xd1 */, 0 /* 0xd2 */, 0 /* 0xd3 */, - 0 /* 0xd4 */, 0 /* 0xd5 */, 0 /* 0xd6 */, 0 /* 0xd7 */, - 0 /* 0xd8 */, 0 /* 0xd9 */, 0 /* 0xda */, 0 /* 0xdb */, - 0 /* 0xdc */, 0 /* 0xdd */, 0 /* 0xde */, 0 /* 0xdf */, - 0 /* 0xe0 */, 0 /* 0xe1 */, 0 /* 0xe2 */, 0 /* 0xe3 */, - 0 /* 0xe4 */, 0 /* 0xe5 */, 0 /* 0xe6 */, 0 /* 0xe7 */, - 0 /* 0xe8 */, 0 /* 0xe9 */, 0 /* 0xea */, 0 /* 0xeb */, - 0 /* 0xec */, 0 /* 0xed */, 0 /* 0xee */, 0 /* 0xef */, - 0 /* 0xf0 */, 0 /* 0xf1 */, 0 /* 0xf2 */, 0 /* 0xf3 */, - 0 /* 0xf4 */, 0 /* 0xf5 */, 0 /* 0xf6 */, 0 /* 0xf7 */, - 0 /* 0xf8 */, 0 /* 0xf9 */, 0 /* 0xfa */, 0 /* 0xfb */, - 0 /* 0xfc */, 0 /* 0xfd */, 0 /* 0xfe */, 0 /* 0xff */ -}; - -int nghttp2_check_header_name(const uint8_t *name, size_t len) { - const uint8_t *last; - if (len == 0) { - return 0; - } - if (*name == ':') { - if (len == 1) { - return 0; - } - ++name; - --len; - } - for (last = name + len; name != last; ++name) { - if (!VALID_HD_NAME_CHARS[*name]) { - return 0; - } - } - return 1; -} - -/* Generated by genvchartbl.py */ -static const int VALID_HD_VALUE_CHARS[] = { - 0 /* NUL */, 0 /* SOH */, 0 /* STX */, 0 /* ETX */, - 0 /* EOT */, 0 /* ENQ */, 0 /* ACK */, 0 /* BEL */, - 0 /* BS */, 1 /* HT */, 0 /* LF */, 0 /* VT */, - 0 /* FF */, 0 /* CR */, 0 /* SO */, 0 /* SI */, - 0 /* DLE */, 0 /* DC1 */, 0 /* DC2 */, 0 /* DC3 */, - 0 /* DC4 */, 0 /* NAK */, 0 /* SYN */, 0 /* ETB */, - 0 /* CAN */, 0 /* EM */, 0 /* SUB */, 0 /* ESC */, - 0 /* FS */, 0 /* GS */, 0 /* RS */, 0 /* US */, - 1 /* SPC */, 1 /* ! */, 1 /* " */, 1 /* # */, - 1 /* $ */, 1 /* % */, 1 /* & */, 1 /* ' */, - 1 /* ( */, 1 /* ) */, 1 /* * */, 1 /* + */, - 1 /* , */, 1 /* - */, 1 /* . */, 1 /* / */, - 1 /* 0 */, 1 /* 1 */, 1 /* 2 */, 1 /* 3 */, - 1 /* 4 */, 1 /* 5 */, 1 /* 6 */, 1 /* 7 */, - 1 /* 8 */, 1 /* 9 */, 1 /* : */, 1 /* ; */, - 1 /* < */, 1 /* = */, 1 /* > */, 1 /* ? */, - 1 /* @ */, 1 /* A */, 1 /* B */, 1 /* C */, - 1 /* D */, 1 /* E */, 1 /* F */, 1 /* G */, - 1 /* H */, 1 /* I */, 1 /* J */, 1 /* K */, - 1 /* L */, 1 /* M */, 1 /* N */, 1 /* O */, - 1 /* P */, 1 /* Q */, 1 /* R */, 1 /* S */, - 1 /* T */, 1 /* U */, 1 /* V */, 1 /* W */, - 1 /* X */, 1 /* Y */, 1 /* Z */, 1 /* [ */, - 1 /* \ */, 1 /* ] */, 1 /* ^ */, 1 /* _ */, - 1 /* ` */, 1 /* a */, 1 /* b */, 1 /* c */, - 1 /* d */, 1 /* e */, 1 /* f */, 1 /* g */, - 1 /* h */, 1 /* i */, 1 /* j */, 1 /* k */, - 1 /* l */, 1 /* m */, 1 /* n */, 1 /* o */, - 1 /* p */, 1 /* q */, 1 /* r */, 1 /* s */, - 1 /* t */, 1 /* u */, 1 /* v */, 1 /* w */, - 1 /* x */, 1 /* y */, 1 /* z */, 1 /* { */, - 1 /* | */, 1 /* } */, 1 /* ~ */, 0 /* DEL */, - 1 /* 0x80 */, 1 /* 0x81 */, 1 /* 0x82 */, 1 /* 0x83 */, - 1 /* 0x84 */, 1 /* 0x85 */, 1 /* 0x86 */, 1 /* 0x87 */, - 1 /* 0x88 */, 1 /* 0x89 */, 1 /* 0x8a */, 1 /* 0x8b */, - 1 /* 0x8c */, 1 /* 0x8d */, 1 /* 0x8e */, 1 /* 0x8f */, - 1 /* 0x90 */, 1 /* 0x91 */, 1 /* 0x92 */, 1 /* 0x93 */, - 1 /* 0x94 */, 1 /* 0x95 */, 1 /* 0x96 */, 1 /* 0x97 */, - 1 /* 0x98 */, 1 /* 0x99 */, 1 /* 0x9a */, 1 /* 0x9b */, - 1 /* 0x9c */, 1 /* 0x9d */, 1 /* 0x9e */, 1 /* 0x9f */, - 1 /* 0xa0 */, 1 /* 0xa1 */, 1 /* 0xa2 */, 1 /* 0xa3 */, - 1 /* 0xa4 */, 1 /* 0xa5 */, 1 /* 0xa6 */, 1 /* 0xa7 */, - 1 /* 0xa8 */, 1 /* 0xa9 */, 1 /* 0xaa */, 1 /* 0xab */, - 1 /* 0xac */, 1 /* 0xad */, 1 /* 0xae */, 1 /* 0xaf */, - 1 /* 0xb0 */, 1 /* 0xb1 */, 1 /* 0xb2 */, 1 /* 0xb3 */, - 1 /* 0xb4 */, 1 /* 0xb5 */, 1 /* 0xb6 */, 1 /* 0xb7 */, - 1 /* 0xb8 */, 1 /* 0xb9 */, 1 /* 0xba */, 1 /* 0xbb */, - 1 /* 0xbc */, 1 /* 0xbd */, 1 /* 0xbe */, 1 /* 0xbf */, - 1 /* 0xc0 */, 1 /* 0xc1 */, 1 /* 0xc2 */, 1 /* 0xc3 */, - 1 /* 0xc4 */, 1 /* 0xc5 */, 1 /* 0xc6 */, 1 /* 0xc7 */, - 1 /* 0xc8 */, 1 /* 0xc9 */, 1 /* 0xca */, 1 /* 0xcb */, - 1 /* 0xcc */, 1 /* 0xcd */, 1 /* 0xce */, 1 /* 0xcf */, - 1 /* 0xd0 */, 1 /* 0xd1 */, 1 /* 0xd2 */, 1 /* 0xd3 */, - 1 /* 0xd4 */, 1 /* 0xd5 */, 1 /* 0xd6 */, 1 /* 0xd7 */, - 1 /* 0xd8 */, 1 /* 0xd9 */, 1 /* 0xda */, 1 /* 0xdb */, - 1 /* 0xdc */, 1 /* 0xdd */, 1 /* 0xde */, 1 /* 0xdf */, - 1 /* 0xe0 */, 1 /* 0xe1 */, 1 /* 0xe2 */, 1 /* 0xe3 */, - 1 /* 0xe4 */, 1 /* 0xe5 */, 1 /* 0xe6 */, 1 /* 0xe7 */, - 1 /* 0xe8 */, 1 /* 0xe9 */, 1 /* 0xea */, 1 /* 0xeb */, - 1 /* 0xec */, 1 /* 0xed */, 1 /* 0xee */, 1 /* 0xef */, - 1 /* 0xf0 */, 1 /* 0xf1 */, 1 /* 0xf2 */, 1 /* 0xf3 */, - 1 /* 0xf4 */, 1 /* 0xf5 */, 1 /* 0xf6 */, 1 /* 0xf7 */, - 1 /* 0xf8 */, 1 /* 0xf9 */, 1 /* 0xfa */, 1 /* 0xfb */, - 1 /* 0xfc */, 1 /* 0xfd */, 1 /* 0xfe */, 1 /* 0xff */ -}; - -int nghttp2_check_header_value(const uint8_t *value, size_t len) { - const uint8_t *last; - for (last = value + len; value != last; ++value) { - if (!VALID_HD_VALUE_CHARS[*value]) { - return 0; - } - } - return 1; -} - -int nghttp2_check_header_value_rfc9113(const uint8_t *value, size_t len) { - if (len == 0) { - return 1; - } - - if (*value == ' ' || *value == '\t' || *(value + len - 1) == ' ' || - *(value + len - 1) == '\t') { - return 0; - } - - return nghttp2_check_header_value(value, len); -} - -/* Generated by genmethodchartbl.py */ -static char VALID_METHOD_CHARS[] = { - 0 /* NUL */, 0 /* SOH */, 0 /* STX */, 0 /* ETX */, - 0 /* EOT */, 0 /* ENQ */, 0 /* ACK */, 0 /* BEL */, - 0 /* BS */, 0 /* HT */, 0 /* LF */, 0 /* VT */, - 0 /* FF */, 0 /* CR */, 0 /* SO */, 0 /* SI */, - 0 /* DLE */, 0 /* DC1 */, 0 /* DC2 */, 0 /* DC3 */, - 0 /* DC4 */, 0 /* NAK */, 0 /* SYN */, 0 /* ETB */, - 0 /* CAN */, 0 /* EM */, 0 /* SUB */, 0 /* ESC */, - 0 /* FS */, 0 /* GS */, 0 /* RS */, 0 /* US */, - 0 /* SPC */, 1 /* ! */, 0 /* " */, 1 /* # */, - 1 /* $ */, 1 /* % */, 1 /* & */, 1 /* ' */, - 0 /* ( */, 0 /* ) */, 1 /* * */, 1 /* + */, - 0 /* , */, 1 /* - */, 1 /* . */, 0 /* / */, - 1 /* 0 */, 1 /* 1 */, 1 /* 2 */, 1 /* 3 */, - 1 /* 4 */, 1 /* 5 */, 1 /* 6 */, 1 /* 7 */, - 1 /* 8 */, 1 /* 9 */, 0 /* : */, 0 /* ; */, - 0 /* < */, 0 /* = */, 0 /* > */, 0 /* ? */, - 0 /* @ */, 1 /* A */, 1 /* B */, 1 /* C */, - 1 /* D */, 1 /* E */, 1 /* F */, 1 /* G */, - 1 /* H */, 1 /* I */, 1 /* J */, 1 /* K */, - 1 /* L */, 1 /* M */, 1 /* N */, 1 /* O */, - 1 /* P */, 1 /* Q */, 1 /* R */, 1 /* S */, - 1 /* T */, 1 /* U */, 1 /* V */, 1 /* W */, - 1 /* X */, 1 /* Y */, 1 /* Z */, 0 /* [ */, - 0 /* \ */, 0 /* ] */, 1 /* ^ */, 1 /* _ */, - 1 /* ` */, 1 /* a */, 1 /* b */, 1 /* c */, - 1 /* d */, 1 /* e */, 1 /* f */, 1 /* g */, - 1 /* h */, 1 /* i */, 1 /* j */, 1 /* k */, - 1 /* l */, 1 /* m */, 1 /* n */, 1 /* o */, - 1 /* p */, 1 /* q */, 1 /* r */, 1 /* s */, - 1 /* t */, 1 /* u */, 1 /* v */, 1 /* w */, - 1 /* x */, 1 /* y */, 1 /* z */, 0 /* { */, - 1 /* | */, 0 /* } */, 1 /* ~ */, 0 /* DEL */, - 0 /* 0x80 */, 0 /* 0x81 */, 0 /* 0x82 */, 0 /* 0x83 */, - 0 /* 0x84 */, 0 /* 0x85 */, 0 /* 0x86 */, 0 /* 0x87 */, - 0 /* 0x88 */, 0 /* 0x89 */, 0 /* 0x8a */, 0 /* 0x8b */, - 0 /* 0x8c */, 0 /* 0x8d */, 0 /* 0x8e */, 0 /* 0x8f */, - 0 /* 0x90 */, 0 /* 0x91 */, 0 /* 0x92 */, 0 /* 0x93 */, - 0 /* 0x94 */, 0 /* 0x95 */, 0 /* 0x96 */, 0 /* 0x97 */, - 0 /* 0x98 */, 0 /* 0x99 */, 0 /* 0x9a */, 0 /* 0x9b */, - 0 /* 0x9c */, 0 /* 0x9d */, 0 /* 0x9e */, 0 /* 0x9f */, - 0 /* 0xa0 */, 0 /* 0xa1 */, 0 /* 0xa2 */, 0 /* 0xa3 */, - 0 /* 0xa4 */, 0 /* 0xa5 */, 0 /* 0xa6 */, 0 /* 0xa7 */, - 0 /* 0xa8 */, 0 /* 0xa9 */, 0 /* 0xaa */, 0 /* 0xab */, - 0 /* 0xac */, 0 /* 0xad */, 0 /* 0xae */, 0 /* 0xaf */, - 0 /* 0xb0 */, 0 /* 0xb1 */, 0 /* 0xb2 */, 0 /* 0xb3 */, - 0 /* 0xb4 */, 0 /* 0xb5 */, 0 /* 0xb6 */, 0 /* 0xb7 */, - 0 /* 0xb8 */, 0 /* 0xb9 */, 0 /* 0xba */, 0 /* 0xbb */, - 0 /* 0xbc */, 0 /* 0xbd */, 0 /* 0xbe */, 0 /* 0xbf */, - 0 /* 0xc0 */, 0 /* 0xc1 */, 0 /* 0xc2 */, 0 /* 0xc3 */, - 0 /* 0xc4 */, 0 /* 0xc5 */, 0 /* 0xc6 */, 0 /* 0xc7 */, - 0 /* 0xc8 */, 0 /* 0xc9 */, 0 /* 0xca */, 0 /* 0xcb */, - 0 /* 0xcc */, 0 /* 0xcd */, 0 /* 0xce */, 0 /* 0xcf */, - 0 /* 0xd0 */, 0 /* 0xd1 */, 0 /* 0xd2 */, 0 /* 0xd3 */, - 0 /* 0xd4 */, 0 /* 0xd5 */, 0 /* 0xd6 */, 0 /* 0xd7 */, - 0 /* 0xd8 */, 0 /* 0xd9 */, 0 /* 0xda */, 0 /* 0xdb */, - 0 /* 0xdc */, 0 /* 0xdd */, 0 /* 0xde */, 0 /* 0xdf */, - 0 /* 0xe0 */, 0 /* 0xe1 */, 0 /* 0xe2 */, 0 /* 0xe3 */, - 0 /* 0xe4 */, 0 /* 0xe5 */, 0 /* 0xe6 */, 0 /* 0xe7 */, - 0 /* 0xe8 */, 0 /* 0xe9 */, 0 /* 0xea */, 0 /* 0xeb */, - 0 /* 0xec */, 0 /* 0xed */, 0 /* 0xee */, 0 /* 0xef */, - 0 /* 0xf0 */, 0 /* 0xf1 */, 0 /* 0xf2 */, 0 /* 0xf3 */, - 0 /* 0xf4 */, 0 /* 0xf5 */, 0 /* 0xf6 */, 0 /* 0xf7 */, - 0 /* 0xf8 */, 0 /* 0xf9 */, 0 /* 0xfa */, 0 /* 0xfb */, - 0 /* 0xfc */, 0 /* 0xfd */, 0 /* 0xfe */, 0 /* 0xff */ -}; - -int nghttp2_check_method(const uint8_t *value, size_t len) { - const uint8_t *last; - if (len == 0) { - return 0; - } - for (last = value + len; value != last; ++value) { - if (!VALID_METHOD_CHARS[*value]) { - return 0; - } - } - return 1; -} - -/* Generated by genpathchartbl.py */ -static char VALID_PATH_CHARS[] = { - 0 /* NUL */, 0 /* SOH */, 0 /* STX */, 0 /* ETX */, - 0 /* EOT */, 0 /* ENQ */, 0 /* ACK */, 0 /* BEL */, - 0 /* BS */, 0 /* HT */, 0 /* LF */, 0 /* VT */, - 0 /* FF */, 0 /* CR */, 0 /* SO */, 0 /* SI */, - 0 /* DLE */, 0 /* DC1 */, 0 /* DC2 */, 0 /* DC3 */, - 0 /* DC4 */, 0 /* NAK */, 0 /* SYN */, 0 /* ETB */, - 0 /* CAN */, 0 /* EM */, 0 /* SUB */, 0 /* ESC */, - 0 /* FS */, 0 /* GS */, 0 /* RS */, 0 /* US */, - 0 /* SPC */, 1 /* ! */, 1 /* " */, 1 /* # */, - 1 /* $ */, 1 /* % */, 1 /* & */, 1 /* ' */, - 1 /* ( */, 1 /* ) */, 1 /* * */, 1 /* + */, - 1 /* , */, 1 /* - */, 1 /* . */, 1 /* / */, - 1 /* 0 */, 1 /* 1 */, 1 /* 2 */, 1 /* 3 */, - 1 /* 4 */, 1 /* 5 */, 1 /* 6 */, 1 /* 7 */, - 1 /* 8 */, 1 /* 9 */, 1 /* : */, 1 /* ; */, - 1 /* < */, 1 /* = */, 1 /* > */, 1 /* ? */, - 1 /* @ */, 1 /* A */, 1 /* B */, 1 /* C */, - 1 /* D */, 1 /* E */, 1 /* F */, 1 /* G */, - 1 /* H */, 1 /* I */, 1 /* J */, 1 /* K */, - 1 /* L */, 1 /* M */, 1 /* N */, 1 /* O */, - 1 /* P */, 1 /* Q */, 1 /* R */, 1 /* S */, - 1 /* T */, 1 /* U */, 1 /* V */, 1 /* W */, - 1 /* X */, 1 /* Y */, 1 /* Z */, 1 /* [ */, - 1 /* \ */, 1 /* ] */, 1 /* ^ */, 1 /* _ */, - 1 /* ` */, 1 /* a */, 1 /* b */, 1 /* c */, - 1 /* d */, 1 /* e */, 1 /* f */, 1 /* g */, - 1 /* h */, 1 /* i */, 1 /* j */, 1 /* k */, - 1 /* l */, 1 /* m */, 1 /* n */, 1 /* o */, - 1 /* p */, 1 /* q */, 1 /* r */, 1 /* s */, - 1 /* t */, 1 /* u */, 1 /* v */, 1 /* w */, - 1 /* x */, 1 /* y */, 1 /* z */, 1 /* { */, - 1 /* | */, 1 /* } */, 1 /* ~ */, 0 /* DEL */, - 1 /* 0x80 */, 1 /* 0x81 */, 1 /* 0x82 */, 1 /* 0x83 */, - 1 /* 0x84 */, 1 /* 0x85 */, 1 /* 0x86 */, 1 /* 0x87 */, - 1 /* 0x88 */, 1 /* 0x89 */, 1 /* 0x8a */, 1 /* 0x8b */, - 1 /* 0x8c */, 1 /* 0x8d */, 1 /* 0x8e */, 1 /* 0x8f */, - 1 /* 0x90 */, 1 /* 0x91 */, 1 /* 0x92 */, 1 /* 0x93 */, - 1 /* 0x94 */, 1 /* 0x95 */, 1 /* 0x96 */, 1 /* 0x97 */, - 1 /* 0x98 */, 1 /* 0x99 */, 1 /* 0x9a */, 1 /* 0x9b */, - 1 /* 0x9c */, 1 /* 0x9d */, 1 /* 0x9e */, 1 /* 0x9f */, - 1 /* 0xa0 */, 1 /* 0xa1 */, 1 /* 0xa2 */, 1 /* 0xa3 */, - 1 /* 0xa4 */, 1 /* 0xa5 */, 1 /* 0xa6 */, 1 /* 0xa7 */, - 1 /* 0xa8 */, 1 /* 0xa9 */, 1 /* 0xaa */, 1 /* 0xab */, - 1 /* 0xac */, 1 /* 0xad */, 1 /* 0xae */, 1 /* 0xaf */, - 1 /* 0xb0 */, 1 /* 0xb1 */, 1 /* 0xb2 */, 1 /* 0xb3 */, - 1 /* 0xb4 */, 1 /* 0xb5 */, 1 /* 0xb6 */, 1 /* 0xb7 */, - 1 /* 0xb8 */, 1 /* 0xb9 */, 1 /* 0xba */, 1 /* 0xbb */, - 1 /* 0xbc */, 1 /* 0xbd */, 1 /* 0xbe */, 1 /* 0xbf */, - 1 /* 0xc0 */, 1 /* 0xc1 */, 1 /* 0xc2 */, 1 /* 0xc3 */, - 1 /* 0xc4 */, 1 /* 0xc5 */, 1 /* 0xc6 */, 1 /* 0xc7 */, - 1 /* 0xc8 */, 1 /* 0xc9 */, 1 /* 0xca */, 1 /* 0xcb */, - 1 /* 0xcc */, 1 /* 0xcd */, 1 /* 0xce */, 1 /* 0xcf */, - 1 /* 0xd0 */, 1 /* 0xd1 */, 1 /* 0xd2 */, 1 /* 0xd3 */, - 1 /* 0xd4 */, 1 /* 0xd5 */, 1 /* 0xd6 */, 1 /* 0xd7 */, - 1 /* 0xd8 */, 1 /* 0xd9 */, 1 /* 0xda */, 1 /* 0xdb */, - 1 /* 0xdc */, 1 /* 0xdd */, 1 /* 0xde */, 1 /* 0xdf */, - 1 /* 0xe0 */, 1 /* 0xe1 */, 1 /* 0xe2 */, 1 /* 0xe3 */, - 1 /* 0xe4 */, 1 /* 0xe5 */, 1 /* 0xe6 */, 1 /* 0xe7 */, - 1 /* 0xe8 */, 1 /* 0xe9 */, 1 /* 0xea */, 1 /* 0xeb */, - 1 /* 0xec */, 1 /* 0xed */, 1 /* 0xee */, 1 /* 0xef */, - 1 /* 0xf0 */, 1 /* 0xf1 */, 1 /* 0xf2 */, 1 /* 0xf3 */, - 1 /* 0xf4 */, 1 /* 0xf5 */, 1 /* 0xf6 */, 1 /* 0xf7 */, - 1 /* 0xf8 */, 1 /* 0xf9 */, 1 /* 0xfa */, 1 /* 0xfb */, - 1 /* 0xfc */, 1 /* 0xfd */, 1 /* 0xfe */, 1 /* 0xff */ -}; - -int nghttp2_check_path(const uint8_t *value, size_t len) { - const uint8_t *last; - for (last = value + len; value != last; ++value) { - if (!VALID_PATH_CHARS[*value]) { - return 0; - } - } - return 1; -} - -/* Generated by genauthoritychartbl.py */ -static char VALID_AUTHORITY_CHARS[] = { - 0 /* NUL */, 0 /* SOH */, 0 /* STX */, 0 /* ETX */, - 0 /* EOT */, 0 /* ENQ */, 0 /* ACK */, 0 /* BEL */, - 0 /* BS */, 0 /* HT */, 0 /* LF */, 0 /* VT */, - 0 /* FF */, 0 /* CR */, 0 /* SO */, 0 /* SI */, - 0 /* DLE */, 0 /* DC1 */, 0 /* DC2 */, 0 /* DC3 */, - 0 /* DC4 */, 0 /* NAK */, 0 /* SYN */, 0 /* ETB */, - 0 /* CAN */, 0 /* EM */, 0 /* SUB */, 0 /* ESC */, - 0 /* FS */, 0 /* GS */, 0 /* RS */, 0 /* US */, - 0 /* SPC */, 1 /* ! */, 0 /* " */, 0 /* # */, - 1 /* $ */, 1 /* % */, 1 /* & */, 1 /* ' */, - 1 /* ( */, 1 /* ) */, 1 /* * */, 1 /* + */, - 1 /* , */, 1 /* - */, 1 /* . */, 0 /* / */, - 1 /* 0 */, 1 /* 1 */, 1 /* 2 */, 1 /* 3 */, - 1 /* 4 */, 1 /* 5 */, 1 /* 6 */, 1 /* 7 */, - 1 /* 8 */, 1 /* 9 */, 1 /* : */, 1 /* ; */, - 0 /* < */, 1 /* = */, 0 /* > */, 0 /* ? */, - 1 /* @ */, 1 /* A */, 1 /* B */, 1 /* C */, - 1 /* D */, 1 /* E */, 1 /* F */, 1 /* G */, - 1 /* H */, 1 /* I */, 1 /* J */, 1 /* K */, - 1 /* L */, 1 /* M */, 1 /* N */, 1 /* O */, - 1 /* P */, 1 /* Q */, 1 /* R */, 1 /* S */, - 1 /* T */, 1 /* U */, 1 /* V */, 1 /* W */, - 1 /* X */, 1 /* Y */, 1 /* Z */, 1 /* [ */, - 0 /* \ */, 1 /* ] */, 0 /* ^ */, 1 /* _ */, - 0 /* ` */, 1 /* a */, 1 /* b */, 1 /* c */, - 1 /* d */, 1 /* e */, 1 /* f */, 1 /* g */, - 1 /* h */, 1 /* i */, 1 /* j */, 1 /* k */, - 1 /* l */, 1 /* m */, 1 /* n */, 1 /* o */, - 1 /* p */, 1 /* q */, 1 /* r */, 1 /* s */, - 1 /* t */, 1 /* u */, 1 /* v */, 1 /* w */, - 1 /* x */, 1 /* y */, 1 /* z */, 0 /* { */, - 0 /* | */, 0 /* } */, 1 /* ~ */, 0 /* DEL */, - 0 /* 0x80 */, 0 /* 0x81 */, 0 /* 0x82 */, 0 /* 0x83 */, - 0 /* 0x84 */, 0 /* 0x85 */, 0 /* 0x86 */, 0 /* 0x87 */, - 0 /* 0x88 */, 0 /* 0x89 */, 0 /* 0x8a */, 0 /* 0x8b */, - 0 /* 0x8c */, 0 /* 0x8d */, 0 /* 0x8e */, 0 /* 0x8f */, - 0 /* 0x90 */, 0 /* 0x91 */, 0 /* 0x92 */, 0 /* 0x93 */, - 0 /* 0x94 */, 0 /* 0x95 */, 0 /* 0x96 */, 0 /* 0x97 */, - 0 /* 0x98 */, 0 /* 0x99 */, 0 /* 0x9a */, 0 /* 0x9b */, - 0 /* 0x9c */, 0 /* 0x9d */, 0 /* 0x9e */, 0 /* 0x9f */, - 0 /* 0xa0 */, 0 /* 0xa1 */, 0 /* 0xa2 */, 0 /* 0xa3 */, - 0 /* 0xa4 */, 0 /* 0xa5 */, 0 /* 0xa6 */, 0 /* 0xa7 */, - 0 /* 0xa8 */, 0 /* 0xa9 */, 0 /* 0xaa */, 0 /* 0xab */, - 0 /* 0xac */, 0 /* 0xad */, 0 /* 0xae */, 0 /* 0xaf */, - 0 /* 0xb0 */, 0 /* 0xb1 */, 0 /* 0xb2 */, 0 /* 0xb3 */, - 0 /* 0xb4 */, 0 /* 0xb5 */, 0 /* 0xb6 */, 0 /* 0xb7 */, - 0 /* 0xb8 */, 0 /* 0xb9 */, 0 /* 0xba */, 0 /* 0xbb */, - 0 /* 0xbc */, 0 /* 0xbd */, 0 /* 0xbe */, 0 /* 0xbf */, - 0 /* 0xc0 */, 0 /* 0xc1 */, 0 /* 0xc2 */, 0 /* 0xc3 */, - 0 /* 0xc4 */, 0 /* 0xc5 */, 0 /* 0xc6 */, 0 /* 0xc7 */, - 0 /* 0xc8 */, 0 /* 0xc9 */, 0 /* 0xca */, 0 /* 0xcb */, - 0 /* 0xcc */, 0 /* 0xcd */, 0 /* 0xce */, 0 /* 0xcf */, - 0 /* 0xd0 */, 0 /* 0xd1 */, 0 /* 0xd2 */, 0 /* 0xd3 */, - 0 /* 0xd4 */, 0 /* 0xd5 */, 0 /* 0xd6 */, 0 /* 0xd7 */, - 0 /* 0xd8 */, 0 /* 0xd9 */, 0 /* 0xda */, 0 /* 0xdb */, - 0 /* 0xdc */, 0 /* 0xdd */, 0 /* 0xde */, 0 /* 0xdf */, - 0 /* 0xe0 */, 0 /* 0xe1 */, 0 /* 0xe2 */, 0 /* 0xe3 */, - 0 /* 0xe4 */, 0 /* 0xe5 */, 0 /* 0xe6 */, 0 /* 0xe7 */, - 0 /* 0xe8 */, 0 /* 0xe9 */, 0 /* 0xea */, 0 /* 0xeb */, - 0 /* 0xec */, 0 /* 0xed */, 0 /* 0xee */, 0 /* 0xef */, - 0 /* 0xf0 */, 0 /* 0xf1 */, 0 /* 0xf2 */, 0 /* 0xf3 */, - 0 /* 0xf4 */, 0 /* 0xf5 */, 0 /* 0xf6 */, 0 /* 0xf7 */, - 0 /* 0xf8 */, 0 /* 0xf9 */, 0 /* 0xfa */, 0 /* 0xfb */, - 0 /* 0xfc */, 0 /* 0xfd */, 0 /* 0xfe */, 0 /* 0xff */ -}; - -int nghttp2_check_authority(const uint8_t *value, size_t len) { - const uint8_t *last; - for (last = value + len; value != last; ++value) { - if (!VALID_AUTHORITY_CHARS[*value]) { - return 0; - } - } - return 1; -} - -uint8_t *nghttp2_cpymem(uint8_t *dest, const void *src, size_t len) { - if (len == 0) { - return dest; - } - - memcpy(dest, src, len); - - return dest + len; -} - -const char *nghttp2_http2_strerror(uint32_t error_code) { - switch (error_code) { - case NGHTTP2_NO_ERROR: - return "NO_ERROR"; - case NGHTTP2_PROTOCOL_ERROR: - return "PROTOCOL_ERROR"; - case NGHTTP2_INTERNAL_ERROR: - return "INTERNAL_ERROR"; - case NGHTTP2_FLOW_CONTROL_ERROR: - return "FLOW_CONTROL_ERROR"; - case NGHTTP2_SETTINGS_TIMEOUT: - return "SETTINGS_TIMEOUT"; - case NGHTTP2_STREAM_CLOSED: - return "STREAM_CLOSED"; - case NGHTTP2_FRAME_SIZE_ERROR: - return "FRAME_SIZE_ERROR"; - case NGHTTP2_REFUSED_STREAM: - return "REFUSED_STREAM"; - case NGHTTP2_CANCEL: - return "CANCEL"; - case NGHTTP2_COMPRESSION_ERROR: - return "COMPRESSION_ERROR"; - case NGHTTP2_CONNECT_ERROR: - return "CONNECT_ERROR"; - case NGHTTP2_ENHANCE_YOUR_CALM: - return "ENHANCE_YOUR_CALM"; - case NGHTTP2_INADEQUATE_SECURITY: - return "INADEQUATE_SECURITY"; - case NGHTTP2_HTTP_1_1_REQUIRED: - return "HTTP_1_1_REQUIRED"; - default: - return "unknown"; - } -} diff --git a/3rdparty/exported/nghttp2/nghttp2_helper.h b/3rdparty/exported/nghttp2/nghttp2_helper.h deleted file mode 100644 index f5de6290dab0..000000000000 --- a/3rdparty/exported/nghttp2/nghttp2_helper.h +++ /dev/null @@ -1,145 +0,0 @@ -/* - * nghttp2 - HTTP/2 C Library - * - * Copyright (c) 2012 Tatsuhiro Tsujikawa - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE - * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION - * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION - * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ -#ifndef NGHTTP2_HELPER_H -#define NGHTTP2_HELPER_H - -#ifdef HAVE_CONFIG_H -# include -#endif /* HAVE_CONFIG_H */ - -#include -#include - -#include -#include "nghttp2_mem.h" - -#define nghttp2_max_def(SUFFIX, T) \ - static inline T nghttp2_max_##SUFFIX(T a, T b) { return a < b ? b : a; } - -nghttp2_max_def(int8, int8_t) -nghttp2_max_def(int16, int16_t) -nghttp2_max_def(int32, int32_t) -nghttp2_max_def(int64, int64_t) -nghttp2_max_def(uint8, uint8_t) -nghttp2_max_def(uint16, uint16_t) -nghttp2_max_def(uint32, uint32_t) -nghttp2_max_def(uint64, uint64_t) -nghttp2_max_def(size, size_t) - -#define nghttp2_min_def(SUFFIX, T) \ - static inline T nghttp2_min_##SUFFIX(T a, T b) { return a < b ? a : b; } - -nghttp2_min_def(int8, int8_t) -nghttp2_min_def(int16, int16_t) -nghttp2_min_def(int32, int32_t) -nghttp2_min_def(int64, int64_t) -nghttp2_min_def(uint8, uint8_t) -nghttp2_min_def(uint16, uint16_t) -nghttp2_min_def(uint32, uint32_t) -nghttp2_min_def(uint64, uint64_t) -nghttp2_min_def(size, size_t) - -#define lstreq(A, B, N) ((sizeof((A)) - 1) == (N) && memcmp((A), (B), (N)) == 0) - -#define nghttp2_struct_of(ptr, type, member) \ - ((type *)(void *)((char *)(ptr) - offsetof(type, member))) - -/* - * Copies 2 byte unsigned integer |n| in host byte order to |buf| in - * network byte order. - */ -void nghttp2_put_uint16be(uint8_t *buf, uint16_t n); - -/* - * Copies 4 byte unsigned integer |n| in host byte order to |buf| in - * network byte order. - */ -void nghttp2_put_uint32be(uint8_t *buf, uint32_t n); - -/* - * Retrieves 2 byte unsigned integer stored in |data| in network byte - * order and returns it in host byte order. - */ -uint16_t nghttp2_get_uint16(const uint8_t *data); - -/* - * Retrieves 4 byte unsigned integer stored in |data| in network byte - * order and returns it in host byte order. - */ -uint32_t nghttp2_get_uint32(const uint8_t *data); - -void nghttp2_downcase(uint8_t *s, size_t len); - -/* - * Adjusts |*local_window_size_ptr|, |*recv_window_size_ptr|, - * |*recv_reduction_ptr| with |*delta_ptr| which is the - * WINDOW_UPDATE's window_size_increment sent from local side. If - * |delta| is strictly larger than |*recv_window_size_ptr|, - * |*local_window_size_ptr| is increased by delta - - * *recv_window_size_ptr. If |delta| is negative, - * |*local_window_size_ptr| is decreased by delta. - * - * This function returns 0 if it succeeds, or one of the following - * negative error codes: - * - * NGHTTP2_ERR_FLOW_CONTROL - * local_window_size overflow or gets negative. - */ -int nghttp2_adjust_local_window_size(int32_t *local_window_size_ptr, - int32_t *recv_window_size_ptr, - int32_t *recv_reduction_ptr, - int32_t *delta_ptr); - -/* - * This function works like nghttp2_adjust_local_window_size(). The - * difference is that this function assumes *delta_ptr >= 0, and - * *recv_window_size_ptr is not decreased by *delta_ptr. - * - * This function returns 0 if it succeeds, or one of the following - * negative error codes: - * - * NGHTTP2_ERR_FLOW_CONTROL - * local_window_size overflow or gets negative. - */ -int nghttp2_increase_local_window_size(int32_t *local_window_size_ptr, - int32_t *recv_window_size_ptr, - int32_t *recv_reduction_ptr, - int32_t *delta_ptr); - -/* - * Returns non-zero if the function decided that WINDOW_UPDATE should - * be sent. - */ -int nghttp2_should_send_window_update(int32_t local_window_size, - int32_t recv_window_size); - -/* - * Copies the buffer |src| of length |len| to the destination pointed - * by the |dest|, assuming that the |dest| is at lest |len| bytes long - * . Returns dest + len. - */ -uint8_t *nghttp2_cpymem(uint8_t *dest, const void *src, size_t len); - -#endif /* NGHTTP2_HELPER_H */ diff --git a/3rdparty/exported/nghttp2/nghttp2_http.c b/3rdparty/exported/nghttp2/nghttp2_http.c deleted file mode 100644 index f222fe5e3fbe..000000000000 --- a/3rdparty/exported/nghttp2/nghttp2_http.c +++ /dev/null @@ -1,709 +0,0 @@ -/* - * nghttp2 - HTTP/2 C Library - * - * Copyright (c) 2015 Tatsuhiro Tsujikawa - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE - * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION - * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION - * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ -#include "nghttp2_http.h" - -#include -#include -#include - -#include "nghttp2_hd.h" -#include "nghttp2_helper.h" -#include "nghttp2_extpri.h" -#include "sfparse.h" - -static uint8_t downcase(uint8_t c) { - return 'A' <= c && c <= 'Z' ? (uint8_t)(c - 'A' + 'a') : c; -} - -static int memieq(const void *a, const void *b, size_t n) { - size_t i; - const uint8_t *aa = a, *bb = b; - - for (i = 0; i < n; ++i) { - if (downcase(aa[i]) != downcase(bb[i])) { - return 0; - } - } - return 1; -} - -#define lstrieq(A, B, N) ((sizeof((A)) - 1) == (N) && memieq((A), (B), (N))) - -static int64_t parse_uint(const uint8_t *s, size_t len) { - int64_t n = 0; - size_t i; - if (len == 0) { - return -1; - } - for (i = 0; i < len; ++i) { - if ('0' <= s[i] && s[i] <= '9') { - if (n > INT64_MAX / 10) { - return -1; - } - n *= 10; - if (n > INT64_MAX - (s[i] - '0')) { - return -1; - } - n += s[i] - '0'; - continue; - } - return -1; - } - return n; -} - -static int check_pseudo_header(nghttp2_stream *stream, const nghttp2_hd_nv *nv, - uint32_t flag) { - if ((stream->http_flags & flag) || nv->value->len == 0) { - return 0; - } - stream->http_flags = stream->http_flags | flag; - return 1; -} - -static int expect_response_body(nghttp2_stream *stream) { - return (stream->http_flags & NGHTTP2_HTTP_FLAG_METH_HEAD) == 0 && - stream->status_code / 100 != 1 && stream->status_code != 304 && - stream->status_code != 204; -} - -/* For "http" or "https" URIs, OPTIONS request may have "*" in :path - header field to represent system-wide OPTIONS request. Otherwise, - :path header field value must start with "/". This function must - be called after ":method" header field was received. This function - returns nonzero if path is valid.*/ -static int check_path(nghttp2_stream *stream) { - return (stream->http_flags & NGHTTP2_HTTP_FLAG_SCHEME_HTTP) == 0 || - ((stream->http_flags & NGHTTP2_HTTP_FLAG_PATH_REGULAR) || - ((stream->http_flags & NGHTTP2_HTTP_FLAG_METH_OPTIONS) && - (stream->http_flags & NGHTTP2_HTTP_FLAG_PATH_ASTERISK))); -} - -static int http_request_on_header(nghttp2_stream *stream, nghttp2_hd_nv *nv, - int trailer, int connect_protocol) { - nghttp2_extpri extpri; - - if (nv->name->base[0] == ':') { - if (trailer || - (stream->http_flags & NGHTTP2_HTTP_FLAG_PSEUDO_HEADER_DISALLOWED)) { - return NGHTTP2_ERR_HTTP_HEADER; - } - } - - switch (nv->token) { - case NGHTTP2_TOKEN__AUTHORITY: - if (!check_pseudo_header(stream, nv, NGHTTP2_HTTP_FLAG__AUTHORITY)) { - return NGHTTP2_ERR_HTTP_HEADER; - } - break; - case NGHTTP2_TOKEN__METHOD: - if (!check_pseudo_header(stream, nv, NGHTTP2_HTTP_FLAG__METHOD)) { - return NGHTTP2_ERR_HTTP_HEADER; - } - switch (nv->value->len) { - case 4: - if (lstreq("HEAD", nv->value->base, nv->value->len)) { - stream->http_flags |= NGHTTP2_HTTP_FLAG_METH_HEAD; - } - break; - case 7: - switch (nv->value->base[6]) { - case 'T': - if (lstreq("CONNECT", nv->value->base, nv->value->len)) { - if (stream->stream_id % 2 == 0) { - /* we won't allow CONNECT for push */ - return NGHTTP2_ERR_HTTP_HEADER; - } - stream->http_flags |= NGHTTP2_HTTP_FLAG_METH_CONNECT; - } - break; - case 'S': - if (lstreq("OPTIONS", nv->value->base, nv->value->len)) { - stream->http_flags |= NGHTTP2_HTTP_FLAG_METH_OPTIONS; - } - break; - } - break; - } - break; - case NGHTTP2_TOKEN__PATH: - if (!check_pseudo_header(stream, nv, NGHTTP2_HTTP_FLAG__PATH)) { - return NGHTTP2_ERR_HTTP_HEADER; - } - if (nv->value->base[0] == '/') { - stream->http_flags |= NGHTTP2_HTTP_FLAG_PATH_REGULAR; - } else if (nv->value->len == 1 && nv->value->base[0] == '*') { - stream->http_flags |= NGHTTP2_HTTP_FLAG_PATH_ASTERISK; - } - break; - case NGHTTP2_TOKEN__SCHEME: - if (!check_pseudo_header(stream, nv, NGHTTP2_HTTP_FLAG__SCHEME)) { - return NGHTTP2_ERR_HTTP_HEADER; - } - if ((nv->value->len == 4 && memieq("http", nv->value->base, 4)) || - (nv->value->len == 5 && memieq("https", nv->value->base, 5))) { - stream->http_flags |= NGHTTP2_HTTP_FLAG_SCHEME_HTTP; - } - break; - case NGHTTP2_TOKEN__PROTOCOL: - if (!connect_protocol) { - return NGHTTP2_ERR_HTTP_HEADER; - } - - if (!check_pseudo_header(stream, nv, NGHTTP2_HTTP_FLAG__PROTOCOL)) { - return NGHTTP2_ERR_HTTP_HEADER; - } - break; - case NGHTTP2_TOKEN_HOST: - if (!check_pseudo_header(stream, nv, NGHTTP2_HTTP_FLAG_HOST)) { - return NGHTTP2_ERR_HTTP_HEADER; - } - break; - case NGHTTP2_TOKEN_CONTENT_LENGTH: { - if (stream->content_length != -1) { - return NGHTTP2_ERR_HTTP_HEADER; - } - stream->content_length = parse_uint(nv->value->base, nv->value->len); - if (stream->content_length == -1) { - return NGHTTP2_ERR_HTTP_HEADER; - } - break; - } - /* disallowed header fields */ - case NGHTTP2_TOKEN_CONNECTION: - case NGHTTP2_TOKEN_KEEP_ALIVE: - case NGHTTP2_TOKEN_PROXY_CONNECTION: - case NGHTTP2_TOKEN_TRANSFER_ENCODING: - case NGHTTP2_TOKEN_UPGRADE: - return NGHTTP2_ERR_HTTP_HEADER; - case NGHTTP2_TOKEN_TE: - if (!lstrieq("trailers", nv->value->base, nv->value->len)) { - return NGHTTP2_ERR_HTTP_HEADER; - } - break; - case NGHTTP2_TOKEN_PRIORITY: - if (!trailer && - /* Do not parse the header field in PUSH_PROMISE. */ - (stream->stream_id & 1) && - (stream->flags & NGHTTP2_STREAM_FLAG_NO_RFC7540_PRIORITIES) && - !(stream->http_flags & NGHTTP2_HTTP_FLAG_BAD_PRIORITY)) { - nghttp2_extpri_from_uint8(&extpri, stream->http_extpri); - if (nghttp2_http_parse_priority(&extpri, nv->value->base, - nv->value->len) == 0) { - stream->http_extpri = nghttp2_extpri_to_uint8(&extpri); - stream->http_flags |= NGHTTP2_HTTP_FLAG_PRIORITY; - } else { - stream->http_flags &= (uint32_t)~NGHTTP2_HTTP_FLAG_PRIORITY; - stream->http_flags |= NGHTTP2_HTTP_FLAG_BAD_PRIORITY; - } - } - break; - default: - if (nv->name->base[0] == ':') { - return NGHTTP2_ERR_HTTP_HEADER; - } - } - - if (nv->name->base[0] != ':') { - stream->http_flags |= NGHTTP2_HTTP_FLAG_PSEUDO_HEADER_DISALLOWED; - } - - return 0; -} - -static int http_response_on_header(nghttp2_stream *stream, nghttp2_hd_nv *nv, - int trailer) { - if (nv->name->base[0] == ':') { - if (trailer || - (stream->http_flags & NGHTTP2_HTTP_FLAG_PSEUDO_HEADER_DISALLOWED)) { - return NGHTTP2_ERR_HTTP_HEADER; - } - } - - switch (nv->token) { - case NGHTTP2_TOKEN__STATUS: { - if (!check_pseudo_header(stream, nv, NGHTTP2_HTTP_FLAG__STATUS)) { - return NGHTTP2_ERR_HTTP_HEADER; - } - if (nv->value->len != 3) { - return NGHTTP2_ERR_HTTP_HEADER; - } - stream->status_code = (int16_t)parse_uint(nv->value->base, nv->value->len); - if (stream->status_code == -1 || stream->status_code == 101) { - return NGHTTP2_ERR_HTTP_HEADER; - } - break; - } - case NGHTTP2_TOKEN_CONTENT_LENGTH: { - if (stream->status_code == 204) { - /* content-length header field in 204 response is prohibited by - RFC 7230. But some widely used servers send content-length: - 0. Until they get fixed, we ignore it. */ - if (stream->content_length != -1) { - /* Found multiple content-length field */ - return NGHTTP2_ERR_HTTP_HEADER; - } - if (!lstrieq("0", nv->value->base, nv->value->len)) { - return NGHTTP2_ERR_HTTP_HEADER; - } - stream->content_length = 0; - return NGHTTP2_ERR_REMOVE_HTTP_HEADER; - } - if (stream->status_code / 100 == 1) { - return NGHTTP2_ERR_HTTP_HEADER; - } - /* https://tools.ietf.org/html/rfc7230#section-3.3.3 */ - if (stream->status_code / 100 == 2 && - (stream->http_flags & NGHTTP2_HTTP_FLAG_METH_CONNECT)) { - return NGHTTP2_ERR_REMOVE_HTTP_HEADER; - } - if (stream->content_length != -1) { - return NGHTTP2_ERR_HTTP_HEADER; - } - stream->content_length = parse_uint(nv->value->base, nv->value->len); - if (stream->content_length == -1) { - return NGHTTP2_ERR_HTTP_HEADER; - } - break; - } - /* disallowed header fields */ - case NGHTTP2_TOKEN_CONNECTION: - case NGHTTP2_TOKEN_KEEP_ALIVE: - case NGHTTP2_TOKEN_PROXY_CONNECTION: - case NGHTTP2_TOKEN_TRANSFER_ENCODING: - case NGHTTP2_TOKEN_UPGRADE: - return NGHTTP2_ERR_HTTP_HEADER; - case NGHTTP2_TOKEN_TE: - if (!lstrieq("trailers", nv->value->base, nv->value->len)) { - return NGHTTP2_ERR_HTTP_HEADER; - } - break; - default: - if (nv->name->base[0] == ':') { - return NGHTTP2_ERR_HTTP_HEADER; - } - } - - if (nv->name->base[0] != ':') { - stream->http_flags |= NGHTTP2_HTTP_FLAG_PSEUDO_HEADER_DISALLOWED; - } - - return 0; -} - -static int check_scheme(const uint8_t *value, size_t len) { - const uint8_t *last; - if (len == 0) { - return 0; - } - - if (!(('A' <= *value && *value <= 'Z') || ('a' <= *value && *value <= 'z'))) { - return 0; - } - - last = value + len; - ++value; - - for (; value != last; ++value) { - if (!(('A' <= *value && *value <= 'Z') || - ('a' <= *value && *value <= 'z') || - ('0' <= *value && *value <= '9') || *value == '+' || *value == '-' || - *value == '.')) { - return 0; - } - } - return 1; -} - -static int lws(const uint8_t *s, size_t n) { - size_t i; - for (i = 0; i < n; ++i) { - if (s[i] != ' ' && s[i] != '\t') { - return 0; - } - } - return 1; -} - -/* Generated by genauthoritychartbl.py, but '@' is not allowed */ -static char VALID_AUTHORITY_CHARS[] = { - 0 /* NUL */, 0 /* SOH */, 0 /* STX */, 0 /* ETX */, - 0 /* EOT */, 0 /* ENQ */, 0 /* ACK */, 0 /* BEL */, - 0 /* BS */, 0 /* HT */, 0 /* LF */, 0 /* VT */, - 0 /* FF */, 0 /* CR */, 0 /* SO */, 0 /* SI */, - 0 /* DLE */, 0 /* DC1 */, 0 /* DC2 */, 0 /* DC3 */, - 0 /* DC4 */, 0 /* NAK */, 0 /* SYN */, 0 /* ETB */, - 0 /* CAN */, 0 /* EM */, 0 /* SUB */, 0 /* ESC */, - 0 /* FS */, 0 /* GS */, 0 /* RS */, 0 /* US */, - 0 /* SPC */, 1 /* ! */, 0 /* " */, 0 /* # */, - 1 /* $ */, 1 /* % */, 1 /* & */, 1 /* ' */, - 1 /* ( */, 1 /* ) */, 1 /* * */, 1 /* + */, - 1 /* , */, 1 /* - */, 1 /* . */, 0 /* / */, - 1 /* 0 */, 1 /* 1 */, 1 /* 2 */, 1 /* 3 */, - 1 /* 4 */, 1 /* 5 */, 1 /* 6 */, 1 /* 7 */, - 1 /* 8 */, 1 /* 9 */, 1 /* : */, 1 /* ; */, - 0 /* < */, 1 /* = */, 0 /* > */, 0 /* ? */, - 0 /* @ */, 1 /* A */, 1 /* B */, 1 /* C */, - 1 /* D */, 1 /* E */, 1 /* F */, 1 /* G */, - 1 /* H */, 1 /* I */, 1 /* J */, 1 /* K */, - 1 /* L */, 1 /* M */, 1 /* N */, 1 /* O */, - 1 /* P */, 1 /* Q */, 1 /* R */, 1 /* S */, - 1 /* T */, 1 /* U */, 1 /* V */, 1 /* W */, - 1 /* X */, 1 /* Y */, 1 /* Z */, 1 /* [ */, - 0 /* \ */, 1 /* ] */, 0 /* ^ */, 1 /* _ */, - 0 /* ` */, 1 /* a */, 1 /* b */, 1 /* c */, - 1 /* d */, 1 /* e */, 1 /* f */, 1 /* g */, - 1 /* h */, 1 /* i */, 1 /* j */, 1 /* k */, - 1 /* l */, 1 /* m */, 1 /* n */, 1 /* o */, - 1 /* p */, 1 /* q */, 1 /* r */, 1 /* s */, - 1 /* t */, 1 /* u */, 1 /* v */, 1 /* w */, - 1 /* x */, 1 /* y */, 1 /* z */, 0 /* { */, - 0 /* | */, 0 /* } */, 1 /* ~ */, 0 /* DEL */, - 0 /* 0x80 */, 0 /* 0x81 */, 0 /* 0x82 */, 0 /* 0x83 */, - 0 /* 0x84 */, 0 /* 0x85 */, 0 /* 0x86 */, 0 /* 0x87 */, - 0 /* 0x88 */, 0 /* 0x89 */, 0 /* 0x8a */, 0 /* 0x8b */, - 0 /* 0x8c */, 0 /* 0x8d */, 0 /* 0x8e */, 0 /* 0x8f */, - 0 /* 0x90 */, 0 /* 0x91 */, 0 /* 0x92 */, 0 /* 0x93 */, - 0 /* 0x94 */, 0 /* 0x95 */, 0 /* 0x96 */, 0 /* 0x97 */, - 0 /* 0x98 */, 0 /* 0x99 */, 0 /* 0x9a */, 0 /* 0x9b */, - 0 /* 0x9c */, 0 /* 0x9d */, 0 /* 0x9e */, 0 /* 0x9f */, - 0 /* 0xa0 */, 0 /* 0xa1 */, 0 /* 0xa2 */, 0 /* 0xa3 */, - 0 /* 0xa4 */, 0 /* 0xa5 */, 0 /* 0xa6 */, 0 /* 0xa7 */, - 0 /* 0xa8 */, 0 /* 0xa9 */, 0 /* 0xaa */, 0 /* 0xab */, - 0 /* 0xac */, 0 /* 0xad */, 0 /* 0xae */, 0 /* 0xaf */, - 0 /* 0xb0 */, 0 /* 0xb1 */, 0 /* 0xb2 */, 0 /* 0xb3 */, - 0 /* 0xb4 */, 0 /* 0xb5 */, 0 /* 0xb6 */, 0 /* 0xb7 */, - 0 /* 0xb8 */, 0 /* 0xb9 */, 0 /* 0xba */, 0 /* 0xbb */, - 0 /* 0xbc */, 0 /* 0xbd */, 0 /* 0xbe */, 0 /* 0xbf */, - 0 /* 0xc0 */, 0 /* 0xc1 */, 0 /* 0xc2 */, 0 /* 0xc3 */, - 0 /* 0xc4 */, 0 /* 0xc5 */, 0 /* 0xc6 */, 0 /* 0xc7 */, - 0 /* 0xc8 */, 0 /* 0xc9 */, 0 /* 0xca */, 0 /* 0xcb */, - 0 /* 0xcc */, 0 /* 0xcd */, 0 /* 0xce */, 0 /* 0xcf */, - 0 /* 0xd0 */, 0 /* 0xd1 */, 0 /* 0xd2 */, 0 /* 0xd3 */, - 0 /* 0xd4 */, 0 /* 0xd5 */, 0 /* 0xd6 */, 0 /* 0xd7 */, - 0 /* 0xd8 */, 0 /* 0xd9 */, 0 /* 0xda */, 0 /* 0xdb */, - 0 /* 0xdc */, 0 /* 0xdd */, 0 /* 0xde */, 0 /* 0xdf */, - 0 /* 0xe0 */, 0 /* 0xe1 */, 0 /* 0xe2 */, 0 /* 0xe3 */, - 0 /* 0xe4 */, 0 /* 0xe5 */, 0 /* 0xe6 */, 0 /* 0xe7 */, - 0 /* 0xe8 */, 0 /* 0xe9 */, 0 /* 0xea */, 0 /* 0xeb */, - 0 /* 0xec */, 0 /* 0xed */, 0 /* 0xee */, 0 /* 0xef */, - 0 /* 0xf0 */, 0 /* 0xf1 */, 0 /* 0xf2 */, 0 /* 0xf3 */, - 0 /* 0xf4 */, 0 /* 0xf5 */, 0 /* 0xf6 */, 0 /* 0xf7 */, - 0 /* 0xf8 */, 0 /* 0xf9 */, 0 /* 0xfa */, 0 /* 0xfb */, - 0 /* 0xfc */, 0 /* 0xfd */, 0 /* 0xfe */, 0 /* 0xff */ -}; - -static int check_authority(const uint8_t *value, size_t len) { - const uint8_t *last; - for (last = value + len; value != last; ++value) { - if (!VALID_AUTHORITY_CHARS[*value]) { - return 0; - } - } - return 1; -} - -int nghttp2_http_on_header(nghttp2_session *session, nghttp2_stream *stream, - nghttp2_frame *frame, nghttp2_hd_nv *nv, - int trailer) { - int rv; - - /* We are strict for pseudo header field. One bad character should - lead to fail. OTOH, we should be a bit forgiving for regular - headers, since existing public internet has so much illegal - headers floating around and if we kill the stream because of - this, we may disrupt many web sites and/or libraries. So we - become conservative here, and just ignore those illegal regular - headers. */ - if (!nghttp2_check_header_name(nv->name->base, nv->name->len)) { - size_t i; - if (nv->name->len > 0 && nv->name->base[0] == ':') { - return NGHTTP2_ERR_HTTP_HEADER; - } - /* header field name must be lower-cased without exception */ - for (i = 0; i < nv->name->len; ++i) { - uint8_t c = nv->name->base[i]; - if ('A' <= c && c <= 'Z') { - return NGHTTP2_ERR_HTTP_HEADER; - } - } - /* When ignoring regular headers, we set this flag so that we - still enforce header field ordering rule for pseudo header - fields. */ - stream->http_flags |= NGHTTP2_HTTP_FLAG_PSEUDO_HEADER_DISALLOWED; - return NGHTTP2_ERR_IGN_HTTP_HEADER; - } - - switch (nv->token) { - case NGHTTP2_TOKEN__METHOD: - rv = nghttp2_check_method(nv->value->base, nv->value->len); - break; - case NGHTTP2_TOKEN__PATH: - rv = nghttp2_check_path(nv->value->base, nv->value->len); - break; - case NGHTTP2_TOKEN__AUTHORITY: - case NGHTTP2_TOKEN_HOST: - if (session->server || frame->hd.type == NGHTTP2_PUSH_PROMISE) { - rv = check_authority(nv->value->base, nv->value->len); - } else if ( - stream->flags & - NGHTTP2_STREAM_FLAG_NO_RFC9113_LEADING_AND_TRAILING_WS_VALIDATION) { - rv = nghttp2_check_header_value(nv->value->base, nv->value->len); - } else { - rv = nghttp2_check_header_value_rfc9113(nv->value->base, nv->value->len); - } - break; - case NGHTTP2_TOKEN__SCHEME: - rv = check_scheme(nv->value->base, nv->value->len); - break; - case NGHTTP2_TOKEN__PROTOCOL: - /* Check the value consists of just white spaces, which was done - in check_pseudo_header before - nghttp2_check_header_value_rfc9113 has been introduced. */ - if ((stream->flags & - NGHTTP2_STREAM_FLAG_NO_RFC9113_LEADING_AND_TRAILING_WS_VALIDATION) && - lws(nv->value->base, nv->value->len)) { - rv = 0; - break; - } - /* fall through */ - default: - if (stream->flags & - NGHTTP2_STREAM_FLAG_NO_RFC9113_LEADING_AND_TRAILING_WS_VALIDATION) { - rv = nghttp2_check_header_value(nv->value->base, nv->value->len); - } else { - rv = nghttp2_check_header_value_rfc9113(nv->value->base, nv->value->len); - } - } - - if (rv == 0) { - assert(nv->name->len > 0); - if (nv->name->base[0] == ':') { - return NGHTTP2_ERR_HTTP_HEADER; - } - /* When ignoring regular headers, we set this flag so that we - still enforce header field ordering rule for pseudo header - fields. */ - stream->http_flags |= NGHTTP2_HTTP_FLAG_PSEUDO_HEADER_DISALLOWED; - return NGHTTP2_ERR_IGN_HTTP_HEADER; - } - - if (session->server || frame->hd.type == NGHTTP2_PUSH_PROMISE) { - return http_request_on_header(stream, nv, trailer, - session->server && - session->pending_enable_connect_protocol); - } - - return http_response_on_header(stream, nv, trailer); -} - -int nghttp2_http_on_request_headers(nghttp2_stream *stream, - nghttp2_frame *frame) { - if (!(stream->http_flags & NGHTTP2_HTTP_FLAG__PROTOCOL) && - (stream->http_flags & NGHTTP2_HTTP_FLAG_METH_CONNECT)) { - if ((stream->http_flags & - (NGHTTP2_HTTP_FLAG__SCHEME | NGHTTP2_HTTP_FLAG__PATH)) || - (stream->http_flags & NGHTTP2_HTTP_FLAG__AUTHORITY) == 0) { - return -1; - } - stream->content_length = -1; - } else { - if ((stream->http_flags & NGHTTP2_HTTP_FLAG_REQ_HEADERS) != - NGHTTP2_HTTP_FLAG_REQ_HEADERS || - (stream->http_flags & - (NGHTTP2_HTTP_FLAG__AUTHORITY | NGHTTP2_HTTP_FLAG_HOST)) == 0) { - return -1; - } - if ((stream->http_flags & NGHTTP2_HTTP_FLAG__PROTOCOL) && - ((stream->http_flags & NGHTTP2_HTTP_FLAG_METH_CONNECT) == 0 || - (stream->http_flags & NGHTTP2_HTTP_FLAG__AUTHORITY) == 0)) { - return -1; - } - if (!check_path(stream)) { - return -1; - } - } - - if (frame->hd.type == NGHTTP2_PUSH_PROMISE) { - /* we are going to reuse data fields for upcoming response. Clear - them now, except for method flags. */ - stream->http_flags &= NGHTTP2_HTTP_FLAG_METH_ALL; - stream->content_length = -1; - } - - return 0; -} - -int nghttp2_http_on_response_headers(nghttp2_stream *stream) { - if ((stream->http_flags & NGHTTP2_HTTP_FLAG__STATUS) == 0) { - return -1; - } - - if (stream->status_code / 100 == 1) { - /* non-final response */ - stream->http_flags = (stream->http_flags & NGHTTP2_HTTP_FLAG_METH_ALL) | - NGHTTP2_HTTP_FLAG_EXPECT_FINAL_RESPONSE; - stream->content_length = -1; - stream->status_code = -1; - return 0; - } - - stream->http_flags = - stream->http_flags & (uint32_t)~NGHTTP2_HTTP_FLAG_EXPECT_FINAL_RESPONSE; - - if (!expect_response_body(stream)) { - stream->content_length = 0; - } else if (stream->http_flags & (NGHTTP2_HTTP_FLAG_METH_CONNECT | - NGHTTP2_HTTP_FLAG_METH_UPGRADE_WORKAROUND)) { - stream->content_length = -1; - } - - return 0; -} - -int nghttp2_http_on_trailer_headers(nghttp2_stream *stream, - nghttp2_frame *frame) { - (void)stream; - - if ((frame->hd.flags & NGHTTP2_FLAG_END_STREAM) == 0) { - return -1; - } - - return 0; -} - -int nghttp2_http_on_remote_end_stream(nghttp2_stream *stream) { - if (stream->http_flags & NGHTTP2_HTTP_FLAG_EXPECT_FINAL_RESPONSE) { - return -1; - } - - if (stream->content_length != -1 && - stream->content_length != stream->recv_content_length) { - return -1; - } - - return 0; -} - -int nghttp2_http_on_data_chunk(nghttp2_stream *stream, size_t n) { - stream->recv_content_length += (int64_t)n; - - if ((stream->http_flags & NGHTTP2_HTTP_FLAG_EXPECT_FINAL_RESPONSE) || - (stream->content_length != -1 && - stream->recv_content_length > stream->content_length)) { - return -1; - } - - return 0; -} - -void nghttp2_http_record_request_method(nghttp2_stream *stream, - nghttp2_frame *frame) { - const nghttp2_nv *nva; - size_t nvlen; - size_t i; - - switch (frame->hd.type) { - case NGHTTP2_HEADERS: - nva = frame->headers.nva; - nvlen = frame->headers.nvlen; - break; - case NGHTTP2_PUSH_PROMISE: - nva = frame->push_promise.nva; - nvlen = frame->push_promise.nvlen; - break; - default: - return; - } - - /* TODO we should do this strictly. */ - for (i = 0; i < nvlen; ++i) { - const nghttp2_nv *nv = &nva[i]; - if (!(nv->namelen == 7 && nv->name[6] == 'd' && - memcmp(":metho", nv->name, nv->namelen - 1) == 0)) { - continue; - } - if (lstreq("CONNECT", nv->value, nv->valuelen)) { - stream->http_flags |= NGHTTP2_HTTP_FLAG_METH_CONNECT; - return; - } - if (lstreq("HEAD", nv->value, nv->valuelen)) { - stream->http_flags |= NGHTTP2_HTTP_FLAG_METH_HEAD; - return; - } - return; - } -} - -int nghttp2_http_parse_priority(nghttp2_extpri *dest, const uint8_t *value, - size_t valuelen) { - nghttp2_extpri pri = *dest; - sf_parser sfp; - sf_vec key; - sf_value val; - int rv; - - sf_parser_init(&sfp, value, valuelen); - - for (;;) { - rv = sf_parser_dict(&sfp, &key, &val); - if (rv != 0) { - if (rv == SF_ERR_EOF) { - break; - } - - return NGHTTP2_ERR_INVALID_ARGUMENT; - } - - if (key.len != 1) { - continue; - } - - switch (key.base[0]) { - case 'i': - if (val.type != SF_TYPE_BOOLEAN) { - return NGHTTP2_ERR_INVALID_ARGUMENT; - } - - pri.inc = val.boolean; - - break; - case 'u': - if (val.type != SF_TYPE_INTEGER || - val.integer < NGHTTP2_EXTPRI_URGENCY_HIGH || - NGHTTP2_EXTPRI_URGENCY_LOW < val.integer) { - return NGHTTP2_ERR_INVALID_ARGUMENT; - } - - pri.urgency = (uint32_t)val.integer; - - break; - } - } - - *dest = pri; - - return 0; -} diff --git a/3rdparty/exported/nghttp2/nghttp2_http.h b/3rdparty/exported/nghttp2/nghttp2_http.h deleted file mode 100644 index d9992fe69083..000000000000 --- a/3rdparty/exported/nghttp2/nghttp2_http.h +++ /dev/null @@ -1,100 +0,0 @@ -/* - * nghttp2 - HTTP/2 C Library - * - * Copyright (c) 2015 Tatsuhiro Tsujikawa - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE - * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION - * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION - * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ -#ifndef NGHTTP2_HTTP_H -#define NGHTTP2_HTTP_H - -#ifdef HAVE_CONFIG_H -# include -#endif /* HAVE_CONFIG_H */ - -#include -#include "nghttp2_session.h" -#include "nghttp2_stream.h" - -/* - * This function is called when HTTP header field |nv| in |frame| is - * received for |stream|. This function will validate |nv| against - * the current state of stream. - * - * This function returns 0 if it succeeds, or one of the following - * negative error codes: - * - * NGHTTP2_ERR_HTTP_HEADER - * Invalid HTTP header field was received. - * NGHTTP2_ERR_IGN_HTTP_HEADER - * Invalid HTTP header field was received but it can be treated as - * if it was not received because of compatibility reasons. - */ -int nghttp2_http_on_header(nghttp2_session *session, nghttp2_stream *stream, - nghttp2_frame *frame, nghttp2_hd_nv *nv, - int trailer); - -/* - * This function is called when request header is received. This - * function performs validation and returns 0 if it succeeds, or -1. - */ -int nghttp2_http_on_request_headers(nghttp2_stream *stream, - nghttp2_frame *frame); - -/* - * This function is called when response header is received. This - * function performs validation and returns 0 if it succeeds, or -1. - */ -int nghttp2_http_on_response_headers(nghttp2_stream *stream); - -/* - * This function is called trailer header (for both request and - * response) is received. This function performs validation and - * returns 0 if it succeeds, or -1. - */ -int nghttp2_http_on_trailer_headers(nghttp2_stream *stream, - nghttp2_frame *frame); - -/* - * This function is called when END_STREAM flag is seen in incoming - * frame. This function performs validation and returns 0 if it - * succeeds, or -1. - */ -int nghttp2_http_on_remote_end_stream(nghttp2_stream *stream); - -/* - * This function is called when chunk of data is received. This - * function performs validation and returns 0 if it succeeds, or -1. - */ -int nghttp2_http_on_data_chunk(nghttp2_stream *stream, size_t n); - -/* - * This function inspects header field in |frame| and records its - * method in stream->http_flags. If frame->hd.type is neither - * NGHTTP2_HEADERS nor NGHTTP2_PUSH_PROMISE, this function does - * nothing. - */ -void nghttp2_http_record_request_method(nghttp2_stream *stream, - nghttp2_frame *frame); - -int nghttp2_http_parse_priority(nghttp2_extpri *dest, const uint8_t *value, - size_t valuelen); - -#endif /* NGHTTP2_HTTP_H */ diff --git a/3rdparty/exported/nghttp2/nghttp2_int.h b/3rdparty/exported/nghttp2/nghttp2_int.h deleted file mode 100644 index b23585ccb27d..000000000000 --- a/3rdparty/exported/nghttp2/nghttp2_int.h +++ /dev/null @@ -1,58 +0,0 @@ -/* - * nghttp2 - HTTP/2 C Library - * - * Copyright (c) 2012 Tatsuhiro Tsujikawa - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE - * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION - * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION - * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ -#ifndef NGHTTP2_INT_H -#define NGHTTP2_INT_H - -#ifdef HAVE_CONFIG_H -# include -#endif /* HAVE_CONFIG_H */ - -#include - -/* Macros, types and constants for internal use */ - -/* "less" function, return nonzero if |lhs| is less than |rhs|. */ -typedef int (*nghttp2_less)(const void *lhs, const void *rhs); - -/* Internal error code. They must be in the range [-499, -100], - inclusive. */ -typedef enum { - NGHTTP2_ERR_CREDENTIAL_PENDING = -101, - NGHTTP2_ERR_IGN_HEADER_BLOCK = -103, - NGHTTP2_ERR_IGN_PAYLOAD = -104, - /* - * Invalid HTTP header field was received but it can be treated as - * if it was not received because of compatibility reasons. - */ - NGHTTP2_ERR_IGN_HTTP_HEADER = -105, - /* - * Invalid HTTP header field was received, and it is ignored. - * Unlike NGHTTP2_ERR_IGN_HTTP_HEADER, this does not invoke - * nghttp2_on_invalid_header_callback. - */ - NGHTTP2_ERR_REMOVE_HTTP_HEADER = -106 -} nghttp2_internal_error; - -#endif /* NGHTTP2_INT_H */ diff --git a/3rdparty/exported/nghttp2/nghttp2_map.c b/3rdparty/exported/nghttp2/nghttp2_map.c deleted file mode 100644 index ee6bb1967ec6..000000000000 --- a/3rdparty/exported/nghttp2/nghttp2_map.c +++ /dev/null @@ -1,302 +0,0 @@ -/* - * nghttp2 - HTTP/2 C Library - * - * Copyright (c) 2017 ngtcp2 contributors - * Copyright (c) 2012 nghttp2 contributors - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE - * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION - * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION - * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ -#include "nghttp2_map.h" - -#include -#include -#include - -#include "nghttp2_helper.h" - -#define NGHTTP2_INITIAL_TABLE_LENBITS 4 - -void nghttp2_map_init(nghttp2_map *map, nghttp2_mem *mem) { - map->mem = mem; - map->hashbits = 0; - map->table = NULL; - map->size = 0; -} - -void nghttp2_map_free(nghttp2_map *map) { - if (!map) { - return; - } - - nghttp2_mem_free(map->mem, map->table); -} - -int nghttp2_map_each(const nghttp2_map *map, int (*func)(void *data, void *ptr), - void *ptr) { - int rv; - size_t i; - nghttp2_map_bucket *bkt; - size_t tablelen; - - if (map->size == 0) { - return 0; - } - - tablelen = 1u << map->hashbits; - - for (i = 0; i < tablelen; ++i) { - bkt = &map->table[i]; - - if (bkt->data == NULL) { - continue; - } - - rv = func(bkt->data, ptr); - if (rv != 0) { - return rv; - } - } - - return 0; -} - -static size_t hash(nghttp2_map_key_type key, size_t bits) { - return (size_t)(((uint32_t)key * 2654435769u) >> (32 - bits)); -} - -static void map_bucket_swap(nghttp2_map_bucket *a, nghttp2_map_bucket *b) { - nghttp2_map_bucket c = *a; - - *a = *b; - *b = c; -} - -#ifndef WIN32 -void nghttp2_map_print_distance(const nghttp2_map *map) { - size_t i; - size_t idx; - nghttp2_map_bucket *bkt; - size_t tablelen; - - if (map->size == 0) { - return; - } - - tablelen = 1u << map->hashbits; - - for (i = 0; i < tablelen; ++i) { - bkt = &map->table[i]; - - if (bkt->data == NULL) { - fprintf(stderr, "@%zu \n", i); - continue; - } - - idx = hash(bkt->key, map->hashbits); - fprintf(stderr, "@%zu hash=%zu key=%d base=%zu distance=%u\n", i, - hash(bkt->key, map->hashbits), bkt->key, idx, bkt->psl); - } -} -#endif /* !WIN32 */ - -static int insert(nghttp2_map_bucket *table, size_t hashbits, - nghttp2_map_key_type key, void *data) { - size_t idx = hash(key, hashbits); - nghttp2_map_bucket b = {0, key, data}, *bkt; - size_t mask = (1u << hashbits) - 1; - - for (;;) { - bkt = &table[idx]; - - if (bkt->data == NULL) { - *bkt = b; - return 0; - } - - if (b.psl > bkt->psl) { - map_bucket_swap(bkt, &b); - } else if (bkt->key == key) { - /* TODO This check is just a waste after first swap or if this - function is called from map_resize. That said, there is no - difference with or without this conditional in performance - wise. */ - return NGHTTP2_ERR_INVALID_ARGUMENT; - } - - ++b.psl; - idx = (idx + 1) & mask; - } -} - -static int map_resize(nghttp2_map *map, size_t new_hashbits) { - size_t i; - nghttp2_map_bucket *new_table; - nghttp2_map_bucket *bkt; - size_t tablelen; - int rv; - (void)rv; - - new_table = nghttp2_mem_calloc(map->mem, 1u << new_hashbits, - sizeof(nghttp2_map_bucket)); - if (new_table == NULL) { - return NGHTTP2_ERR_NOMEM; - } - - if (map->size) { - tablelen = 1u << map->hashbits; - - for (i = 0; i < tablelen; ++i) { - bkt = &map->table[i]; - if (bkt->data == NULL) { - continue; - } - - rv = insert(new_table, new_hashbits, bkt->key, bkt->data); - - assert(0 == rv); - } - } - - nghttp2_mem_free(map->mem, map->table); - map->hashbits = new_hashbits; - map->table = new_table; - - return 0; -} - -int nghttp2_map_insert(nghttp2_map *map, nghttp2_map_key_type key, void *data) { - int rv; - - assert(data); - - /* Load factor is 0.75 */ - /* Under the very initial condition, that is map->size == 0 and - map->hashbits == 0, 4 > 3 still holds nicely. */ - if ((map->size + 1) * 4 > (1u << map->hashbits) * 3) { - if (map->hashbits) { - rv = map_resize(map, map->hashbits + 1); - if (rv != 0) { - return rv; - } - } else { - rv = map_resize(map, NGHTTP2_INITIAL_TABLE_LENBITS); - if (rv != 0) { - return rv; - } - } - } - - rv = insert(map->table, map->hashbits, key, data); - if (rv != 0) { - return rv; - } - - ++map->size; - - return 0; -} - -void *nghttp2_map_find(const nghttp2_map *map, nghttp2_map_key_type key) { - size_t idx; - nghttp2_map_bucket *bkt; - size_t psl = 0; - size_t mask; - - if (map->size == 0) { - return NULL; - } - - idx = hash(key, map->hashbits); - mask = (1u << map->hashbits) - 1; - - for (;;) { - bkt = &map->table[idx]; - - if (bkt->data == NULL || psl > bkt->psl) { - return NULL; - } - - if (bkt->key == key) { - return bkt->data; - } - - ++psl; - idx = (idx + 1) & mask; - } -} - -int nghttp2_map_remove(nghttp2_map *map, nghttp2_map_key_type key) { - size_t idx; - nghttp2_map_bucket *b, *bkt; - size_t psl = 0; - size_t mask; - - if (map->size == 0) { - return NGHTTP2_ERR_INVALID_ARGUMENT; - } - - idx = hash(key, map->hashbits); - mask = (1u << map->hashbits) - 1; - - for (;;) { - bkt = &map->table[idx]; - - if (bkt->data == NULL || psl > bkt->psl) { - return NGHTTP2_ERR_INVALID_ARGUMENT; - } - - if (bkt->key == key) { - b = bkt; - idx = (idx + 1) & mask; - - for (;;) { - bkt = &map->table[idx]; - if (bkt->data == NULL || bkt->psl == 0) { - b->data = NULL; - break; - } - - --bkt->psl; - *b = *bkt; - b = bkt; - - idx = (idx + 1) & mask; - } - - --map->size; - - return 0; - } - - ++psl; - idx = (idx + 1) & mask; - } -} - -void nghttp2_map_clear(nghttp2_map *map) { - if (map->size == 0) { - return; - } - - memset(map->table, 0, sizeof(*map->table) * (1u << map->hashbits)); - map->size = 0; -} - -size_t nghttp2_map_size(const nghttp2_map *map) { return map->size; } diff --git a/3rdparty/exported/nghttp2/nghttp2_map.h b/3rdparty/exported/nghttp2/nghttp2_map.h deleted file mode 100644 index 5adfb78d0276..000000000000 --- a/3rdparty/exported/nghttp2/nghttp2_map.h +++ /dev/null @@ -1,128 +0,0 @@ -/* - * nghttp2 - HTTP/2 C Library - * - * Copyright (c) 2017 ngtcp2 contributors - * Copyright (c) 2012 nghttp2 contributors - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE - * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION - * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION - * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ -#ifndef NGHTTP2_MAP_H -#define NGHTTP2_MAP_H - -#ifdef HAVE_CONFIG_H -# include -#endif /* HAVE_CONFIG_H */ - -#include - -#include "nghttp2_mem.h" - -/* Implementation of unordered map */ - -typedef int32_t nghttp2_map_key_type; - -typedef struct nghttp2_map_bucket { - uint32_t psl; - nghttp2_map_key_type key; - void *data; -} nghttp2_map_bucket; - -typedef struct nghttp2_map { - nghttp2_map_bucket *table; - nghttp2_mem *mem; - size_t size; - size_t hashbits; -} nghttp2_map; - -/* - * nghttp2_map_init initializes the map |map|. - */ -void nghttp2_map_init(nghttp2_map *map, nghttp2_mem *mem); - -/* - * nghttp2_map_free deallocates any resources allocated for |map|. - * The stored entries are not freed by this function. Use - * nghttp2_map_each() to free each entry. - */ -void nghttp2_map_free(nghttp2_map *map); - -/* - * nghttp2_map_insert inserts the new |data| with the |key| to the map - * |map|. - * - * This function returns 0 if it succeeds, or one of the following - * negative error codes: - * - * NGHTTP2_ERR_INVALID_ARGUMENT - * The item associated by |key| already exists. - * NGHTTP2_ERR_NOMEM - * Out of memory - */ -int nghttp2_map_insert(nghttp2_map *map, nghttp2_map_key_type key, void *data); - -/* - * nghttp2_map_find returns the entry associated by the key |key|. If - * there is no such entry, this function returns NULL. - */ -void *nghttp2_map_find(const nghttp2_map *map, nghttp2_map_key_type key); - -/* - * nghttp2_map_remove removes the entry associated by the key |key| - * from the |map|. The removed entry is not freed by this function. - * - * This function returns 0 if it succeeds, or one of the following - * negative error codes: - * - * NGHTTP2_ERR_INVALID_ARGUMENT - * The entry associated by |key| does not exist. - */ -int nghttp2_map_remove(nghttp2_map *map, nghttp2_map_key_type key); - -/* - * nghttp2_map_clear removes all entries from |map|. The removed - * entry is not freed by this function. - */ -void nghttp2_map_clear(nghttp2_map *map); - -/* - * nghttp2_map_size returns the number of items stored in the map - * |map|. - */ -size_t nghttp2_map_size(const nghttp2_map *map); - -/* - * nghttp2_map_each applies the function |func| to each entry in the - * |map| with the optional user supplied pointer |ptr|. - * - * If the |func| returns 0, this function calls the |func| with the - * next entry. If the |func| returns nonzero, it will not call the - * |func| for further entries and return the return value of the - * |func| immediately. Thus, this function returns 0 if all the - * invocations of the |func| return 0, or nonzero value which the last - * invocation of |func| returns. - */ -int nghttp2_map_each(const nghttp2_map *map, int (*func)(void *data, void *ptr), - void *ptr); - -#ifndef WIN32 -void nghttp2_map_print_distance(const nghttp2_map *map); -#endif /* !WIN32 */ - -#endif /* NGHTTP2_MAP_H */ diff --git a/3rdparty/exported/nghttp2/nghttp2_mem.c b/3rdparty/exported/nghttp2/nghttp2_mem.c deleted file mode 100644 index 6a449cffd701..000000000000 --- a/3rdparty/exported/nghttp2/nghttp2_mem.c +++ /dev/null @@ -1,74 +0,0 @@ -/* - * nghttp2 - HTTP/2 C Library - * - * Copyright (c) 2014 Tatsuhiro Tsujikawa - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE - * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION - * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION - * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ -#include "nghttp2_mem.h" - -static void *default_malloc(size_t size, void *mem_user_data) { - (void)mem_user_data; - - return malloc(size); -} - -static void default_free(void *ptr, void *mem_user_data) { - (void)mem_user_data; - - free(ptr); -} - -static void *default_calloc(size_t nmemb, size_t size, void *mem_user_data) { - (void)mem_user_data; - - return calloc(nmemb, size); -} - -static void *default_realloc(void *ptr, size_t size, void *mem_user_data) { - (void)mem_user_data; - - return realloc(ptr, size); -} - -static nghttp2_mem mem_default = {NULL, default_malloc, default_free, - default_calloc, default_realloc}; - -nghttp2_mem *nghttp2_mem_default(void) { return &mem_default; } - -void *nghttp2_mem_malloc(nghttp2_mem *mem, size_t size) { - return mem->malloc(size, mem->mem_user_data); -} - -void nghttp2_mem_free(nghttp2_mem *mem, void *ptr) { - mem->free(ptr, mem->mem_user_data); -} - -void nghttp2_mem_free2(nghttp2_free free_func, void *ptr, void *mem_user_data) { - free_func(ptr, mem_user_data); -} - -void *nghttp2_mem_calloc(nghttp2_mem *mem, size_t nmemb, size_t size) { - return mem->calloc(nmemb, size, mem->mem_user_data); -} - -void *nghttp2_mem_realloc(nghttp2_mem *mem, void *ptr, size_t size) { - return mem->realloc(ptr, size, mem->mem_user_data); -} diff --git a/3rdparty/exported/nghttp2/nghttp2_mem.h b/3rdparty/exported/nghttp2/nghttp2_mem.h deleted file mode 100644 index f83dbcb8f9a5..000000000000 --- a/3rdparty/exported/nghttp2/nghttp2_mem.h +++ /dev/null @@ -1,45 +0,0 @@ -/* - * nghttp2 - HTTP/2 C Library - * - * Copyright (c) 2014 Tatsuhiro Tsujikawa - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE - * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION - * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION - * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ -#ifndef NGHTTP2_MEM_H -#define NGHTTP2_MEM_H - -#ifdef HAVE_CONFIG_H -# include -#endif /* HAVE_CONFIG_H */ - -#include - -/* The default, system standard memory allocator */ -nghttp2_mem *nghttp2_mem_default(void); - -/* Convenient wrapper functions to call allocator function in - |mem|. */ -void *nghttp2_mem_malloc(nghttp2_mem *mem, size_t size); -void nghttp2_mem_free(nghttp2_mem *mem, void *ptr); -void nghttp2_mem_free2(nghttp2_free free_func, void *ptr, void *mem_user_data); -void *nghttp2_mem_calloc(nghttp2_mem *mem, size_t nmemb, size_t size); -void *nghttp2_mem_realloc(nghttp2_mem *mem, void *ptr, size_t size); - -#endif /* NGHTTP2_MEM_H */ diff --git a/3rdparty/exported/nghttp2/nghttp2_net.h b/3rdparty/exported/nghttp2/nghttp2_net.h deleted file mode 100644 index 521f98143e47..000000000000 --- a/3rdparty/exported/nghttp2/nghttp2_net.h +++ /dev/null @@ -1,91 +0,0 @@ -/* - * nghttp2 - HTTP/2 C Library - * - * Copyright (c) 2012 Tatsuhiro Tsujikawa - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE - * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION - * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION - * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ -#ifndef NGHTTP2_NET_H -#define NGHTTP2_NET_H - -#ifdef HAVE_CONFIG_H -# include -#endif /* HAVE_CONFIG_H */ - -#ifdef HAVE_ARPA_INET_H -# include -#endif /* HAVE_ARPA_INET_H */ - -#ifdef HAVE_NETINET_IN_H -# include -#endif /* HAVE_NETINET_IN_H */ - -#include - -#if defined(WIN32) -/* Windows requires ws2_32 library for ntonl family functions. We - define inline functions for those function so that we don't have - dependency on that lib. */ - -# ifdef _MSC_VER -# define STIN static __inline -# else -# define STIN static inline -# endif - -STIN uint32_t htonl(uint32_t hostlong) { - uint32_t res; - unsigned char *p = (unsigned char *)&res; - *p++ = (unsigned char)(hostlong >> 24); - *p++ = (hostlong >> 16) & 0xffu; - *p++ = (hostlong >> 8) & 0xffu; - *p = hostlong & 0xffu; - return res; -} - -STIN uint16_t htons(uint16_t hostshort) { - uint16_t res; - unsigned char *p = (unsigned char *)&res; - *p++ = (unsigned char)(hostshort >> 8); - *p = hostshort & 0xffu; - return res; -} - -STIN uint32_t ntohl(uint32_t netlong) { - uint32_t res; - unsigned char *p = (unsigned char *)&netlong; - res = (uint32_t)(*p++ << 24); - res += (uint32_t)(*p++ << 16); - res += (uint32_t)(*p++ << 8); - res += *p; - return res; -} - -STIN uint16_t ntohs(uint16_t netshort) { - uint16_t res; - unsigned char *p = (unsigned char *)&netshort; - res = (uint16_t)(*p++ << 8); - res += *p; - return res; -} - -#endif /* WIN32 */ - -#endif /* NGHTTP2_NET_H */ diff --git a/3rdparty/exported/nghttp2/nghttp2_option.c b/3rdparty/exported/nghttp2/nghttp2_option.c deleted file mode 100644 index 02a24eee6b26..000000000000 --- a/3rdparty/exported/nghttp2/nghttp2_option.c +++ /dev/null @@ -1,157 +0,0 @@ -/* - * nghttp2 - HTTP/2 C Library - * - * Copyright (c) 2014 Tatsuhiro Tsujikawa - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE - * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION - * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION - * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ -#include "nghttp2_option.h" - -#include "nghttp2_session.h" - -int nghttp2_option_new(nghttp2_option **option_ptr) { - *option_ptr = calloc(1, sizeof(nghttp2_option)); - - if (*option_ptr == NULL) { - return NGHTTP2_ERR_NOMEM; - } - - return 0; -} - -void nghttp2_option_del(nghttp2_option *option) { free(option); } - -void nghttp2_option_set_no_auto_window_update(nghttp2_option *option, int val) { - option->opt_set_mask |= NGHTTP2_OPT_NO_AUTO_WINDOW_UPDATE; - option->no_auto_window_update = val; -} - -void nghttp2_option_set_peer_max_concurrent_streams(nghttp2_option *option, - uint32_t val) { - option->opt_set_mask |= NGHTTP2_OPT_PEER_MAX_CONCURRENT_STREAMS; - option->peer_max_concurrent_streams = val; -} - -void nghttp2_option_set_no_recv_client_magic(nghttp2_option *option, int val) { - option->opt_set_mask |= NGHTTP2_OPT_NO_RECV_CLIENT_MAGIC; - option->no_recv_client_magic = val; -} - -void nghttp2_option_set_no_http_messaging(nghttp2_option *option, int val) { - option->opt_set_mask |= NGHTTP2_OPT_NO_HTTP_MESSAGING; - option->no_http_messaging = val; -} - -void nghttp2_option_set_max_reserved_remote_streams(nghttp2_option *option, - uint32_t val) { - option->opt_set_mask |= NGHTTP2_OPT_MAX_RESERVED_REMOTE_STREAMS; - option->max_reserved_remote_streams = val; -} - -static void set_ext_type(uint8_t *ext_types, uint8_t type) { - ext_types[type / 8] = (uint8_t)(ext_types[type / 8] | (1 << (type & 0x7))); -} - -void nghttp2_option_set_user_recv_extension_type(nghttp2_option *option, - uint8_t type) { - if (type < 10) { - return; - } - - option->opt_set_mask |= NGHTTP2_OPT_USER_RECV_EXT_TYPES; - set_ext_type(option->user_recv_ext_types, type); -} - -void nghttp2_option_set_builtin_recv_extension_type(nghttp2_option *option, - uint8_t type) { - switch (type) { - case NGHTTP2_ALTSVC: - option->opt_set_mask |= NGHTTP2_OPT_BUILTIN_RECV_EXT_TYPES; - option->builtin_recv_ext_types |= NGHTTP2_TYPEMASK_ALTSVC; - return; - case NGHTTP2_ORIGIN: - option->opt_set_mask |= NGHTTP2_OPT_BUILTIN_RECV_EXT_TYPES; - option->builtin_recv_ext_types |= NGHTTP2_TYPEMASK_ORIGIN; - return; - case NGHTTP2_PRIORITY_UPDATE: - option->opt_set_mask |= NGHTTP2_OPT_BUILTIN_RECV_EXT_TYPES; - option->builtin_recv_ext_types |= NGHTTP2_TYPEMASK_PRIORITY_UPDATE; - return; - default: - return; - } -} - -void nghttp2_option_set_no_auto_ping_ack(nghttp2_option *option, int val) { - option->opt_set_mask |= NGHTTP2_OPT_NO_AUTO_PING_ACK; - option->no_auto_ping_ack = val; -} - -void nghttp2_option_set_max_send_header_block_length(nghttp2_option *option, - size_t val) { - option->opt_set_mask |= NGHTTP2_OPT_MAX_SEND_HEADER_BLOCK_LENGTH; - option->max_send_header_block_length = val; -} - -void nghttp2_option_set_max_deflate_dynamic_table_size(nghttp2_option *option, - size_t val) { - option->opt_set_mask |= NGHTTP2_OPT_MAX_DEFLATE_DYNAMIC_TABLE_SIZE; - option->max_deflate_dynamic_table_size = val; -} - -void nghttp2_option_set_no_closed_streams(nghttp2_option *option, int val) { - option->opt_set_mask |= NGHTTP2_OPT_NO_CLOSED_STREAMS; - option->no_closed_streams = val; -} - -void nghttp2_option_set_max_outbound_ack(nghttp2_option *option, size_t val) { - option->opt_set_mask |= NGHTTP2_OPT_MAX_OUTBOUND_ACK; - option->max_outbound_ack = val; -} - -void nghttp2_option_set_max_settings(nghttp2_option *option, size_t val) { - option->opt_set_mask |= NGHTTP2_OPT_MAX_SETTINGS; - option->max_settings = val; -} - -void nghttp2_option_set_server_fallback_rfc7540_priorities( - nghttp2_option *option, int val) { - option->opt_set_mask |= NGHTTP2_OPT_SERVER_FALLBACK_RFC7540_PRIORITIES; - option->server_fallback_rfc7540_priorities = val; -} - -void nghttp2_option_set_no_rfc9113_leading_and_trailing_ws_validation( - nghttp2_option *option, int val) { - option->opt_set_mask |= - NGHTTP2_OPT_NO_RFC9113_LEADING_AND_TRAILING_WS_VALIDATION; - option->no_rfc9113_leading_and_trailing_ws_validation = val; -} - -void nghttp2_option_set_stream_reset_rate_limit(nghttp2_option *option, - uint64_t burst, uint64_t rate) { - option->opt_set_mask |= NGHTTP2_OPT_STREAM_RESET_RATE_LIMIT; - option->stream_reset_burst = burst; - option->stream_reset_rate = rate; -} - -void nghttp2_option_set_max_continuations(nghttp2_option *option, size_t val) { - option->opt_set_mask |= NGHTTP2_OPT_MAX_CONTINUATIONS; - option->max_continuations = val; -} diff --git a/3rdparty/exported/nghttp2/nghttp2_option.h b/3rdparty/exported/nghttp2/nghttp2_option.h deleted file mode 100644 index c89cb97f8bb6..000000000000 --- a/3rdparty/exported/nghttp2/nghttp2_option.h +++ /dev/null @@ -1,157 +0,0 @@ -/* - * nghttp2 - HTTP/2 C Library - * - * Copyright (c) 2014 Tatsuhiro Tsujikawa - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE - * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION - * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION - * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ -#ifndef NGHTTP2_OPTION_H -#define NGHTTP2_OPTION_H - -#ifdef HAVE_CONFIG_H -# include -#endif /* HAVE_CONFIG_H */ - -#include - -/** - * Configuration options - */ -typedef enum { - /** - * This option prevents the library from sending WINDOW_UPDATE for a - * connection automatically. If this option is set to nonzero, the - * library won't send WINDOW_UPDATE for DATA until application calls - * nghttp2_session_consume() to indicate the amount of consumed - * DATA. By default, this option is set to zero. - */ - NGHTTP2_OPT_NO_AUTO_WINDOW_UPDATE = 1, - /** - * This option sets the SETTINGS_MAX_CONCURRENT_STREAMS value of - * remote endpoint as if it is received in SETTINGS frame. Without - * specifying this option, before the local endpoint receives - * SETTINGS_MAX_CONCURRENT_STREAMS in SETTINGS frame from remote - * endpoint, SETTINGS_MAX_CONCURRENT_STREAMS is unlimited. This may - * cause problem if local endpoint submits lots of requests - * initially and sending them at once to the remote peer may lead to - * the rejection of some requests. Specifying this option to the - * sensible value, say 100, may avoid this kind of issue. This value - * will be overwritten if the local endpoint receives - * SETTINGS_MAX_CONCURRENT_STREAMS from the remote endpoint. - */ - NGHTTP2_OPT_PEER_MAX_CONCURRENT_STREAMS = 1 << 1, - NGHTTP2_OPT_NO_RECV_CLIENT_MAGIC = 1 << 2, - NGHTTP2_OPT_NO_HTTP_MESSAGING = 1 << 3, - NGHTTP2_OPT_MAX_RESERVED_REMOTE_STREAMS = 1 << 4, - NGHTTP2_OPT_USER_RECV_EXT_TYPES = 1 << 5, - NGHTTP2_OPT_NO_AUTO_PING_ACK = 1 << 6, - NGHTTP2_OPT_BUILTIN_RECV_EXT_TYPES = 1 << 7, - NGHTTP2_OPT_MAX_SEND_HEADER_BLOCK_LENGTH = 1 << 8, - NGHTTP2_OPT_MAX_DEFLATE_DYNAMIC_TABLE_SIZE = 1 << 9, - NGHTTP2_OPT_NO_CLOSED_STREAMS = 1 << 10, - NGHTTP2_OPT_MAX_OUTBOUND_ACK = 1 << 11, - NGHTTP2_OPT_MAX_SETTINGS = 1 << 12, - NGHTTP2_OPT_SERVER_FALLBACK_RFC7540_PRIORITIES = 1 << 13, - NGHTTP2_OPT_NO_RFC9113_LEADING_AND_TRAILING_WS_VALIDATION = 1 << 14, - NGHTTP2_OPT_STREAM_RESET_RATE_LIMIT = 1 << 15, - NGHTTP2_OPT_MAX_CONTINUATIONS = 1 << 16, -} nghttp2_option_flag; - -/** - * Struct to store option values for nghttp2_session. - */ -struct nghttp2_option { - /** - * NGHTTP2_OPT_STREAM_RESET_RATE_LIMIT - */ - uint64_t stream_reset_burst; - uint64_t stream_reset_rate; - /** - * NGHTTP2_OPT_MAX_SEND_HEADER_BLOCK_LENGTH - */ - size_t max_send_header_block_length; - /** - * NGHTTP2_OPT_MAX_DEFLATE_DYNAMIC_TABLE_SIZE - */ - size_t max_deflate_dynamic_table_size; - /** - * NGHTTP2_OPT_MAX_OUTBOUND_ACK - */ - size_t max_outbound_ack; - /** - * NGHTTP2_OPT_MAX_SETTINGS - */ - size_t max_settings; - /** - * NGHTTP2_OPT_MAX_CONTINUATIONS - */ - size_t max_continuations; - /** - * Bitwise OR of nghttp2_option_flag to determine that which fields - * are specified. - */ - uint32_t opt_set_mask; - /** - * NGHTTP2_OPT_PEER_MAX_CONCURRENT_STREAMS - */ - uint32_t peer_max_concurrent_streams; - /** - * NGHTTP2_OPT_MAX_RESERVED_REMOTE_STREAMS - */ - uint32_t max_reserved_remote_streams; - /** - * NGHTTP2_OPT_BUILTIN_RECV_EXT_TYPES - */ - uint32_t builtin_recv_ext_types; - /** - * NGHTTP2_OPT_NO_AUTO_WINDOW_UPDATE - */ - int no_auto_window_update; - /** - * NGHTTP2_OPT_NO_RECV_CLIENT_MAGIC - */ - int no_recv_client_magic; - /** - * NGHTTP2_OPT_NO_HTTP_MESSAGING - */ - int no_http_messaging; - /** - * NGHTTP2_OPT_NO_AUTO_PING_ACK - */ - int no_auto_ping_ack; - /** - * NGHTTP2_OPT_NO_CLOSED_STREAMS - */ - int no_closed_streams; - /** - * NGHTTP2_OPT_SERVER_FALLBACK_RFC7540_PRIORITIES - */ - int server_fallback_rfc7540_priorities; - /** - * NGHTTP2_OPT_NO_RFC9113_LEADING_AND_TRAILING_WS_VALIDATION - */ - int no_rfc9113_leading_and_trailing_ws_validation; - /** - * NGHTTP2_OPT_USER_RECV_EXT_TYPES - */ - uint8_t user_recv_ext_types[32]; -}; - -#endif /* NGHTTP2_OPTION_H */ diff --git a/3rdparty/exported/nghttp2/nghttp2_outbound_item.c b/3rdparty/exported/nghttp2/nghttp2_outbound_item.c deleted file mode 100644 index a9e9f7693eda..000000000000 --- a/3rdparty/exported/nghttp2/nghttp2_outbound_item.c +++ /dev/null @@ -1,156 +0,0 @@ -/* - * nghttp2 - HTTP/2 C Library - * - * Copyright (c) 2012 Tatsuhiro Tsujikawa - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE - * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION - * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION - * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ -#include "nghttp2_outbound_item.h" - -#include -#include - -nghttp2_data_provider_wrap * -nghttp2_data_provider_wrap_v1(nghttp2_data_provider_wrap *dpw, - const nghttp2_data_provider *data_prd) { - if (!data_prd) { - return NULL; - } - - dpw->version = NGHTTP2_DATA_PROVIDER_V1; - dpw->data_prd.v1 = *data_prd; - - return dpw; -} - -nghttp2_data_provider_wrap * -nghttp2_data_provider_wrap_v2(nghttp2_data_provider_wrap *dpw, - const nghttp2_data_provider2 *data_prd) { - if (!data_prd) { - return NULL; - } - - dpw->version = NGHTTP2_DATA_PROVIDER_V2; - dpw->data_prd.v2 = *data_prd; - - return dpw; -} - -void nghttp2_outbound_item_init(nghttp2_outbound_item *item) { - item->cycle = 0; - item->qnext = NULL; - item->queued = 0; - - memset(&item->aux_data, 0, sizeof(nghttp2_aux_data)); -} - -void nghttp2_outbound_item_free(nghttp2_outbound_item *item, nghttp2_mem *mem) { - nghttp2_frame *frame; - - if (item == NULL) { - return; - } - - frame = &item->frame; - - switch (frame->hd.type) { - case NGHTTP2_DATA: - nghttp2_frame_data_free(&frame->data); - break; - case NGHTTP2_HEADERS: - nghttp2_frame_headers_free(&frame->headers, mem); - break; - case NGHTTP2_PRIORITY: - nghttp2_frame_priority_free(&frame->priority); - break; - case NGHTTP2_RST_STREAM: - nghttp2_frame_rst_stream_free(&frame->rst_stream); - break; - case NGHTTP2_SETTINGS: - nghttp2_frame_settings_free(&frame->settings, mem); - break; - case NGHTTP2_PUSH_PROMISE: - nghttp2_frame_push_promise_free(&frame->push_promise, mem); - break; - case NGHTTP2_PING: - nghttp2_frame_ping_free(&frame->ping); - break; - case NGHTTP2_GOAWAY: - nghttp2_frame_goaway_free(&frame->goaway, mem); - break; - case NGHTTP2_WINDOW_UPDATE: - nghttp2_frame_window_update_free(&frame->window_update); - break; - default: { - nghttp2_ext_aux_data *aux_data; - - aux_data = &item->aux_data.ext; - - if (aux_data->builtin == 0) { - nghttp2_frame_extension_free(&frame->ext); - break; - } - - switch (frame->hd.type) { - case NGHTTP2_ALTSVC: - nghttp2_frame_altsvc_free(&frame->ext, mem); - break; - case NGHTTP2_ORIGIN: - nghttp2_frame_origin_free(&frame->ext, mem); - break; - case NGHTTP2_PRIORITY_UPDATE: - nghttp2_frame_priority_update_free(&frame->ext, mem); - break; - default: - assert(0); - break; - } - } - } -} - -void nghttp2_outbound_queue_init(nghttp2_outbound_queue *q) { - q->head = q->tail = NULL; - q->n = 0; -} - -void nghttp2_outbound_queue_push(nghttp2_outbound_queue *q, - nghttp2_outbound_item *item) { - if (q->tail) { - q->tail = q->tail->qnext = item; - } else { - q->head = q->tail = item; - } - ++q->n; -} - -void nghttp2_outbound_queue_pop(nghttp2_outbound_queue *q) { - nghttp2_outbound_item *item; - if (!q->head) { - return; - } - item = q->head; - q->head = q->head->qnext; - item->qnext = NULL; - if (!q->head) { - q->tail = NULL; - } - --q->n; -} diff --git a/3rdparty/exported/nghttp2/nghttp2_outbound_item.h b/3rdparty/exported/nghttp2/nghttp2_outbound_item.h deleted file mode 100644 index 4e91750088f8..000000000000 --- a/3rdparty/exported/nghttp2/nghttp2_outbound_item.h +++ /dev/null @@ -1,189 +0,0 @@ -/* - * nghttp2 - HTTP/2 C Library - * - * Copyright (c) 2012 Tatsuhiro Tsujikawa - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE - * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION - * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION - * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ -#ifndef NGHTTP2_OUTBOUND_ITEM_H -#define NGHTTP2_OUTBOUND_ITEM_H - -#ifdef HAVE_CONFIG_H -# include -#endif /* HAVE_CONFIG_H */ - -#include -#include "nghttp2_frame.h" -#include "nghttp2_mem.h" - -#define NGHTTP2_DATA_PROVIDER_V1 1 -#define NGHTTP2_DATA_PROVIDER_V2 2 - -typedef struct nghttp2_data_provider_wrap { - int version; - union { - struct { - nghttp2_data_source source; - void *read_callback; - }; - nghttp2_data_provider v1; - nghttp2_data_provider2 v2; - } data_prd; -} nghttp2_data_provider_wrap; - -nghttp2_data_provider_wrap * -nghttp2_data_provider_wrap_v1(nghttp2_data_provider_wrap *dpw, - const nghttp2_data_provider *data_prd); - -nghttp2_data_provider_wrap * -nghttp2_data_provider_wrap_v2(nghttp2_data_provider_wrap *dpw, - const nghttp2_data_provider2 *data_prd); - -/* struct used for HEADERS and PUSH_PROMISE frame */ -typedef struct { - nghttp2_data_provider_wrap dpw; - void *stream_user_data; - /* error code when request HEADERS is canceled by RST_STREAM while - it is in queue. */ - uint32_t error_code; - /* nonzero if request HEADERS is canceled. The error code is stored - in |error_code|. */ - uint8_t canceled; -} nghttp2_headers_aux_data; - -/* struct used for DATA frame */ -typedef struct { - /** - * The data to be sent for this DATA frame. - */ - nghttp2_data_provider_wrap dpw; - /** - * The flags of DATA frame. We use separate flags here and - * nghttp2_data frame. The latter contains flags actually sent to - * peer. This |flags| may contain NGHTTP2_FLAG_END_STREAM and only - * when |eof| becomes nonzero, flags in nghttp2_data has - * NGHTTP2_FLAG_END_STREAM set. - */ - uint8_t flags; - /** - * The flag to indicate whether EOF was reached or not. Initially - * |eof| is 0. It becomes 1 after all data were read. - */ - uint8_t eof; - /** - * The flag to indicate that NGHTTP2_DATA_FLAG_NO_COPY is used. - */ - uint8_t no_copy; -} nghttp2_data_aux_data; - -typedef enum { - NGHTTP2_GOAWAY_AUX_NONE = 0x0, - /* indicates that session should be terminated after the - transmission of this frame. */ - NGHTTP2_GOAWAY_AUX_TERM_ON_SEND = 0x1, - /* indicates that this GOAWAY is just a notification for graceful - shutdown. No nghttp2_session.goaway_flags should be updated on - the reaction to this frame. */ - NGHTTP2_GOAWAY_AUX_SHUTDOWN_NOTICE = 0x2 -} nghttp2_goaway_aux_flag; - -/* struct used for GOAWAY frame */ -typedef struct { - /* bitwise-OR of one or more of nghttp2_goaway_aux_flag. */ - uint8_t flags; -} nghttp2_goaway_aux_data; - -/* struct used for extension frame */ -typedef struct { - /* nonzero if this extension frame is serialized by library - function, instead of user-defined callbacks. */ - uint8_t builtin; -} nghttp2_ext_aux_data; - -/* Additional data which cannot be stored in nghttp2_frame struct */ -typedef union { - nghttp2_data_aux_data data; - nghttp2_headers_aux_data headers; - nghttp2_goaway_aux_data goaway; - nghttp2_ext_aux_data ext; -} nghttp2_aux_data; - -struct nghttp2_outbound_item; -typedef struct nghttp2_outbound_item nghttp2_outbound_item; - -struct nghttp2_outbound_item { - nghttp2_frame frame; - /* Storage for extension frame payload. frame->ext.payload points - to this structure to avoid frequent memory allocation. */ - nghttp2_ext_frame_payload ext_frame_payload; - nghttp2_aux_data aux_data; - /* The priority used in priority comparison. Smaller is served - earlier. For PING, SETTINGS and non-DATA frames (excluding - response HEADERS frame) have dedicated cycle value defined above. - For DATA frame, cycle is computed by taking into account of - effective weight and frame payload length previously sent, so - that the amount of transmission is distributed across streams - proportional to effective weight (inside a tree). */ - uint64_t cycle; - nghttp2_outbound_item *qnext; - /* nonzero if this object is queued, except for DATA or HEADERS - which are attached to stream as item. */ - uint8_t queued; -}; - -/* - * Initializes |item|. No memory allocation is done in this function. - * Don't call nghttp2_outbound_item_free() until frame member is - * initialized. - */ -void nghttp2_outbound_item_init(nghttp2_outbound_item *item); - -/* - * Deallocates resource for |item|. If |item| is NULL, this function - * does nothing. - */ -void nghttp2_outbound_item_free(nghttp2_outbound_item *item, nghttp2_mem *mem); - -/* - * queue for nghttp2_outbound_item. - */ -typedef struct { - nghttp2_outbound_item *head, *tail; - /* number of items in this queue. */ - size_t n; -} nghttp2_outbound_queue; - -void nghttp2_outbound_queue_init(nghttp2_outbound_queue *q); - -/* Pushes |item| into |q| */ -void nghttp2_outbound_queue_push(nghttp2_outbound_queue *q, - nghttp2_outbound_item *item); - -/* Pops |item| at the top from |q|. If |q| is empty, nothing - happens. */ -void nghttp2_outbound_queue_pop(nghttp2_outbound_queue *q); - -/* Returns the top item. */ -#define nghttp2_outbound_queue_top(Q) ((Q)->head) - -/* Returns the size of the queue */ -#define nghttp2_outbound_queue_size(Q) ((Q)->n) - -#endif /* NGHTTP2_OUTBOUND_ITEM_H */ diff --git a/3rdparty/exported/nghttp2/nghttp2_pq.c b/3rdparty/exported/nghttp2/nghttp2_pq.c deleted file mode 100644 index e79ba8365e82..000000000000 --- a/3rdparty/exported/nghttp2/nghttp2_pq.c +++ /dev/null @@ -1,183 +0,0 @@ -/* - * nghttp2 - HTTP/2 C Library - * - * Copyright (c) 2012 Tatsuhiro Tsujikawa - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE - * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION - * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION - * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ -#include "nghttp2_pq.h" - -#include -#include - -#include "nghttp2_helper.h" - -void nghttp2_pq_init(nghttp2_pq *pq, nghttp2_less less, nghttp2_mem *mem) { - pq->mem = mem; - pq->capacity = 0; - pq->q = NULL; - pq->length = 0; - pq->less = less; -} - -void nghttp2_pq_free(nghttp2_pq *pq) { - nghttp2_mem_free(pq->mem, pq->q); - pq->q = NULL; -} - -static void swap(nghttp2_pq *pq, size_t i, size_t j) { - nghttp2_pq_entry *a = pq->q[i]; - nghttp2_pq_entry *b = pq->q[j]; - - pq->q[i] = b; - b->index = i; - pq->q[j] = a; - a->index = j; -} - -static void bubble_up(nghttp2_pq *pq, size_t index) { - size_t parent; - while (index != 0) { - parent = (index - 1) / 2; - if (!pq->less(pq->q[index], pq->q[parent])) { - return; - } - swap(pq, parent, index); - index = parent; - } -} - -int nghttp2_pq_push(nghttp2_pq *pq, nghttp2_pq_entry *item) { - if (pq->capacity <= pq->length) { - void *nq; - size_t ncapacity; - - ncapacity = nghttp2_max_size(4, (pq->capacity * 2)); - - nq = nghttp2_mem_realloc(pq->mem, pq->q, - ncapacity * sizeof(nghttp2_pq_entry *)); - if (nq == NULL) { - return NGHTTP2_ERR_NOMEM; - } - pq->capacity = ncapacity; - pq->q = nq; - } - pq->q[pq->length] = item; - item->index = pq->length; - ++pq->length; - bubble_up(pq, pq->length - 1); - return 0; -} - -nghttp2_pq_entry *nghttp2_pq_top(nghttp2_pq *pq) { - if (pq->length == 0) { - return NULL; - } else { - return pq->q[0]; - } -} - -static void bubble_down(nghttp2_pq *pq, size_t index) { - size_t i, j, minindex; - for (;;) { - j = index * 2 + 1; - minindex = index; - for (i = 0; i < 2; ++i, ++j) { - if (j >= pq->length) { - break; - } - if (pq->less(pq->q[j], pq->q[minindex])) { - minindex = j; - } - } - if (minindex == index) { - return; - } - swap(pq, index, minindex); - index = minindex; - } -} - -void nghttp2_pq_pop(nghttp2_pq *pq) { - if (pq->length > 0) { - pq->q[0] = pq->q[pq->length - 1]; - pq->q[0]->index = 0; - --pq->length; - bubble_down(pq, 0); - } -} - -void nghttp2_pq_remove(nghttp2_pq *pq, nghttp2_pq_entry *item) { - assert(pq->q[item->index] == item); - - if (item->index == 0) { - nghttp2_pq_pop(pq); - return; - } - - if (item->index == pq->length - 1) { - --pq->length; - return; - } - - pq->q[item->index] = pq->q[pq->length - 1]; - pq->q[item->index]->index = item->index; - --pq->length; - - if (pq->less(item, pq->q[item->index])) { - bubble_down(pq, item->index); - } else { - bubble_up(pq, item->index); - } -} - -int nghttp2_pq_empty(nghttp2_pq *pq) { return pq->length == 0; } - -size_t nghttp2_pq_size(nghttp2_pq *pq) { return pq->length; } - -void nghttp2_pq_update(nghttp2_pq *pq, nghttp2_pq_item_cb fun, void *arg) { - size_t i; - int rv = 0; - if (pq->length == 0) { - return; - } - for (i = 0; i < pq->length; ++i) { - rv |= (*fun)(pq->q[i], arg); - } - if (rv) { - for (i = pq->length; i > 0; --i) { - bubble_down(pq, i - 1); - } - } -} - -int nghttp2_pq_each(nghttp2_pq *pq, nghttp2_pq_item_cb fun, void *arg) { - size_t i; - - if (pq->length == 0) { - return 0; - } - for (i = 0; i < pq->length; ++i) { - if ((*fun)(pq->q[i], arg)) { - return 1; - } - } - return 0; -} diff --git a/3rdparty/exported/nghttp2/nghttp2_pq.h b/3rdparty/exported/nghttp2/nghttp2_pq.h deleted file mode 100644 index c8d90ef2cc8f..000000000000 --- a/3rdparty/exported/nghttp2/nghttp2_pq.h +++ /dev/null @@ -1,124 +0,0 @@ -/* - * nghttp2 - HTTP/2 C Library - * - * Copyright (c) 2012 Tatsuhiro Tsujikawa - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE - * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION - * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION - * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ -#ifndef NGHTTP2_PQ_H -#define NGHTTP2_PQ_H - -#ifdef HAVE_CONFIG_H -# include -#endif /* HAVE_CONFIG_H */ - -#include -#include "nghttp2_int.h" -#include "nghttp2_mem.h" - -/* Implementation of priority queue */ - -typedef struct { - size_t index; -} nghttp2_pq_entry; - -typedef struct { - /* The pointer to the pointer to the item stored */ - nghttp2_pq_entry **q; - /* Memory allocator */ - nghttp2_mem *mem; - /* The number of items stored */ - size_t length; - /* The maximum number of items this pq can store. This is - automatically extended when length is reached to this value. */ - size_t capacity; - /* The less function between items */ - nghttp2_less less; -} nghttp2_pq; - -/* - * Initializes priority queue |pq| with compare function |cmp|. - */ -void nghttp2_pq_init(nghttp2_pq *pq, nghttp2_less less, nghttp2_mem *mem); - -/* - * Deallocates any resources allocated for |pq|. The stored items are - * not freed by this function. - */ -void nghttp2_pq_free(nghttp2_pq *pq); - -/* - * Adds |item| to the priority queue |pq|. - * - * This function returns 0 if it succeeds, or one of the following - * negative error codes: - * - * NGHTTP2_ERR_NOMEM - * Out of memory. - */ -int nghttp2_pq_push(nghttp2_pq *pq, nghttp2_pq_entry *item); - -/* - * Returns item at the top of the queue |pq|. If the queue is empty, - * this function returns NULL. - */ -nghttp2_pq_entry *nghttp2_pq_top(nghttp2_pq *pq); - -/* - * Pops item at the top of the queue |pq|. The popped item is not - * freed by this function. - */ -void nghttp2_pq_pop(nghttp2_pq *pq); - -/* - * Returns nonzero if the queue |pq| is empty. - */ -int nghttp2_pq_empty(nghttp2_pq *pq); - -/* - * Returns the number of items in the queue |pq|. - */ -size_t nghttp2_pq_size(nghttp2_pq *pq); - -typedef int (*nghttp2_pq_item_cb)(nghttp2_pq_entry *item, void *arg); - -/* - * Updates each item in |pq| using function |fun| and re-construct - * priority queue. The |fun| must return non-zero if it modifies the - * item in a way that it affects ordering in the priority queue. The - * |arg| is passed to the 2nd parameter of |fun|. - */ -void nghttp2_pq_update(nghttp2_pq *pq, nghttp2_pq_item_cb fun, void *arg); - -/* - * Applies |fun| to each item in |pq|. The |arg| is passed as arg - * parameter to callback function. This function must not change the - * ordering key. If the return value from callback is nonzero, this - * function returns 1 immediately without iterating remaining items. - * Otherwise this function returns 0. - */ -int nghttp2_pq_each(nghttp2_pq *pq, nghttp2_pq_item_cb fun, void *arg); - -/* - * Removes |item| from priority queue. - */ -void nghttp2_pq_remove(nghttp2_pq *pq, nghttp2_pq_entry *item); - -#endif /* NGHTTP2_PQ_H */ diff --git a/3rdparty/exported/nghttp2/nghttp2_priority_spec.c b/3rdparty/exported/nghttp2/nghttp2_priority_spec.c deleted file mode 100644 index c2196e306302..000000000000 --- a/3rdparty/exported/nghttp2/nghttp2_priority_spec.c +++ /dev/null @@ -1,52 +0,0 @@ -/* - * nghttp2 - HTTP/2 C Library - * - * Copyright (c) 2014 Tatsuhiro Tsujikawa - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE - * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION - * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION - * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ -#include "nghttp2_priority_spec.h" - -void nghttp2_priority_spec_init(nghttp2_priority_spec *pri_spec, - int32_t stream_id, int32_t weight, - int exclusive) { - pri_spec->stream_id = stream_id; - pri_spec->weight = weight; - pri_spec->exclusive = exclusive != 0; -} - -void nghttp2_priority_spec_default_init(nghttp2_priority_spec *pri_spec) { - pri_spec->stream_id = 0; - pri_spec->weight = NGHTTP2_DEFAULT_WEIGHT; - pri_spec->exclusive = 0; -} - -int nghttp2_priority_spec_check_default(const nghttp2_priority_spec *pri_spec) { - return pri_spec->stream_id == 0 && - pri_spec->weight == NGHTTP2_DEFAULT_WEIGHT && pri_spec->exclusive == 0; -} - -void nghttp2_priority_spec_normalize_weight(nghttp2_priority_spec *pri_spec) { - if (pri_spec->weight < NGHTTP2_MIN_WEIGHT) { - pri_spec->weight = NGHTTP2_MIN_WEIGHT; - } else if (pri_spec->weight > NGHTTP2_MAX_WEIGHT) { - pri_spec->weight = NGHTTP2_MAX_WEIGHT; - } -} diff --git a/3rdparty/exported/nghttp2/nghttp2_priority_spec.h b/3rdparty/exported/nghttp2/nghttp2_priority_spec.h deleted file mode 100644 index 92ece822a8f2..000000000000 --- a/3rdparty/exported/nghttp2/nghttp2_priority_spec.h +++ /dev/null @@ -1,42 +0,0 @@ -/* - * nghttp2 - HTTP/2 C Library - * - * Copyright (c) 2014 Tatsuhiro Tsujikawa - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE - * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION - * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION - * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ -#ifndef NGHTTP2_PRIORITY_SPEC_H -#define NGHTTP2_PRIORITY_SPEC_H - -#ifdef HAVE_CONFIG_H -# include -#endif /* HAVE_CONFIG_H */ - -#include - -/* - * This function normalizes pri_spec->weight if it is out of range. - * If pri_spec->weight is less than NGHTTP2_MIN_WEIGHT, it is set to - * NGHTTP2_MIN_WEIGHT. If pri_spec->weight is larger than - * NGHTTP2_MAX_WEIGHT, it is set to NGHTTP2_MAX_WEIGHT. - */ -void nghttp2_priority_spec_normalize_weight(nghttp2_priority_spec *pri_spec); - -#endif /* NGHTTP2_PRIORITY_SPEC_H */ diff --git a/3rdparty/exported/nghttp2/nghttp2_queue.c b/3rdparty/exported/nghttp2/nghttp2_queue.c deleted file mode 100644 index 3b6315852459..000000000000 --- a/3rdparty/exported/nghttp2/nghttp2_queue.c +++ /dev/null @@ -1,85 +0,0 @@ -/* - * nghttp2 - HTTP/2 C Library - * - * Copyright (c) 2012 Tatsuhiro Tsujikawa - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE - * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION - * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION - * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ -#include "nghttp2_queue.h" - -#include -#include - -void nghttp2_queue_init(nghttp2_queue *queue) { - queue->front = queue->back = NULL; -} - -void nghttp2_queue_free(nghttp2_queue *queue) { - if (!queue) { - return; - } else { - nghttp2_queue_cell *p = queue->front; - while (p) { - nghttp2_queue_cell *next = p->next; - free(p); - p = next; - } - } -} - -int nghttp2_queue_push(nghttp2_queue *queue, void *data) { - nghttp2_queue_cell *new_cell = - (nghttp2_queue_cell *)malloc(sizeof(nghttp2_queue_cell)); - if (!new_cell) { - return NGHTTP2_ERR_NOMEM; - } - new_cell->data = data; - new_cell->next = NULL; - if (queue->back) { - queue->back->next = new_cell; - queue->back = new_cell; - - } else { - queue->front = queue->back = new_cell; - } - return 0; -} - -void nghttp2_queue_pop(nghttp2_queue *queue) { - nghttp2_queue_cell *front = queue->front; - assert(front); - queue->front = front->next; - if (front == queue->back) { - queue->back = NULL; - } - free(front); -} - -void *nghttp2_queue_front(nghttp2_queue *queue) { - assert(queue->front); - return queue->front->data; -} - -void *nghttp2_queue_back(nghttp2_queue *queue) { - assert(queue->back); - return queue->back->data; -} - -int nghttp2_queue_empty(nghttp2_queue *queue) { return queue->front == NULL; } diff --git a/3rdparty/exported/nghttp2/nghttp2_queue.h b/3rdparty/exported/nghttp2/nghttp2_queue.h deleted file mode 100644 index a06fa6c7a46f..000000000000 --- a/3rdparty/exported/nghttp2/nghttp2_queue.h +++ /dev/null @@ -1,51 +0,0 @@ -/* - * nghttp2 - HTTP/2 C Library - * - * Copyright (c) 2012 Tatsuhiro Tsujikawa - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE - * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION - * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION - * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ -#ifndef NGHTTP2_QUEUE_H -#define NGHTTP2_QUEUE_H - -#ifdef HAVE_CONFIG_H -# include "config.h" -#endif /* HAVE_CONFIG_H */ - -#include - -typedef struct nghttp2_queue_cell { - void *data; - struct nghttp2_queue_cell *next; -} nghttp2_queue_cell; - -typedef struct { - nghttp2_queue_cell *front, *back; -} nghttp2_queue; - -void nghttp2_queue_init(nghttp2_queue *queue); -void nghttp2_queue_free(nghttp2_queue *queue); -int nghttp2_queue_push(nghttp2_queue *queue, void *data); -void nghttp2_queue_pop(nghttp2_queue *queue); -void *nghttp2_queue_front(nghttp2_queue *queue); -void *nghttp2_queue_back(nghttp2_queue *queue); -int nghttp2_queue_empty(nghttp2_queue *queue); - -#endif /* NGHTTP2_QUEUE_H */ diff --git a/3rdparty/exported/nghttp2/nghttp2_ratelim.c b/3rdparty/exported/nghttp2/nghttp2_ratelim.c deleted file mode 100644 index 604ac0801a7a..000000000000 --- a/3rdparty/exported/nghttp2/nghttp2_ratelim.c +++ /dev/null @@ -1,75 +0,0 @@ -/* - * nghttp2 - HTTP/2 C Library - * - * Copyright (c) 2023 nghttp2 contributors - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE - * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION - * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION - * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ -#include "nghttp2_ratelim.h" -#include "nghttp2_helper.h" - -void nghttp2_ratelim_init(nghttp2_ratelim *rl, uint64_t burst, uint64_t rate) { - rl->val = rl->burst = burst; - rl->rate = rate; - rl->tstamp = 0; -} - -void nghttp2_ratelim_update(nghttp2_ratelim *rl, uint64_t tstamp) { - uint64_t d, gain; - - if (tstamp == rl->tstamp) { - return; - } - - if (tstamp > rl->tstamp) { - d = tstamp - rl->tstamp; - } else { - d = 1; - } - - rl->tstamp = tstamp; - - if (UINT64_MAX / d < rl->rate) { - rl->val = rl->burst; - - return; - } - - gain = rl->rate * d; - - if (UINT64_MAX - gain < rl->val) { - rl->val = rl->burst; - - return; - } - - rl->val += gain; - rl->val = nghttp2_min_uint64(rl->val, rl->burst); -} - -int nghttp2_ratelim_drain(nghttp2_ratelim *rl, uint64_t n) { - if (rl->val < n) { - return -1; - } - - rl->val -= n; - - return 0; -} diff --git a/3rdparty/exported/nghttp2/nghttp2_ratelim.h b/3rdparty/exported/nghttp2/nghttp2_ratelim.h deleted file mode 100644 index 866ed3f00aed..000000000000 --- a/3rdparty/exported/nghttp2/nghttp2_ratelim.h +++ /dev/null @@ -1,57 +0,0 @@ -/* - * nghttp2 - HTTP/2 C Library - * - * Copyright (c) 2023 nghttp2 contributors - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE - * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION - * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION - * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ -#ifndef NGHTTP2_RATELIM_H -#define NGHTTP2_RATELIM_H - -#ifdef HAVE_CONFIG_H -# include -#endif /* HAVE_CONFIG_H */ - -#include - -typedef struct nghttp2_ratelim { - /* burst is the maximum value of val. */ - uint64_t burst; - /* rate is the amount of value that is regenerated per 1 tstamp. */ - uint64_t rate; - /* val is the amount of value available to drain. */ - uint64_t val; - /* tstamp is the last timestamp in second resolution that is known - to this object. */ - uint64_t tstamp; -} nghttp2_ratelim; - -/* nghttp2_ratelim_init initializes |rl| with the given parameters. */ -void nghttp2_ratelim_init(nghttp2_ratelim *rl, uint64_t burst, uint64_t rate); - -/* nghttp2_ratelim_update updates rl->val with the current |tstamp| - given in second resolution. */ -void nghttp2_ratelim_update(nghttp2_ratelim *rl, uint64_t tstamp); - -/* nghttp2_ratelim_drain drains |n| from rl->val. It returns 0 if it - succeeds, or -1. */ -int nghttp2_ratelim_drain(nghttp2_ratelim *rl, uint64_t n); - -#endif /* NGHTTP2_RATELIM_H */ diff --git a/3rdparty/exported/nghttp2/nghttp2_rcbuf.c b/3rdparty/exported/nghttp2/nghttp2_rcbuf.c deleted file mode 100644 index 7e7814d2d3ca..000000000000 --- a/3rdparty/exported/nghttp2/nghttp2_rcbuf.c +++ /dev/null @@ -1,102 +0,0 @@ -/* - * nghttp2 - HTTP/2 C Library - * - * Copyright (c) 2016 Tatsuhiro Tsujikawa - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE - * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION - * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION - * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ -#include "nghttp2_rcbuf.h" - -#include -#include - -#include "nghttp2_mem.h" -#include "nghttp2_helper.h" - -int nghttp2_rcbuf_new(nghttp2_rcbuf **rcbuf_ptr, size_t size, - nghttp2_mem *mem) { - uint8_t *p; - - p = nghttp2_mem_malloc(mem, sizeof(nghttp2_rcbuf) + size); - if (p == NULL) { - return NGHTTP2_ERR_NOMEM; - } - - *rcbuf_ptr = (void *)p; - - (*rcbuf_ptr)->mem_user_data = mem->mem_user_data; - (*rcbuf_ptr)->free = mem->free; - (*rcbuf_ptr)->base = p + sizeof(nghttp2_rcbuf); - (*rcbuf_ptr)->len = size; - (*rcbuf_ptr)->ref = 1; - - return 0; -} - -int nghttp2_rcbuf_new2(nghttp2_rcbuf **rcbuf_ptr, const uint8_t *src, - size_t srclen, nghttp2_mem *mem) { - int rv; - - rv = nghttp2_rcbuf_new(rcbuf_ptr, srclen + 1, mem); - if (rv != 0) { - return rv; - } - - (*rcbuf_ptr)->len = srclen; - *nghttp2_cpymem((*rcbuf_ptr)->base, src, srclen) = '\0'; - - return 0; -} - -/* - * Frees |rcbuf| itself, regardless of its reference cout. - */ -void nghttp2_rcbuf_del(nghttp2_rcbuf *rcbuf) { - nghttp2_mem_free2(rcbuf->free, rcbuf, rcbuf->mem_user_data); -} - -void nghttp2_rcbuf_incref(nghttp2_rcbuf *rcbuf) { - if (rcbuf->ref == -1) { - return; - } - - ++rcbuf->ref; -} - -void nghttp2_rcbuf_decref(nghttp2_rcbuf *rcbuf) { - if (rcbuf == NULL || rcbuf->ref == -1) { - return; - } - - assert(rcbuf->ref > 0); - - if (--rcbuf->ref == 0) { - nghttp2_rcbuf_del(rcbuf); - } -} - -nghttp2_vec nghttp2_rcbuf_get_buf(nghttp2_rcbuf *rcbuf) { - nghttp2_vec res = {rcbuf->base, rcbuf->len}; - return res; -} - -int nghttp2_rcbuf_is_static(const nghttp2_rcbuf *rcbuf) { - return rcbuf->ref == -1; -} diff --git a/3rdparty/exported/nghttp2/nghttp2_rcbuf.h b/3rdparty/exported/nghttp2/nghttp2_rcbuf.h deleted file mode 100644 index 6814e709fb41..000000000000 --- a/3rdparty/exported/nghttp2/nghttp2_rcbuf.h +++ /dev/null @@ -1,80 +0,0 @@ -/* - * nghttp2 - HTTP/2 C Library - * - * Copyright (c) 2016 Tatsuhiro Tsujikawa - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE - * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION - * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION - * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ -#ifndef NGHTTP2_RCBUF_H -#define NGHTTP2_RCBUF_H - -#ifdef HAVE_CONFIG_H -# include -#endif /* HAVE_CONFIG_H */ - -#include - -struct nghttp2_rcbuf { - /* custom memory allocator belongs to the mem parameter when - creating this object. */ - void *mem_user_data; - nghttp2_free free; - /* The pointer to the underlying buffer */ - uint8_t *base; - /* Size of buffer pointed by |base|. */ - size_t len; - /* Reference count */ - int32_t ref; -}; - -/* - * Allocates nghttp2_rcbuf object with |size| as initial buffer size. - * When the function succeeds, the reference count becomes 1. - * - * This function returns 0 if it succeeds, or one of the following - * negative error codes: - * - * NGHTTP2_ERR_NOMEM: - * Out of memory. - */ -int nghttp2_rcbuf_new(nghttp2_rcbuf **rcbuf_ptr, size_t size, nghttp2_mem *mem); - -/* - * Like nghttp2_rcbuf_new(), but initializes the buffer with |src| of - * length |srclen|. This function allocates additional byte at the - * end and puts '\0' into it, so that the resulting buffer could be - * used as NULL-terminated string. Still (*rcbuf_ptr)->len equals to - * |srclen|. - * - * This function returns 0 if it succeeds, or one of the following - * negative error codes: - * - * NGHTTP2_ERR_NOMEM: - * Out of memory. - */ -int nghttp2_rcbuf_new2(nghttp2_rcbuf **rcbuf_ptr, const uint8_t *src, - size_t srclen, nghttp2_mem *mem); - -/* - * Frees |rcbuf| itself, regardless of its reference cout. - */ -void nghttp2_rcbuf_del(nghttp2_rcbuf *rcbuf); - -#endif /* NGHTTP2_RCBUF_H */ diff --git a/3rdparty/exported/nghttp2/nghttp2_session.c b/3rdparty/exported/nghttp2/nghttp2_session.c deleted file mode 100644 index df33a89efdc1..000000000000 --- a/3rdparty/exported/nghttp2/nghttp2_session.c +++ /dev/null @@ -1,8459 +0,0 @@ -/* - * nghttp2 - HTTP/2 C Library - * - * Copyright (c) 2012 Tatsuhiro Tsujikawa - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE - * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION - * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION - * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ -#include "nghttp2_session.h" - -#include -#include -#include -#include -#include - -#include "nghttp2_helper.h" -#include "nghttp2_net.h" -#include "nghttp2_priority_spec.h" -#include "nghttp2_option.h" -#include "nghttp2_http.h" -#include "nghttp2_pq.h" -#include "nghttp2_extpri.h" -#include "nghttp2_time.h" -#include "nghttp2_debug.h" -#include "nghttp2_submit.h" - -/* - * Returns non-zero if the number of outgoing opened streams is larger - * than or equal to - * remote_settings.max_concurrent_streams. - */ -static int -session_is_outgoing_concurrent_streams_max(nghttp2_session *session) { - return session->remote_settings.max_concurrent_streams <= - session->num_outgoing_streams; -} - -/* - * Returns non-zero if the number of incoming opened streams is larger - * than or equal to - * local_settings.max_concurrent_streams. - */ -static int -session_is_incoming_concurrent_streams_max(nghttp2_session *session) { - return session->local_settings.max_concurrent_streams <= - session->num_incoming_streams; -} - -/* - * Returns non-zero if the number of incoming opened streams is larger - * than or equal to - * session->pending_local_max_concurrent_stream. - */ -static int -session_is_incoming_concurrent_streams_pending_max(nghttp2_session *session) { - return session->pending_local_max_concurrent_stream <= - session->num_incoming_streams; -} - -/* - * Returns non-zero if |lib_error| is non-fatal error. - */ -static int is_non_fatal(int lib_error_code) { - return lib_error_code < 0 && lib_error_code > NGHTTP2_ERR_FATAL; -} - -int nghttp2_is_fatal(int lib_error_code) { - return lib_error_code < NGHTTP2_ERR_FATAL; -} - -static int session_enforce_http_messaging(nghttp2_session *session) { - return (session->opt_flags & NGHTTP2_OPTMASK_NO_HTTP_MESSAGING) == 0; -} - -/* - * Returns nonzero if |frame| is trailer headers. - */ -static int session_trailer_headers(nghttp2_session *session, - nghttp2_stream *stream, - nghttp2_frame *frame) { - if (!stream || frame->hd.type != NGHTTP2_HEADERS) { - return 0; - } - if (session->server) { - return frame->headers.cat == NGHTTP2_HCAT_HEADERS; - } - - return frame->headers.cat == NGHTTP2_HCAT_HEADERS && - (stream->http_flags & NGHTTP2_HTTP_FLAG_EXPECT_FINAL_RESPONSE) == 0; -} - -/* Returns nonzero if the |stream| is in reserved(remote) state */ -static int state_reserved_remote(nghttp2_session *session, - nghttp2_stream *stream) { - return stream->state == NGHTTP2_STREAM_RESERVED && - !nghttp2_session_is_my_stream_id(session, stream->stream_id); -} - -/* Returns nonzero if the |stream| is in reserved(local) state */ -static int state_reserved_local(nghttp2_session *session, - nghttp2_stream *stream) { - return stream->state == NGHTTP2_STREAM_RESERVED && - nghttp2_session_is_my_stream_id(session, stream->stream_id); -} - -/* - * Checks whether received stream_id is valid. This function returns - * 1 if it succeeds, or 0. - */ -static int session_is_new_peer_stream_id(nghttp2_session *session, - int32_t stream_id) { - return stream_id != 0 && - !nghttp2_session_is_my_stream_id(session, stream_id) && - session->last_recv_stream_id < stream_id; -} - -static int session_detect_idle_stream(nghttp2_session *session, - int32_t stream_id) { - /* Assume that stream object with stream_id does not exist */ - if (nghttp2_session_is_my_stream_id(session, stream_id)) { - if (session->last_sent_stream_id < stream_id) { - return 1; - } - return 0; - } - if (session_is_new_peer_stream_id(session, stream_id)) { - return 1; - } - return 0; -} - -static int session_no_rfc7540_pri_no_fallback(nghttp2_session *session) { - return session->pending_no_rfc7540_priorities == 1 && - !session->fallback_rfc7540_priorities; -} - -static int check_ext_type_set(const uint8_t *ext_types, uint8_t type) { - return (ext_types[type / 8] & (1 << (type & 0x7))) > 0; -} - -static int session_call_error_callback(nghttp2_session *session, - int lib_error_code, const char *fmt, - ...) { - size_t bufsize; - va_list ap; - char *buf; - int rv; - nghttp2_mem *mem; - - if (!session->callbacks.error_callback && - !session->callbacks.error_callback2) { - return 0; - } - - mem = &session->mem; - - va_start(ap, fmt); - rv = vsnprintf(NULL, 0, fmt, ap); - va_end(ap); - - if (rv < 0) { - return NGHTTP2_ERR_NOMEM; - } - - bufsize = (size_t)(rv + 1); - - buf = nghttp2_mem_malloc(mem, bufsize); - if (buf == NULL) { - return NGHTTP2_ERR_NOMEM; - } - - va_start(ap, fmt); - rv = vsnprintf(buf, bufsize, fmt, ap); - va_end(ap); - - if (rv < 0) { - nghttp2_mem_free(mem, buf); - /* vsnprintf may return error because of various things we can - imagine, but typically we don't want to drop session just for - debug callback. */ - DEBUGF("error_callback: vsnprintf failed. The template was %s\n", fmt); - return 0; - } - - if (session->callbacks.error_callback2) { - rv = session->callbacks.error_callback2(session, lib_error_code, buf, - (size_t)rv, session->user_data); - } else { - rv = session->callbacks.error_callback(session, buf, (size_t)rv, - session->user_data); - } - - nghttp2_mem_free(mem, buf); - - if (rv != 0) { - return NGHTTP2_ERR_CALLBACK_FAILURE; - } - - return 0; -} - -static int session_terminate_session(nghttp2_session *session, - int32_t last_stream_id, - uint32_t error_code, const char *reason) { - int rv; - const uint8_t *debug_data; - size_t debug_datalen; - - if (session->goaway_flags & NGHTTP2_GOAWAY_TERM_ON_SEND) { - return 0; - } - - /* Ignore all incoming frames because we are going to tear down the - session. */ - session->iframe.state = NGHTTP2_IB_IGN_ALL; - - if (reason == NULL) { - debug_data = NULL; - debug_datalen = 0; - } else { - debug_data = (const uint8_t *)reason; - debug_datalen = strlen(reason); - } - - rv = - nghttp2_session_add_goaway(session, last_stream_id, error_code, debug_data, - debug_datalen, NGHTTP2_GOAWAY_AUX_TERM_ON_SEND); - - if (rv != 0) { - return rv; - } - - session->goaway_flags |= NGHTTP2_GOAWAY_TERM_ON_SEND; - - return 0; -} - -int nghttp2_session_terminate_session(nghttp2_session *session, - uint32_t error_code) { - return session_terminate_session(session, session->last_proc_stream_id, - error_code, NULL); -} - -int nghttp2_session_terminate_session2(nghttp2_session *session, - int32_t last_stream_id, - uint32_t error_code) { - return session_terminate_session(session, last_stream_id, error_code, NULL); -} - -int nghttp2_session_terminate_session_with_reason(nghttp2_session *session, - uint32_t error_code, - const char *reason) { - return session_terminate_session(session, session->last_proc_stream_id, - error_code, reason); -} - -int nghttp2_session_is_my_stream_id(nghttp2_session *session, - int32_t stream_id) { - int rem; - if (stream_id == 0) { - return 0; - } - rem = stream_id & 0x1; - if (session->server) { - return rem == 0; - } - return rem == 1; -} - -nghttp2_stream *nghttp2_session_get_stream(nghttp2_session *session, - int32_t stream_id) { - nghttp2_stream *stream; - - stream = (nghttp2_stream *)nghttp2_map_find(&session->streams, stream_id); - - if (stream == NULL || (stream->flags & NGHTTP2_STREAM_FLAG_CLOSED) || - stream->state == NGHTTP2_STREAM_IDLE) { - return NULL; - } - - return stream; -} - -nghttp2_stream *nghttp2_session_get_stream_raw(nghttp2_session *session, - int32_t stream_id) { - return (nghttp2_stream *)nghttp2_map_find(&session->streams, stream_id); -} - -static void session_inbound_frame_reset(nghttp2_session *session) { - nghttp2_inbound_frame *iframe = &session->iframe; - nghttp2_mem *mem = &session->mem; - /* A bit risky code, since if this function is called from - nghttp2_session_new(), we rely on the fact that - iframe->frame.hd.type is 0, so that no free is performed. */ - switch (iframe->frame.hd.type) { - case NGHTTP2_DATA: - break; - case NGHTTP2_HEADERS: - nghttp2_frame_headers_free(&iframe->frame.headers, mem); - break; - case NGHTTP2_PRIORITY: - nghttp2_frame_priority_free(&iframe->frame.priority); - break; - case NGHTTP2_RST_STREAM: - nghttp2_frame_rst_stream_free(&iframe->frame.rst_stream); - break; - case NGHTTP2_SETTINGS: - nghttp2_frame_settings_free(&iframe->frame.settings, mem); - - nghttp2_mem_free(mem, iframe->iv); - - iframe->iv = NULL; - iframe->niv = 0; - iframe->max_niv = 0; - - break; - case NGHTTP2_PUSH_PROMISE: - nghttp2_frame_push_promise_free(&iframe->frame.push_promise, mem); - break; - case NGHTTP2_PING: - nghttp2_frame_ping_free(&iframe->frame.ping); - break; - case NGHTTP2_GOAWAY: - nghttp2_frame_goaway_free(&iframe->frame.goaway, mem); - break; - case NGHTTP2_WINDOW_UPDATE: - nghttp2_frame_window_update_free(&iframe->frame.window_update); - break; - default: - /* extension frame */ - if (check_ext_type_set(session->user_recv_ext_types, - iframe->frame.hd.type)) { - nghttp2_frame_extension_free(&iframe->frame.ext); - } else { - switch (iframe->frame.hd.type) { - case NGHTTP2_ALTSVC: - if ((session->builtin_recv_ext_types & NGHTTP2_TYPEMASK_ALTSVC) == 0) { - break; - } - nghttp2_frame_altsvc_free(&iframe->frame.ext, mem); - break; - case NGHTTP2_ORIGIN: - if ((session->builtin_recv_ext_types & NGHTTP2_TYPEMASK_ORIGIN) == 0) { - break; - } - nghttp2_frame_origin_free(&iframe->frame.ext, mem); - break; - case NGHTTP2_PRIORITY_UPDATE: - if ((session->builtin_recv_ext_types & - NGHTTP2_TYPEMASK_PRIORITY_UPDATE) == 0) { - break; - } - /* Do not call nghttp2_frame_priority_update_free, because all - fields point to sbuf. */ - break; - } - } - - break; - } - - memset(&iframe->frame, 0, sizeof(nghttp2_frame)); - memset(&iframe->ext_frame_payload, 0, sizeof(nghttp2_ext_frame_payload)); - - iframe->state = NGHTTP2_IB_READ_HEAD; - - nghttp2_buf_wrap_init(&iframe->sbuf, iframe->raw_sbuf, - sizeof(iframe->raw_sbuf)); - iframe->sbuf.mark += NGHTTP2_FRAME_HDLEN; - - nghttp2_buf_free(&iframe->lbuf, mem); - nghttp2_buf_wrap_init(&iframe->lbuf, NULL, 0); - - iframe->raw_lbuf = NULL; - - iframe->payloadleft = 0; - iframe->padlen = 0; -} - -static void init_settings(nghttp2_settings_storage *settings) { - settings->header_table_size = NGHTTP2_HD_DEFAULT_MAX_BUFFER_SIZE; - settings->enable_push = 1; - settings->max_concurrent_streams = NGHTTP2_DEFAULT_MAX_CONCURRENT_STREAMS; - settings->initial_window_size = NGHTTP2_INITIAL_WINDOW_SIZE; - settings->max_frame_size = NGHTTP2_MAX_FRAME_SIZE_MIN; - settings->max_header_list_size = UINT32_MAX; - settings->no_rfc7540_priorities = UINT32_MAX; -} - -static void active_outbound_item_reset(nghttp2_active_outbound_item *aob, - nghttp2_mem *mem) { - DEBUGF("send: reset nghttp2_active_outbound_item\n"); - DEBUGF("send: aob->item = %p\n", aob->item); - nghttp2_outbound_item_free(aob->item, mem); - nghttp2_mem_free(mem, aob->item); - aob->item = NULL; - nghttp2_bufs_reset(&aob->framebufs); - aob->state = NGHTTP2_OB_POP_ITEM; -} - -#define NGHTTP2_STREAM_MAX_CYCLE_GAP ((uint64_t)NGHTTP2_MAX_FRAME_SIZE_MAX) - -static int stream_less(const void *lhsx, const void *rhsx) { - const nghttp2_stream *lhs, *rhs; - - lhs = nghttp2_struct_of(lhsx, nghttp2_stream, pq_entry); - rhs = nghttp2_struct_of(rhsx, nghttp2_stream, pq_entry); - - if (lhs->cycle == rhs->cycle) { - return lhs->seq < rhs->seq; - } - - return rhs->cycle - lhs->cycle <= NGHTTP2_STREAM_MAX_CYCLE_GAP; -} - -int nghttp2_enable_strict_preface = 1; - -static int session_new(nghttp2_session **session_ptr, - const nghttp2_session_callbacks *callbacks, - void *user_data, int server, - const nghttp2_option *option, nghttp2_mem *mem) { - int rv; - size_t nbuffer; - size_t max_deflate_dynamic_table_size = - NGHTTP2_HD_DEFAULT_MAX_DEFLATE_BUFFER_SIZE; - size_t i; - - if (mem == NULL) { - mem = nghttp2_mem_default(); - } - - *session_ptr = nghttp2_mem_calloc(mem, 1, sizeof(nghttp2_session)); - if (*session_ptr == NULL) { - rv = NGHTTP2_ERR_NOMEM; - goto fail_session; - } - - (*session_ptr)->mem = *mem; - mem = &(*session_ptr)->mem; - - /* next_stream_id is initialized in either - nghttp2_session_client_new2 or nghttp2_session_server_new2 */ - - nghttp2_stream_init(&(*session_ptr)->root, 0, NGHTTP2_STREAM_FLAG_NONE, - NGHTTP2_STREAM_IDLE, NGHTTP2_DEFAULT_WEIGHT, 0, 0, NULL, - mem); - - (*session_ptr)->remote_window_size = NGHTTP2_INITIAL_CONNECTION_WINDOW_SIZE; - (*session_ptr)->recv_window_size = 0; - (*session_ptr)->consumed_size = 0; - (*session_ptr)->recv_reduction = 0; - (*session_ptr)->local_window_size = NGHTTP2_INITIAL_CONNECTION_WINDOW_SIZE; - - (*session_ptr)->goaway_flags = NGHTTP2_GOAWAY_NONE; - (*session_ptr)->local_last_stream_id = (1u << 31) - 1; - (*session_ptr)->remote_last_stream_id = (1u << 31) - 1; - - (*session_ptr)->pending_local_max_concurrent_stream = - NGHTTP2_DEFAULT_MAX_CONCURRENT_STREAMS; - (*session_ptr)->pending_enable_push = 1; - (*session_ptr)->pending_no_rfc7540_priorities = UINT8_MAX; - - nghttp2_ratelim_init(&(*session_ptr)->stream_reset_ratelim, - NGHTTP2_DEFAULT_STREAM_RESET_BURST, - NGHTTP2_DEFAULT_STREAM_RESET_RATE); - - if (server) { - (*session_ptr)->server = 1; - } - - init_settings(&(*session_ptr)->remote_settings); - init_settings(&(*session_ptr)->local_settings); - - (*session_ptr)->max_incoming_reserved_streams = - NGHTTP2_MAX_INCOMING_RESERVED_STREAMS; - - /* Limit max outgoing concurrent streams to sensible value */ - (*session_ptr)->remote_settings.max_concurrent_streams = 100; - - (*session_ptr)->max_send_header_block_length = NGHTTP2_MAX_HEADERSLEN; - (*session_ptr)->max_outbound_ack = NGHTTP2_DEFAULT_MAX_OBQ_FLOOD_ITEM; - (*session_ptr)->max_settings = NGHTTP2_DEFAULT_MAX_SETTINGS; - (*session_ptr)->max_continuations = NGHTTP2_DEFAULT_MAX_CONTINUATIONS; - - if (option) { - if ((option->opt_set_mask & NGHTTP2_OPT_NO_AUTO_WINDOW_UPDATE) && - option->no_auto_window_update) { - (*session_ptr)->opt_flags |= NGHTTP2_OPTMASK_NO_AUTO_WINDOW_UPDATE; - } - - if (option->opt_set_mask & NGHTTP2_OPT_PEER_MAX_CONCURRENT_STREAMS) { - (*session_ptr)->remote_settings.max_concurrent_streams = - option->peer_max_concurrent_streams; - } - - if (option->opt_set_mask & NGHTTP2_OPT_MAX_RESERVED_REMOTE_STREAMS) { - (*session_ptr)->max_incoming_reserved_streams = - option->max_reserved_remote_streams; - } - - if ((option->opt_set_mask & NGHTTP2_OPT_NO_RECV_CLIENT_MAGIC) && - option->no_recv_client_magic) { - (*session_ptr)->opt_flags |= NGHTTP2_OPTMASK_NO_RECV_CLIENT_MAGIC; - } - - if ((option->opt_set_mask & NGHTTP2_OPT_NO_HTTP_MESSAGING) && - option->no_http_messaging) { - (*session_ptr)->opt_flags |= NGHTTP2_OPTMASK_NO_HTTP_MESSAGING; - } - - if (option->opt_set_mask & NGHTTP2_OPT_USER_RECV_EXT_TYPES) { - memcpy((*session_ptr)->user_recv_ext_types, option->user_recv_ext_types, - sizeof((*session_ptr)->user_recv_ext_types)); - } - - if (option->opt_set_mask & NGHTTP2_OPT_BUILTIN_RECV_EXT_TYPES) { - (*session_ptr)->builtin_recv_ext_types = option->builtin_recv_ext_types; - } - - if ((option->opt_set_mask & NGHTTP2_OPT_NO_AUTO_PING_ACK) && - option->no_auto_ping_ack) { - (*session_ptr)->opt_flags |= NGHTTP2_OPTMASK_NO_AUTO_PING_ACK; - } - - if (option->opt_set_mask & NGHTTP2_OPT_MAX_SEND_HEADER_BLOCK_LENGTH) { - (*session_ptr)->max_send_header_block_length = - option->max_send_header_block_length; - } - - if (option->opt_set_mask & NGHTTP2_OPT_MAX_DEFLATE_DYNAMIC_TABLE_SIZE) { - max_deflate_dynamic_table_size = option->max_deflate_dynamic_table_size; - } - - if ((option->opt_set_mask & NGHTTP2_OPT_NO_CLOSED_STREAMS) && - option->no_closed_streams) { - (*session_ptr)->opt_flags |= NGHTTP2_OPTMASK_NO_CLOSED_STREAMS; - } - - if (option->opt_set_mask & NGHTTP2_OPT_MAX_OUTBOUND_ACK) { - (*session_ptr)->max_outbound_ack = option->max_outbound_ack; - } - - if ((option->opt_set_mask & NGHTTP2_OPT_MAX_SETTINGS) && - option->max_settings) { - (*session_ptr)->max_settings = option->max_settings; - } - - if ((option->opt_set_mask & - NGHTTP2_OPT_SERVER_FALLBACK_RFC7540_PRIORITIES) && - option->server_fallback_rfc7540_priorities) { - (*session_ptr)->opt_flags |= - NGHTTP2_OPTMASK_SERVER_FALLBACK_RFC7540_PRIORITIES; - } - - if ((option->opt_set_mask & - NGHTTP2_OPT_NO_RFC9113_LEADING_AND_TRAILING_WS_VALIDATION) && - option->no_rfc9113_leading_and_trailing_ws_validation) { - (*session_ptr)->opt_flags |= - NGHTTP2_OPTMASK_NO_RFC9113_LEADING_AND_TRAILING_WS_VALIDATION; - } - - if (option->opt_set_mask & NGHTTP2_OPT_STREAM_RESET_RATE_LIMIT) { - nghttp2_ratelim_init(&(*session_ptr)->stream_reset_ratelim, - option->stream_reset_burst, - option->stream_reset_rate); - } - - if (option->opt_set_mask & NGHTTP2_OPT_MAX_CONTINUATIONS) { - (*session_ptr)->max_continuations = option->max_continuations; - } - } - - rv = nghttp2_hd_deflate_init2(&(*session_ptr)->hd_deflater, - max_deflate_dynamic_table_size, mem); - if (rv != 0) { - goto fail_hd_deflater; - } - rv = nghttp2_hd_inflate_init(&(*session_ptr)->hd_inflater, mem); - if (rv != 0) { - goto fail_hd_inflater; - } - - nbuffer = ((*session_ptr)->max_send_header_block_length + - NGHTTP2_FRAMEBUF_CHUNKLEN - 1) / - NGHTTP2_FRAMEBUF_CHUNKLEN; - - if (nbuffer == 0) { - nbuffer = 1; - } - - /* 1 for Pad Field. */ - rv = nghttp2_bufs_init3(&(*session_ptr)->aob.framebufs, - NGHTTP2_FRAMEBUF_CHUNKLEN, nbuffer, 1, - NGHTTP2_FRAME_HDLEN + 1, mem); - if (rv != 0) { - goto fail_aob_framebuf; - } - - nghttp2_map_init(&(*session_ptr)->streams, mem); - - active_outbound_item_reset(&(*session_ptr)->aob, mem); - - (*session_ptr)->callbacks = *callbacks; - (*session_ptr)->user_data = user_data; - - session_inbound_frame_reset(*session_ptr); - - if (nghttp2_enable_strict_preface) { - nghttp2_inbound_frame *iframe = &(*session_ptr)->iframe; - - if (server && ((*session_ptr)->opt_flags & - NGHTTP2_OPTMASK_NO_RECV_CLIENT_MAGIC) == 0) { - iframe->state = NGHTTP2_IB_READ_CLIENT_MAGIC; - iframe->payloadleft = NGHTTP2_CLIENT_MAGIC_LEN; - } else { - iframe->state = NGHTTP2_IB_READ_FIRST_SETTINGS; - } - - if (!server) { - (*session_ptr)->aob.state = NGHTTP2_OB_SEND_CLIENT_MAGIC; - nghttp2_bufs_add(&(*session_ptr)->aob.framebufs, NGHTTP2_CLIENT_MAGIC, - NGHTTP2_CLIENT_MAGIC_LEN); - } - } - - for (i = 0; i < NGHTTP2_EXTPRI_URGENCY_LEVELS; ++i) { - nghttp2_pq_init(&(*session_ptr)->sched[i].ob_data, stream_less, mem); - } - - return 0; - -fail_aob_framebuf: - nghttp2_hd_inflate_free(&(*session_ptr)->hd_inflater); -fail_hd_inflater: - nghttp2_hd_deflate_free(&(*session_ptr)->hd_deflater); -fail_hd_deflater: - nghttp2_mem_free(mem, *session_ptr); -fail_session: - return rv; -} - -int nghttp2_session_client_new(nghttp2_session **session_ptr, - const nghttp2_session_callbacks *callbacks, - void *user_data) { - return nghttp2_session_client_new3(session_ptr, callbacks, user_data, NULL, - NULL); -} - -int nghttp2_session_client_new2(nghttp2_session **session_ptr, - const nghttp2_session_callbacks *callbacks, - void *user_data, const nghttp2_option *option) { - return nghttp2_session_client_new3(session_ptr, callbacks, user_data, option, - NULL); -} - -int nghttp2_session_client_new3(nghttp2_session **session_ptr, - const nghttp2_session_callbacks *callbacks, - void *user_data, const nghttp2_option *option, - nghttp2_mem *mem) { - int rv; - nghttp2_session *session; - - rv = session_new(&session, callbacks, user_data, 0, option, mem); - - if (rv != 0) { - return rv; - } - /* IDs for use in client */ - session->next_stream_id = 1; - - *session_ptr = session; - - return 0; -} - -int nghttp2_session_server_new(nghttp2_session **session_ptr, - const nghttp2_session_callbacks *callbacks, - void *user_data) { - return nghttp2_session_server_new3(session_ptr, callbacks, user_data, NULL, - NULL); -} - -int nghttp2_session_server_new2(nghttp2_session **session_ptr, - const nghttp2_session_callbacks *callbacks, - void *user_data, const nghttp2_option *option) { - return nghttp2_session_server_new3(session_ptr, callbacks, user_data, option, - NULL); -} - -int nghttp2_session_server_new3(nghttp2_session **session_ptr, - const nghttp2_session_callbacks *callbacks, - void *user_data, const nghttp2_option *option, - nghttp2_mem *mem) { - int rv; - nghttp2_session *session; - - rv = session_new(&session, callbacks, user_data, 1, option, mem); - - if (rv != 0) { - return rv; - } - /* IDs for use in client */ - session->next_stream_id = 2; - - *session_ptr = session; - - return 0; -} - -static int free_streams(void *entry, void *ptr) { - nghttp2_session *session; - nghttp2_stream *stream; - nghttp2_outbound_item *item; - nghttp2_mem *mem; - - session = (nghttp2_session *)ptr; - mem = &session->mem; - stream = (nghttp2_stream *)entry; - item = stream->item; - - if (item && !item->queued && item != session->aob.item) { - nghttp2_outbound_item_free(item, mem); - nghttp2_mem_free(mem, item); - } - - nghttp2_stream_free(stream); - nghttp2_mem_free(mem, stream); - - return 0; -} - -static void ob_q_free(nghttp2_outbound_queue *q, nghttp2_mem *mem) { - nghttp2_outbound_item *item, *next; - for (item = q->head; item;) { - next = item->qnext; - nghttp2_outbound_item_free(item, mem); - nghttp2_mem_free(mem, item); - item = next; - } -} - -static int inflight_settings_new(nghttp2_inflight_settings **settings_ptr, - const nghttp2_settings_entry *iv, size_t niv, - nghttp2_mem *mem) { - *settings_ptr = nghttp2_mem_malloc(mem, sizeof(nghttp2_inflight_settings)); - if (!*settings_ptr) { - return NGHTTP2_ERR_NOMEM; - } - - if (niv > 0) { - (*settings_ptr)->iv = nghttp2_frame_iv_copy(iv, niv, mem); - if (!(*settings_ptr)->iv) { - nghttp2_mem_free(mem, *settings_ptr); - return NGHTTP2_ERR_NOMEM; - } - } else { - (*settings_ptr)->iv = NULL; - } - - (*settings_ptr)->niv = niv; - (*settings_ptr)->next = NULL; - - return 0; -} - -static void inflight_settings_del(nghttp2_inflight_settings *settings, - nghttp2_mem *mem) { - if (!settings) { - return; - } - - nghttp2_mem_free(mem, settings->iv); - nghttp2_mem_free(mem, settings); -} - -void nghttp2_session_del(nghttp2_session *session) { - nghttp2_mem *mem; - nghttp2_inflight_settings *settings; - size_t i; - - if (session == NULL) { - return; - } - - mem = &session->mem; - - for (settings = session->inflight_settings_head; settings;) { - nghttp2_inflight_settings *next = settings->next; - inflight_settings_del(settings, mem); - settings = next; - } - - for (i = 0; i < NGHTTP2_EXTPRI_URGENCY_LEVELS; ++i) { - nghttp2_pq_free(&session->sched[i].ob_data); - } - nghttp2_stream_free(&session->root); - - /* Have to free streams first, so that we can check - stream->item->queued */ - nghttp2_map_each(&session->streams, free_streams, session); - nghttp2_map_free(&session->streams); - - ob_q_free(&session->ob_urgent, mem); - ob_q_free(&session->ob_reg, mem); - ob_q_free(&session->ob_syn, mem); - - active_outbound_item_reset(&session->aob, mem); - session_inbound_frame_reset(session); - nghttp2_hd_deflate_free(&session->hd_deflater); - nghttp2_hd_inflate_free(&session->hd_inflater); - nghttp2_bufs_free(&session->aob.framebufs); - nghttp2_mem_free(mem, session); -} - -int nghttp2_session_reprioritize_stream( - nghttp2_session *session, nghttp2_stream *stream, - const nghttp2_priority_spec *pri_spec_in) { - int rv; - nghttp2_stream *dep_stream = NULL; - nghttp2_priority_spec pri_spec_default; - const nghttp2_priority_spec *pri_spec = pri_spec_in; - - assert((!session->server && session->pending_no_rfc7540_priorities != 1) || - (session->server && !session_no_rfc7540_pri_no_fallback(session))); - assert(pri_spec->stream_id != stream->stream_id); - - if (!nghttp2_stream_in_dep_tree(stream)) { - return 0; - } - - if (pri_spec->stream_id != 0) { - dep_stream = nghttp2_session_get_stream_raw(session, pri_spec->stream_id); - - if (!dep_stream && - session_detect_idle_stream(session, pri_spec->stream_id)) { - nghttp2_priority_spec_default_init(&pri_spec_default); - - dep_stream = nghttp2_session_open_stream( - session, pri_spec->stream_id, NGHTTP2_FLAG_NONE, &pri_spec_default, - NGHTTP2_STREAM_IDLE, NULL); - - if (dep_stream == NULL) { - return NGHTTP2_ERR_NOMEM; - } - } else if (!dep_stream || !nghttp2_stream_in_dep_tree(dep_stream)) { - nghttp2_priority_spec_default_init(&pri_spec_default); - pri_spec = &pri_spec_default; - } - } - - if (pri_spec->stream_id == 0) { - dep_stream = &session->root; - } else if (nghttp2_stream_dep_find_ancestor(dep_stream, stream)) { - DEBUGF("stream: cycle detected, dep_stream(%p)=%d stream(%p)=%d\n", - dep_stream, dep_stream->stream_id, stream, stream->stream_id); - - nghttp2_stream_dep_remove_subtree(dep_stream); - rv = nghttp2_stream_dep_add_subtree(stream->dep_prev, dep_stream); - if (rv != 0) { - return rv; - } - } - - assert(dep_stream); - - if (dep_stream == stream->dep_prev && !pri_spec->exclusive) { - /* This is minor optimization when just weight is changed. */ - nghttp2_stream_change_weight(stream, pri_spec->weight); - - return 0; - } - - nghttp2_stream_dep_remove_subtree(stream); - - /* We have to update weight after removing stream from tree */ - stream->weight = pri_spec->weight; - - if (pri_spec->exclusive) { - rv = nghttp2_stream_dep_insert_subtree(dep_stream, stream); - } else { - rv = nghttp2_stream_dep_add_subtree(dep_stream, stream); - } - - if (rv != 0) { - return rv; - } - - return 0; -} - -static uint64_t pq_get_first_cycle(nghttp2_pq *pq) { - nghttp2_stream *stream; - - if (nghttp2_pq_empty(pq)) { - return 0; - } - - stream = nghttp2_struct_of(nghttp2_pq_top(pq), nghttp2_stream, pq_entry); - return stream->cycle; -} - -static int session_ob_data_push(nghttp2_session *session, - nghttp2_stream *stream) { - int rv; - uint32_t urgency; - int inc; - nghttp2_pq *pq; - - assert(stream->flags & NGHTTP2_STREAM_FLAG_NO_RFC7540_PRIORITIES); - assert(stream->queued == 0); - - urgency = nghttp2_extpri_uint8_urgency(stream->extpri); - inc = nghttp2_extpri_uint8_inc(stream->extpri); - - assert(urgency < NGHTTP2_EXTPRI_URGENCY_LEVELS); - - pq = &session->sched[urgency].ob_data; - - stream->cycle = pq_get_first_cycle(pq); - if (inc) { - stream->cycle += stream->last_writelen; - } - - rv = nghttp2_pq_push(pq, &stream->pq_entry); - if (rv != 0) { - return rv; - } - - stream->queued = 1; - - return 0; -} - -static void session_ob_data_remove(nghttp2_session *session, - nghttp2_stream *stream) { - uint32_t urgency; - - assert(stream->flags & NGHTTP2_STREAM_FLAG_NO_RFC7540_PRIORITIES); - assert(stream->queued == 1); - - urgency = nghttp2_extpri_uint8_urgency(stream->extpri); - - assert(urgency < NGHTTP2_EXTPRI_URGENCY_LEVELS); - - nghttp2_pq_remove(&session->sched[urgency].ob_data, &stream->pq_entry); - - stream->queued = 0; -} - -static int session_attach_stream_item(nghttp2_session *session, - nghttp2_stream *stream, - nghttp2_outbound_item *item) { - int rv; - - rv = nghttp2_stream_attach_item(stream, item); - if (rv != 0) { - return rv; - } - - if (!(stream->flags & NGHTTP2_STREAM_FLAG_NO_RFC7540_PRIORITIES)) { - return 0; - } - - rv = session_ob_data_push(session, stream); - if (rv != 0) { - nghttp2_stream_detach_item(stream); - - return rv; - } - - return 0; -} - -static void session_detach_stream_item(nghttp2_session *session, - nghttp2_stream *stream) { - nghttp2_stream_detach_item(stream); - - if (!(stream->flags & NGHTTP2_STREAM_FLAG_NO_RFC7540_PRIORITIES) || - !stream->queued) { - return; - } - - session_ob_data_remove(session, stream); -} - -static void session_defer_stream_item(nghttp2_session *session, - nghttp2_stream *stream, uint8_t flags) { - nghttp2_stream_defer_item(stream, flags); - - if (!(stream->flags & NGHTTP2_STREAM_FLAG_NO_RFC7540_PRIORITIES) || - !stream->queued) { - return; - } - - session_ob_data_remove(session, stream); -} - -static int session_resume_deferred_stream_item(nghttp2_session *session, - nghttp2_stream *stream, - uint8_t flags) { - int rv; - - rv = nghttp2_stream_resume_deferred_item(stream, flags); - if (rv != 0) { - return rv; - } - - if (!(stream->flags & NGHTTP2_STREAM_FLAG_NO_RFC7540_PRIORITIES) || - (stream->flags & NGHTTP2_STREAM_FLAG_DEFERRED_ALL)) { - return 0; - } - - return session_ob_data_push(session, stream); -} - -static nghttp2_outbound_item * -session_sched_get_next_outbound_item(nghttp2_session *session) { - size_t i; - nghttp2_pq_entry *ent; - nghttp2_stream *stream; - - for (i = 0; i < NGHTTP2_EXTPRI_URGENCY_LEVELS; ++i) { - ent = nghttp2_pq_top(&session->sched[i].ob_data); - if (!ent) { - continue; - } - - stream = nghttp2_struct_of(ent, nghttp2_stream, pq_entry); - return stream->item; - } - - return NULL; -} - -static int session_sched_empty(nghttp2_session *session) { - size_t i; - - for (i = 0; i < NGHTTP2_EXTPRI_URGENCY_LEVELS; ++i) { - if (!nghttp2_pq_empty(&session->sched[i].ob_data)) { - return 0; - } - } - - return 1; -} - -static void session_sched_reschedule_stream(nghttp2_session *session, - nghttp2_stream *stream) { - nghttp2_pq *pq; - uint32_t urgency = nghttp2_extpri_uint8_urgency(stream->extpri); - int inc = nghttp2_extpri_uint8_inc(stream->extpri); - uint64_t penalty = (uint64_t)stream->last_writelen; - int rv; - - (void)rv; - - assert(urgency < NGHTTP2_EXTPRI_URGENCY_LEVELS); - - pq = &session->sched[urgency].ob_data; - - if (!inc || nghttp2_pq_size(pq) == 1) { - return; - } - - nghttp2_pq_remove(pq, &stream->pq_entry); - - stream->cycle += penalty; - - rv = nghttp2_pq_push(pq, &stream->pq_entry); - - assert(0 == rv); -} - -static int session_update_stream_priority(nghttp2_session *session, - nghttp2_stream *stream, - uint8_t u8extpri) { - if (stream->extpri == u8extpri) { - return 0; - } - - if (stream->queued) { - session_ob_data_remove(session, stream); - - stream->extpri = u8extpri; - - return session_ob_data_push(session, stream); - } - - stream->extpri = u8extpri; - - return 0; -} - -int nghttp2_session_add_item(nghttp2_session *session, - nghttp2_outbound_item *item) { - /* TODO Return error if stream is not found for the frame requiring - stream presence. */ - int rv = 0; - nghttp2_stream *stream; - nghttp2_frame *frame; - - frame = &item->frame; - stream = nghttp2_session_get_stream(session, frame->hd.stream_id); - - switch (frame->hd.type) { - case NGHTTP2_DATA: - if (!stream) { - return NGHTTP2_ERR_STREAM_CLOSED; - } - - if (stream->item) { - return NGHTTP2_ERR_DATA_EXIST; - } - - rv = session_attach_stream_item(session, stream, item); - - if (rv != 0) { - return rv; - } - - return 0; - case NGHTTP2_HEADERS: - /* We push request HEADERS and push response HEADERS to - dedicated queue because their transmission is affected by - SETTINGS_MAX_CONCURRENT_STREAMS */ - /* TODO If 2 HEADERS are submitted for reserved stream, then - both of them are queued into ob_syn, which is not - desirable. */ - if (frame->headers.cat == NGHTTP2_HCAT_REQUEST || - (stream && stream->state == NGHTTP2_STREAM_RESERVED)) { - nghttp2_outbound_queue_push(&session->ob_syn, item); - item->queued = 1; - return 0; - ; - } - - nghttp2_outbound_queue_push(&session->ob_reg, item); - item->queued = 1; - return 0; - case NGHTTP2_SETTINGS: - case NGHTTP2_PING: - nghttp2_outbound_queue_push(&session->ob_urgent, item); - item->queued = 1; - return 0; - case NGHTTP2_RST_STREAM: - if (stream) { - stream->state = NGHTTP2_STREAM_CLOSING; - } - nghttp2_outbound_queue_push(&session->ob_reg, item); - item->queued = 1; - return 0; - case NGHTTP2_PUSH_PROMISE: { - nghttp2_headers_aux_data *aux_data; - nghttp2_priority_spec pri_spec; - - aux_data = &item->aux_data.headers; - - if (!stream) { - return NGHTTP2_ERR_STREAM_CLOSED; - } - - nghttp2_priority_spec_init(&pri_spec, stream->stream_id, - NGHTTP2_DEFAULT_WEIGHT, 0); - - if (!nghttp2_session_open_stream( - session, frame->push_promise.promised_stream_id, - NGHTTP2_STREAM_FLAG_NONE, &pri_spec, NGHTTP2_STREAM_RESERVED, - aux_data->stream_user_data)) { - return NGHTTP2_ERR_NOMEM; - } - - /* We don't have to call nghttp2_session_adjust_closed_stream() - here, since stream->stream_id is local stream_id, and it does - not affect closed stream count. */ - - nghttp2_outbound_queue_push(&session->ob_reg, item); - item->queued = 1; - - return 0; - } - case NGHTTP2_WINDOW_UPDATE: - if (stream) { - stream->window_update_queued = 1; - } else if (frame->hd.stream_id == 0) { - session->window_update_queued = 1; - } - nghttp2_outbound_queue_push(&session->ob_reg, item); - item->queued = 1; - return 0; - default: - nghttp2_outbound_queue_push(&session->ob_reg, item); - item->queued = 1; - return 0; - } -} - -int nghttp2_session_add_rst_stream(nghttp2_session *session, int32_t stream_id, - uint32_t error_code) { - int rv; - nghttp2_outbound_item *item; - nghttp2_frame *frame; - nghttp2_stream *stream; - nghttp2_mem *mem; - - mem = &session->mem; - stream = nghttp2_session_get_stream(session, stream_id); - if (stream && stream->state == NGHTTP2_STREAM_CLOSING) { - return 0; - } - - /* Sending RST_STREAM to an idle stream is subject to protocol - violation. Historically, nghttp2 allows this. In order not to - disrupt the existing applications, we don't error out this case - and simply ignore it. */ - if (nghttp2_session_is_my_stream_id(session, stream_id)) { - if ((uint32_t)stream_id >= session->next_stream_id) { - return 0; - } - } else if (session->last_recv_stream_id < stream_id) { - return 0; - } - - /* Cancel pending request HEADERS in ob_syn if this RST_STREAM - refers to that stream. */ - if (!session->server && nghttp2_session_is_my_stream_id(session, stream_id) && - nghttp2_outbound_queue_top(&session->ob_syn)) { - nghttp2_headers_aux_data *aux_data; - nghttp2_frame *headers_frame; - - headers_frame = &nghttp2_outbound_queue_top(&session->ob_syn)->frame; - assert(headers_frame->hd.type == NGHTTP2_HEADERS); - - if (headers_frame->hd.stream_id <= stream_id) { - for (item = session->ob_syn.head; item; item = item->qnext) { - aux_data = &item->aux_data.headers; - - if (item->frame.hd.stream_id < stream_id) { - continue; - } - - /* stream_id in ob_syn queue must be strictly increasing. If - we found larger ID, then we can break here. */ - if (item->frame.hd.stream_id > stream_id || aux_data->canceled) { - break; - } - - aux_data->error_code = error_code; - aux_data->canceled = 1; - - return 0; - } - } - } - - item = nghttp2_mem_malloc(mem, sizeof(nghttp2_outbound_item)); - if (item == NULL) { - return NGHTTP2_ERR_NOMEM; - } - - nghttp2_outbound_item_init(item); - - frame = &item->frame; - - nghttp2_frame_rst_stream_init(&frame->rst_stream, stream_id, error_code); - rv = nghttp2_session_add_item(session, item); - if (rv != 0) { - nghttp2_frame_rst_stream_free(&frame->rst_stream); - nghttp2_mem_free(mem, item); - return rv; - } - return 0; -} - -nghttp2_stream *nghttp2_session_open_stream(nghttp2_session *session, - int32_t stream_id, uint8_t flags, - nghttp2_priority_spec *pri_spec_in, - nghttp2_stream_state initial_state, - void *stream_user_data) { - int rv; - nghttp2_stream *stream; - nghttp2_stream *dep_stream = NULL; - int stream_alloc = 0; - nghttp2_priority_spec pri_spec_default; - nghttp2_priority_spec *pri_spec = pri_spec_in; - nghttp2_mem *mem; - - mem = &session->mem; - stream = nghttp2_session_get_stream_raw(session, stream_id); - - if (session->opt_flags & - NGHTTP2_OPTMASK_NO_RFC9113_LEADING_AND_TRAILING_WS_VALIDATION) { - flags |= NGHTTP2_STREAM_FLAG_NO_RFC9113_LEADING_AND_TRAILING_WS_VALIDATION; - } - - if (stream) { - assert(stream->state == NGHTTP2_STREAM_IDLE); - assert((stream->flags & NGHTTP2_STREAM_FLAG_NO_RFC7540_PRIORITIES) || - nghttp2_stream_in_dep_tree(stream)); - - nghttp2_session_detach_idle_stream(session, stream); - - if (nghttp2_stream_in_dep_tree(stream)) { - assert(!(stream->flags & NGHTTP2_STREAM_FLAG_NO_RFC7540_PRIORITIES)); - - rv = nghttp2_stream_dep_remove(stream); - if (rv != 0) { - return NULL; - } - - if (session_no_rfc7540_pri_no_fallback(session)) { - stream->flags |= NGHTTP2_STREAM_FLAG_NO_RFC7540_PRIORITIES; - } - } - } else { - stream = nghttp2_mem_malloc(mem, sizeof(nghttp2_stream)); - if (stream == NULL) { - return NULL; - } - - stream_alloc = 1; - } - - if (session_no_rfc7540_pri_no_fallback(session) || - session->remote_settings.no_rfc7540_priorities == 1) { - /* For client which has not received server - SETTINGS_NO_RFC7540_PRIORITIES = 1, send a priority signal - opportunistically. */ - if (session->server || - session->remote_settings.no_rfc7540_priorities == 1) { - nghttp2_priority_spec_default_init(&pri_spec_default); - pri_spec = &pri_spec_default; - } - - if (session->pending_no_rfc7540_priorities == 1) { - flags |= NGHTTP2_STREAM_FLAG_NO_RFC7540_PRIORITIES; - } - } else if (pri_spec->stream_id != 0) { - dep_stream = nghttp2_session_get_stream_raw(session, pri_spec->stream_id); - - if (!dep_stream && - session_detect_idle_stream(session, pri_spec->stream_id)) { - /* Depends on idle stream, which does not exist in memory. - Assign default priority for it. */ - nghttp2_priority_spec_default_init(&pri_spec_default); - - dep_stream = nghttp2_session_open_stream( - session, pri_spec->stream_id, NGHTTP2_FLAG_NONE, &pri_spec_default, - NGHTTP2_STREAM_IDLE, NULL); - - if (dep_stream == NULL) { - if (stream_alloc) { - nghttp2_mem_free(mem, stream); - } - - return NULL; - } - } else if (!dep_stream || !nghttp2_stream_in_dep_tree(dep_stream)) { - /* If dep_stream is not part of dependency tree, stream will get - default priority. This handles the case when - pri_spec->stream_id == stream_id. This happens because we - don't check pri_spec->stream_id against new stream ID in - nghttp2_submit_request. This also handles the case when idle - stream created by PRIORITY frame was opened. Somehow we - first remove the idle stream from dependency tree. This is - done to simplify code base, but ideally we should retain old - dependency. But I'm not sure this adds values. */ - nghttp2_priority_spec_default_init(&pri_spec_default); - pri_spec = &pri_spec_default; - } - } - - if (initial_state == NGHTTP2_STREAM_RESERVED) { - flags |= NGHTTP2_STREAM_FLAG_PUSH; - } - - if (stream_alloc) { - nghttp2_stream_init(stream, stream_id, flags, initial_state, - pri_spec->weight, - (int32_t)session->remote_settings.initial_window_size, - (int32_t)session->local_settings.initial_window_size, - stream_user_data, mem); - - if (session_no_rfc7540_pri_no_fallback(session)) { - stream->seq = session->stream_seq++; - } - - rv = nghttp2_map_insert(&session->streams, stream_id, stream); - if (rv != 0) { - nghttp2_stream_free(stream); - nghttp2_mem_free(mem, stream); - return NULL; - } - } else { - stream->flags = flags; - stream->state = initial_state; - stream->weight = pri_spec->weight; - stream->stream_user_data = stream_user_data; - } - - switch (initial_state) { - case NGHTTP2_STREAM_RESERVED: - if (nghttp2_session_is_my_stream_id(session, stream_id)) { - /* reserved (local) */ - nghttp2_stream_shutdown(stream, NGHTTP2_SHUT_RD); - } else { - /* reserved (remote) */ - nghttp2_stream_shutdown(stream, NGHTTP2_SHUT_WR); - ++session->num_incoming_reserved_streams; - } - /* Reserved stream does not count in the concurrent streams - limit. That is one of the DOS vector. */ - break; - case NGHTTP2_STREAM_IDLE: - /* Idle stream does not count toward the concurrent streams limit. - This is used as anchor node in dependency tree. */ - nghttp2_session_keep_idle_stream(session, stream); - break; - default: - if (nghttp2_session_is_my_stream_id(session, stream_id)) { - ++session->num_outgoing_streams; - } else { - ++session->num_incoming_streams; - } - } - - if (stream->flags & NGHTTP2_STREAM_FLAG_NO_RFC7540_PRIORITIES) { - return stream; - } - - if (pri_spec->stream_id == 0) { - dep_stream = &session->root; - } - - assert(dep_stream); - - if (pri_spec->exclusive) { - rv = nghttp2_stream_dep_insert(dep_stream, stream); - if (rv != 0) { - return NULL; - } - } else { - nghttp2_stream_dep_add(dep_stream, stream); - } - - return stream; -} - -int nghttp2_session_close_stream(nghttp2_session *session, int32_t stream_id, - uint32_t error_code) { - int rv; - nghttp2_stream *stream; - nghttp2_mem *mem; - int is_my_stream_id; - - mem = &session->mem; - stream = nghttp2_session_get_stream(session, stream_id); - - if (!stream) { - return NGHTTP2_ERR_INVALID_ARGUMENT; - } - - DEBUGF("stream: stream(%p)=%d close\n", stream, stream->stream_id); - - /* We call on_stream_close_callback even if stream->state is - NGHTTP2_STREAM_INITIAL. This will happen while sending request - HEADERS, a local endpoint receives RST_STREAM for that stream. It - may be PROTOCOL_ERROR, but without notifying stream closure will - hang the stream in a local endpoint. - */ - - if (session->callbacks.on_stream_close_callback) { - if (session->callbacks.on_stream_close_callback( - session, stream_id, error_code, session->user_data) != 0) { - return NGHTTP2_ERR_CALLBACK_FAILURE; - } - } - - if (stream->item) { - nghttp2_outbound_item *item; - - item = stream->item; - - session_detach_stream_item(session, stream); - - /* If item is queued, it will be deleted when it is popped - (nghttp2_session_prep_frame() will fail). If session->aob.item - points to this item, let active_outbound_item_reset() - free the item. */ - if (!item->queued && item != session->aob.item) { - nghttp2_outbound_item_free(item, mem); - nghttp2_mem_free(mem, item); - } - } - - is_my_stream_id = nghttp2_session_is_my_stream_id(session, stream_id); - - /* pushed streams which is not opened yet is not counted toward max - concurrent limits */ - if ((stream->flags & NGHTTP2_STREAM_FLAG_PUSH)) { - if (!is_my_stream_id) { - --session->num_incoming_reserved_streams; - } - } else { - if (is_my_stream_id) { - --session->num_outgoing_streams; - } else { - --session->num_incoming_streams; - } - } - - /* Closes both directions just in case they are not closed yet */ - stream->flags |= NGHTTP2_STREAM_FLAG_CLOSED; - - if (session->pending_no_rfc7540_priorities == 1) { - return nghttp2_session_destroy_stream(session, stream); - } - - if ((session->opt_flags & NGHTTP2_OPTMASK_NO_CLOSED_STREAMS) == 0 && - session->server && !is_my_stream_id && - nghttp2_stream_in_dep_tree(stream)) { - /* On server side, retain stream at most MAX_CONCURRENT_STREAMS - combined with the current active incoming streams to make - dependency tree work better. */ - nghttp2_session_keep_closed_stream(session, stream); - } else { - rv = nghttp2_session_destroy_stream(session, stream); - if (rv != 0) { - return rv; - } - } - - return 0; -} - -int nghttp2_session_destroy_stream(nghttp2_session *session, - nghttp2_stream *stream) { - nghttp2_mem *mem; - int rv; - - DEBUGF("stream: destroy closed stream(%p)=%d\n", stream, stream->stream_id); - - mem = &session->mem; - - if (nghttp2_stream_in_dep_tree(stream)) { - rv = nghttp2_stream_dep_remove(stream); - if (rv != 0) { - return rv; - } - } - - if (stream->queued && - (stream->flags & NGHTTP2_STREAM_FLAG_NO_RFC7540_PRIORITIES)) { - session_ob_data_remove(session, stream); - } - - nghttp2_map_remove(&session->streams, stream->stream_id); - nghttp2_stream_free(stream); - nghttp2_mem_free(mem, stream); - - return 0; -} - -void nghttp2_session_keep_closed_stream(nghttp2_session *session, - nghttp2_stream *stream) { - DEBUGF("stream: keep closed stream(%p)=%d, state=%d\n", stream, - stream->stream_id, stream->state); - - if (session->closed_stream_tail) { - session->closed_stream_tail->closed_next = stream; - stream->closed_prev = session->closed_stream_tail; - } else { - session->closed_stream_head = stream; - } - session->closed_stream_tail = stream; - - ++session->num_closed_streams; -} - -void nghttp2_session_keep_idle_stream(nghttp2_session *session, - nghttp2_stream *stream) { - DEBUGF("stream: keep idle stream(%p)=%d, state=%d\n", stream, - stream->stream_id, stream->state); - - if (session->idle_stream_tail) { - session->idle_stream_tail->closed_next = stream; - stream->closed_prev = session->idle_stream_tail; - } else { - session->idle_stream_head = stream; - } - session->idle_stream_tail = stream; - - ++session->num_idle_streams; -} - -void nghttp2_session_detach_idle_stream(nghttp2_session *session, - nghttp2_stream *stream) { - nghttp2_stream *prev_stream, *next_stream; - - DEBUGF("stream: detach idle stream(%p)=%d, state=%d\n", stream, - stream->stream_id, stream->state); - - prev_stream = stream->closed_prev; - next_stream = stream->closed_next; - - if (prev_stream) { - prev_stream->closed_next = next_stream; - } else { - session->idle_stream_head = next_stream; - } - - if (next_stream) { - next_stream->closed_prev = prev_stream; - } else { - session->idle_stream_tail = prev_stream; - } - - stream->closed_prev = NULL; - stream->closed_next = NULL; - - --session->num_idle_streams; -} - -int nghttp2_session_adjust_closed_stream(nghttp2_session *session) { - size_t num_stream_max; - int rv; - - if (session->local_settings.max_concurrent_streams == - NGHTTP2_DEFAULT_MAX_CONCURRENT_STREAMS) { - num_stream_max = session->pending_local_max_concurrent_stream; - } else { - num_stream_max = session->local_settings.max_concurrent_streams; - } - - DEBUGF("stream: adjusting kept closed streams num_closed_streams=%zu, " - "num_incoming_streams=%zu, max_concurrent_streams=%zu\n", - session->num_closed_streams, session->num_incoming_streams, - num_stream_max); - - while (session->num_closed_streams > 0 && - session->num_closed_streams + session->num_incoming_streams > - num_stream_max) { - nghttp2_stream *head_stream; - nghttp2_stream *next; - - head_stream = session->closed_stream_head; - - assert(head_stream); - - next = head_stream->closed_next; - - rv = nghttp2_session_destroy_stream(session, head_stream); - if (rv != 0) { - return rv; - } - - /* head_stream is now freed */ - - session->closed_stream_head = next; - - if (session->closed_stream_head) { - session->closed_stream_head->closed_prev = NULL; - } else { - session->closed_stream_tail = NULL; - } - - --session->num_closed_streams; - } - - return 0; -} - -int nghttp2_session_adjust_idle_stream(nghttp2_session *session) { - size_t max; - int rv; - - /* Make minimum number of idle streams 16, and maximum 100, which - are arbitrary chosen numbers. */ - max = nghttp2_min_uint32( - 100, - nghttp2_max_uint32( - 16, nghttp2_min_uint32(session->local_settings.max_concurrent_streams, - session->pending_local_max_concurrent_stream))); - - DEBUGF("stream: adjusting kept idle streams num_idle_streams=%zu, max=%zu\n", - session->num_idle_streams, max); - - while (session->num_idle_streams > max) { - nghttp2_stream *head; - nghttp2_stream *next; - - head = session->idle_stream_head; - assert(head); - - next = head->closed_next; - - rv = nghttp2_session_destroy_stream(session, head); - if (rv != 0) { - return rv; - } - - /* head is now destroyed */ - - session->idle_stream_head = next; - - if (session->idle_stream_head) { - session->idle_stream_head->closed_prev = NULL; - } else { - session->idle_stream_tail = NULL; - } - - --session->num_idle_streams; - } - - return 0; -} - -/* - * Closes stream with stream ID |stream_id| if both transmission and - * reception of the stream were disallowed. The |error_code| indicates - * the reason of the closure. - * - * This function returns 0 if it succeeds, or one of the following - * negative error codes: - * - * NGHTTP2_ERR_INVALID_ARGUMENT - * The stream is not found. - * NGHTTP2_ERR_CALLBACK_FAILURE - * The callback function failed. - */ -int nghttp2_session_close_stream_if_shut_rdwr(nghttp2_session *session, - nghttp2_stream *stream) { - if ((stream->shut_flags & NGHTTP2_SHUT_RDWR) == NGHTTP2_SHUT_RDWR) { - return nghttp2_session_close_stream(session, stream->stream_id, - NGHTTP2_NO_ERROR); - } - return 0; -} - -/* - * Returns nonzero if local endpoint allows reception of new stream - * from remote. - */ -static int session_allow_incoming_new_stream(nghttp2_session *session) { - return (session->goaway_flags & - (NGHTTP2_GOAWAY_TERM_ON_SEND | NGHTTP2_GOAWAY_SENT)) == 0; -} - -/* - * This function returns nonzero if session is closing. - */ -static int session_is_closing(nghttp2_session *session) { - return (session->goaway_flags & NGHTTP2_GOAWAY_TERM_ON_SEND) != 0 || - (nghttp2_session_want_read(session) == 0 && - nghttp2_session_want_write(session) == 0); -} - -/* - * Check that we can send a frame to the |stream|. This function - * returns 0 if we can send a frame to the |frame|, or one of the - * following negative error codes: - * - * NGHTTP2_ERR_STREAM_CLOSED - * The stream is already closed. - * NGHTTP2_ERR_STREAM_SHUT_WR - * The stream is half-closed for transmission. - * NGHTTP2_ERR_SESSION_CLOSING - * This session is closing. - */ -static int session_predicate_for_stream_send(nghttp2_session *session, - nghttp2_stream *stream) { - if (stream == NULL) { - return NGHTTP2_ERR_STREAM_CLOSED; - } - if (session_is_closing(session)) { - return NGHTTP2_ERR_SESSION_CLOSING; - } - if (stream->shut_flags & NGHTTP2_SHUT_WR) { - return NGHTTP2_ERR_STREAM_SHUT_WR; - } - return 0; -} - -int nghttp2_session_check_request_allowed(nghttp2_session *session) { - return !session->server && session->next_stream_id <= INT32_MAX && - (session->goaway_flags & NGHTTP2_GOAWAY_RECV) == 0 && - !session_is_closing(session); -} - -/* - * This function checks request HEADERS frame, which opens stream, can - * be sent at this time. - * - * This function returns 0 if it succeeds, or one of the following - * negative error codes: - * - * NGHTTP2_ERR_START_STREAM_NOT_ALLOWED - * New stream cannot be created because of GOAWAY: session is - * going down or received last_stream_id is strictly less than - * frame->hd.stream_id. - * NGHTTP2_ERR_STREAM_CLOSING - * request HEADERS was canceled by RST_STREAM while it is in queue. - */ -static int session_predicate_request_headers_send(nghttp2_session *session, - nghttp2_outbound_item *item) { - if (item->aux_data.headers.canceled) { - return NGHTTP2_ERR_STREAM_CLOSING; - } - /* If we are terminating session (NGHTTP2_GOAWAY_TERM_ON_SEND), - GOAWAY was received from peer, or session is about to close, new - request is not allowed. */ - if ((session->goaway_flags & NGHTTP2_GOAWAY_RECV) || - session_is_closing(session)) { - return NGHTTP2_ERR_START_STREAM_NOT_ALLOWED; - } - return 0; -} - -/* - * This function checks HEADERS, which is the first frame from the - * server, with the |stream| can be sent at this time. The |stream| - * can be NULL. - * - * This function returns 0 if it succeeds, or one of the following - * negative error codes: - * - * NGHTTP2_ERR_STREAM_CLOSED - * The stream is already closed or does not exist. - * NGHTTP2_ERR_STREAM_SHUT_WR - * The transmission is not allowed for this stream (e.g., a frame - * with END_STREAM flag set has already sent) - * NGHTTP2_ERR_INVALID_STREAM_ID - * The stream ID is invalid. - * NGHTTP2_ERR_STREAM_CLOSING - * RST_STREAM was queued for this stream. - * NGHTTP2_ERR_INVALID_STREAM_STATE - * The state of the stream is not valid. - * NGHTTP2_ERR_SESSION_CLOSING - * This session is closing. - * NGHTTP2_ERR_PROTO - * Client side attempted to send response. - */ -static int session_predicate_response_headers_send(nghttp2_session *session, - nghttp2_stream *stream) { - int rv; - rv = session_predicate_for_stream_send(session, stream); - if (rv != 0) { - return rv; - } - assert(stream); - if (!session->server) { - return NGHTTP2_ERR_PROTO; - } - if (nghttp2_session_is_my_stream_id(session, stream->stream_id)) { - return NGHTTP2_ERR_INVALID_STREAM_ID; - } - switch (stream->state) { - case NGHTTP2_STREAM_OPENING: - return 0; - case NGHTTP2_STREAM_CLOSING: - return NGHTTP2_ERR_STREAM_CLOSING; - default: - return NGHTTP2_ERR_INVALID_STREAM_STATE; - } -} - -/* - * This function checks HEADERS for reserved stream can be sent. The - * |stream| must be reserved state and the |session| is server side. - * The |stream| can be NULL. - * - * This function returns 0 if it succeeds, or one of the following - * error codes: - * - * NGHTTP2_ERR_STREAM_CLOSED - * The stream is already closed. - * NGHTTP2_ERR_STREAM_SHUT_WR - * The stream is half-closed for transmission. - * NGHTTP2_ERR_PROTO - * The stream is not reserved state - * NGHTTP2_ERR_STREAM_CLOSED - * RST_STREAM was queued for this stream. - * NGHTTP2_ERR_SESSION_CLOSING - * This session is closing. - * NGHTTP2_ERR_START_STREAM_NOT_ALLOWED - * New stream cannot be created because GOAWAY is already sent or - * received. - * NGHTTP2_ERR_PROTO - * Client side attempted to send push response. - */ -static int -session_predicate_push_response_headers_send(nghttp2_session *session, - nghttp2_stream *stream) { - int rv; - /* TODO Should disallow HEADERS if GOAWAY has already been issued? */ - rv = session_predicate_for_stream_send(session, stream); - if (rv != 0) { - return rv; - } - assert(stream); - if (!session->server) { - return NGHTTP2_ERR_PROTO; - } - if (stream->state != NGHTTP2_STREAM_RESERVED) { - return NGHTTP2_ERR_PROTO; - } - if (session->goaway_flags & NGHTTP2_GOAWAY_RECV) { - return NGHTTP2_ERR_START_STREAM_NOT_ALLOWED; - } - return 0; -} - -/* - * This function checks HEADERS, which is neither stream-opening nor - * first response header, with the |stream| can be sent at this time. - * The |stream| can be NULL. - * - * This function returns 0 if it succeeds, or one of the following - * negative error codes: - * - * NGHTTP2_ERR_STREAM_CLOSED - * The stream is already closed or does not exist. - * NGHTTP2_ERR_STREAM_SHUT_WR - * The transmission is not allowed for this stream (e.g., a frame - * with END_STREAM flag set has already sent) - * NGHTTP2_ERR_STREAM_CLOSING - * RST_STREAM was queued for this stream. - * NGHTTP2_ERR_INVALID_STREAM_STATE - * The state of the stream is not valid. - * NGHTTP2_ERR_SESSION_CLOSING - * This session is closing. - */ -static int session_predicate_headers_send(nghttp2_session *session, - nghttp2_stream *stream) { - int rv; - rv = session_predicate_for_stream_send(session, stream); - if (rv != 0) { - return rv; - } - assert(stream); - - switch (stream->state) { - case NGHTTP2_STREAM_OPENED: - return 0; - case NGHTTP2_STREAM_CLOSING: - return NGHTTP2_ERR_STREAM_CLOSING; - default: - if (nghttp2_session_is_my_stream_id(session, stream->stream_id)) { - return 0; - } - return NGHTTP2_ERR_INVALID_STREAM_STATE; - } -} - -/* - * This function checks PUSH_PROMISE frame |frame| with the |stream| - * can be sent at this time. The |stream| can be NULL. - * - * This function returns 0 if it succeeds, or one of the following - * negative error codes: - * - * NGHTTP2_ERR_START_STREAM_NOT_ALLOWED - * New stream cannot be created because GOAWAY is already sent or - * received. - * NGHTTP2_ERR_PROTO - * The client side attempts to send PUSH_PROMISE, or the server - * sends PUSH_PROMISE for the stream not initiated by the client. - * NGHTTP2_ERR_STREAM_CLOSED - * The stream is already closed or does not exist. - * NGHTTP2_ERR_STREAM_CLOSING - * RST_STREAM was queued for this stream. - * NGHTTP2_ERR_STREAM_SHUT_WR - * The transmission is not allowed for this stream (e.g., a frame - * with END_STREAM flag set has already sent) - * NGHTTP2_ERR_PUSH_DISABLED - * The remote peer disabled reception of PUSH_PROMISE. - * NGHTTP2_ERR_SESSION_CLOSING - * This session is closing. - */ -static int session_predicate_push_promise_send(nghttp2_session *session, - nghttp2_stream *stream) { - int rv; - - if (!session->server) { - return NGHTTP2_ERR_PROTO; - } - - rv = session_predicate_for_stream_send(session, stream); - if (rv != 0) { - return rv; - } - - assert(stream); - - if (session->remote_settings.enable_push == 0) { - return NGHTTP2_ERR_PUSH_DISABLED; - } - if (stream->state == NGHTTP2_STREAM_CLOSING) { - return NGHTTP2_ERR_STREAM_CLOSING; - } - if (session->goaway_flags & NGHTTP2_GOAWAY_RECV) { - return NGHTTP2_ERR_START_STREAM_NOT_ALLOWED; - } - return 0; -} - -/* - * This function checks WINDOW_UPDATE with the stream ID |stream_id| - * can be sent at this time. Note that END_STREAM flag of the previous - * frame does not affect the transmission of the WINDOW_UPDATE frame. - * - * This function returns 0 if it succeeds, or one of the following - * negative error codes: - * - * NGHTTP2_ERR_STREAM_CLOSED - * The stream is already closed or does not exist. - * NGHTTP2_ERR_STREAM_CLOSING - * RST_STREAM was queued for this stream. - * NGHTTP2_ERR_INVALID_STREAM_STATE - * The state of the stream is not valid. - * NGHTTP2_ERR_SESSION_CLOSING - * This session is closing. - */ -static int session_predicate_window_update_send(nghttp2_session *session, - int32_t stream_id) { - nghttp2_stream *stream; - - if (session_is_closing(session)) { - return NGHTTP2_ERR_SESSION_CLOSING; - } - - if (stream_id == 0) { - /* Connection-level window update */ - return 0; - } - stream = nghttp2_session_get_stream(session, stream_id); - if (stream == NULL) { - return NGHTTP2_ERR_STREAM_CLOSED; - } - if (stream->state == NGHTTP2_STREAM_CLOSING) { - return NGHTTP2_ERR_STREAM_CLOSING; - } - if (state_reserved_local(session, stream)) { - return NGHTTP2_ERR_INVALID_STREAM_STATE; - } - return 0; -} - -static int session_predicate_altsvc_send(nghttp2_session *session, - int32_t stream_id) { - nghttp2_stream *stream; - - if (session_is_closing(session)) { - return NGHTTP2_ERR_SESSION_CLOSING; - } - - if (stream_id == 0) { - return 0; - } - - stream = nghttp2_session_get_stream(session, stream_id); - if (stream == NULL) { - return NGHTTP2_ERR_STREAM_CLOSED; - } - if (stream->state == NGHTTP2_STREAM_CLOSING) { - return NGHTTP2_ERR_STREAM_CLOSING; - } - - return 0; -} - -static int session_predicate_origin_send(nghttp2_session *session) { - if (session_is_closing(session)) { - return NGHTTP2_ERR_SESSION_CLOSING; - } - return 0; -} - -static int session_predicate_priority_update_send(nghttp2_session *session, - int32_t stream_id) { - nghttp2_stream *stream; - - if (session_is_closing(session)) { - return NGHTTP2_ERR_SESSION_CLOSING; - } - - stream = nghttp2_session_get_stream(session, stream_id); - if (stream == NULL) { - return 0; - } - if (stream->state == NGHTTP2_STREAM_CLOSING) { - return NGHTTP2_ERR_STREAM_CLOSING; - } - if (stream->shut_flags & NGHTTP2_SHUT_RD) { - return NGHTTP2_ERR_INVALID_STREAM_STATE; - } - - return 0; -} - -/* Take into account settings max frame size and both connection-level - flow control here */ -static nghttp2_ssize nghttp2_session_enforce_flow_control_limits( - nghttp2_session *session, nghttp2_stream *stream, - nghttp2_ssize requested_window_size) { - DEBUGF("send: remote windowsize connection=%d, remote maxframsize=%u, " - "stream(id %d)=%d\n", - session->remote_window_size, session->remote_settings.max_frame_size, - stream->stream_id, stream->remote_window_size); - - return nghttp2_min_int32( - nghttp2_min_int32(nghttp2_min_int32((int32_t)requested_window_size, - stream->remote_window_size), - session->remote_window_size), - (int32_t)session->remote_settings.max_frame_size); -} - -/* - * Returns the maximum length of next data read. If the - * connection-level and/or stream-wise flow control are enabled, the - * return value takes into account those current window sizes. The remote - * settings for max frame size is also taken into account. - */ -static size_t nghttp2_session_next_data_read(nghttp2_session *session, - nghttp2_stream *stream) { - nghttp2_ssize window_size; - - window_size = nghttp2_session_enforce_flow_control_limits( - session, stream, NGHTTP2_DATA_PAYLOADLEN); - - DEBUGF("send: available window=%td\n", window_size); - - return window_size > 0 ? (size_t)window_size : 0; -} - -/* - * This function checks DATA with the |stream| can be sent at this - * time. The |stream| can be NULL. - * - * This function returns 0 if it succeeds, or one of the following - * negative error codes: - * - * NGHTTP2_ERR_STREAM_CLOSED - * The stream is already closed or does not exist. - * NGHTTP2_ERR_STREAM_SHUT_WR - * The transmission is not allowed for this stream (e.g., a frame - * with END_STREAM flag set has already sent) - * NGHTTP2_ERR_STREAM_CLOSING - * RST_STREAM was queued for this stream. - * NGHTTP2_ERR_INVALID_STREAM_STATE - * The state of the stream is not valid. - * NGHTTP2_ERR_SESSION_CLOSING - * This session is closing. - */ -static int nghttp2_session_predicate_data_send(nghttp2_session *session, - nghttp2_stream *stream) { - int rv; - rv = session_predicate_for_stream_send(session, stream); - if (rv != 0) { - return rv; - } - assert(stream); - if (nghttp2_session_is_my_stream_id(session, stream->stream_id)) { - /* Request body data */ - /* If stream->state is NGHTTP2_STREAM_CLOSING, RST_STREAM was - queued but not yet sent. In this case, we won't send DATA - frames. */ - if (stream->state == NGHTTP2_STREAM_CLOSING) { - return NGHTTP2_ERR_STREAM_CLOSING; - } - if (stream->state == NGHTTP2_STREAM_RESERVED) { - return NGHTTP2_ERR_INVALID_STREAM_STATE; - } - return 0; - } - /* Response body data */ - if (stream->state == NGHTTP2_STREAM_OPENED) { - return 0; - } - if (stream->state == NGHTTP2_STREAM_CLOSING) { - return NGHTTP2_ERR_STREAM_CLOSING; - } - return NGHTTP2_ERR_INVALID_STREAM_STATE; -} - -static nghttp2_ssize session_call_select_padding(nghttp2_session *session, - const nghttp2_frame *frame, - size_t max_payloadlen) { - nghttp2_ssize rv; - size_t max_paddedlen; - - if (frame->hd.length >= max_payloadlen || - (!session->callbacks.select_padding_callback2 && - !session->callbacks.select_padding_callback)) { - return (nghttp2_ssize)frame->hd.length; - } - - max_paddedlen = - nghttp2_min_size(frame->hd.length + NGHTTP2_MAX_PADLEN, max_payloadlen); - - if (session->callbacks.select_padding_callback2) { - rv = session->callbacks.select_padding_callback2( - session, frame, max_paddedlen, session->user_data); - } else { - rv = (nghttp2_ssize)session->callbacks.select_padding_callback( - session, frame, max_paddedlen, session->user_data); - } - if (rv < (nghttp2_ssize)frame->hd.length || - rv > (nghttp2_ssize)max_paddedlen) { - return NGHTTP2_ERR_CALLBACK_FAILURE; - } - return rv; -} - -/* Add padding to HEADERS or PUSH_PROMISE. We use - frame->headers.padlen in this function to use the fact that - frame->push_promise has also padlen in the same position. */ -static int session_headers_add_pad(nghttp2_session *session, - nghttp2_frame *frame) { - nghttp2_ssize padded_payloadlen; - nghttp2_active_outbound_item *aob; - nghttp2_bufs *framebufs; - size_t padlen; - size_t max_payloadlen; - - aob = &session->aob; - framebufs = &aob->framebufs; - - max_payloadlen = nghttp2_min_size(NGHTTP2_MAX_PAYLOADLEN, - frame->hd.length + NGHTTP2_MAX_PADLEN); - - padded_payloadlen = - session_call_select_padding(session, frame, max_payloadlen); - - if (nghttp2_is_fatal((int)padded_payloadlen)) { - return (int)padded_payloadlen; - } - - padlen = (size_t)padded_payloadlen - frame->hd.length; - - DEBUGF("send: padding selected: payloadlen=%td, padlen=%zu\n", - padded_payloadlen, padlen); - - nghttp2_frame_add_pad(framebufs, &frame->hd, padlen, 0); - - frame->headers.padlen = padlen; - - return 0; -} - -static size_t session_estimate_headers_payload(nghttp2_session *session, - const nghttp2_nv *nva, - size_t nvlen, - size_t additional) { - return nghttp2_hd_deflate_bound(&session->hd_deflater, nva, nvlen) + - additional; -} - -static int session_pack_extension(nghttp2_session *session, nghttp2_bufs *bufs, - nghttp2_frame *frame) { - nghttp2_ssize rv; - nghttp2_buf *buf; - size_t buflen; - size_t framelen; - - assert(session->callbacks.pack_extension_callback2 || - session->callbacks.pack_extension_callback); - - buf = &bufs->head->buf; - buflen = nghttp2_min_size(nghttp2_buf_avail(buf), NGHTTP2_MAX_PAYLOADLEN); - - if (session->callbacks.pack_extension_callback2) { - rv = session->callbacks.pack_extension_callback2(session, buf->last, buflen, - frame, session->user_data); - } else { - rv = (nghttp2_ssize)session->callbacks.pack_extension_callback( - session, buf->last, buflen, frame, session->user_data); - } - if (rv == NGHTTP2_ERR_CANCEL) { - return (int)rv; - } - - if (rv < 0 || (size_t)rv > buflen) { - return NGHTTP2_ERR_CALLBACK_FAILURE; - } - - framelen = (size_t)rv; - - frame->hd.length = framelen; - - assert(buf->pos == buf->last); - buf->last += framelen; - buf->pos -= NGHTTP2_FRAME_HDLEN; - - nghttp2_frame_pack_frame_hd(buf->pos, &frame->hd); - - return 0; -} - -/* - * This function serializes frame for transmission. - * - * This function returns 0 if it succeeds, or one of negative error - * codes, including both fatal and non-fatal ones. - */ -static int session_prep_frame(nghttp2_session *session, - nghttp2_outbound_item *item) { - int rv; - nghttp2_frame *frame; - nghttp2_mem *mem; - - mem = &session->mem; - frame = &item->frame; - - switch (frame->hd.type) { - case NGHTTP2_DATA: { - size_t next_readmax; - nghttp2_stream *stream; - - stream = nghttp2_session_get_stream(session, frame->hd.stream_id); - - if (stream) { - assert(stream->item == item); - } - - rv = nghttp2_session_predicate_data_send(session, stream); - if (rv != 0) { - // If stream was already closed, nghttp2_session_get_stream() - // returns NULL, but item is still attached to the stream. - // Search stream including closed again. - stream = nghttp2_session_get_stream_raw(session, frame->hd.stream_id); - if (stream) { - session_detach_stream_item(session, stream); - } - - return rv; - } - /* Assuming stream is not NULL */ - assert(stream); - next_readmax = nghttp2_session_next_data_read(session, stream); - - if (next_readmax == 0) { - /* This must be true since we only pop DATA frame item from - queue when session->remote_window_size > 0 */ - assert(session->remote_window_size > 0); - - session_defer_stream_item(session, stream, - NGHTTP2_STREAM_FLAG_DEFERRED_FLOW_CONTROL); - - session->aob.item = NULL; - active_outbound_item_reset(&session->aob, mem); - return NGHTTP2_ERR_DEFERRED; - } - - rv = - nghttp2_session_pack_data(session, &session->aob.framebufs, next_readmax, - frame, &item->aux_data.data, stream); - if (rv == NGHTTP2_ERR_PAUSE) { - return rv; - } - if (rv == NGHTTP2_ERR_DEFERRED) { - session_defer_stream_item(session, stream, - NGHTTP2_STREAM_FLAG_DEFERRED_USER); - - session->aob.item = NULL; - active_outbound_item_reset(&session->aob, mem); - return NGHTTP2_ERR_DEFERRED; - } - if (rv == NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE) { - session_detach_stream_item(session, stream); - - rv = nghttp2_session_add_rst_stream(session, frame->hd.stream_id, - NGHTTP2_INTERNAL_ERROR); - if (nghttp2_is_fatal(rv)) { - return rv; - } - return NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE; - } - if (rv != 0) { - session_detach_stream_item(session, stream); - - return rv; - } - return 0; - } - case NGHTTP2_HEADERS: { - nghttp2_headers_aux_data *aux_data; - size_t estimated_payloadlen; - - aux_data = &item->aux_data.headers; - - if (frame->headers.cat == NGHTTP2_HCAT_REQUEST) { - /* initial HEADERS, which opens stream */ - nghttp2_stream *stream; - - stream = nghttp2_session_open_stream( - session, frame->hd.stream_id, NGHTTP2_STREAM_FLAG_NONE, - &frame->headers.pri_spec, NGHTTP2_STREAM_INITIAL, - aux_data->stream_user_data); - - if (stream == NULL) { - return NGHTTP2_ERR_NOMEM; - } - - /* We don't call nghttp2_session_adjust_closed_stream() here, - since we don't keep closed stream in client side */ - - rv = session_predicate_request_headers_send(session, item); - if (rv != 0) { - return rv; - } - - if (session_enforce_http_messaging(session)) { - nghttp2_http_record_request_method(stream, frame); - } - } else { - nghttp2_stream *stream; - - stream = nghttp2_session_get_stream(session, frame->hd.stream_id); - - if (stream && stream->state == NGHTTP2_STREAM_RESERVED) { - rv = session_predicate_push_response_headers_send(session, stream); - if (rv == 0) { - frame->headers.cat = NGHTTP2_HCAT_PUSH_RESPONSE; - - if (aux_data->stream_user_data) { - stream->stream_user_data = aux_data->stream_user_data; - } - } - } else if (session_predicate_response_headers_send(session, stream) == - 0) { - frame->headers.cat = NGHTTP2_HCAT_RESPONSE; - rv = 0; - } else { - frame->headers.cat = NGHTTP2_HCAT_HEADERS; - - rv = session_predicate_headers_send(session, stream); - } - - if (rv != 0) { - return rv; - } - } - - estimated_payloadlen = session_estimate_headers_payload( - session, frame->headers.nva, frame->headers.nvlen, - NGHTTP2_PRIORITY_SPECLEN); - - if (estimated_payloadlen > session->max_send_header_block_length) { - return NGHTTP2_ERR_FRAME_SIZE_ERROR; - } - - rv = nghttp2_frame_pack_headers(&session->aob.framebufs, &frame->headers, - &session->hd_deflater); - - if (rv != 0) { - return rv; - } - - DEBUGF("send: before padding, HEADERS serialized in %zu bytes\n", - nghttp2_bufs_len(&session->aob.framebufs)); - - rv = session_headers_add_pad(session, frame); - - if (rv != 0) { - return rv; - } - - DEBUGF("send: HEADERS finally serialized in %zu bytes\n", - nghttp2_bufs_len(&session->aob.framebufs)); - - if (frame->headers.cat == NGHTTP2_HCAT_REQUEST) { - assert(session->last_sent_stream_id < frame->hd.stream_id); - session->last_sent_stream_id = frame->hd.stream_id; - } - - return 0; - } - case NGHTTP2_PRIORITY: { - if (session_is_closing(session)) { - return NGHTTP2_ERR_SESSION_CLOSING; - } - /* PRIORITY frame can be sent at any time and to any stream - ID. */ - nghttp2_frame_pack_priority(&session->aob.framebufs, &frame->priority); - - /* Peer can send PRIORITY frame against idle stream to create - "anchor" in dependency tree. Only client can do this in - nghttp2. In nghttp2, only server retains non-active (closed - or idle) streams in memory, so we don't open stream here. */ - return 0; - } - case NGHTTP2_RST_STREAM: - if (session_is_closing(session)) { - return NGHTTP2_ERR_SESSION_CLOSING; - } - nghttp2_frame_pack_rst_stream(&session->aob.framebufs, &frame->rst_stream); - return 0; - case NGHTTP2_SETTINGS: { - if (frame->hd.flags & NGHTTP2_FLAG_ACK) { - assert(session->obq_flood_counter_ > 0); - --session->obq_flood_counter_; - /* When session is about to close, don't send SETTINGS ACK. - We are required to send SETTINGS without ACK though; for - example, we have to send SETTINGS as a part of connection - preface. */ - if (session_is_closing(session)) { - return NGHTTP2_ERR_SESSION_CLOSING; - } - } - - rv = nghttp2_frame_pack_settings(&session->aob.framebufs, &frame->settings); - if (rv != 0) { - return rv; - } - return 0; - } - case NGHTTP2_PUSH_PROMISE: { - nghttp2_stream *stream; - size_t estimated_payloadlen; - - /* stream could be NULL if associated stream was already - closed. */ - stream = nghttp2_session_get_stream(session, frame->hd.stream_id); - - /* predicate should fail if stream is NULL. */ - rv = session_predicate_push_promise_send(session, stream); - if (rv != 0) { - return rv; - } - - assert(stream); - - estimated_payloadlen = session_estimate_headers_payload( - session, frame->push_promise.nva, frame->push_promise.nvlen, 0); - - if (estimated_payloadlen > session->max_send_header_block_length) { - return NGHTTP2_ERR_FRAME_SIZE_ERROR; - } - - rv = nghttp2_frame_pack_push_promise( - &session->aob.framebufs, &frame->push_promise, &session->hd_deflater); - if (rv != 0) { - return rv; - } - rv = session_headers_add_pad(session, frame); - if (rv != 0) { - return rv; - } - - assert(session->last_sent_stream_id + 2 <= - frame->push_promise.promised_stream_id); - session->last_sent_stream_id = frame->push_promise.promised_stream_id; - - return 0; - } - case NGHTTP2_PING: - if (frame->hd.flags & NGHTTP2_FLAG_ACK) { - assert(session->obq_flood_counter_ > 0); - --session->obq_flood_counter_; - } - /* PING frame is allowed to be sent unless termination GOAWAY is - sent */ - if (session->goaway_flags & NGHTTP2_GOAWAY_TERM_ON_SEND) { - return NGHTTP2_ERR_SESSION_CLOSING; - } - nghttp2_frame_pack_ping(&session->aob.framebufs, &frame->ping); - return 0; - case NGHTTP2_GOAWAY: - rv = nghttp2_frame_pack_goaway(&session->aob.framebufs, &frame->goaway); - if (rv != 0) { - return rv; - } - session->local_last_stream_id = frame->goaway.last_stream_id; - - return 0; - case NGHTTP2_WINDOW_UPDATE: - rv = session_predicate_window_update_send(session, frame->hd.stream_id); - if (rv != 0) { - return rv; - } - nghttp2_frame_pack_window_update(&session->aob.framebufs, - &frame->window_update); - return 0; - case NGHTTP2_CONTINUATION: - /* We never handle CONTINUATION here. */ - assert(0); - return 0; - default: { - nghttp2_ext_aux_data *aux_data; - - /* extension frame */ - - aux_data = &item->aux_data.ext; - - if (aux_data->builtin == 0) { - if (session_is_closing(session)) { - return NGHTTP2_ERR_SESSION_CLOSING; - } - - return session_pack_extension(session, &session->aob.framebufs, frame); - } - - switch (frame->hd.type) { - case NGHTTP2_ALTSVC: - rv = session_predicate_altsvc_send(session, frame->hd.stream_id); - if (rv != 0) { - return rv; - } - - nghttp2_frame_pack_altsvc(&session->aob.framebufs, &frame->ext); - - return 0; - case NGHTTP2_ORIGIN: - rv = session_predicate_origin_send(session); - if (rv != 0) { - return rv; - } - - rv = nghttp2_frame_pack_origin(&session->aob.framebufs, &frame->ext); - if (rv != 0) { - return rv; - } - - return 0; - case NGHTTP2_PRIORITY_UPDATE: { - nghttp2_ext_priority_update *priority_update = frame->ext.payload; - rv = session_predicate_priority_update_send(session, - priority_update->stream_id); - if (rv != 0) { - return rv; - } - - nghttp2_frame_pack_priority_update(&session->aob.framebufs, &frame->ext); - - return 0; - } - default: - /* Unreachable here */ - assert(0); - return 0; - } - } - } -} - -nghttp2_outbound_item * -nghttp2_session_get_next_ob_item(nghttp2_session *session) { - nghttp2_outbound_item *item; - - if (nghttp2_outbound_queue_top(&session->ob_urgent)) { - return nghttp2_outbound_queue_top(&session->ob_urgent); - } - - if (nghttp2_outbound_queue_top(&session->ob_reg)) { - return nghttp2_outbound_queue_top(&session->ob_reg); - } - - if (!session_is_outgoing_concurrent_streams_max(session)) { - if (nghttp2_outbound_queue_top(&session->ob_syn)) { - return nghttp2_outbound_queue_top(&session->ob_syn); - } - } - - if (session->remote_window_size > 0) { - item = nghttp2_stream_next_outbound_item(&session->root); - if (item) { - return item; - } - - return session_sched_get_next_outbound_item(session); - } - - return NULL; -} - -nghttp2_outbound_item * -nghttp2_session_pop_next_ob_item(nghttp2_session *session) { - nghttp2_outbound_item *item; - - item = nghttp2_outbound_queue_top(&session->ob_urgent); - if (item) { - nghttp2_outbound_queue_pop(&session->ob_urgent); - item->queued = 0; - return item; - } - - item = nghttp2_outbound_queue_top(&session->ob_reg); - if (item) { - nghttp2_outbound_queue_pop(&session->ob_reg); - item->queued = 0; - return item; - } - - if (!session_is_outgoing_concurrent_streams_max(session)) { - item = nghttp2_outbound_queue_top(&session->ob_syn); - if (item) { - nghttp2_outbound_queue_pop(&session->ob_syn); - item->queued = 0; - return item; - } - } - - if (session->remote_window_size > 0) { - item = nghttp2_stream_next_outbound_item(&session->root); - if (item) { - return item; - } - - return session_sched_get_next_outbound_item(session); - } - - return NULL; -} - -static int session_call_before_frame_send(nghttp2_session *session, - nghttp2_frame *frame) { - int rv; - if (session->callbacks.before_frame_send_callback) { - rv = session->callbacks.before_frame_send_callback(session, frame, - session->user_data); - if (rv == NGHTTP2_ERR_CANCEL) { - return rv; - } - - if (rv != 0) { - return NGHTTP2_ERR_CALLBACK_FAILURE; - } - } - return 0; -} - -static int session_call_on_frame_send(nghttp2_session *session, - nghttp2_frame *frame) { - int rv; - if (session->callbacks.on_frame_send_callback) { - rv = session->callbacks.on_frame_send_callback(session, frame, - session->user_data); - if (rv != 0) { - return NGHTTP2_ERR_CALLBACK_FAILURE; - } - } - return 0; -} - -static int find_stream_on_goaway_func(void *entry, void *ptr) { - nghttp2_close_stream_on_goaway_arg *arg; - nghttp2_stream *stream; - - arg = (nghttp2_close_stream_on_goaway_arg *)ptr; - stream = (nghttp2_stream *)entry; - - if (nghttp2_session_is_my_stream_id(arg->session, stream->stream_id)) { - if (arg->incoming) { - return 0; - } - } else if (!arg->incoming) { - return 0; - } - - if (stream->state != NGHTTP2_STREAM_IDLE && - (stream->flags & NGHTTP2_STREAM_FLAG_CLOSED) == 0 && - stream->stream_id > arg->last_stream_id) { - /* We are collecting streams to close because we cannot call - nghttp2_session_close_stream() inside nghttp2_map_each(). - Reuse closed_next member.. bad choice? */ - assert(stream->closed_next == NULL); - assert(stream->closed_prev == NULL); - - if (arg->head) { - stream->closed_next = arg->head; - arg->head = stream; - } else { - arg->head = stream; - } - } - - return 0; -} - -/* Closes non-idle and non-closed streams whose stream ID > - last_stream_id. If incoming is nonzero, we are going to close - incoming streams. Otherwise, close outgoing streams. */ -static int session_close_stream_on_goaway(nghttp2_session *session, - int32_t last_stream_id, - int incoming) { - int rv; - nghttp2_stream *stream, *next_stream; - nghttp2_close_stream_on_goaway_arg arg = {session, NULL, last_stream_id, - incoming}; - - rv = nghttp2_map_each(&session->streams, find_stream_on_goaway_func, &arg); - assert(rv == 0); - - stream = arg.head; - while (stream) { - next_stream = stream->closed_next; - stream->closed_next = NULL; - rv = nghttp2_session_close_stream(session, stream->stream_id, - NGHTTP2_REFUSED_STREAM); - - /* stream may be deleted here */ - - stream = next_stream; - - if (nghttp2_is_fatal(rv)) { - /* Clean up closed_next member just in case */ - while (stream) { - next_stream = stream->closed_next; - stream->closed_next = NULL; - stream = next_stream; - } - return rv; - } - } - - return 0; -} - -static void session_reschedule_stream(nghttp2_session *session, - nghttp2_stream *stream) { - stream->last_writelen = stream->item->frame.hd.length; - - if (!(stream->flags & NGHTTP2_STREAM_FLAG_NO_RFC7540_PRIORITIES)) { - nghttp2_stream_reschedule(stream); - return; - } - - if (!session->server) { - return; - } - - session_sched_reschedule_stream(session, stream); -} - -static int session_update_stream_consumed_size(nghttp2_session *session, - nghttp2_stream *stream, - size_t delta_size); - -static int session_update_connection_consumed_size(nghttp2_session *session, - size_t delta_size); - -/* - * Called after a frame is sent. This function runs - * on_frame_send_callback and handles stream closure upon END_STREAM - * or RST_STREAM. This function does not reset session->aob. It is a - * responsibility of session_after_frame_sent2. - * - * This function returns 0 if it succeeds, or one of the following - * negative error codes: - * - * NGHTTP2_ERR_NOMEM - * Out of memory. - * NGHTTP2_ERR_CALLBACK_FAILURE - * The callback function failed. - */ -static int session_after_frame_sent1(nghttp2_session *session) { - int rv; - nghttp2_active_outbound_item *aob = &session->aob; - nghttp2_outbound_item *item = aob->item; - nghttp2_bufs *framebufs = &aob->framebufs; - nghttp2_frame *frame; - nghttp2_stream *stream; - - frame = &item->frame; - - if (frame->hd.type == NGHTTP2_DATA) { - nghttp2_data_aux_data *aux_data; - - aux_data = &item->aux_data.data; - - stream = nghttp2_session_get_stream(session, frame->hd.stream_id); - /* We update flow control window after a frame was completely - sent. This is possible because we choose payload length not to - exceed the window */ - session->remote_window_size -= (int32_t)frame->hd.length; - if (stream) { - stream->remote_window_size -= (int32_t)frame->hd.length; - } - - if (stream && aux_data->eof) { - session_detach_stream_item(session, stream); - - /* Call on_frame_send_callback after - nghttp2_stream_detach_item(), so that application can issue - nghttp2_submit_data2() in the callback. */ - if (session->callbacks.on_frame_send_callback) { - rv = session_call_on_frame_send(session, frame); - if (nghttp2_is_fatal(rv)) { - return rv; - } - } - - if (frame->hd.flags & NGHTTP2_FLAG_END_STREAM) { - int stream_closed; - - stream_closed = - (stream->shut_flags & NGHTTP2_SHUT_RDWR) == NGHTTP2_SHUT_RDWR; - - nghttp2_stream_shutdown(stream, NGHTTP2_SHUT_WR); - - rv = nghttp2_session_close_stream_if_shut_rdwr(session, stream); - if (nghttp2_is_fatal(rv)) { - return rv; - } - /* stream may be NULL if it was closed */ - if (stream_closed) { - stream = NULL; - } - } - return 0; - } - - if (session->callbacks.on_frame_send_callback) { - rv = session_call_on_frame_send(session, frame); - if (nghttp2_is_fatal(rv)) { - return rv; - } - } - - return 0; - } - - /* non-DATA frame */ - - if (frame->hd.type == NGHTTP2_HEADERS || - frame->hd.type == NGHTTP2_PUSH_PROMISE) { - if (nghttp2_bufs_next_present(framebufs)) { - DEBUGF("send: CONTINUATION exists, just return\n"); - return 0; - } - } - rv = session_call_on_frame_send(session, frame); - if (nghttp2_is_fatal(rv)) { - return rv; - } - switch (frame->hd.type) { - case NGHTTP2_HEADERS: { - nghttp2_headers_aux_data *aux_data; - - stream = nghttp2_session_get_stream(session, frame->hd.stream_id); - if (!stream) { - return 0; - } - - switch (frame->headers.cat) { - case NGHTTP2_HCAT_REQUEST: { - stream->state = NGHTTP2_STREAM_OPENING; - if (frame->hd.flags & NGHTTP2_FLAG_END_STREAM) { - nghttp2_stream_shutdown(stream, NGHTTP2_SHUT_WR); - } - rv = nghttp2_session_close_stream_if_shut_rdwr(session, stream); - if (nghttp2_is_fatal(rv)) { - return rv; - } - /* We assume aux_data is a pointer to nghttp2_headers_aux_data */ - aux_data = &item->aux_data.headers; - if (aux_data->dpw.data_prd.read_callback) { - /* nghttp2_submit_data_shared() makes a copy of - aux_data->dpw */ - rv = nghttp2_submit_data_shared(session, NGHTTP2_FLAG_END_STREAM, - frame->hd.stream_id, &aux_data->dpw); - if (nghttp2_is_fatal(rv)) { - return rv; - } - /* TODO nghttp2_submit_data_shared() may fail if stream has - already DATA frame item. We might have to handle it - here. */ - } - return 0; - } - case NGHTTP2_HCAT_PUSH_RESPONSE: - stream->flags = (uint8_t)(stream->flags & ~NGHTTP2_STREAM_FLAG_PUSH); - ++session->num_outgoing_streams; - /* Fall through */ - case NGHTTP2_HCAT_RESPONSE: - stream->state = NGHTTP2_STREAM_OPENED; - /* Fall through */ - case NGHTTP2_HCAT_HEADERS: - if (frame->hd.flags & NGHTTP2_FLAG_END_STREAM) { - nghttp2_stream_shutdown(stream, NGHTTP2_SHUT_WR); - } - rv = nghttp2_session_close_stream_if_shut_rdwr(session, stream); - if (nghttp2_is_fatal(rv)) { - return rv; - } - /* We assume aux_data is a pointer to nghttp2_headers_aux_data */ - aux_data = &item->aux_data.headers; - if (aux_data->dpw.data_prd.read_callback) { - rv = nghttp2_submit_data_shared(session, NGHTTP2_FLAG_END_STREAM, - frame->hd.stream_id, &aux_data->dpw); - if (nghttp2_is_fatal(rv)) { - return rv; - } - /* TODO nghttp2_submit_data_shared() may fail if stream has - already DATA frame item. We might have to handle it - here. */ - } - return 0; - default: - /* Unreachable */ - assert(0); - return 0; - } - } - case NGHTTP2_PRIORITY: - if (session->server || session->pending_no_rfc7540_priorities == 1) { - return 0; - } - - stream = nghttp2_session_get_stream_raw(session, frame->hd.stream_id); - - if (!stream) { - if (!session_detect_idle_stream(session, frame->hd.stream_id)) { - return 0; - } - - stream = nghttp2_session_open_stream( - session, frame->hd.stream_id, NGHTTP2_FLAG_NONE, - &frame->priority.pri_spec, NGHTTP2_STREAM_IDLE, NULL); - if (!stream) { - return NGHTTP2_ERR_NOMEM; - } - } else { - rv = nghttp2_session_reprioritize_stream(session, stream, - &frame->priority.pri_spec); - if (nghttp2_is_fatal(rv)) { - return rv; - } - } - - rv = nghttp2_session_adjust_idle_stream(session); - - if (nghttp2_is_fatal(rv)) { - return rv; - } - - return 0; - case NGHTTP2_RST_STREAM: - rv = nghttp2_session_close_stream(session, frame->hd.stream_id, - frame->rst_stream.error_code); - if (nghttp2_is_fatal(rv)) { - return rv; - } - return 0; - case NGHTTP2_GOAWAY: { - nghttp2_goaway_aux_data *aux_data; - - aux_data = &item->aux_data.goaway; - - if ((aux_data->flags & NGHTTP2_GOAWAY_AUX_SHUTDOWN_NOTICE) == 0) { - if (aux_data->flags & NGHTTP2_GOAWAY_AUX_TERM_ON_SEND) { - session->goaway_flags |= NGHTTP2_GOAWAY_TERM_SENT; - } - - session->goaway_flags |= NGHTTP2_GOAWAY_SENT; - - rv = session_close_stream_on_goaway(session, frame->goaway.last_stream_id, - 1); - - if (nghttp2_is_fatal(rv)) { - return rv; - } - } - - return 0; - } - case NGHTTP2_WINDOW_UPDATE: - if (frame->hd.stream_id == 0) { - session->window_update_queued = 0; - if (session->opt_flags & NGHTTP2_OPTMASK_NO_AUTO_WINDOW_UPDATE) { - rv = session_update_connection_consumed_size(session, 0); - } else { - rv = nghttp2_session_update_recv_connection_window_size(session, 0); - } - - if (nghttp2_is_fatal(rv)) { - return rv; - } - - return 0; - } - - stream = nghttp2_session_get_stream(session, frame->hd.stream_id); - if (!stream) { - return 0; - } - - stream->window_update_queued = 0; - - /* We don't have to send WINDOW_UPDATE if END_STREAM from peer - is seen. */ - if (stream->shut_flags & NGHTTP2_SHUT_RD) { - return 0; - } - - if (session->opt_flags & NGHTTP2_OPTMASK_NO_AUTO_WINDOW_UPDATE) { - rv = session_update_stream_consumed_size(session, stream, 0); - } else { - rv = - nghttp2_session_update_recv_stream_window_size(session, stream, 0, 1); - } - - if (nghttp2_is_fatal(rv)) { - return rv; - } - - return 0; - default: - return 0; - } -} - -/* - * Called after a frame is sent and session_after_frame_sent1. This - * function is responsible to reset session->aob. - */ -static void session_after_frame_sent2(nghttp2_session *session) { - nghttp2_active_outbound_item *aob = &session->aob; - nghttp2_outbound_item *item = aob->item; - nghttp2_bufs *framebufs = &aob->framebufs; - nghttp2_frame *frame; - nghttp2_mem *mem; - nghttp2_stream *stream; - nghttp2_data_aux_data *aux_data; - - mem = &session->mem; - frame = &item->frame; - - if (frame->hd.type != NGHTTP2_DATA) { - if (frame->hd.type == NGHTTP2_HEADERS || - frame->hd.type == NGHTTP2_PUSH_PROMISE) { - if (nghttp2_bufs_next_present(framebufs)) { - framebufs->cur = framebufs->cur->next; - - DEBUGF("send: next CONTINUATION frame, %zu bytes\n", - nghttp2_buf_len(&framebufs->cur->buf)); - - return; - } - } - - active_outbound_item_reset(&session->aob, mem); - - return; - } - - /* DATA frame */ - - aux_data = &item->aux_data.data; - - /* On EOF, we have already detached data. Please note that - application may issue nghttp2_submit_data2() in - on_frame_send_callback (call from session_after_frame_sent1), - which attach data to stream. We don't want to detach it. */ - if (aux_data->eof) { - active_outbound_item_reset(aob, mem); - - return; - } - - /* Reset no_copy here because next write may not use this. */ - aux_data->no_copy = 0; - - stream = nghttp2_session_get_stream(session, frame->hd.stream_id); - - /* If session is closed or RST_STREAM was queued, we won't send - further data. */ - if (nghttp2_session_predicate_data_send(session, stream) != 0) { - if (stream) { - session_detach_stream_item(session, stream); - } - - active_outbound_item_reset(aob, mem); - - return; - } - - aob->item = NULL; - active_outbound_item_reset(&session->aob, mem); - - return; -} - -static int session_call_send_data(nghttp2_session *session, - nghttp2_outbound_item *item, - nghttp2_bufs *framebufs) { - int rv; - nghttp2_buf *buf; - size_t length; - nghttp2_frame *frame; - nghttp2_data_aux_data *aux_data; - - buf = &framebufs->cur->buf; - frame = &item->frame; - length = frame->hd.length - frame->data.padlen; - aux_data = &item->aux_data.data; - - rv = session->callbacks.send_data_callback(session, frame, buf->pos, length, - &aux_data->dpw.data_prd.source, - session->user_data); - - switch (rv) { - case 0: - case NGHTTP2_ERR_WOULDBLOCK: - case NGHTTP2_ERR_PAUSE: - case NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE: - return rv; - default: - return NGHTTP2_ERR_CALLBACK_FAILURE; - } -} - -static nghttp2_ssize nghttp2_session_mem_send_internal(nghttp2_session *session, - const uint8_t **data_ptr, - int fast_cb) { - int rv; - nghttp2_active_outbound_item *aob; - nghttp2_bufs *framebufs; - nghttp2_mem *mem; - - mem = &session->mem; - aob = &session->aob; - framebufs = &aob->framebufs; - - /* We may have idle streams more than we expect (e.g., - nghttp2_session_change_stream_priority() or - nghttp2_session_create_idle_stream()). Adjust them here. */ - rv = nghttp2_session_adjust_idle_stream(session); - if (nghttp2_is_fatal(rv)) { - return rv; - } - - for (;;) { - switch (aob->state) { - case NGHTTP2_OB_POP_ITEM: { - nghttp2_outbound_item *item; - - item = nghttp2_session_pop_next_ob_item(session); - if (item == NULL) { - return 0; - } - - rv = session_prep_frame(session, item); - if (rv == NGHTTP2_ERR_PAUSE) { - return 0; - } - if (rv == NGHTTP2_ERR_DEFERRED) { - DEBUGF("send: frame transmission deferred\n"); - break; - } - if (rv < 0) { - int32_t opened_stream_id = 0; - uint32_t error_code = NGHTTP2_INTERNAL_ERROR; - int rv2 = 0; - - DEBUGF("send: frame preparation failed with %s\n", - nghttp2_strerror(rv)); - /* TODO If the error comes from compressor, the connection - must be closed. */ - if (item->frame.hd.type != NGHTTP2_DATA && - session->callbacks.on_frame_not_send_callback && is_non_fatal(rv)) { - nghttp2_frame *frame = &item->frame; - /* The library is responsible for the transmission of - WINDOW_UPDATE frame, so we don't call error callback for - it. */ - if (frame->hd.type != NGHTTP2_WINDOW_UPDATE && - session->callbacks.on_frame_not_send_callback( - session, frame, rv, session->user_data) != 0) { - nghttp2_outbound_item_free(item, mem); - nghttp2_mem_free(mem, item); - - return NGHTTP2_ERR_CALLBACK_FAILURE; - } - } - /* We have to close stream opened by failed request HEADERS - or PUSH_PROMISE. */ - switch (item->frame.hd.type) { - case NGHTTP2_HEADERS: - if (item->frame.headers.cat == NGHTTP2_HCAT_REQUEST) { - opened_stream_id = item->frame.hd.stream_id; - if (item->aux_data.headers.canceled) { - error_code = item->aux_data.headers.error_code; - } else { - /* Set error_code to REFUSED_STREAM so that application - can send request again. */ - error_code = NGHTTP2_REFUSED_STREAM; - } - } - break; - case NGHTTP2_PUSH_PROMISE: - opened_stream_id = item->frame.push_promise.promised_stream_id; - break; - } - if (opened_stream_id) { - /* careful not to override rv */ - rv2 = - nghttp2_session_close_stream(session, opened_stream_id, error_code); - } - - nghttp2_outbound_item_free(item, mem); - nghttp2_mem_free(mem, item); - active_outbound_item_reset(aob, mem); - - if (nghttp2_is_fatal(rv2)) { - return rv2; - } - - if (rv == NGHTTP2_ERR_HEADER_COMP) { - /* If header compression error occurred, should terminate - connection. */ - rv = - nghttp2_session_terminate_session(session, NGHTTP2_INTERNAL_ERROR); - } - if (nghttp2_is_fatal(rv)) { - return rv; - } - break; - } - - aob->item = item; - - nghttp2_bufs_rewind(framebufs); - - if (item->frame.hd.type != NGHTTP2_DATA) { - nghttp2_frame *frame; - - frame = &item->frame; - - DEBUGF("send: next frame: payloadlen=%zu, type=%u, flags=0x%02x, " - "stream_id=%d\n", - frame->hd.length, frame->hd.type, frame->hd.flags, - frame->hd.stream_id); - - rv = session_call_before_frame_send(session, frame); - if (nghttp2_is_fatal(rv)) { - return rv; - } - - if (rv == NGHTTP2_ERR_CANCEL) { - int32_t opened_stream_id = 0; - uint32_t error_code = NGHTTP2_INTERNAL_ERROR; - - if (session->callbacks.on_frame_not_send_callback) { - if (session->callbacks.on_frame_not_send_callback( - session, frame, rv, session->user_data) != 0) { - return NGHTTP2_ERR_CALLBACK_FAILURE; - } - } - - /* We have to close stream opened by canceled request - HEADERS or PUSH_PROMISE. */ - switch (item->frame.hd.type) { - case NGHTTP2_HEADERS: - if (item->frame.headers.cat == NGHTTP2_HCAT_REQUEST) { - opened_stream_id = item->frame.hd.stream_id; - /* We don't have to check - item->aux_data.headers.canceled since it has already - been checked. */ - /* Set error_code to REFUSED_STREAM so that application - can send request again. */ - error_code = NGHTTP2_REFUSED_STREAM; - } - break; - case NGHTTP2_PUSH_PROMISE: - opened_stream_id = item->frame.push_promise.promised_stream_id; - break; - } - if (opened_stream_id) { - /* careful not to override rv */ - int rv2; - rv2 = nghttp2_session_close_stream(session, opened_stream_id, - error_code); - - if (nghttp2_is_fatal(rv2)) { - return rv2; - } - } - - active_outbound_item_reset(aob, mem); - - break; - } - } else { - DEBUGF("send: next frame: DATA\n"); - - if (item->aux_data.data.no_copy) { - aob->state = NGHTTP2_OB_SEND_NO_COPY; - break; - } - } - - DEBUGF("send: start transmitting frame type=%u, length=%td\n", - framebufs->cur->buf.pos[3], - framebufs->cur->buf.last - framebufs->cur->buf.pos); - - aob->state = NGHTTP2_OB_SEND_DATA; - - break; - } - case NGHTTP2_OB_SEND_DATA: { - size_t datalen; - nghttp2_buf *buf; - - buf = &framebufs->cur->buf; - - if (buf->pos == buf->last) { - DEBUGF("send: end transmission of a frame\n"); - - /* Frame has completely sent */ - if (fast_cb) { - session_after_frame_sent2(session); - } else { - rv = session_after_frame_sent1(session); - if (rv < 0) { - /* FATAL */ - assert(nghttp2_is_fatal(rv)); - return rv; - } - session_after_frame_sent2(session); - } - /* We have already adjusted the next state */ - break; - } - - *data_ptr = buf->pos; - datalen = nghttp2_buf_len(buf); - - /* We increment the offset here. If send_callback does not send - everything, we will adjust it. */ - buf->pos += datalen; - - return (nghttp2_ssize)datalen; - } - case NGHTTP2_OB_SEND_NO_COPY: { - nghttp2_stream *stream; - nghttp2_frame *frame; - int pause; - - DEBUGF("send: no copy DATA\n"); - - frame = &aob->item->frame; - - stream = nghttp2_session_get_stream(session, frame->hd.stream_id); - if (stream == NULL) { - DEBUGF("send: no copy DATA cancelled because stream was closed\n"); - - active_outbound_item_reset(aob, mem); - - break; - } - - rv = session_call_send_data(session, aob->item, framebufs); - if (nghttp2_is_fatal(rv)) { - return rv; - } - - if (rv == NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE) { - session_detach_stream_item(session, stream); - - rv = nghttp2_session_add_rst_stream(session, frame->hd.stream_id, - NGHTTP2_INTERNAL_ERROR); - if (nghttp2_is_fatal(rv)) { - return rv; - } - - active_outbound_item_reset(aob, mem); - - break; - } - - if (rv == NGHTTP2_ERR_WOULDBLOCK) { - return 0; - } - - pause = (rv == NGHTTP2_ERR_PAUSE); - - rv = session_after_frame_sent1(session); - if (rv < 0) { - assert(nghttp2_is_fatal(rv)); - return rv; - } - session_after_frame_sent2(session); - - /* We have already adjusted the next state */ - - if (pause) { - return 0; - } - - break; - } - case NGHTTP2_OB_SEND_CLIENT_MAGIC: { - size_t datalen; - nghttp2_buf *buf; - - buf = &framebufs->cur->buf; - - if (buf->pos == buf->last) { - DEBUGF("send: end transmission of client magic\n"); - active_outbound_item_reset(aob, mem); - break; - } - - *data_ptr = buf->pos; - datalen = nghttp2_buf_len(buf); - - buf->pos += datalen; - - return (nghttp2_ssize)datalen; - } - } - } -} - -ssize_t nghttp2_session_mem_send(nghttp2_session *session, - const uint8_t **data_ptr) { - return (ssize_t)nghttp2_session_mem_send2(session, data_ptr); -} - -nghttp2_ssize nghttp2_session_mem_send2(nghttp2_session *session, - const uint8_t **data_ptr) { - int rv; - nghttp2_ssize len; - - *data_ptr = NULL; - - len = nghttp2_session_mem_send_internal(session, data_ptr, 1); - if (len <= 0) { - return len; - } - - if (session->aob.item) { - /* We have to call session_after_frame_sent1 here to handle stream - closure upon transmission of frames. Otherwise, END_STREAM may - be reached to client before we call nghttp2_session_mem_send - again and we may get exceeding number of incoming streams. */ - rv = session_after_frame_sent1(session); - if (rv < 0) { - assert(nghttp2_is_fatal(rv)); - return (nghttp2_ssize)rv; - } - } - - return len; -} - -int nghttp2_session_send(nghttp2_session *session) { - const uint8_t *data = NULL; - nghttp2_ssize datalen; - nghttp2_ssize sentlen; - nghttp2_bufs *framebufs; - - framebufs = &session->aob.framebufs; - - for (;;) { - datalen = nghttp2_session_mem_send_internal(session, &data, 0); - if (datalen <= 0) { - return (int)datalen; - } - if (session->callbacks.send_callback2) { - sentlen = session->callbacks.send_callback2( - session, data, (size_t)datalen, 0, session->user_data); - } else { - sentlen = (nghttp2_ssize)session->callbacks.send_callback( - session, data, (size_t)datalen, 0, session->user_data); - } - if (sentlen < 0) { - if (sentlen == NGHTTP2_ERR_WOULDBLOCK) { - /* Transmission canceled. Rewind the offset */ - framebufs->cur->buf.pos -= datalen; - - return 0; - } - return NGHTTP2_ERR_CALLBACK_FAILURE; - } - /* Rewind the offset to the amount of unsent bytes */ - framebufs->cur->buf.pos -= datalen - sentlen; - } -} - -static nghttp2_ssize session_recv(nghttp2_session *session, uint8_t *buf, - size_t len) { - nghttp2_ssize rv; - - if (session->callbacks.recv_callback2) { - rv = session->callbacks.recv_callback2(session, buf, len, 0, - session->user_data); - } else { - rv = (nghttp2_ssize)session->callbacks.recv_callback(session, buf, len, 0, - session->user_data); - } - if (rv > 0) { - if ((size_t)rv > len) { - return NGHTTP2_ERR_CALLBACK_FAILURE; - } - } else if (rv < 0 && rv != NGHTTP2_ERR_WOULDBLOCK && rv != NGHTTP2_ERR_EOF) { - return NGHTTP2_ERR_CALLBACK_FAILURE; - } - return rv; -} - -static int session_call_on_begin_frame(nghttp2_session *session, - const nghttp2_frame_hd *hd) { - int rv; - - if (session->callbacks.on_begin_frame_callback) { - rv = session->callbacks.on_begin_frame_callback(session, hd, - session->user_data); - - if (rv != 0) { - return NGHTTP2_ERR_CALLBACK_FAILURE; - } - } - - return 0; -} - -static int session_call_on_frame_received(nghttp2_session *session, - nghttp2_frame *frame) { - int rv; - if (session->callbacks.on_frame_recv_callback) { - rv = session->callbacks.on_frame_recv_callback(session, frame, - session->user_data); - if (rv != 0) { - return NGHTTP2_ERR_CALLBACK_FAILURE; - } - } - return 0; -} - -static int session_call_on_begin_headers(nghttp2_session *session, - nghttp2_frame *frame) { - int rv; - DEBUGF("recv: call on_begin_headers callback stream_id=%d\n", - frame->hd.stream_id); - if (session->callbacks.on_begin_headers_callback) { - rv = session->callbacks.on_begin_headers_callback(session, frame, - session->user_data); - if (rv == NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE) { - return rv; - } - if (rv != 0) { - return NGHTTP2_ERR_CALLBACK_FAILURE; - } - } - return 0; -} - -static int session_call_on_header(nghttp2_session *session, - const nghttp2_frame *frame, - const nghttp2_hd_nv *nv) { - int rv = 0; - if (session->callbacks.on_header_callback2) { - rv = session->callbacks.on_header_callback2( - session, frame, nv->name, nv->value, nv->flags, session->user_data); - } else if (session->callbacks.on_header_callback) { - rv = session->callbacks.on_header_callback( - session, frame, nv->name->base, nv->name->len, nv->value->base, - nv->value->len, nv->flags, session->user_data); - } - - if (rv == NGHTTP2_ERR_PAUSE || rv == NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE) { - return rv; - } - if (rv != 0) { - return NGHTTP2_ERR_CALLBACK_FAILURE; - } - - return 0; -} - -static int session_call_on_invalid_header(nghttp2_session *session, - const nghttp2_frame *frame, - const nghttp2_hd_nv *nv) { - int rv; - if (session->callbacks.on_invalid_header_callback2) { - rv = session->callbacks.on_invalid_header_callback2( - session, frame, nv->name, nv->value, nv->flags, session->user_data); - } else if (session->callbacks.on_invalid_header_callback) { - rv = session->callbacks.on_invalid_header_callback( - session, frame, nv->name->base, nv->name->len, nv->value->base, - nv->value->len, nv->flags, session->user_data); - } else { - return NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE; - } - - if (rv == NGHTTP2_ERR_PAUSE || rv == NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE) { - return rv; - } - if (rv != 0) { - return NGHTTP2_ERR_CALLBACK_FAILURE; - } - - return 0; -} - -static int -session_call_on_extension_chunk_recv_callback(nghttp2_session *session, - const uint8_t *data, size_t len) { - int rv; - nghttp2_inbound_frame *iframe = &session->iframe; - nghttp2_frame *frame = &iframe->frame; - - if (session->callbacks.on_extension_chunk_recv_callback) { - rv = session->callbacks.on_extension_chunk_recv_callback( - session, &frame->hd, data, len, session->user_data); - if (rv == NGHTTP2_ERR_CANCEL) { - return rv; - } - if (rv != 0) { - return NGHTTP2_ERR_CALLBACK_FAILURE; - } - } - - return 0; -} - -static int session_call_unpack_extension_callback(nghttp2_session *session) { - int rv; - nghttp2_inbound_frame *iframe = &session->iframe; - nghttp2_frame *frame = &iframe->frame; - void *payload = NULL; - - rv = session->callbacks.unpack_extension_callback( - session, &payload, &frame->hd, session->user_data); - if (rv == NGHTTP2_ERR_CANCEL) { - return rv; - } - if (rv != 0) { - return NGHTTP2_ERR_CALLBACK_FAILURE; - } - - frame->ext.payload = payload; - - return 0; -} - -/* - * Handles frame size error. - * - * This function returns 0 if it succeeds, or one of the following - * negative error codes: - * - * NGHTTP2_ERR_NOMEM - * Out of memory. - */ -static int session_handle_frame_size_error(nghttp2_session *session) { - /* TODO Currently no callback is called for this error, because we - call this callback before reading any payload */ - return nghttp2_session_terminate_session(session, NGHTTP2_FRAME_SIZE_ERROR); -} - -static uint32_t get_error_code_from_lib_error_code(int lib_error_code) { - switch (lib_error_code) { - case NGHTTP2_ERR_STREAM_CLOSED: - return NGHTTP2_STREAM_CLOSED; - case NGHTTP2_ERR_HEADER_COMP: - return NGHTTP2_COMPRESSION_ERROR; - case NGHTTP2_ERR_FRAME_SIZE_ERROR: - return NGHTTP2_FRAME_SIZE_ERROR; - case NGHTTP2_ERR_FLOW_CONTROL: - return NGHTTP2_FLOW_CONTROL_ERROR; - case NGHTTP2_ERR_REFUSED_STREAM: - return NGHTTP2_REFUSED_STREAM; - case NGHTTP2_ERR_PROTO: - case NGHTTP2_ERR_HTTP_HEADER: - case NGHTTP2_ERR_HTTP_MESSAGING: - return NGHTTP2_PROTOCOL_ERROR; - default: - return NGHTTP2_INTERNAL_ERROR; - } -} - -/* - * Calls on_invalid_frame_recv_callback if it is set to |session|. - * - * This function returns 0 if it succeeds, or one of the following - * negative error codes: - * - * NGHTTP2_ERR_CALLBACK_FAILURE - * User defined callback function fails. - */ -static int session_call_on_invalid_frame_recv_callback(nghttp2_session *session, - nghttp2_frame *frame, - int lib_error_code) { - if (session->callbacks.on_invalid_frame_recv_callback) { - if (session->callbacks.on_invalid_frame_recv_callback( - session, frame, lib_error_code, session->user_data) != 0) { - return NGHTTP2_ERR_CALLBACK_FAILURE; - } - } - return 0; -} - -static int session_handle_invalid_stream2(nghttp2_session *session, - int32_t stream_id, - nghttp2_frame *frame, - int lib_error_code) { - int rv; - rv = nghttp2_session_add_rst_stream( - session, stream_id, get_error_code_from_lib_error_code(lib_error_code)); - if (rv != 0) { - return rv; - } - if (session->callbacks.on_invalid_frame_recv_callback) { - if (session->callbacks.on_invalid_frame_recv_callback( - session, frame, lib_error_code, session->user_data) != 0) { - return NGHTTP2_ERR_CALLBACK_FAILURE; - } - } - return 0; -} - -static int session_handle_invalid_stream(nghttp2_session *session, - nghttp2_frame *frame, - int lib_error_code) { - return session_handle_invalid_stream2(session, frame->hd.stream_id, frame, - lib_error_code); -} - -static int session_inflate_handle_invalid_stream(nghttp2_session *session, - nghttp2_frame *frame, - int lib_error_code) { - int rv; - rv = session_handle_invalid_stream(session, frame, lib_error_code); - if (nghttp2_is_fatal(rv)) { - return rv; - } - return NGHTTP2_ERR_IGN_HEADER_BLOCK; -} - -/* - * Handles invalid frame which causes connection error. - */ -static int session_handle_invalid_connection(nghttp2_session *session, - nghttp2_frame *frame, - int lib_error_code, - const char *reason) { - if (session->callbacks.on_invalid_frame_recv_callback) { - if (session->callbacks.on_invalid_frame_recv_callback( - session, frame, lib_error_code, session->user_data) != 0) { - return NGHTTP2_ERR_CALLBACK_FAILURE; - } - } - return nghttp2_session_terminate_session_with_reason( - session, get_error_code_from_lib_error_code(lib_error_code), reason); -} - -static int session_inflate_handle_invalid_connection(nghttp2_session *session, - nghttp2_frame *frame, - int lib_error_code, - const char *reason) { - int rv; - rv = - session_handle_invalid_connection(session, frame, lib_error_code, reason); - if (nghttp2_is_fatal(rv)) { - return rv; - } - return NGHTTP2_ERR_IGN_HEADER_BLOCK; -} - -/* - * Inflates header block in the memory pointed by |in| with |inlen| - * bytes. If this function returns NGHTTP2_ERR_PAUSE, the caller must - * call this function again, until it returns 0 or one of negative - * error code. If |call_header_cb| is zero, the on_header_callback - * are not invoked and the function never return NGHTTP2_ERR_PAUSE. If - * the given |in| is the last chunk of header block, the |final| must - * be nonzero. If header block is successfully processed (which is - * indicated by the return value 0, NGHTTP2_ERR_PAUSE or - * NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE), the number of processed - * input bytes is assigned to the |*readlen_ptr|. - * - * This function return 0 if it succeeds, or one of the negative error - * codes: - * - * NGHTTP2_ERR_CALLBACK_FAILURE - * The callback function failed. - * NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE - * The callback returns this error code, indicating that this - * stream should be RST_STREAMed. - * NGHTTP2_ERR_NOMEM - * Out of memory. - * NGHTTP2_ERR_PAUSE - * The callback function returned NGHTTP2_ERR_PAUSE - * NGHTTP2_ERR_HEADER_COMP - * Header decompression failed - */ -static int inflate_header_block(nghttp2_session *session, nghttp2_frame *frame, - size_t *readlen_ptr, uint8_t *in, size_t inlen, - int final, int call_header_cb) { - nghttp2_ssize proclen; - int rv; - int inflate_flags; - nghttp2_hd_nv nv; - nghttp2_stream *stream; - nghttp2_stream *subject_stream; - int trailer = 0; - - *readlen_ptr = 0; - stream = nghttp2_session_get_stream(session, frame->hd.stream_id); - - if (frame->hd.type == NGHTTP2_PUSH_PROMISE) { - subject_stream = nghttp2_session_get_stream( - session, frame->push_promise.promised_stream_id); - } else { - subject_stream = stream; - trailer = session_trailer_headers(session, stream, frame); - } - - DEBUGF("recv: decoding header block %zu bytes\n", inlen); - for (;;) { - inflate_flags = 0; - proclen = nghttp2_hd_inflate_hd_nv(&session->hd_inflater, &nv, - &inflate_flags, in, inlen, final); - if (nghttp2_is_fatal((int)proclen)) { - return (int)proclen; - } - if (proclen < 0) { - if (session->iframe.state == NGHTTP2_IB_READ_HEADER_BLOCK) { - if (subject_stream && subject_stream->state != NGHTTP2_STREAM_CLOSING) { - /* Adding RST_STREAM here is very important. It prevents - from invoking subsequent callbacks for the same stream - ID. */ - rv = nghttp2_session_add_rst_stream( - session, subject_stream->stream_id, NGHTTP2_COMPRESSION_ERROR); - - if (nghttp2_is_fatal(rv)) { - return rv; - } - } - } - rv = - nghttp2_session_terminate_session(session, NGHTTP2_COMPRESSION_ERROR); - if (nghttp2_is_fatal(rv)) { - return rv; - } - - return NGHTTP2_ERR_HEADER_COMP; - } - in += proclen; - inlen -= (size_t)proclen; - *readlen_ptr += (size_t)proclen; - - DEBUGF("recv: proclen=%td\n", proclen); - - if (call_header_cb && (inflate_flags & NGHTTP2_HD_INFLATE_EMIT)) { - rv = 0; - if (subject_stream) { - if (session_enforce_http_messaging(session)) { - rv = nghttp2_http_on_header(session, subject_stream, frame, &nv, - trailer); - - if (rv == NGHTTP2_ERR_IGN_HTTP_HEADER) { - /* Don't overwrite rv here */ - int rv2; - - rv2 = session_call_on_invalid_header(session, frame, &nv); - if (rv2 == NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE) { - rv = NGHTTP2_ERR_HTTP_HEADER; - } else { - if (rv2 != 0) { - return rv2; - } - - /* header is ignored */ - DEBUGF("recv: HTTP ignored: type=%u, id=%d, header %.*s: %.*s\n", - frame->hd.type, frame->hd.stream_id, (int)nv.name->len, - nv.name->base, (int)nv.value->len, nv.value->base); - - rv2 = session_call_error_callback( - session, NGHTTP2_ERR_HTTP_HEADER, - "Ignoring received invalid HTTP header field: frame type: " - "%u, stream: %d, name: [%.*s], value: [%.*s]", - frame->hd.type, frame->hd.stream_id, (int)nv.name->len, - nv.name->base, (int)nv.value->len, nv.value->base); - - if (nghttp2_is_fatal(rv2)) { - return rv2; - } - } - } - - if (rv == NGHTTP2_ERR_HTTP_HEADER) { - DEBUGF("recv: HTTP error: type=%u, id=%d, header %.*s: %.*s\n", - frame->hd.type, frame->hd.stream_id, (int)nv.name->len, - nv.name->base, (int)nv.value->len, nv.value->base); - - rv = session_call_error_callback( - session, NGHTTP2_ERR_HTTP_HEADER, - "Invalid HTTP header field was received: frame type: " - "%u, stream: %d, name: [%.*s], value: [%.*s]", - frame->hd.type, frame->hd.stream_id, (int)nv.name->len, - nv.name->base, (int)nv.value->len, nv.value->base); - - if (nghttp2_is_fatal(rv)) { - return rv; - } - - rv = - session_handle_invalid_stream2(session, subject_stream->stream_id, - frame, NGHTTP2_ERR_HTTP_HEADER); - if (nghttp2_is_fatal(rv)) { - return rv; - } - return NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE; - } - } - if (rv == 0) { - rv = session_call_on_header(session, frame, &nv); - /* This handles NGHTTP2_ERR_PAUSE and - NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE as well */ - if (rv != 0) { - return rv; - } - } - } - } - if (inflate_flags & NGHTTP2_HD_INFLATE_FINAL) { - nghttp2_hd_inflate_end_headers(&session->hd_inflater); - break; - } - if ((inflate_flags & NGHTTP2_HD_INFLATE_EMIT) == 0 && inlen == 0) { - break; - } - } - return 0; -} - -/* - * Call this function when HEADERS frame was completely received. - * - * This function returns 0 if it succeeds, or one of negative error - * codes: - * - * NGHTTP2_ERR_CALLBACK_FAILURE - * The callback function failed. - * NGHTTP2_ERR_NOMEM - * Out of memory. - */ -static int session_end_stream_headers_received(nghttp2_session *session, - nghttp2_frame *frame, - nghttp2_stream *stream) { - int rv; - - assert(frame->hd.type == NGHTTP2_HEADERS); - - if (session->server && session_enforce_http_messaging(session) && - frame->headers.cat == NGHTTP2_HCAT_REQUEST && - (stream->flags & NGHTTP2_STREAM_FLAG_NO_RFC7540_PRIORITIES) && - !(stream->flags & NGHTTP2_STREAM_FLAG_IGNORE_CLIENT_PRIORITIES) && - (stream->http_flags & NGHTTP2_HTTP_FLAG_PRIORITY)) { - rv = session_update_stream_priority(session, stream, stream->http_extpri); - if (rv != 0) { - assert(nghttp2_is_fatal(rv)); - return rv; - } - } - - if ((frame->hd.flags & NGHTTP2_FLAG_END_STREAM) == 0) { - return 0; - } - - nghttp2_stream_shutdown(stream, NGHTTP2_SHUT_RD); - rv = nghttp2_session_close_stream_if_shut_rdwr(session, stream); - if (nghttp2_is_fatal(rv)) { - return rv; - } - - return 0; -} - -static int session_after_header_block_received(nghttp2_session *session) { - int rv = 0; - nghttp2_frame *frame = &session->iframe.frame; - nghttp2_stream *stream; - - /* We don't call on_frame_recv_callback if stream has been closed - already or being closed. */ - stream = nghttp2_session_get_stream(session, frame->hd.stream_id); - if (!stream || stream->state == NGHTTP2_STREAM_CLOSING) { - return 0; - } - - if (session_enforce_http_messaging(session)) { - if (frame->hd.type == NGHTTP2_PUSH_PROMISE) { - nghttp2_stream *subject_stream; - - subject_stream = nghttp2_session_get_stream( - session, frame->push_promise.promised_stream_id); - if (subject_stream) { - rv = nghttp2_http_on_request_headers(subject_stream, frame); - } - } else { - assert(frame->hd.type == NGHTTP2_HEADERS); - switch (frame->headers.cat) { - case NGHTTP2_HCAT_REQUEST: - rv = nghttp2_http_on_request_headers(stream, frame); - break; - case NGHTTP2_HCAT_RESPONSE: - case NGHTTP2_HCAT_PUSH_RESPONSE: - rv = nghttp2_http_on_response_headers(stream); - break; - case NGHTTP2_HCAT_HEADERS: - if (stream->http_flags & NGHTTP2_HTTP_FLAG_EXPECT_FINAL_RESPONSE) { - assert(!session->server); - rv = nghttp2_http_on_response_headers(stream); - } else { - rv = nghttp2_http_on_trailer_headers(stream, frame); - } - break; - default: - assert(0); - } - if (rv == 0 && (frame->hd.flags & NGHTTP2_FLAG_END_STREAM)) { - rv = nghttp2_http_on_remote_end_stream(stream); - } - } - if (rv != 0) { - int32_t stream_id; - - if (frame->hd.type == NGHTTP2_PUSH_PROMISE) { - stream_id = frame->push_promise.promised_stream_id; - } else { - stream_id = frame->hd.stream_id; - } - - rv = session_handle_invalid_stream2(session, stream_id, frame, - NGHTTP2_ERR_HTTP_MESSAGING); - if (nghttp2_is_fatal(rv)) { - return rv; - } - - if (frame->hd.type == NGHTTP2_HEADERS && - (frame->hd.flags & NGHTTP2_FLAG_END_STREAM)) { - nghttp2_stream_shutdown(stream, NGHTTP2_SHUT_RD); - /* Don't call nghttp2_session_close_stream_if_shut_rdwr - because RST_STREAM has been submitted. */ - } - return 0; - } - } - - rv = session_call_on_frame_received(session, frame); - if (nghttp2_is_fatal(rv)) { - return rv; - } - - if (frame->hd.type != NGHTTP2_HEADERS) { - return 0; - } - - return session_end_stream_headers_received(session, frame, stream); -} - -int nghttp2_session_on_request_headers_received(nghttp2_session *session, - nghttp2_frame *frame) { - int rv = 0; - nghttp2_stream *stream; - if (frame->hd.stream_id == 0) { - return session_inflate_handle_invalid_connection( - session, frame, NGHTTP2_ERR_PROTO, "request HEADERS: stream_id == 0"); - } - - /* If client receives idle stream from server, it is invalid - regardless stream ID is even or odd. This is because client is - not expected to receive request from server. */ - if (!session->server) { - if (session_detect_idle_stream(session, frame->hd.stream_id)) { - return session_inflate_handle_invalid_connection( - session, frame, NGHTTP2_ERR_PROTO, - "request HEADERS: client received request"); - } - - return NGHTTP2_ERR_IGN_HEADER_BLOCK; - } - - assert(session->server); - - if (!session_is_new_peer_stream_id(session, frame->hd.stream_id)) { - if (frame->hd.stream_id == 0 || - nghttp2_session_is_my_stream_id(session, frame->hd.stream_id)) { - return session_inflate_handle_invalid_connection( - session, frame, NGHTTP2_ERR_PROTO, - "request HEADERS: invalid stream_id"); - } - - /* RFC 7540 says if an endpoint receives a HEADERS with invalid - * stream ID (e.g, numerically smaller than previous), it MUST - * issue connection error with error code PROTOCOL_ERROR. It is a - * bit hard to detect this, since we cannot remember all streams - * we observed so far. - * - * You might imagine this is really easy. But no. HTTP/2 is - * asynchronous protocol, and usually client and server do not - * share the complete picture of open/closed stream status. For - * example, after server sends RST_STREAM for a stream, client may - * send trailer HEADERS for that stream. If naive server detects - * that, and issued connection error, then it is a bug of server - * implementation since client is not wrong if it did not get - * RST_STREAM when it issued trailer HEADERS. - * - * At the moment, we are very conservative here. We only use - * connection error if stream ID refers idle stream, or we are - * sure that stream is half-closed(remote) or closed. Otherwise - * we just ignore HEADERS for now. - */ - stream = nghttp2_session_get_stream_raw(session, frame->hd.stream_id); - if (stream && (stream->shut_flags & NGHTTP2_SHUT_RD)) { - return session_inflate_handle_invalid_connection( - session, frame, NGHTTP2_ERR_STREAM_CLOSED, "HEADERS: stream closed"); - } - - return NGHTTP2_ERR_IGN_HEADER_BLOCK; - } - session->last_recv_stream_id = frame->hd.stream_id; - - if (session_is_incoming_concurrent_streams_max(session)) { - return session_inflate_handle_invalid_connection( - session, frame, NGHTTP2_ERR_PROTO, - "request HEADERS: max concurrent streams exceeded"); - } - - if (!session_allow_incoming_new_stream(session)) { - /* We just ignore stream after GOAWAY was sent */ - return NGHTTP2_ERR_IGN_HEADER_BLOCK; - } - - if (frame->headers.pri_spec.stream_id == frame->hd.stream_id) { - return session_inflate_handle_invalid_connection( - session, frame, NGHTTP2_ERR_PROTO, "request HEADERS: depend on itself"); - } - - if (session_is_incoming_concurrent_streams_pending_max(session)) { - return session_inflate_handle_invalid_stream(session, frame, - NGHTTP2_ERR_REFUSED_STREAM); - } - - stream = nghttp2_session_open_stream( - session, frame->hd.stream_id, NGHTTP2_STREAM_FLAG_NONE, - &frame->headers.pri_spec, NGHTTP2_STREAM_OPENING, NULL); - if (!stream) { - return NGHTTP2_ERR_NOMEM; - } - - rv = nghttp2_session_adjust_closed_stream(session); - if (nghttp2_is_fatal(rv)) { - return rv; - } - - session->last_proc_stream_id = session->last_recv_stream_id; - - rv = session_call_on_begin_headers(session, frame); - if (rv != 0) { - return rv; - } - return 0; -} - -int nghttp2_session_on_response_headers_received(nghttp2_session *session, - nghttp2_frame *frame, - nghttp2_stream *stream) { - int rv; - /* This function is only called if stream->state == - NGHTTP2_STREAM_OPENING and stream_id is local side initiated. */ - assert(stream->state == NGHTTP2_STREAM_OPENING && - nghttp2_session_is_my_stream_id(session, frame->hd.stream_id)); - if (frame->hd.stream_id == 0) { - return session_inflate_handle_invalid_connection( - session, frame, NGHTTP2_ERR_PROTO, "response HEADERS: stream_id == 0"); - } - if (stream->shut_flags & NGHTTP2_SHUT_RD) { - /* half closed (remote): from the spec: - - If an endpoint receives additional frames for a stream that is - in this state it MUST respond with a stream error (Section - 5.4.2) of type STREAM_CLOSED. - - We go further, and make it connection error. - */ - return session_inflate_handle_invalid_connection( - session, frame, NGHTTP2_ERR_STREAM_CLOSED, "HEADERS: stream closed"); - } - stream->state = NGHTTP2_STREAM_OPENED; - rv = session_call_on_begin_headers(session, frame); - if (rv != 0) { - return rv; - } - return 0; -} - -int nghttp2_session_on_push_response_headers_received(nghttp2_session *session, - nghttp2_frame *frame, - nghttp2_stream *stream) { - int rv = 0; - assert(stream->state == NGHTTP2_STREAM_RESERVED); - if (frame->hd.stream_id == 0) { - return session_inflate_handle_invalid_connection( - session, frame, NGHTTP2_ERR_PROTO, - "push response HEADERS: stream_id == 0"); - } - - if (session->server) { - return session_inflate_handle_invalid_connection( - session, frame, NGHTTP2_ERR_PROTO, - "HEADERS: no HEADERS allowed from client in reserved state"); - } - - if (session_is_incoming_concurrent_streams_max(session)) { - return session_inflate_handle_invalid_connection( - session, frame, NGHTTP2_ERR_PROTO, - "push response HEADERS: max concurrent streams exceeded"); - } - - if (!session_allow_incoming_new_stream(session)) { - /* We don't accept new stream after GOAWAY was sent. */ - return NGHTTP2_ERR_IGN_HEADER_BLOCK; - } - - if (session_is_incoming_concurrent_streams_pending_max(session)) { - return session_inflate_handle_invalid_stream(session, frame, - NGHTTP2_ERR_REFUSED_STREAM); - } - - nghttp2_stream_promise_fulfilled(stream); - if (!nghttp2_session_is_my_stream_id(session, stream->stream_id)) { - --session->num_incoming_reserved_streams; - } - ++session->num_incoming_streams; - rv = session_call_on_begin_headers(session, frame); - if (rv != 0) { - return rv; - } - return 0; -} - -int nghttp2_session_on_headers_received(nghttp2_session *session, - nghttp2_frame *frame, - nghttp2_stream *stream) { - int rv = 0; - if (frame->hd.stream_id == 0) { - return session_inflate_handle_invalid_connection( - session, frame, NGHTTP2_ERR_PROTO, "HEADERS: stream_id == 0"); - } - if ((stream->shut_flags & NGHTTP2_SHUT_RD)) { - /* half closed (remote): from the spec: - - If an endpoint receives additional frames for a stream that is - in this state it MUST respond with a stream error (Section - 5.4.2) of type STREAM_CLOSED. - - we go further, and make it connection error. - */ - return session_inflate_handle_invalid_connection( - session, frame, NGHTTP2_ERR_STREAM_CLOSED, "HEADERS: stream closed"); - } - if (nghttp2_session_is_my_stream_id(session, frame->hd.stream_id)) { - if (stream->state == NGHTTP2_STREAM_OPENED) { - rv = session_call_on_begin_headers(session, frame); - if (rv != 0) { - return rv; - } - return 0; - } - - return NGHTTP2_ERR_IGN_HEADER_BLOCK; - } - /* If this is remote peer initiated stream, it is OK unless it - has sent END_STREAM frame already. But if stream is in - NGHTTP2_STREAM_CLOSING, we discard the frame. This is a race - condition. */ - if (stream->state != NGHTTP2_STREAM_CLOSING) { - rv = session_call_on_begin_headers(session, frame); - if (rv != 0) { - return rv; - } - return 0; - } - return NGHTTP2_ERR_IGN_HEADER_BLOCK; -} - -static int session_process_headers_frame(nghttp2_session *session) { - nghttp2_inbound_frame *iframe = &session->iframe; - nghttp2_frame *frame = &iframe->frame; - nghttp2_stream *stream; - - nghttp2_frame_unpack_headers_payload(&frame->headers, iframe->sbuf.pos); - - stream = nghttp2_session_get_stream(session, frame->hd.stream_id); - if (!stream) { - frame->headers.cat = NGHTTP2_HCAT_REQUEST; - return nghttp2_session_on_request_headers_received(session, frame); - } - - if (stream->state == NGHTTP2_STREAM_RESERVED) { - frame->headers.cat = NGHTTP2_HCAT_PUSH_RESPONSE; - return nghttp2_session_on_push_response_headers_received(session, frame, - stream); - } - - if (stream->state == NGHTTP2_STREAM_OPENING && - nghttp2_session_is_my_stream_id(session, frame->hd.stream_id)) { - frame->headers.cat = NGHTTP2_HCAT_RESPONSE; - return nghttp2_session_on_response_headers_received(session, frame, stream); - } - - frame->headers.cat = NGHTTP2_HCAT_HEADERS; - return nghttp2_session_on_headers_received(session, frame, stream); -} - -int nghttp2_session_on_priority_received(nghttp2_session *session, - nghttp2_frame *frame) { - int rv; - nghttp2_stream *stream; - - assert(!session_no_rfc7540_pri_no_fallback(session)); - - if (frame->hd.stream_id == 0) { - return session_handle_invalid_connection(session, frame, NGHTTP2_ERR_PROTO, - "PRIORITY: stream_id == 0"); - } - - if (frame->priority.pri_spec.stream_id == frame->hd.stream_id) { - return nghttp2_session_terminate_session_with_reason( - session, NGHTTP2_PROTOCOL_ERROR, "depend on itself"); - } - - if (!session->server) { - /* Re-prioritization works only in server */ - return session_call_on_frame_received(session, frame); - } - - stream = nghttp2_session_get_stream_raw(session, frame->hd.stream_id); - - if (!stream) { - /* PRIORITY against idle stream can create anchor node in - dependency tree. */ - if (!session_detect_idle_stream(session, frame->hd.stream_id)) { - return 0; - } - - stream = nghttp2_session_open_stream( - session, frame->hd.stream_id, NGHTTP2_STREAM_FLAG_NONE, - &frame->priority.pri_spec, NGHTTP2_STREAM_IDLE, NULL); - - if (stream == NULL) { - return NGHTTP2_ERR_NOMEM; - } - - rv = nghttp2_session_adjust_idle_stream(session); - if (nghttp2_is_fatal(rv)) { - return rv; - } - } else { - rv = nghttp2_session_reprioritize_stream(session, stream, - &frame->priority.pri_spec); - - if (nghttp2_is_fatal(rv)) { - return rv; - } - - rv = nghttp2_session_adjust_idle_stream(session); - if (nghttp2_is_fatal(rv)) { - return rv; - } - } - - return session_call_on_frame_received(session, frame); -} - -static int session_process_priority_frame(nghttp2_session *session) { - nghttp2_inbound_frame *iframe = &session->iframe; - nghttp2_frame *frame = &iframe->frame; - - assert(!session_no_rfc7540_pri_no_fallback(session)); - - nghttp2_frame_unpack_priority_payload(&frame->priority, iframe->sbuf.pos); - - return nghttp2_session_on_priority_received(session, frame); -} - -static int session_update_stream_reset_ratelim(nghttp2_session *session) { - if (!session->server || (session->goaway_flags & NGHTTP2_GOAWAY_SUBMITTED)) { - return 0; - } - - nghttp2_ratelim_update(&session->stream_reset_ratelim, - nghttp2_time_now_sec()); - - if (nghttp2_ratelim_drain(&session->stream_reset_ratelim, 1) == 0) { - return 0; - } - - return nghttp2_session_add_goaway(session, session->last_recv_stream_id, - NGHTTP2_INTERNAL_ERROR, NULL, 0, - NGHTTP2_GOAWAY_AUX_NONE); -} - -int nghttp2_session_on_rst_stream_received(nghttp2_session *session, - nghttp2_frame *frame) { - int rv; - nghttp2_stream *stream; - if (frame->hd.stream_id == 0) { - return session_handle_invalid_connection(session, frame, NGHTTP2_ERR_PROTO, - "RST_STREAM: stream_id == 0"); - } - - if (session_detect_idle_stream(session, frame->hd.stream_id)) { - return session_handle_invalid_connection(session, frame, NGHTTP2_ERR_PROTO, - "RST_STREAM: stream in idle"); - } - - stream = nghttp2_session_get_stream(session, frame->hd.stream_id); - if (stream) { - /* We may use stream->shut_flags for strict error checking. */ - nghttp2_stream_shutdown(stream, NGHTTP2_SHUT_RD); - } - - rv = session_call_on_frame_received(session, frame); - if (rv != 0) { - return rv; - } - rv = nghttp2_session_close_stream(session, frame->hd.stream_id, - frame->rst_stream.error_code); - if (nghttp2_is_fatal(rv)) { - return rv; - } - - return session_update_stream_reset_ratelim(session); -} - -static int session_process_rst_stream_frame(nghttp2_session *session) { - nghttp2_inbound_frame *iframe = &session->iframe; - nghttp2_frame *frame = &iframe->frame; - - nghttp2_frame_unpack_rst_stream_payload(&frame->rst_stream, iframe->sbuf.pos); - - return nghttp2_session_on_rst_stream_received(session, frame); -} - -static int update_remote_initial_window_size_func(void *entry, void *ptr) { - int rv; - nghttp2_update_window_size_arg *arg; - nghttp2_stream *stream; - - arg = (nghttp2_update_window_size_arg *)ptr; - stream = (nghttp2_stream *)entry; - - rv = nghttp2_stream_update_remote_initial_window_size( - stream, arg->new_window_size, arg->old_window_size); - if (rv != 0) { - return nghttp2_session_add_rst_stream(arg->session, stream->stream_id, - NGHTTP2_FLOW_CONTROL_ERROR); - } - - /* If window size gets positive, push deferred DATA frame to - outbound queue. */ - if (stream->remote_window_size > 0 && - nghttp2_stream_check_deferred_by_flow_control(stream)) { - rv = session_resume_deferred_stream_item( - arg->session, stream, NGHTTP2_STREAM_FLAG_DEFERRED_FLOW_CONTROL); - - if (nghttp2_is_fatal(rv)) { - return rv; - } - } - return 0; -} - -/* - * Updates the remote initial window size of all active streams. If - * error occurs, all streams may not be updated. - * - * This function returns 0 if it succeeds, or one of the following - * negative error codes: - * - * NGHTTP2_ERR_NOMEM - * Out of memory. - */ -static int -session_update_remote_initial_window_size(nghttp2_session *session, - int32_t new_initial_window_size) { - nghttp2_update_window_size_arg arg; - - arg.session = session; - arg.new_window_size = new_initial_window_size; - arg.old_window_size = (int32_t)session->remote_settings.initial_window_size; - - return nghttp2_map_each(&session->streams, - update_remote_initial_window_size_func, &arg); -} - -static int update_local_initial_window_size_func(void *entry, void *ptr) { - int rv; - nghttp2_update_window_size_arg *arg; - nghttp2_stream *stream; - arg = (nghttp2_update_window_size_arg *)ptr; - stream = (nghttp2_stream *)entry; - rv = nghttp2_stream_update_local_initial_window_size( - stream, arg->new_window_size, arg->old_window_size); - if (rv != 0) { - return nghttp2_session_add_rst_stream(arg->session, stream->stream_id, - NGHTTP2_FLOW_CONTROL_ERROR); - } - - if (stream->window_update_queued) { - return 0; - } - - if (arg->session->opt_flags & NGHTTP2_OPTMASK_NO_AUTO_WINDOW_UPDATE) { - return session_update_stream_consumed_size(arg->session, stream, 0); - } - - if (nghttp2_should_send_window_update(stream->local_window_size, - stream->recv_window_size)) { - rv = nghttp2_session_add_window_update(arg->session, NGHTTP2_FLAG_NONE, - stream->stream_id, - stream->recv_window_size); - if (rv != 0) { - return rv; - } - - stream->recv_window_size = 0; - } - return 0; -} - -/* - * Updates the local initial window size of all active streams. If - * error occurs, all streams may not be updated. - * - * This function returns 0 if it succeeds, or one of the following - * negative error codes: - * - * NGHTTP2_ERR_NOMEM - * Out of memory. - */ -static int -session_update_local_initial_window_size(nghttp2_session *session, - int32_t new_initial_window_size, - int32_t old_initial_window_size) { - nghttp2_update_window_size_arg arg; - arg.session = session; - arg.new_window_size = new_initial_window_size; - arg.old_window_size = old_initial_window_size; - return nghttp2_map_each(&session->streams, - update_local_initial_window_size_func, &arg); -} - -/* - * Apply SETTINGS values |iv| having |niv| elements to the local - * settings. We assumes that all values in |iv| is correct, since we - * validated them in nghttp2_session_add_settings() already. - * - * This function returns 0 if it succeeds, or one of the following - * negative error codes: - * - * NGHTTP2_ERR_HEADER_COMP - * The header table size is out of range - * NGHTTP2_ERR_NOMEM - * Out of memory - */ -int nghttp2_session_update_local_settings(nghttp2_session *session, - nghttp2_settings_entry *iv, - size_t niv) { - int rv; - size_t i; - int32_t new_initial_window_size = -1; - uint32_t header_table_size = 0; - uint32_t min_header_table_size = UINT32_MAX; - uint8_t header_table_size_seen = 0; - /* For NGHTTP2_SETTINGS_INITIAL_WINDOW_SIZE, use the value last - seen. For NGHTTP2_SETTINGS_HEADER_TABLE_SIZE, use both minimum - value and last seen value. */ - for (i = 0; i < niv; ++i) { - switch (iv[i].settings_id) { - case NGHTTP2_SETTINGS_HEADER_TABLE_SIZE: - header_table_size_seen = 1; - header_table_size = iv[i].value; - min_header_table_size = - nghttp2_min_uint32(min_header_table_size, iv[i].value); - break; - case NGHTTP2_SETTINGS_INITIAL_WINDOW_SIZE: - new_initial_window_size = (int32_t)iv[i].value; - break; - } - } - if (header_table_size_seen) { - if (min_header_table_size < header_table_size) { - rv = nghttp2_hd_inflate_change_table_size(&session->hd_inflater, - min_header_table_size); - if (rv != 0) { - return rv; - } - } - - rv = nghttp2_hd_inflate_change_table_size(&session->hd_inflater, - header_table_size); - if (rv != 0) { - return rv; - } - } - if (new_initial_window_size != -1) { - rv = session_update_local_initial_window_size( - session, new_initial_window_size, - (int32_t)session->local_settings.initial_window_size); - if (rv != 0) { - return rv; - } - } - - for (i = 0; i < niv; ++i) { - switch (iv[i].settings_id) { - case NGHTTP2_SETTINGS_HEADER_TABLE_SIZE: - session->local_settings.header_table_size = iv[i].value; - break; - case NGHTTP2_SETTINGS_ENABLE_PUSH: - session->local_settings.enable_push = iv[i].value; - break; - case NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS: - session->local_settings.max_concurrent_streams = iv[i].value; - break; - case NGHTTP2_SETTINGS_INITIAL_WINDOW_SIZE: - session->local_settings.initial_window_size = iv[i].value; - break; - case NGHTTP2_SETTINGS_MAX_FRAME_SIZE: - session->local_settings.max_frame_size = iv[i].value; - break; - case NGHTTP2_SETTINGS_MAX_HEADER_LIST_SIZE: - session->local_settings.max_header_list_size = iv[i].value; - break; - case NGHTTP2_SETTINGS_ENABLE_CONNECT_PROTOCOL: - session->local_settings.enable_connect_protocol = iv[i].value; - break; - case NGHTTP2_SETTINGS_NO_RFC7540_PRIORITIES: - session->local_settings.no_rfc7540_priorities = iv[i].value; - break; - } - } - - return 0; -} - -int nghttp2_session_on_settings_received(nghttp2_session *session, - nghttp2_frame *frame, int noack) { - int rv; - size_t i; - nghttp2_mem *mem; - nghttp2_inflight_settings *settings; - - mem = &session->mem; - - if (frame->hd.stream_id != 0) { - return session_handle_invalid_connection(session, frame, NGHTTP2_ERR_PROTO, - "SETTINGS: stream_id != 0"); - } - if (frame->hd.flags & NGHTTP2_FLAG_ACK) { - if (frame->settings.niv != 0) { - return session_handle_invalid_connection( - session, frame, NGHTTP2_ERR_FRAME_SIZE_ERROR, - "SETTINGS: ACK and payload != 0"); - } - - settings = session->inflight_settings_head; - - if (!settings) { - return session_handle_invalid_connection( - session, frame, NGHTTP2_ERR_PROTO, "SETTINGS: unexpected ACK"); - } - - rv = nghttp2_session_update_local_settings(session, settings->iv, - settings->niv); - - session->inflight_settings_head = settings->next; - - inflight_settings_del(settings, mem); - - if (rv != 0) { - if (nghttp2_is_fatal(rv)) { - return rv; - } - return session_handle_invalid_connection(session, frame, rv, NULL); - } - return session_call_on_frame_received(session, frame); - } - - if (!session->remote_settings_received) { - session->remote_settings.max_concurrent_streams = - NGHTTP2_DEFAULT_MAX_CONCURRENT_STREAMS; - session->remote_settings_received = 1; - } - - for (i = 0; i < frame->settings.niv; ++i) { - nghttp2_settings_entry *entry = &frame->settings.iv[i]; - - switch (entry->settings_id) { - case NGHTTP2_SETTINGS_HEADER_TABLE_SIZE: - - rv = nghttp2_hd_deflate_change_table_size(&session->hd_deflater, - entry->value); - if (rv != 0) { - if (nghttp2_is_fatal(rv)) { - return rv; - } else { - return session_handle_invalid_connection( - session, frame, NGHTTP2_ERR_HEADER_COMP, NULL); - } - } - - session->remote_settings.header_table_size = entry->value; - - break; - case NGHTTP2_SETTINGS_ENABLE_PUSH: - - if (entry->value != 0 && entry->value != 1) { - return session_handle_invalid_connection( - session, frame, NGHTTP2_ERR_PROTO, - "SETTINGS: invalid SETTINGS_ENBLE_PUSH"); - } - - if (!session->server && entry->value != 0) { - return session_handle_invalid_connection( - session, frame, NGHTTP2_ERR_PROTO, - "SETTINGS: server attempted to enable push"); - } - - session->remote_settings.enable_push = entry->value; - - break; - case NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS: - - session->remote_settings.max_concurrent_streams = entry->value; - - break; - case NGHTTP2_SETTINGS_INITIAL_WINDOW_SIZE: - - /* Update the initial window size of the all active streams */ - /* Check that initial_window_size < (1u << 31) */ - if (entry->value > NGHTTP2_MAX_WINDOW_SIZE) { - return session_handle_invalid_connection( - session, frame, NGHTTP2_ERR_FLOW_CONTROL, - "SETTINGS: too large SETTINGS_INITIAL_WINDOW_SIZE"); - } - - rv = session_update_remote_initial_window_size(session, - (int32_t)entry->value); - - if (nghttp2_is_fatal(rv)) { - return rv; - } - - if (rv != 0) { - return session_handle_invalid_connection( - session, frame, NGHTTP2_ERR_FLOW_CONTROL, NULL); - } - - session->remote_settings.initial_window_size = entry->value; - - break; - case NGHTTP2_SETTINGS_MAX_FRAME_SIZE: - - if (entry->value < NGHTTP2_MAX_FRAME_SIZE_MIN || - entry->value > NGHTTP2_MAX_FRAME_SIZE_MAX) { - return session_handle_invalid_connection( - session, frame, NGHTTP2_ERR_PROTO, - "SETTINGS: invalid SETTINGS_MAX_FRAME_SIZE"); - } - - session->remote_settings.max_frame_size = entry->value; - - break; - case NGHTTP2_SETTINGS_MAX_HEADER_LIST_SIZE: - - session->remote_settings.max_header_list_size = entry->value; - - break; - case NGHTTP2_SETTINGS_ENABLE_CONNECT_PROTOCOL: - - if (entry->value != 0 && entry->value != 1) { - return session_handle_invalid_connection( - session, frame, NGHTTP2_ERR_PROTO, - "SETTINGS: invalid SETTINGS_ENABLE_CONNECT_PROTOCOL"); - } - - if (!session->server && - session->remote_settings.enable_connect_protocol && - entry->value == 0) { - return session_handle_invalid_connection( - session, frame, NGHTTP2_ERR_PROTO, - "SETTINGS: server attempted to disable " - "SETTINGS_ENABLE_CONNECT_PROTOCOL"); - } - - session->remote_settings.enable_connect_protocol = entry->value; - - break; - case NGHTTP2_SETTINGS_NO_RFC7540_PRIORITIES: - - if (entry->value != 0 && entry->value != 1) { - return session_handle_invalid_connection( - session, frame, NGHTTP2_ERR_PROTO, - "SETTINGS: invalid SETTINGS_NO_RFC7540_PRIORITIES"); - } - - if (session->remote_settings.no_rfc7540_priorities != UINT32_MAX && - session->remote_settings.no_rfc7540_priorities != entry->value) { - return session_handle_invalid_connection( - session, frame, NGHTTP2_ERR_PROTO, - "SETTINGS: SETTINGS_NO_RFC7540_PRIORITIES cannot be changed"); - } - - session->remote_settings.no_rfc7540_priorities = entry->value; - - break; - } - } - - if (session->remote_settings.no_rfc7540_priorities == UINT32_MAX) { - session->remote_settings.no_rfc7540_priorities = 0; - - if (session->server && session->pending_no_rfc7540_priorities && - (session->opt_flags & - NGHTTP2_OPTMASK_SERVER_FALLBACK_RFC7540_PRIORITIES)) { - session->fallback_rfc7540_priorities = 1; - } - } - - if (!noack && !session_is_closing(session)) { - rv = nghttp2_session_add_settings(session, NGHTTP2_FLAG_ACK, NULL, 0); - - if (rv != 0) { - if (nghttp2_is_fatal(rv)) { - return rv; - } - - return session_handle_invalid_connection(session, frame, - NGHTTP2_ERR_INTERNAL, NULL); - } - } - - return session_call_on_frame_received(session, frame); -} - -static int session_process_settings_frame(nghttp2_session *session) { - nghttp2_inbound_frame *iframe = &session->iframe; - nghttp2_frame *frame = &iframe->frame; - size_t i; - nghttp2_settings_entry min_header_size_entry; - - if (iframe->max_niv) { - min_header_size_entry = iframe->iv[iframe->max_niv - 1]; - - if (min_header_size_entry.value < UINT32_MAX) { - /* If we have less value, then we must have - SETTINGS_HEADER_TABLE_SIZE in i < iframe->niv */ - for (i = 0; i < iframe->niv; ++i) { - if (iframe->iv[i].settings_id == NGHTTP2_SETTINGS_HEADER_TABLE_SIZE) { - break; - } - } - - assert(i < iframe->niv); - - if (min_header_size_entry.value != iframe->iv[i].value) { - iframe->iv[iframe->niv++] = iframe->iv[i]; - iframe->iv[i] = min_header_size_entry; - } - } - } - - nghttp2_frame_unpack_settings_payload(&frame->settings, iframe->iv, - iframe->niv); - - iframe->iv = NULL; - iframe->niv = 0; - iframe->max_niv = 0; - - return nghttp2_session_on_settings_received(session, frame, 0 /* ACK */); -} - -int nghttp2_session_on_push_promise_received(nghttp2_session *session, - nghttp2_frame *frame) { - int rv; - nghttp2_stream *stream; - nghttp2_stream *promised_stream; - nghttp2_priority_spec pri_spec; - - if (frame->hd.stream_id == 0) { - return session_inflate_handle_invalid_connection( - session, frame, NGHTTP2_ERR_PROTO, "PUSH_PROMISE: stream_id == 0"); - } - if (session->server || session->local_settings.enable_push == 0) { - return session_inflate_handle_invalid_connection( - session, frame, NGHTTP2_ERR_PROTO, "PUSH_PROMISE: push disabled"); - } - - if (!nghttp2_session_is_my_stream_id(session, frame->hd.stream_id)) { - return session_inflate_handle_invalid_connection( - session, frame, NGHTTP2_ERR_PROTO, "PUSH_PROMISE: invalid stream_id"); - } - - if (!session_allow_incoming_new_stream(session)) { - /* We just discard PUSH_PROMISE after GOAWAY was sent */ - return NGHTTP2_ERR_IGN_HEADER_BLOCK; - } - - if (!session_is_new_peer_stream_id(session, - frame->push_promise.promised_stream_id)) { - /* The spec says if an endpoint receives a PUSH_PROMISE with - illegal stream ID is subject to a connection error of type - PROTOCOL_ERROR. */ - return session_inflate_handle_invalid_connection( - session, frame, NGHTTP2_ERR_PROTO, - "PUSH_PROMISE: invalid promised_stream_id"); - } - - if (session_detect_idle_stream(session, frame->hd.stream_id)) { - return session_inflate_handle_invalid_connection( - session, frame, NGHTTP2_ERR_PROTO, "PUSH_PROMISE: stream in idle"); - } - - session->last_recv_stream_id = frame->push_promise.promised_stream_id; - stream = nghttp2_session_get_stream(session, frame->hd.stream_id); - if (!stream || stream->state == NGHTTP2_STREAM_CLOSING || - !session->pending_enable_push || - session->num_incoming_reserved_streams >= - session->max_incoming_reserved_streams) { - /* Currently, client does not retain closed stream, so we don't - check NGHTTP2_SHUT_RD condition here. */ - - rv = nghttp2_session_add_rst_stream( - session, frame->push_promise.promised_stream_id, NGHTTP2_CANCEL); - if (rv != 0) { - return rv; - } - return NGHTTP2_ERR_IGN_HEADER_BLOCK; - } - - if (stream->shut_flags & NGHTTP2_SHUT_RD) { - return session_inflate_handle_invalid_connection( - session, frame, NGHTTP2_ERR_STREAM_CLOSED, "PUSH_PROMISE: stream closed"); - } - - nghttp2_priority_spec_init(&pri_spec, stream->stream_id, - NGHTTP2_DEFAULT_WEIGHT, 0); - - promised_stream = nghttp2_session_open_stream( - session, frame->push_promise.promised_stream_id, NGHTTP2_STREAM_FLAG_NONE, - &pri_spec, NGHTTP2_STREAM_RESERVED, NULL); - - if (!promised_stream) { - return NGHTTP2_ERR_NOMEM; - } - - /* We don't call nghttp2_session_adjust_closed_stream(), since we - don't keep closed stream in client side */ - - session->last_proc_stream_id = session->last_recv_stream_id; - rv = session_call_on_begin_headers(session, frame); - if (rv != 0) { - return rv; - } - return 0; -} - -static int session_process_push_promise_frame(nghttp2_session *session) { - nghttp2_inbound_frame *iframe = &session->iframe; - nghttp2_frame *frame = &iframe->frame; - - nghttp2_frame_unpack_push_promise_payload(&frame->push_promise, - iframe->sbuf.pos); - - return nghttp2_session_on_push_promise_received(session, frame); -} - -int nghttp2_session_on_ping_received(nghttp2_session *session, - nghttp2_frame *frame) { - int rv = 0; - if (frame->hd.stream_id != 0) { - return session_handle_invalid_connection(session, frame, NGHTTP2_ERR_PROTO, - "PING: stream_id != 0"); - } - if ((session->opt_flags & NGHTTP2_OPTMASK_NO_AUTO_PING_ACK) == 0 && - (frame->hd.flags & NGHTTP2_FLAG_ACK) == 0 && - !session_is_closing(session)) { - /* Peer sent ping, so ping it back */ - rv = nghttp2_session_add_ping(session, NGHTTP2_FLAG_ACK, - frame->ping.opaque_data); - if (rv != 0) { - return rv; - } - } - return session_call_on_frame_received(session, frame); -} - -static int session_process_ping_frame(nghttp2_session *session) { - nghttp2_inbound_frame *iframe = &session->iframe; - nghttp2_frame *frame = &iframe->frame; - - nghttp2_frame_unpack_ping_payload(&frame->ping, iframe->sbuf.pos); - - return nghttp2_session_on_ping_received(session, frame); -} - -int nghttp2_session_on_goaway_received(nghttp2_session *session, - nghttp2_frame *frame) { - int rv; - - if (frame->hd.stream_id != 0) { - return session_handle_invalid_connection(session, frame, NGHTTP2_ERR_PROTO, - "GOAWAY: stream_id != 0"); - } - /* Spec says Endpoints MUST NOT increase the value they send in the - last stream identifier. */ - if ((frame->goaway.last_stream_id > 0 && - !nghttp2_session_is_my_stream_id(session, - frame->goaway.last_stream_id)) || - session->remote_last_stream_id < frame->goaway.last_stream_id) { - return session_handle_invalid_connection(session, frame, NGHTTP2_ERR_PROTO, - "GOAWAY: invalid last_stream_id"); - } - - session->goaway_flags |= NGHTTP2_GOAWAY_RECV; - - session->remote_last_stream_id = frame->goaway.last_stream_id; - - rv = session_call_on_frame_received(session, frame); - - if (nghttp2_is_fatal(rv)) { - return rv; - } - - return session_close_stream_on_goaway(session, frame->goaway.last_stream_id, - 0); -} - -static int session_process_goaway_frame(nghttp2_session *session) { - nghttp2_inbound_frame *iframe = &session->iframe; - nghttp2_frame *frame = &iframe->frame; - - nghttp2_frame_unpack_goaway_payload(&frame->goaway, iframe->sbuf.pos, - iframe->lbuf.pos, - nghttp2_buf_len(&iframe->lbuf)); - - nghttp2_buf_wrap_init(&iframe->lbuf, NULL, 0); - - return nghttp2_session_on_goaway_received(session, frame); -} - -static int -session_on_connection_window_update_received(nghttp2_session *session, - nghttp2_frame *frame) { - /* Handle connection-level flow control */ - if (frame->window_update.window_size_increment == 0) { - return session_handle_invalid_connection( - session, frame, NGHTTP2_ERR_PROTO, - "WINDOW_UPDATE: window_size_increment == 0"); - } - - if (NGHTTP2_MAX_WINDOW_SIZE - frame->window_update.window_size_increment < - session->remote_window_size) { - return session_handle_invalid_connection(session, frame, - NGHTTP2_ERR_FLOW_CONTROL, NULL); - } - session->remote_window_size += frame->window_update.window_size_increment; - - return session_call_on_frame_received(session, frame); -} - -static int session_on_stream_window_update_received(nghttp2_session *session, - nghttp2_frame *frame) { - int rv; - nghttp2_stream *stream; - - if (session_detect_idle_stream(session, frame->hd.stream_id)) { - return session_handle_invalid_connection(session, frame, NGHTTP2_ERR_PROTO, - "WINDOW_UPDATE to idle stream"); - } - - stream = nghttp2_session_get_stream(session, frame->hd.stream_id); - if (!stream) { - return 0; - } - if (state_reserved_remote(session, stream)) { - return session_handle_invalid_connection( - session, frame, NGHTTP2_ERR_PROTO, "WINDOW_UPADATE to reserved stream"); - } - if (frame->window_update.window_size_increment == 0) { - return session_handle_invalid_connection( - session, frame, NGHTTP2_ERR_PROTO, - "WINDOW_UPDATE: window_size_increment == 0"); - } - if (NGHTTP2_MAX_WINDOW_SIZE - frame->window_update.window_size_increment < - stream->remote_window_size) { - return session_handle_invalid_stream(session, frame, - NGHTTP2_ERR_FLOW_CONTROL); - } - stream->remote_window_size += frame->window_update.window_size_increment; - - if (stream->remote_window_size > 0 && - nghttp2_stream_check_deferred_by_flow_control(stream)) { - rv = session_resume_deferred_stream_item( - session, stream, NGHTTP2_STREAM_FLAG_DEFERRED_FLOW_CONTROL); - - if (nghttp2_is_fatal(rv)) { - return rv; - } - } - return session_call_on_frame_received(session, frame); -} - -int nghttp2_session_on_window_update_received(nghttp2_session *session, - nghttp2_frame *frame) { - if (frame->hd.stream_id == 0) { - return session_on_connection_window_update_received(session, frame); - } else { - return session_on_stream_window_update_received(session, frame); - } -} - -static int session_process_window_update_frame(nghttp2_session *session) { - nghttp2_inbound_frame *iframe = &session->iframe; - nghttp2_frame *frame = &iframe->frame; - - nghttp2_frame_unpack_window_update_payload(&frame->window_update, - iframe->sbuf.pos); - - return nghttp2_session_on_window_update_received(session, frame); -} - -int nghttp2_session_on_altsvc_received(nghttp2_session *session, - nghttp2_frame *frame) { - nghttp2_ext_altsvc *altsvc; - nghttp2_stream *stream; - - altsvc = frame->ext.payload; - - /* session->server case has been excluded */ - - if (frame->hd.stream_id == 0) { - if (altsvc->origin_len == 0) { - return session_call_on_invalid_frame_recv_callback(session, frame, - NGHTTP2_ERR_PROTO); - } - } else { - if (altsvc->origin_len > 0) { - return session_call_on_invalid_frame_recv_callback(session, frame, - NGHTTP2_ERR_PROTO); - } - - stream = nghttp2_session_get_stream(session, frame->hd.stream_id); - if (!stream) { - return 0; - } - - if (stream->state == NGHTTP2_STREAM_CLOSING) { - return 0; - } - } - - if (altsvc->field_value_len == 0) { - return session_call_on_invalid_frame_recv_callback(session, frame, - NGHTTP2_ERR_PROTO); - } - - return session_call_on_frame_received(session, frame); -} - -int nghttp2_session_on_origin_received(nghttp2_session *session, - nghttp2_frame *frame) { - return session_call_on_frame_received(session, frame); -} - -int nghttp2_session_on_priority_update_received(nghttp2_session *session, - nghttp2_frame *frame) { - nghttp2_ext_priority_update *priority_update; - nghttp2_stream *stream; - nghttp2_priority_spec pri_spec; - nghttp2_extpri extpri; - int rv; - - assert(session->server); - - priority_update = frame->ext.payload; - - if (frame->hd.stream_id != 0) { - return session_handle_invalid_connection(session, frame, NGHTTP2_ERR_PROTO, - "PRIORITY_UPDATE: stream_id == 0"); - } - - if (nghttp2_session_is_my_stream_id(session, priority_update->stream_id)) { - if (session_detect_idle_stream(session, priority_update->stream_id)) { - return session_handle_invalid_connection( - session, frame, NGHTTP2_ERR_PROTO, - "PRIORITY_UPDATE: prioritizing idle push is not allowed"); - } - - /* TODO Ignore priority signal to a push stream for now */ - return session_call_on_frame_received(session, frame); - } - - stream = nghttp2_session_get_stream_raw(session, priority_update->stream_id); - if (stream) { - /* Stream already exists. */ - if (stream->flags & NGHTTP2_STREAM_FLAG_IGNORE_CLIENT_PRIORITIES) { - return session_call_on_frame_received(session, frame); - } - } else if (session_detect_idle_stream(session, priority_update->stream_id)) { - if (session->num_idle_streams + session->num_incoming_streams >= - session->local_settings.max_concurrent_streams) { - return session_handle_invalid_connection( - session, frame, NGHTTP2_ERR_PROTO, - "PRIORITY_UPDATE: max concurrent streams exceeded"); - } - - nghttp2_priority_spec_default_init(&pri_spec); - stream = nghttp2_session_open_stream(session, priority_update->stream_id, - NGHTTP2_FLAG_NONE, &pri_spec, - NGHTTP2_STREAM_IDLE, NULL); - if (!stream) { - return NGHTTP2_ERR_NOMEM; - } - } else { - return session_call_on_frame_received(session, frame); - } - - extpri.urgency = NGHTTP2_EXTPRI_DEFAULT_URGENCY; - extpri.inc = 0; - - rv = nghttp2_http_parse_priority(&extpri, priority_update->field_value, - priority_update->field_value_len); - if (rv != 0) { - /* Just ignore field_value if it cannot be parsed. */ - return session_call_on_frame_received(session, frame); - } - - rv = session_update_stream_priority(session, stream, - nghttp2_extpri_to_uint8(&extpri)); - if (rv != 0) { - if (nghttp2_is_fatal(rv)) { - return rv; - } - } - - return session_call_on_frame_received(session, frame); -} - -static int session_process_altsvc_frame(nghttp2_session *session) { - nghttp2_inbound_frame *iframe = &session->iframe; - nghttp2_frame *frame = &iframe->frame; - - nghttp2_frame_unpack_altsvc_payload( - &frame->ext, nghttp2_get_uint16(iframe->sbuf.pos), iframe->lbuf.pos, - nghttp2_buf_len(&iframe->lbuf)); - - /* nghttp2_frame_unpack_altsvc_payload steals buffer from - iframe->lbuf */ - nghttp2_buf_wrap_init(&iframe->lbuf, NULL, 0); - - return nghttp2_session_on_altsvc_received(session, frame); -} - -static int session_process_origin_frame(nghttp2_session *session) { - nghttp2_inbound_frame *iframe = &session->iframe; - nghttp2_frame *frame = &iframe->frame; - nghttp2_mem *mem = &session->mem; - int rv; - - rv = nghttp2_frame_unpack_origin_payload(&frame->ext, iframe->lbuf.pos, - nghttp2_buf_len(&iframe->lbuf), mem); - if (rv != 0) { - if (nghttp2_is_fatal(rv)) { - return rv; - } - /* Ignore ORIGIN frame which cannot be parsed. */ - return 0; - } - - return nghttp2_session_on_origin_received(session, frame); -} - -static int session_process_priority_update_frame(nghttp2_session *session) { - nghttp2_inbound_frame *iframe = &session->iframe; - nghttp2_frame *frame = &iframe->frame; - - nghttp2_frame_unpack_priority_update_payload(&frame->ext, iframe->sbuf.pos, - nghttp2_buf_len(&iframe->sbuf)); - - return nghttp2_session_on_priority_update_received(session, frame); -} - -static int session_process_extension_frame(nghttp2_session *session) { - int rv; - nghttp2_inbound_frame *iframe = &session->iframe; - nghttp2_frame *frame = &iframe->frame; - - rv = session_call_unpack_extension_callback(session); - if (nghttp2_is_fatal(rv)) { - return rv; - } - - /* This handles the case where rv == NGHTTP2_ERR_CANCEL as well */ - if (rv != 0) { - return 0; - } - - return session_call_on_frame_received(session, frame); -} - -int nghttp2_session_on_data_received(nghttp2_session *session, - nghttp2_frame *frame) { - int rv = 0; - nghttp2_stream *stream; - - /* We don't call on_frame_recv_callback if stream has been closed - already or being closed. */ - stream = nghttp2_session_get_stream(session, frame->hd.stream_id); - if (!stream || stream->state == NGHTTP2_STREAM_CLOSING) { - /* This should be treated as stream error, but it results in lots - of RST_STREAM. So just ignore frame against nonexistent stream - for now. */ - return 0; - } - - if (session_enforce_http_messaging(session) && - (frame->hd.flags & NGHTTP2_FLAG_END_STREAM)) { - if (nghttp2_http_on_remote_end_stream(stream) != 0) { - rv = nghttp2_session_add_rst_stream(session, stream->stream_id, - NGHTTP2_PROTOCOL_ERROR); - if (nghttp2_is_fatal(rv)) { - return rv; - } - - nghttp2_stream_shutdown(stream, NGHTTP2_SHUT_RD); - /* Don't call nghttp2_session_close_stream_if_shut_rdwr because - RST_STREAM has been submitted. */ - return 0; - } - } - - rv = session_call_on_frame_received(session, frame); - if (nghttp2_is_fatal(rv)) { - return rv; - } - - if (frame->hd.flags & NGHTTP2_FLAG_END_STREAM) { - nghttp2_stream_shutdown(stream, NGHTTP2_SHUT_RD); - rv = nghttp2_session_close_stream_if_shut_rdwr(session, stream); - if (nghttp2_is_fatal(rv)) { - return rv; - } - } - return 0; -} - -/* For errors, this function only returns FATAL error. */ -static int session_process_data_frame(nghttp2_session *session) { - int rv; - nghttp2_frame *public_data_frame = &session->iframe.frame; - rv = nghttp2_session_on_data_received(session, public_data_frame); - if (nghttp2_is_fatal(rv)) { - return rv; - } - return 0; -} - -/* - * Now we have SETTINGS synchronization, flow control error can be - * detected strictly. If DATA frame is received with length > 0 and - * current received window size + delta length is strictly larger than - * local window size, it is subject to FLOW_CONTROL_ERROR, so return - * -1. Note that local_window_size is calculated after SETTINGS ACK is - * received from peer, so peer must honor this limit. If the resulting - * recv_window_size is strictly larger than NGHTTP2_MAX_WINDOW_SIZE, - * return -1 too. - */ -static int adjust_recv_window_size(int32_t *recv_window_size_ptr, size_t delta, - int32_t local_window_size) { - if (*recv_window_size_ptr > local_window_size - (int32_t)delta || - *recv_window_size_ptr > NGHTTP2_MAX_WINDOW_SIZE - (int32_t)delta) { - return -1; - } - *recv_window_size_ptr += (int32_t)delta; - return 0; -} - -int nghttp2_session_update_recv_stream_window_size(nghttp2_session *session, - nghttp2_stream *stream, - size_t delta_size, - int send_window_update) { - int rv; - rv = adjust_recv_window_size(&stream->recv_window_size, delta_size, - stream->local_window_size); - if (rv != 0) { - return nghttp2_session_add_rst_stream(session, stream->stream_id, - NGHTTP2_FLOW_CONTROL_ERROR); - } - /* We don't have to send WINDOW_UPDATE if the data received is the - last chunk in the incoming stream. */ - /* We have to use local_settings here because it is the constraint - the remote endpoint should honor. */ - if (send_window_update && - !(session->opt_flags & NGHTTP2_OPTMASK_NO_AUTO_WINDOW_UPDATE) && - stream->window_update_queued == 0 && - nghttp2_should_send_window_update(stream->local_window_size, - stream->recv_window_size)) { - rv = nghttp2_session_add_window_update( - session, NGHTTP2_FLAG_NONE, stream->stream_id, stream->recv_window_size); - if (rv != 0) { - return rv; - } - - stream->recv_window_size = 0; - } - return 0; -} - -int nghttp2_session_update_recv_connection_window_size(nghttp2_session *session, - size_t delta_size) { - int rv; - rv = adjust_recv_window_size(&session->recv_window_size, delta_size, - session->local_window_size); - if (rv != 0) { - return nghttp2_session_terminate_session(session, - NGHTTP2_FLOW_CONTROL_ERROR); - } - if (!(session->opt_flags & NGHTTP2_OPTMASK_NO_AUTO_WINDOW_UPDATE) && - session->window_update_queued == 0 && - nghttp2_should_send_window_update(session->local_window_size, - session->recv_window_size)) { - /* Use stream ID 0 to update connection-level flow control - window */ - rv = nghttp2_session_add_window_update(session, NGHTTP2_FLAG_NONE, 0, - session->recv_window_size); - if (rv != 0) { - return rv; - } - - session->recv_window_size = 0; - } - return 0; -} - -static int session_update_consumed_size(nghttp2_session *session, - int32_t *consumed_size_ptr, - int32_t *recv_window_size_ptr, - uint8_t window_update_queued, - int32_t stream_id, size_t delta_size, - int32_t local_window_size) { - int32_t recv_size; - int rv; - - if ((size_t)*consumed_size_ptr > NGHTTP2_MAX_WINDOW_SIZE - delta_size) { - return nghttp2_session_terminate_session(session, - NGHTTP2_FLOW_CONTROL_ERROR); - } - - *consumed_size_ptr += (int32_t)delta_size; - - if (window_update_queued == 0) { - /* recv_window_size may be smaller than consumed_size, because it - may be decreased by negative value with - nghttp2_submit_window_update(). */ - recv_size = nghttp2_min_int32(*consumed_size_ptr, *recv_window_size_ptr); - - if (nghttp2_should_send_window_update(local_window_size, recv_size)) { - rv = nghttp2_session_add_window_update(session, NGHTTP2_FLAG_NONE, - stream_id, recv_size); - - if (rv != 0) { - return rv; - } - - *recv_window_size_ptr -= recv_size; - *consumed_size_ptr -= recv_size; - } - } - - return 0; -} - -static int session_update_stream_consumed_size(nghttp2_session *session, - nghttp2_stream *stream, - size_t delta_size) { - return session_update_consumed_size( - session, &stream->consumed_size, &stream->recv_window_size, - stream->window_update_queued, stream->stream_id, delta_size, - stream->local_window_size); -} - -static int session_update_connection_consumed_size(nghttp2_session *session, - size_t delta_size) { - return session_update_consumed_size( - session, &session->consumed_size, &session->recv_window_size, - session->window_update_queued, 0, delta_size, session->local_window_size); -} - -/* - * Checks that we can receive the DATA frame for stream, which is - * indicated by |session->iframe.frame.hd.stream_id|. If it is a - * connection error situation, GOAWAY frame will be issued by this - * function. - * - * If the DATA frame is allowed, returns 0. - * - * This function returns 0 if it succeeds, or one of the following - * negative error codes: - * - * NGHTTP2_ERR_IGN_PAYLOAD - * The reception of DATA frame is connection error; or should be - * ignored. - * NGHTTP2_ERR_NOMEM - * Out of memory. - */ -static int session_on_data_received_fail_fast(nghttp2_session *session) { - int rv; - nghttp2_stream *stream; - nghttp2_inbound_frame *iframe; - int32_t stream_id; - const char *failure_reason; - uint32_t error_code = NGHTTP2_PROTOCOL_ERROR; - - iframe = &session->iframe; - stream_id = iframe->frame.hd.stream_id; - - if (stream_id == 0) { - /* The spec says that if a DATA frame is received whose stream ID - is 0, the recipient MUST respond with a connection error of - type PROTOCOL_ERROR. */ - failure_reason = "DATA: stream_id == 0"; - goto fail; - } - - if (session_detect_idle_stream(session, stream_id)) { - failure_reason = "DATA: stream in idle"; - error_code = NGHTTP2_PROTOCOL_ERROR; - goto fail; - } - - stream = nghttp2_session_get_stream(session, stream_id); - if (!stream) { - stream = nghttp2_session_get_stream_raw(session, stream_id); - if (stream && (stream->shut_flags & NGHTTP2_SHUT_RD)) { - failure_reason = "DATA: stream closed"; - error_code = NGHTTP2_STREAM_CLOSED; - goto fail; - } - - return NGHTTP2_ERR_IGN_PAYLOAD; - } - if (stream->shut_flags & NGHTTP2_SHUT_RD) { - failure_reason = "DATA: stream in half-closed(remote)"; - error_code = NGHTTP2_STREAM_CLOSED; - goto fail; - } - - if (nghttp2_session_is_my_stream_id(session, stream_id)) { - if (stream->state == NGHTTP2_STREAM_CLOSING) { - return NGHTTP2_ERR_IGN_PAYLOAD; - } - if (stream->state != NGHTTP2_STREAM_OPENED) { - failure_reason = "DATA: stream not opened"; - goto fail; - } - return 0; - } - if (stream->state == NGHTTP2_STREAM_RESERVED) { - failure_reason = "DATA: stream in reserved"; - goto fail; - } - if (stream->state == NGHTTP2_STREAM_CLOSING) { - return NGHTTP2_ERR_IGN_PAYLOAD; - } - return 0; -fail: - rv = nghttp2_session_terminate_session_with_reason(session, error_code, - failure_reason); - if (nghttp2_is_fatal(rv)) { - return rv; - } - return NGHTTP2_ERR_IGN_PAYLOAD; -} - -static size_t inbound_frame_payload_readlen(nghttp2_inbound_frame *iframe, - const uint8_t *in, - const uint8_t *last) { - return nghttp2_min_size((size_t)(last - in), iframe->payloadleft); -} - -/* - * Resets iframe->sbuf and advance its mark pointer by |left| bytes. - */ -static void inbound_frame_set_mark(nghttp2_inbound_frame *iframe, size_t left) { - nghttp2_buf_reset(&iframe->sbuf); - iframe->sbuf.mark += left; -} - -static size_t inbound_frame_buf_read(nghttp2_inbound_frame *iframe, - const uint8_t *in, const uint8_t *last) { - size_t readlen; - - readlen = nghttp2_min_size((size_t)(last - in), - nghttp2_buf_mark_avail(&iframe->sbuf)); - - iframe->sbuf.last = nghttp2_cpymem(iframe->sbuf.last, in, readlen); - - return readlen; -} - -/* - * Unpacks SETTINGS entry in iframe->sbuf. - */ -static void inbound_frame_set_settings_entry(nghttp2_inbound_frame *iframe) { - nghttp2_settings_entry iv; - nghttp2_settings_entry *min_header_table_size_entry; - size_t i; - - nghttp2_frame_unpack_settings_entry(&iv, iframe->sbuf.pos); - - switch (iv.settings_id) { - case NGHTTP2_SETTINGS_HEADER_TABLE_SIZE: - case NGHTTP2_SETTINGS_ENABLE_PUSH: - case NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS: - case NGHTTP2_SETTINGS_INITIAL_WINDOW_SIZE: - case NGHTTP2_SETTINGS_MAX_FRAME_SIZE: - case NGHTTP2_SETTINGS_MAX_HEADER_LIST_SIZE: - case NGHTTP2_SETTINGS_ENABLE_CONNECT_PROTOCOL: - case NGHTTP2_SETTINGS_NO_RFC7540_PRIORITIES: - break; - default: - DEBUGF("recv: unknown settings id=0x%02x\n", iv.settings_id); - - iframe->iv[iframe->niv++] = iv; - - return; - } - - for (i = 0; i < iframe->niv; ++i) { - if (iframe->iv[i].settings_id == iv.settings_id) { - iframe->iv[i] = iv; - break; - } - } - - if (i == iframe->niv) { - iframe->iv[iframe->niv++] = iv; - } - - if (iv.settings_id == NGHTTP2_SETTINGS_HEADER_TABLE_SIZE) { - /* Keep track of minimum value of SETTINGS_HEADER_TABLE_SIZE */ - min_header_table_size_entry = &iframe->iv[iframe->max_niv - 1]; - - if (iv.value < min_header_table_size_entry->value) { - min_header_table_size_entry->value = iv.value; - } - } -} - -/* - * Checks PADDED flags and set iframe->sbuf to read them accordingly. - * If padding is set, this function returns 1. If no padding is set, - * this function returns 0. On error, returns -1. - */ -static int inbound_frame_handle_pad(nghttp2_inbound_frame *iframe, - nghttp2_frame_hd *hd) { - if (hd->flags & NGHTTP2_FLAG_PADDED) { - if (hd->length < 1) { - return -1; - } - inbound_frame_set_mark(iframe, 1); - return 1; - } - DEBUGF("recv: no padding in payload\n"); - return 0; -} - -/* - * Computes number of padding based on flags. This function returns - * the calculated length if it succeeds, or -1. - */ -static nghttp2_ssize inbound_frame_compute_pad(nghttp2_inbound_frame *iframe) { - size_t padlen; - - /* 1 for Pad Length field */ - padlen = (size_t)(iframe->sbuf.pos[0] + 1); - - DEBUGF("recv: padlen=%zu\n", padlen); - - /* We cannot use iframe->frame.hd.length because of CONTINUATION */ - if (padlen - 1 > iframe->payloadleft) { - return -1; - } - - iframe->padlen = padlen; - - return (nghttp2_ssize)padlen; -} - -/* - * This function returns the effective payload length in the data of - * length |readlen| when the remaining payload is |payloadleft|. The - * |payloadleft| does not include |readlen|. If padding was started - * strictly before this data chunk, this function returns -1. - */ -static nghttp2_ssize -inbound_frame_effective_readlen(nghttp2_inbound_frame *iframe, - size_t payloadleft, size_t readlen) { - size_t trail_padlen = - nghttp2_frame_trail_padlen(&iframe->frame, iframe->padlen); - - if (trail_padlen > payloadleft) { - size_t padlen; - padlen = trail_padlen - payloadleft; - if (readlen < padlen) { - return -1; - } - return (nghttp2_ssize)(readlen - padlen); - } - return (nghttp2_ssize)(readlen); -} - -static const uint8_t static_in[] = {0}; - -ssize_t nghttp2_session_mem_recv(nghttp2_session *session, const uint8_t *in, - size_t inlen) { - return (ssize_t)nghttp2_session_mem_recv2(session, in, inlen); -} - -nghttp2_ssize nghttp2_session_mem_recv2(nghttp2_session *session, - const uint8_t *in, size_t inlen) { - const uint8_t *first, *last; - nghttp2_inbound_frame *iframe = &session->iframe; - size_t readlen; - nghttp2_ssize padlen; - int rv; - int busy = 0; - nghttp2_frame_hd cont_hd; - nghttp2_stream *stream; - size_t pri_fieldlen; - nghttp2_mem *mem; - - if (in == NULL) { - assert(inlen == 0); - in = static_in; - } - - first = in; - last = in + inlen; - - DEBUGF("recv: connection recv_window_size=%d, local_window=%d\n", - session->recv_window_size, session->local_window_size); - - mem = &session->mem; - - /* We may have idle streams more than we expect (e.g., - nghttp2_session_change_stream_priority() or - nghttp2_session_create_idle_stream()). Adjust them here. */ - rv = nghttp2_session_adjust_idle_stream(session); - if (nghttp2_is_fatal(rv)) { - return rv; - } - - if (!nghttp2_session_want_read(session)) { - return (nghttp2_ssize)inlen; - } - - for (;;) { - switch (iframe->state) { - case NGHTTP2_IB_READ_CLIENT_MAGIC: - readlen = nghttp2_min_size(inlen, iframe->payloadleft); - - if (memcmp(&NGHTTP2_CLIENT_MAGIC[NGHTTP2_CLIENT_MAGIC_LEN - - iframe->payloadleft], - in, readlen) != 0) { - return NGHTTP2_ERR_BAD_CLIENT_MAGIC; - } - - iframe->payloadleft -= readlen; - in += readlen; - - if (iframe->payloadleft == 0) { - session_inbound_frame_reset(session); - iframe->state = NGHTTP2_IB_READ_FIRST_SETTINGS; - } - - break; - case NGHTTP2_IB_READ_FIRST_SETTINGS: - DEBUGF("recv: [IB_READ_FIRST_SETTINGS]\n"); - - readlen = inbound_frame_buf_read(iframe, in, last); - in += readlen; - - if (nghttp2_buf_mark_avail(&iframe->sbuf)) { - return (nghttp2_ssize)(in - first); - } - - if (iframe->sbuf.pos[3] != NGHTTP2_SETTINGS || - (iframe->sbuf.pos[4] & NGHTTP2_FLAG_ACK)) { - rv = session_call_error_callback( - session, NGHTTP2_ERR_SETTINGS_EXPECTED, - "Remote peer returned unexpected data while we expected " - "SETTINGS frame. Perhaps, peer does not support HTTP/2 " - "properly."); - - if (nghttp2_is_fatal(rv)) { - return rv; - } - - rv = nghttp2_session_terminate_session_with_reason( - session, NGHTTP2_PROTOCOL_ERROR, "SETTINGS expected"); - - if (nghttp2_is_fatal(rv)) { - return rv; - } - - return (nghttp2_ssize)inlen; - } - - iframe->state = NGHTTP2_IB_READ_HEAD; - - /* Fall through */ - case NGHTTP2_IB_READ_HEAD: { - int on_begin_frame_called = 0; - - DEBUGF("recv: [IB_READ_HEAD]\n"); - - readlen = inbound_frame_buf_read(iframe, in, last); - in += readlen; - - if (nghttp2_buf_mark_avail(&iframe->sbuf)) { - return (nghttp2_ssize)(in - first); - } - - nghttp2_frame_unpack_frame_hd(&iframe->frame.hd, iframe->sbuf.pos); - iframe->payloadleft = iframe->frame.hd.length; - - DEBUGF("recv: payloadlen=%zu, type=%u, flags=0x%02x, stream_id=%d\n", - iframe->frame.hd.length, iframe->frame.hd.type, - iframe->frame.hd.flags, iframe->frame.hd.stream_id); - - if (iframe->frame.hd.length > session->local_settings.max_frame_size) { - DEBUGF("recv: length is too large %zu > %u\n", iframe->frame.hd.length, - session->local_settings.max_frame_size); - - rv = nghttp2_session_terminate_session_with_reason( - session, NGHTTP2_FRAME_SIZE_ERROR, "too large frame size"); - - if (nghttp2_is_fatal(rv)) { - return rv; - } - - return (nghttp2_ssize)inlen; - } - - switch (iframe->frame.hd.type) { - case NGHTTP2_DATA: { - DEBUGF("recv: DATA\n"); - - iframe->frame.hd.flags &= - (NGHTTP2_FLAG_END_STREAM | NGHTTP2_FLAG_PADDED); - /* Check stream is open. If it is not open or closing, - ignore payload. */ - busy = 1; - - rv = session_on_data_received_fail_fast(session); - if (iframe->state == NGHTTP2_IB_IGN_ALL) { - return (nghttp2_ssize)inlen; - } - if (rv == NGHTTP2_ERR_IGN_PAYLOAD) { - DEBUGF("recv: DATA not allowed stream_id=%d\n", - iframe->frame.hd.stream_id); - iframe->state = NGHTTP2_IB_IGN_DATA; - break; - } - - if (nghttp2_is_fatal(rv)) { - return rv; - } - - rv = inbound_frame_handle_pad(iframe, &iframe->frame.hd); - if (rv < 0) { - rv = nghttp2_session_terminate_session_with_reason( - session, NGHTTP2_PROTOCOL_ERROR, - "DATA: insufficient padding space"); - - if (nghttp2_is_fatal(rv)) { - return rv; - } - return (nghttp2_ssize)inlen; - } - - if (rv == 1) { - iframe->state = NGHTTP2_IB_READ_PAD_DATA; - break; - } - - iframe->state = NGHTTP2_IB_READ_DATA; - break; - } - case NGHTTP2_HEADERS: - - DEBUGF("recv: HEADERS\n"); - - iframe->frame.hd.flags &= - (NGHTTP2_FLAG_END_STREAM | NGHTTP2_FLAG_END_HEADERS | - NGHTTP2_FLAG_PADDED | NGHTTP2_FLAG_PRIORITY); - - rv = inbound_frame_handle_pad(iframe, &iframe->frame.hd); - if (rv < 0) { - rv = nghttp2_session_terminate_session_with_reason( - session, NGHTTP2_PROTOCOL_ERROR, - "HEADERS: insufficient padding space"); - if (nghttp2_is_fatal(rv)) { - return rv; - } - return (nghttp2_ssize)inlen; - } - - if (rv == 1) { - iframe->state = NGHTTP2_IB_READ_NBYTE; - break; - } - - pri_fieldlen = nghttp2_frame_priority_len(iframe->frame.hd.flags); - - if (pri_fieldlen > 0) { - if (iframe->payloadleft < pri_fieldlen) { - busy = 1; - iframe->state = NGHTTP2_IB_FRAME_SIZE_ERROR; - break; - } - - iframe->state = NGHTTP2_IB_READ_NBYTE; - - inbound_frame_set_mark(iframe, pri_fieldlen); - - break; - } - - /* Call on_begin_frame_callback here because - session_process_headers_frame() may call - on_begin_headers_callback */ - rv = session_call_on_begin_frame(session, &iframe->frame.hd); - - if (nghttp2_is_fatal(rv)) { - return rv; - } - - on_begin_frame_called = 1; - - rv = session_process_headers_frame(session); - if (nghttp2_is_fatal(rv)) { - return rv; - } - - busy = 1; - - if (iframe->state == NGHTTP2_IB_IGN_ALL) { - return (nghttp2_ssize)inlen; - } - - if (rv == NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE) { - rv = nghttp2_session_add_rst_stream( - session, iframe->frame.hd.stream_id, NGHTTP2_INTERNAL_ERROR); - if (nghttp2_is_fatal(rv)) { - return rv; - } - iframe->state = NGHTTP2_IB_IGN_HEADER_BLOCK; - break; - } - - if (rv == NGHTTP2_ERR_IGN_HEADER_BLOCK) { - iframe->state = NGHTTP2_IB_IGN_HEADER_BLOCK; - break; - } - - iframe->state = NGHTTP2_IB_READ_HEADER_BLOCK; - - break; - case NGHTTP2_PRIORITY: - DEBUGF("recv: PRIORITY\n"); - - iframe->frame.hd.flags = NGHTTP2_FLAG_NONE; - - if (iframe->payloadleft != NGHTTP2_PRIORITY_SPECLEN) { - busy = 1; - - iframe->state = NGHTTP2_IB_FRAME_SIZE_ERROR; - - break; - } - - iframe->state = NGHTTP2_IB_READ_NBYTE; - - inbound_frame_set_mark(iframe, NGHTTP2_PRIORITY_SPECLEN); - - break; - case NGHTTP2_RST_STREAM: - case NGHTTP2_WINDOW_UPDATE: -#ifdef DEBUGBUILD - switch (iframe->frame.hd.type) { - case NGHTTP2_RST_STREAM: - DEBUGF("recv: RST_STREAM\n"); - break; - case NGHTTP2_WINDOW_UPDATE: - DEBUGF("recv: WINDOW_UPDATE\n"); - break; - } -#endif /* DEBUGBUILD */ - - iframe->frame.hd.flags = NGHTTP2_FLAG_NONE; - - if (iframe->payloadleft != 4) { - busy = 1; - iframe->state = NGHTTP2_IB_FRAME_SIZE_ERROR; - break; - } - - iframe->state = NGHTTP2_IB_READ_NBYTE; - - inbound_frame_set_mark(iframe, 4); - - break; - case NGHTTP2_SETTINGS: - DEBUGF("recv: SETTINGS\n"); - - iframe->frame.hd.flags &= NGHTTP2_FLAG_ACK; - - if ((iframe->frame.hd.length % NGHTTP2_FRAME_SETTINGS_ENTRY_LENGTH) || - ((iframe->frame.hd.flags & NGHTTP2_FLAG_ACK) && - iframe->payloadleft > 0)) { - busy = 1; - iframe->state = NGHTTP2_IB_FRAME_SIZE_ERROR; - break; - } - - /* Check the settings flood counter early to be safe */ - if (session->obq_flood_counter_ >= session->max_outbound_ack && - !(iframe->frame.hd.flags & NGHTTP2_FLAG_ACK)) { - return NGHTTP2_ERR_FLOODED; - } - - iframe->state = NGHTTP2_IB_READ_SETTINGS; - - if (iframe->payloadleft) { - nghttp2_settings_entry *min_header_table_size_entry; - - /* We allocate iv with additional one entry, to store the - minimum header table size. */ - iframe->max_niv = - iframe->frame.hd.length / NGHTTP2_FRAME_SETTINGS_ENTRY_LENGTH + 1; - - if (iframe->max_niv - 1 > session->max_settings) { - rv = nghttp2_session_terminate_session_with_reason( - session, NGHTTP2_ENHANCE_YOUR_CALM, - "SETTINGS: too many setting entries"); - if (nghttp2_is_fatal(rv)) { - return rv; - } - return (nghttp2_ssize)inlen; - } - - iframe->iv = nghttp2_mem_malloc(mem, sizeof(nghttp2_settings_entry) * - iframe->max_niv); - - if (!iframe->iv) { - return NGHTTP2_ERR_NOMEM; - } - - min_header_table_size_entry = &iframe->iv[iframe->max_niv - 1]; - min_header_table_size_entry->settings_id = - NGHTTP2_SETTINGS_HEADER_TABLE_SIZE; - min_header_table_size_entry->value = UINT32_MAX; - - inbound_frame_set_mark(iframe, NGHTTP2_FRAME_SETTINGS_ENTRY_LENGTH); - break; - } - - busy = 1; - - inbound_frame_set_mark(iframe, 0); - - break; - case NGHTTP2_PUSH_PROMISE: - DEBUGF("recv: PUSH_PROMISE\n"); - - iframe->frame.hd.flags &= - (NGHTTP2_FLAG_END_HEADERS | NGHTTP2_FLAG_PADDED); - - rv = inbound_frame_handle_pad(iframe, &iframe->frame.hd); - if (rv < 0) { - rv = nghttp2_session_terminate_session_with_reason( - session, NGHTTP2_PROTOCOL_ERROR, - "PUSH_PROMISE: insufficient padding space"); - if (nghttp2_is_fatal(rv)) { - return rv; - } - return (nghttp2_ssize)inlen; - } - - if (rv == 1) { - iframe->state = NGHTTP2_IB_READ_NBYTE; - break; - } - - if (iframe->payloadleft < 4) { - busy = 1; - iframe->state = NGHTTP2_IB_FRAME_SIZE_ERROR; - break; - } - - iframe->state = NGHTTP2_IB_READ_NBYTE; - - inbound_frame_set_mark(iframe, 4); - - break; - case NGHTTP2_PING: - DEBUGF("recv: PING\n"); - - iframe->frame.hd.flags &= NGHTTP2_FLAG_ACK; - - if (iframe->payloadleft != 8) { - busy = 1; - iframe->state = NGHTTP2_IB_FRAME_SIZE_ERROR; - break; - } - - iframe->state = NGHTTP2_IB_READ_NBYTE; - inbound_frame_set_mark(iframe, 8); - - break; - case NGHTTP2_GOAWAY: - DEBUGF("recv: GOAWAY\n"); - - iframe->frame.hd.flags = NGHTTP2_FLAG_NONE; - - if (iframe->payloadleft < 8) { - busy = 1; - iframe->state = NGHTTP2_IB_FRAME_SIZE_ERROR; - break; - } - - iframe->state = NGHTTP2_IB_READ_NBYTE; - inbound_frame_set_mark(iframe, 8); - - break; - case NGHTTP2_CONTINUATION: - DEBUGF("recv: unexpected CONTINUATION\n"); - - /* Receiving CONTINUATION in this state are subject to - connection error of type PROTOCOL_ERROR */ - rv = nghttp2_session_terminate_session_with_reason( - session, NGHTTP2_PROTOCOL_ERROR, "CONTINUATION: unexpected"); - if (nghttp2_is_fatal(rv)) { - return rv; - } - - return (nghttp2_ssize)inlen; - default: - DEBUGF("recv: extension frame\n"); - - if (check_ext_type_set(session->user_recv_ext_types, - iframe->frame.hd.type)) { - if (!session->callbacks.unpack_extension_callback) { - /* Silently ignore unknown frame type. */ - - busy = 1; - - iframe->state = NGHTTP2_IB_IGN_PAYLOAD; - - break; - } - - busy = 1; - - iframe->state = NGHTTP2_IB_READ_EXTENSION_PAYLOAD; - - break; - } else { - switch (iframe->frame.hd.type) { - case NGHTTP2_ALTSVC: - if ((session->builtin_recv_ext_types & NGHTTP2_TYPEMASK_ALTSVC) == - 0) { - busy = 1; - iframe->state = NGHTTP2_IB_IGN_PAYLOAD; - break; - } - - DEBUGF("recv: ALTSVC\n"); - - iframe->frame.hd.flags = NGHTTP2_FLAG_NONE; - iframe->frame.ext.payload = &iframe->ext_frame_payload.altsvc; - - if (session->server) { - busy = 1; - iframe->state = NGHTTP2_IB_IGN_PAYLOAD; - break; - } - - if (iframe->payloadleft < 2) { - busy = 1; - iframe->state = NGHTTP2_IB_FRAME_SIZE_ERROR; - break; - } - - busy = 1; - - iframe->state = NGHTTP2_IB_READ_NBYTE; - inbound_frame_set_mark(iframe, 2); - - break; - case NGHTTP2_ORIGIN: - if (!(session->builtin_recv_ext_types & NGHTTP2_TYPEMASK_ORIGIN)) { - busy = 1; - iframe->state = NGHTTP2_IB_IGN_PAYLOAD; - break; - } - - DEBUGF("recv: ORIGIN\n"); - - iframe->frame.ext.payload = &iframe->ext_frame_payload.origin; - - if (session->server || iframe->frame.hd.stream_id || - (iframe->frame.hd.flags & 0xf0)) { - busy = 1; - iframe->state = NGHTTP2_IB_IGN_PAYLOAD; - break; - } - - iframe->frame.hd.flags = NGHTTP2_FLAG_NONE; - - if (iframe->payloadleft) { - iframe->raw_lbuf = nghttp2_mem_malloc(mem, iframe->payloadleft); - - if (iframe->raw_lbuf == NULL) { - return NGHTTP2_ERR_NOMEM; - } - - nghttp2_buf_wrap_init(&iframe->lbuf, iframe->raw_lbuf, - iframe->payloadleft); - } else { - busy = 1; - } - - iframe->state = NGHTTP2_IB_READ_ORIGIN_PAYLOAD; - - break; - case NGHTTP2_PRIORITY_UPDATE: - if ((session->builtin_recv_ext_types & - NGHTTP2_TYPEMASK_PRIORITY_UPDATE) == 0) { - busy = 1; - iframe->state = NGHTTP2_IB_IGN_PAYLOAD; - break; - } - - DEBUGF("recv: PRIORITY_UPDATE\n"); - - iframe->frame.hd.flags = NGHTTP2_FLAG_NONE; - iframe->frame.ext.payload = - &iframe->ext_frame_payload.priority_update; - - if (!session->server) { - rv = nghttp2_session_terminate_session_with_reason( - session, NGHTTP2_PROTOCOL_ERROR, - "PRIORITY_UPDATE is received from server"); - if (nghttp2_is_fatal(rv)) { - return rv; - } - return (nghttp2_ssize)inlen; - } - - if (iframe->payloadleft < 4) { - busy = 1; - iframe->state = NGHTTP2_IB_FRAME_SIZE_ERROR; - break; - } - - if (!session_no_rfc7540_pri_no_fallback(session) || - iframe->payloadleft > sizeof(iframe->raw_sbuf)) { - busy = 1; - iframe->state = NGHTTP2_IB_IGN_PAYLOAD; - break; - } - - busy = 1; - - iframe->state = NGHTTP2_IB_READ_NBYTE; - inbound_frame_set_mark(iframe, iframe->payloadleft); - - break; - default: - busy = 1; - - iframe->state = NGHTTP2_IB_IGN_PAYLOAD; - - break; - } - } - } - - if (!on_begin_frame_called) { - switch (iframe->state) { - case NGHTTP2_IB_IGN_HEADER_BLOCK: - case NGHTTP2_IB_IGN_PAYLOAD: - case NGHTTP2_IB_FRAME_SIZE_ERROR: - case NGHTTP2_IB_IGN_DATA: - case NGHTTP2_IB_IGN_ALL: - break; - default: - rv = session_call_on_begin_frame(session, &iframe->frame.hd); - - if (nghttp2_is_fatal(rv)) { - return rv; - } - } - } - - break; - } - case NGHTTP2_IB_READ_NBYTE: - DEBUGF("recv: [IB_READ_NBYTE]\n"); - - readlen = inbound_frame_buf_read(iframe, in, last); - in += readlen; - iframe->payloadleft -= readlen; - - DEBUGF("recv: readlen=%zu, payloadleft=%zu, left=%zu\n", readlen, - iframe->payloadleft, nghttp2_buf_mark_avail(&iframe->sbuf)); - - if (nghttp2_buf_mark_avail(&iframe->sbuf)) { - return (nghttp2_ssize)(in - first); - } - - switch (iframe->frame.hd.type) { - case NGHTTP2_HEADERS: - if (iframe->padlen == 0 && - (iframe->frame.hd.flags & NGHTTP2_FLAG_PADDED)) { - pri_fieldlen = nghttp2_frame_priority_len(iframe->frame.hd.flags); - padlen = inbound_frame_compute_pad(iframe); - if (padlen < 0 || - (size_t)padlen + pri_fieldlen > 1 + iframe->payloadleft) { - rv = nghttp2_session_terminate_session_with_reason( - session, NGHTTP2_PROTOCOL_ERROR, "HEADERS: invalid padding"); - if (nghttp2_is_fatal(rv)) { - return rv; - } - return (nghttp2_ssize)inlen; - } - iframe->frame.headers.padlen = (size_t)padlen; - - if (pri_fieldlen > 0) { - if (iframe->payloadleft < pri_fieldlen) { - busy = 1; - iframe->state = NGHTTP2_IB_FRAME_SIZE_ERROR; - break; - } - iframe->state = NGHTTP2_IB_READ_NBYTE; - inbound_frame_set_mark(iframe, pri_fieldlen); - break; - } else { - /* Truncate buffers used for padding spec */ - inbound_frame_set_mark(iframe, 0); - } - } - - rv = session_process_headers_frame(session); - if (nghttp2_is_fatal(rv)) { - return rv; - } - - busy = 1; - - if (iframe->state == NGHTTP2_IB_IGN_ALL) { - return (nghttp2_ssize)inlen; - } - - if (rv == NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE) { - rv = nghttp2_session_add_rst_stream( - session, iframe->frame.hd.stream_id, NGHTTP2_INTERNAL_ERROR); - if (nghttp2_is_fatal(rv)) { - return rv; - } - iframe->state = NGHTTP2_IB_IGN_HEADER_BLOCK; - break; - } - - if (rv == NGHTTP2_ERR_IGN_HEADER_BLOCK) { - iframe->state = NGHTTP2_IB_IGN_HEADER_BLOCK; - break; - } - - iframe->state = NGHTTP2_IB_READ_HEADER_BLOCK; - - break; - case NGHTTP2_PRIORITY: - if (!session_no_rfc7540_pri_no_fallback(session) && - session->remote_settings.no_rfc7540_priorities != 1) { - rv = session_process_priority_frame(session); - if (nghttp2_is_fatal(rv)) { - return rv; - } - - if (iframe->state == NGHTTP2_IB_IGN_ALL) { - return (nghttp2_ssize)inlen; - } - } - - session_inbound_frame_reset(session); - - break; - case NGHTTP2_RST_STREAM: - rv = session_process_rst_stream_frame(session); - if (nghttp2_is_fatal(rv)) { - return rv; - } - - if (iframe->state == NGHTTP2_IB_IGN_ALL) { - return (nghttp2_ssize)inlen; - } - - session_inbound_frame_reset(session); - - break; - case NGHTTP2_PUSH_PROMISE: - if (iframe->padlen == 0 && - (iframe->frame.hd.flags & NGHTTP2_FLAG_PADDED)) { - padlen = inbound_frame_compute_pad(iframe); - if (padlen < 0 || (size_t)padlen + 4 /* promised stream id */ - > 1 + iframe->payloadleft) { - rv = nghttp2_session_terminate_session_with_reason( - session, NGHTTP2_PROTOCOL_ERROR, "PUSH_PROMISE: invalid padding"); - if (nghttp2_is_fatal(rv)) { - return rv; - } - return (nghttp2_ssize)inlen; - } - - iframe->frame.push_promise.padlen = (size_t)padlen; - - if (iframe->payloadleft < 4) { - busy = 1; - iframe->state = NGHTTP2_IB_FRAME_SIZE_ERROR; - break; - } - - iframe->state = NGHTTP2_IB_READ_NBYTE; - - inbound_frame_set_mark(iframe, 4); - - break; - } - - rv = session_process_push_promise_frame(session); - if (nghttp2_is_fatal(rv)) { - return rv; - } - - busy = 1; - - if (iframe->state == NGHTTP2_IB_IGN_ALL) { - return (nghttp2_ssize)inlen; - } - - if (rv == NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE) { - rv = nghttp2_session_add_rst_stream( - session, iframe->frame.push_promise.promised_stream_id, - NGHTTP2_INTERNAL_ERROR); - if (nghttp2_is_fatal(rv)) { - return rv; - } - iframe->state = NGHTTP2_IB_IGN_HEADER_BLOCK; - break; - } - - if (rv == NGHTTP2_ERR_IGN_HEADER_BLOCK) { - iframe->state = NGHTTP2_IB_IGN_HEADER_BLOCK; - break; - } - - iframe->state = NGHTTP2_IB_READ_HEADER_BLOCK; - - break; - case NGHTTP2_PING: - rv = session_process_ping_frame(session); - if (nghttp2_is_fatal(rv)) { - return rv; - } - - if (iframe->state == NGHTTP2_IB_IGN_ALL) { - return (nghttp2_ssize)inlen; - } - - session_inbound_frame_reset(session); - - break; - case NGHTTP2_GOAWAY: { - size_t debuglen; - - /* 8 is Last-stream-ID + Error Code */ - debuglen = iframe->frame.hd.length - 8; - - if (debuglen > 0) { - iframe->raw_lbuf = nghttp2_mem_malloc(mem, debuglen); - - if (iframe->raw_lbuf == NULL) { - return NGHTTP2_ERR_NOMEM; - } - - nghttp2_buf_wrap_init(&iframe->lbuf, iframe->raw_lbuf, debuglen); - } - - busy = 1; - - iframe->state = NGHTTP2_IB_READ_GOAWAY_DEBUG; - - break; - } - case NGHTTP2_WINDOW_UPDATE: - rv = session_process_window_update_frame(session); - if (nghttp2_is_fatal(rv)) { - return rv; - } - - if (iframe->state == NGHTTP2_IB_IGN_ALL) { - return (nghttp2_ssize)inlen; - } - - session_inbound_frame_reset(session); - - break; - case NGHTTP2_ALTSVC: { - size_t origin_len; - - origin_len = nghttp2_get_uint16(iframe->sbuf.pos); - - DEBUGF("recv: origin_len=%zu\n", origin_len); - - if (origin_len > iframe->payloadleft) { - busy = 1; - iframe->state = NGHTTP2_IB_FRAME_SIZE_ERROR; - break; - } - - if (iframe->frame.hd.length > 2) { - iframe->raw_lbuf = - nghttp2_mem_malloc(mem, iframe->frame.hd.length - 2); - - if (iframe->raw_lbuf == NULL) { - return NGHTTP2_ERR_NOMEM; - } - - nghttp2_buf_wrap_init(&iframe->lbuf, iframe->raw_lbuf, - iframe->frame.hd.length); - } - - busy = 1; - - iframe->state = NGHTTP2_IB_READ_ALTSVC_PAYLOAD; - - break; - case NGHTTP2_PRIORITY_UPDATE: - DEBUGF("recv: prioritized_stream_id=%d\n", - nghttp2_get_uint32(iframe->sbuf.pos) & NGHTTP2_STREAM_ID_MASK); - - rv = session_process_priority_update_frame(session); - if (nghttp2_is_fatal(rv)) { - return rv; - } - - session_inbound_frame_reset(session); - - break; - } - default: - /* This is unknown frame */ - session_inbound_frame_reset(session); - - break; - } - break; - case NGHTTP2_IB_READ_HEADER_BLOCK: - case NGHTTP2_IB_IGN_HEADER_BLOCK: { - nghttp2_ssize data_readlen; - size_t trail_padlen; - int final; -#ifdef DEBUGBUILD - if (iframe->state == NGHTTP2_IB_READ_HEADER_BLOCK) { - DEBUGF("recv: [IB_READ_HEADER_BLOCK]\n"); - } else { - DEBUGF("recv: [IB_IGN_HEADER_BLOCK]\n"); - } -#endif /* DEBUGBUILD */ - - readlen = inbound_frame_payload_readlen(iframe, in, last); - - DEBUGF("recv: readlen=%zu, payloadleft=%zu\n", readlen, - iframe->payloadleft - readlen); - - data_readlen = inbound_frame_effective_readlen( - iframe, iframe->payloadleft - readlen, readlen); - - if (data_readlen == -1) { - /* everything is padding */ - data_readlen = 0; - } - - trail_padlen = nghttp2_frame_trail_padlen(&iframe->frame, iframe->padlen); - - final = (iframe->frame.hd.flags & NGHTTP2_FLAG_END_HEADERS) && - iframe->payloadleft - (size_t)data_readlen == trail_padlen; - - if (data_readlen > 0 || (data_readlen == 0 && final)) { - size_t hd_proclen = 0; - - DEBUGF("recv: block final=%d\n", final); - - rv = - inflate_header_block(session, &iframe->frame, &hd_proclen, - (uint8_t *)in, (size_t)data_readlen, final, - iframe->state == NGHTTP2_IB_READ_HEADER_BLOCK); - - if (nghttp2_is_fatal(rv)) { - return rv; - } - - if (iframe->state == NGHTTP2_IB_IGN_ALL) { - return (nghttp2_ssize)inlen; - } - - if (rv == NGHTTP2_ERR_PAUSE) { - in += hd_proclen; - iframe->payloadleft -= hd_proclen; - - return (nghttp2_ssize)(in - first); - } - - if (rv == NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE) { - /* The application says no more headers. We decompress the - rest of the header block but not invoke on_header_callback - and on_frame_recv_callback. */ - in += hd_proclen; - iframe->payloadleft -= hd_proclen; - - /* Use promised stream ID for PUSH_PROMISE */ - rv = nghttp2_session_add_rst_stream( - session, - iframe->frame.hd.type == NGHTTP2_PUSH_PROMISE - ? iframe->frame.push_promise.promised_stream_id - : iframe->frame.hd.stream_id, - NGHTTP2_INTERNAL_ERROR); - if (nghttp2_is_fatal(rv)) { - return rv; - } - busy = 1; - iframe->state = NGHTTP2_IB_IGN_HEADER_BLOCK; - break; - } - - in += readlen; - iframe->payloadleft -= readlen; - - if (rv == NGHTTP2_ERR_HEADER_COMP) { - /* GOAWAY is already issued */ - if (iframe->payloadleft == 0) { - session_inbound_frame_reset(session); - } else { - busy = 1; - iframe->state = NGHTTP2_IB_IGN_PAYLOAD; - } - break; - } - } else { - in += readlen; - iframe->payloadleft -= readlen; - } - - if (iframe->payloadleft) { - break; - } - - if ((iframe->frame.hd.flags & NGHTTP2_FLAG_END_HEADERS) == 0) { - inbound_frame_set_mark(iframe, NGHTTP2_FRAME_HDLEN); - - iframe->padlen = 0; - - if (iframe->state == NGHTTP2_IB_READ_HEADER_BLOCK) { - iframe->state = NGHTTP2_IB_EXPECT_CONTINUATION; - } else { - iframe->state = NGHTTP2_IB_IGN_CONTINUATION; - } - } else { - if (iframe->state == NGHTTP2_IB_READ_HEADER_BLOCK) { - rv = session_after_header_block_received(session); - if (nghttp2_is_fatal(rv)) { - return rv; - } - } - session_inbound_frame_reset(session); - - session->num_continuations = 0; - } - break; - } - case NGHTTP2_IB_IGN_PAYLOAD: - DEBUGF("recv: [IB_IGN_PAYLOAD]\n"); - - readlen = inbound_frame_payload_readlen(iframe, in, last); - iframe->payloadleft -= readlen; - in += readlen; - - DEBUGF("recv: readlen=%zu, payloadleft=%zu\n", readlen, - iframe->payloadleft); - - if (iframe->payloadleft) { - break; - } - - switch (iframe->frame.hd.type) { - case NGHTTP2_HEADERS: - case NGHTTP2_PUSH_PROMISE: - case NGHTTP2_CONTINUATION: - /* Mark inflater bad so that we won't perform further decoding */ - session->hd_inflater.ctx.bad = 1; - break; - default: - break; - } - - session_inbound_frame_reset(session); - - break; - case NGHTTP2_IB_FRAME_SIZE_ERROR: - DEBUGF("recv: [IB_FRAME_SIZE_ERROR]\n"); - - rv = session_handle_frame_size_error(session); - if (nghttp2_is_fatal(rv)) { - return rv; - } - - assert(iframe->state == NGHTTP2_IB_IGN_ALL); - - return (nghttp2_ssize)inlen; - case NGHTTP2_IB_READ_SETTINGS: - DEBUGF("recv: [IB_READ_SETTINGS]\n"); - - readlen = inbound_frame_buf_read(iframe, in, last); - iframe->payloadleft -= readlen; - in += readlen; - - DEBUGF("recv: readlen=%zu, payloadleft=%zu\n", readlen, - iframe->payloadleft); - - if (nghttp2_buf_mark_avail(&iframe->sbuf)) { - break; - } - - if (readlen > 0) { - inbound_frame_set_settings_entry(iframe); - } - if (iframe->payloadleft) { - inbound_frame_set_mark(iframe, NGHTTP2_FRAME_SETTINGS_ENTRY_LENGTH); - break; - } - - rv = session_process_settings_frame(session); - - if (nghttp2_is_fatal(rv)) { - return rv; - } - - if (iframe->state == NGHTTP2_IB_IGN_ALL) { - return (nghttp2_ssize)inlen; - } - - session_inbound_frame_reset(session); - - break; - case NGHTTP2_IB_READ_GOAWAY_DEBUG: - DEBUGF("recv: [IB_READ_GOAWAY_DEBUG]\n"); - - readlen = inbound_frame_payload_readlen(iframe, in, last); - - if (readlen > 0) { - iframe->lbuf.last = nghttp2_cpymem(iframe->lbuf.last, in, readlen); - - iframe->payloadleft -= readlen; - in += readlen; - } - - DEBUGF("recv: readlen=%zu, payloadleft=%zu\n", readlen, - iframe->payloadleft); - - if (iframe->payloadleft) { - assert(nghttp2_buf_avail(&iframe->lbuf) > 0); - - break; - } - - rv = session_process_goaway_frame(session); - - if (nghttp2_is_fatal(rv)) { - return rv; - } - - if (iframe->state == NGHTTP2_IB_IGN_ALL) { - return (nghttp2_ssize)inlen; - } - - session_inbound_frame_reset(session); - - break; - case NGHTTP2_IB_EXPECT_CONTINUATION: - case NGHTTP2_IB_IGN_CONTINUATION: -#ifdef DEBUGBUILD - if (iframe->state == NGHTTP2_IB_EXPECT_CONTINUATION) { - fprintf(stderr, "recv: [IB_EXPECT_CONTINUATION]\n"); - } else { - fprintf(stderr, "recv: [IB_IGN_CONTINUATION]\n"); - } -#endif /* DEBUGBUILD */ - - if (++session->num_continuations > session->max_continuations) { - return NGHTTP2_ERR_TOO_MANY_CONTINUATIONS; - } - - readlen = inbound_frame_buf_read(iframe, in, last); - in += readlen; - - if (nghttp2_buf_mark_avail(&iframe->sbuf)) { - return (nghttp2_ssize)(in - first); - } - - nghttp2_frame_unpack_frame_hd(&cont_hd, iframe->sbuf.pos); - iframe->payloadleft = cont_hd.length; - - DEBUGF("recv: payloadlen=%zu, type=%u, flags=0x%02x, stream_id=%d\n", - cont_hd.length, cont_hd.type, cont_hd.flags, cont_hd.stream_id); - - if (cont_hd.type != NGHTTP2_CONTINUATION || - cont_hd.stream_id != iframe->frame.hd.stream_id) { - DEBUGF("recv: expected stream_id=%d, type=%d, but got stream_id=%d, " - "type=%u\n", - iframe->frame.hd.stream_id, NGHTTP2_CONTINUATION, - cont_hd.stream_id, cont_hd.type); - rv = nghttp2_session_terminate_session_with_reason( - session, NGHTTP2_PROTOCOL_ERROR, - "unexpected non-CONTINUATION frame or stream_id is invalid"); - if (nghttp2_is_fatal(rv)) { - return rv; - } - - return (nghttp2_ssize)inlen; - } - - /* CONTINUATION won't bear NGHTTP2_PADDED flag */ - - iframe->frame.hd.flags = - (uint8_t)(iframe->frame.hd.flags | - (cont_hd.flags & NGHTTP2_FLAG_END_HEADERS)); - iframe->frame.hd.length += cont_hd.length; - - busy = 1; - - if (iframe->state == NGHTTP2_IB_EXPECT_CONTINUATION) { - iframe->state = NGHTTP2_IB_READ_HEADER_BLOCK; - - rv = session_call_on_begin_frame(session, &cont_hd); - - if (nghttp2_is_fatal(rv)) { - return rv; - } - } else { - iframe->state = NGHTTP2_IB_IGN_HEADER_BLOCK; - } - - break; - case NGHTTP2_IB_READ_PAD_DATA: - DEBUGF("recv: [IB_READ_PAD_DATA]\n"); - - readlen = inbound_frame_buf_read(iframe, in, last); - in += readlen; - iframe->payloadleft -= readlen; - - DEBUGF("recv: readlen=%zu, payloadleft=%zu, left=%zu\n", readlen, - iframe->payloadleft, nghttp2_buf_mark_avail(&iframe->sbuf)); - - if (nghttp2_buf_mark_avail(&iframe->sbuf)) { - return (nghttp2_ssize)(in - first); - } - - /* Pad Length field is subject to flow control */ - rv = nghttp2_session_update_recv_connection_window_size(session, readlen); - if (nghttp2_is_fatal(rv)) { - return rv; - } - - if (iframe->state == NGHTTP2_IB_IGN_ALL) { - return (nghttp2_ssize)inlen; - } - - /* Pad Length field is consumed immediately */ - rv = - nghttp2_session_consume(session, iframe->frame.hd.stream_id, readlen); - - if (nghttp2_is_fatal(rv)) { - return rv; - } - - if (iframe->state == NGHTTP2_IB_IGN_ALL) { - return (nghttp2_ssize)inlen; - } - - stream = nghttp2_session_get_stream(session, iframe->frame.hd.stream_id); - if (stream) { - rv = nghttp2_session_update_recv_stream_window_size( - session, stream, readlen, - iframe->payloadleft || - (iframe->frame.hd.flags & NGHTTP2_FLAG_END_STREAM) == 0); - if (nghttp2_is_fatal(rv)) { - return rv; - } - } - - busy = 1; - - padlen = inbound_frame_compute_pad(iframe); - if (padlen < 0) { - rv = nghttp2_session_terminate_session_with_reason( - session, NGHTTP2_PROTOCOL_ERROR, "DATA: invalid padding"); - if (nghttp2_is_fatal(rv)) { - return rv; - } - return (nghttp2_ssize)inlen; - } - - iframe->frame.data.padlen = (size_t)padlen; - - iframe->state = NGHTTP2_IB_READ_DATA; - - break; - case NGHTTP2_IB_READ_DATA: - stream = nghttp2_session_get_stream(session, iframe->frame.hd.stream_id); - - if (!stream) { - busy = 1; - iframe->state = NGHTTP2_IB_IGN_DATA; - break; - } - - DEBUGF("recv: [IB_READ_DATA]\n"); - - readlen = inbound_frame_payload_readlen(iframe, in, last); - iframe->payloadleft -= readlen; - in += readlen; - - DEBUGF("recv: readlen=%zu, payloadleft=%zu\n", readlen, - iframe->payloadleft); - - if (readlen > 0) { - nghttp2_ssize data_readlen; - - rv = - nghttp2_session_update_recv_connection_window_size(session, readlen); - if (nghttp2_is_fatal(rv)) { - return rv; - } - - if (iframe->state == NGHTTP2_IB_IGN_ALL) { - return (nghttp2_ssize)inlen; - } - - rv = nghttp2_session_update_recv_stream_window_size( - session, stream, readlen, - iframe->payloadleft || - (iframe->frame.hd.flags & NGHTTP2_FLAG_END_STREAM) == 0); - if (nghttp2_is_fatal(rv)) { - return rv; - } - - data_readlen = - inbound_frame_effective_readlen(iframe, iframe->payloadleft, readlen); - - if (data_readlen == -1) { - /* everything is padding */ - data_readlen = 0; - } - - padlen = (nghttp2_ssize)readlen - data_readlen; - - if (padlen > 0) { - /* Padding is considered as "consumed" immediately */ - rv = nghttp2_session_consume(session, iframe->frame.hd.stream_id, - (size_t)padlen); - - if (nghttp2_is_fatal(rv)) { - return rv; - } - - if (iframe->state == NGHTTP2_IB_IGN_ALL) { - return (nghttp2_ssize)inlen; - } - } - - DEBUGF("recv: data_readlen=%td\n", data_readlen); - - if (data_readlen > 0) { - if (session_enforce_http_messaging(session)) { - if (nghttp2_http_on_data_chunk(stream, (size_t)data_readlen) != 0) { - if (session->opt_flags & NGHTTP2_OPTMASK_NO_AUTO_WINDOW_UPDATE) { - /* Consume all data for connection immediately here */ - rv = session_update_connection_consumed_size( - session, (size_t)data_readlen); - - if (nghttp2_is_fatal(rv)) { - return rv; - } - - if (iframe->state == NGHTTP2_IB_IGN_DATA) { - return (nghttp2_ssize)inlen; - } - } - - rv = nghttp2_session_add_rst_stream( - session, iframe->frame.hd.stream_id, NGHTTP2_PROTOCOL_ERROR); - if (nghttp2_is_fatal(rv)) { - return rv; - } - busy = 1; - iframe->state = NGHTTP2_IB_IGN_DATA; - break; - } - } - if (session->callbacks.on_data_chunk_recv_callback) { - rv = session->callbacks.on_data_chunk_recv_callback( - session, iframe->frame.hd.flags, iframe->frame.hd.stream_id, - in - readlen, (size_t)data_readlen, session->user_data); - if (rv == NGHTTP2_ERR_PAUSE) { - return (nghttp2_ssize)(in - first); - } - - if (nghttp2_is_fatal(rv)) { - return NGHTTP2_ERR_CALLBACK_FAILURE; - } - } - } - } - - if (iframe->payloadleft) { - break; - } - - rv = session_process_data_frame(session); - if (nghttp2_is_fatal(rv)) { - return rv; - } - - session_inbound_frame_reset(session); - - break; - case NGHTTP2_IB_IGN_DATA: - DEBUGF("recv: [IB_IGN_DATA]\n"); - - readlen = inbound_frame_payload_readlen(iframe, in, last); - iframe->payloadleft -= readlen; - in += readlen; - - DEBUGF("recv: readlen=%zu, payloadleft=%zu\n", readlen, - iframe->payloadleft); - - if (readlen > 0) { - /* Update connection-level flow control window for ignored - DATA frame too */ - rv = - nghttp2_session_update_recv_connection_window_size(session, readlen); - if (nghttp2_is_fatal(rv)) { - return rv; - } - - if (iframe->state == NGHTTP2_IB_IGN_ALL) { - return (nghttp2_ssize)inlen; - } - - if (session->opt_flags & NGHTTP2_OPTMASK_NO_AUTO_WINDOW_UPDATE) { - /* Ignored DATA is considered as "consumed" immediately. */ - rv = session_update_connection_consumed_size(session, readlen); - - if (nghttp2_is_fatal(rv)) { - return rv; - } - - if (iframe->state == NGHTTP2_IB_IGN_ALL) { - return (nghttp2_ssize)inlen; - } - } - } - - if (iframe->payloadleft) { - break; - } - - session_inbound_frame_reset(session); - - break; - case NGHTTP2_IB_IGN_ALL: - return (nghttp2_ssize)inlen; - case NGHTTP2_IB_READ_EXTENSION_PAYLOAD: - DEBUGF("recv: [IB_READ_EXTENSION_PAYLOAD]\n"); - - readlen = inbound_frame_payload_readlen(iframe, in, last); - iframe->payloadleft -= readlen; - in += readlen; - - DEBUGF("recv: readlen=%zu, payloadleft=%zu\n", readlen, - iframe->payloadleft); - - if (readlen > 0) { - rv = session_call_on_extension_chunk_recv_callback( - session, in - readlen, readlen); - if (nghttp2_is_fatal(rv)) { - return rv; - } - - if (rv != 0) { - busy = 1; - - iframe->state = NGHTTP2_IB_IGN_PAYLOAD; - - break; - } - } - - if (iframe->payloadleft > 0) { - break; - } - - rv = session_process_extension_frame(session); - if (nghttp2_is_fatal(rv)) { - return rv; - } - - session_inbound_frame_reset(session); - - break; - case NGHTTP2_IB_READ_ALTSVC_PAYLOAD: - DEBUGF("recv: [IB_READ_ALTSVC_PAYLOAD]\n"); - - readlen = inbound_frame_payload_readlen(iframe, in, last); - if (readlen > 0) { - iframe->lbuf.last = nghttp2_cpymem(iframe->lbuf.last, in, readlen); - - iframe->payloadleft -= readlen; - in += readlen; - } - - DEBUGF("recv: readlen=%zu, payloadleft=%zu\n", readlen, - iframe->payloadleft); - - if (iframe->payloadleft) { - assert(nghttp2_buf_avail(&iframe->lbuf) > 0); - - break; - } - - rv = session_process_altsvc_frame(session); - if (nghttp2_is_fatal(rv)) { - return rv; - } - - session_inbound_frame_reset(session); - - break; - case NGHTTP2_IB_READ_ORIGIN_PAYLOAD: - DEBUGF("recv: [IB_READ_ORIGIN_PAYLOAD]\n"); - - readlen = inbound_frame_payload_readlen(iframe, in, last); - - if (readlen > 0) { - iframe->lbuf.last = nghttp2_cpymem(iframe->lbuf.last, in, readlen); - - iframe->payloadleft -= readlen; - in += readlen; - } - - DEBUGF("recv: readlen=%zu, payloadleft=%zu\n", readlen, - iframe->payloadleft); - - if (iframe->payloadleft) { - assert(nghttp2_buf_avail(&iframe->lbuf) > 0); - - break; - } - - rv = session_process_origin_frame(session); - - if (nghttp2_is_fatal(rv)) { - return rv; - } - - if (iframe->state == NGHTTP2_IB_IGN_ALL) { - return (nghttp2_ssize)inlen; - } - - session_inbound_frame_reset(session); - - break; - } - - if (!busy && in == last) { - break; - } - - busy = 0; - } - - assert(in == last); - - return (nghttp2_ssize)(in - first); -} - -int nghttp2_session_recv(nghttp2_session *session) { - uint8_t buf[NGHTTP2_INBOUND_BUFFER_LENGTH]; - while (1) { - nghttp2_ssize readlen; - readlen = session_recv(session, buf, sizeof(buf)); - if (readlen > 0) { - nghttp2_ssize proclen = - nghttp2_session_mem_recv2(session, buf, (size_t)readlen); - if (proclen < 0) { - return (int)proclen; - } - assert(proclen == readlen); - } else if (readlen == 0 || readlen == NGHTTP2_ERR_WOULDBLOCK) { - return 0; - } else if (readlen == NGHTTP2_ERR_EOF) { - return NGHTTP2_ERR_EOF; - } else if (readlen < 0) { - return NGHTTP2_ERR_CALLBACK_FAILURE; - } - } -} - -/* - * Returns the number of active streams, which includes streams in - * reserved state. - */ -static size_t session_get_num_active_streams(nghttp2_session *session) { - return nghttp2_map_size(&session->streams) - session->num_closed_streams - - session->num_idle_streams; -} - -int nghttp2_session_want_read(nghttp2_session *session) { - size_t num_active_streams; - - /* If this flag is set, we don't want to read. The application - should drop the connection. */ - if (session->goaway_flags & NGHTTP2_GOAWAY_TERM_SENT) { - return 0; - } - - num_active_streams = session_get_num_active_streams(session); - - /* Unless termination GOAWAY is sent or received, we always want to - read incoming frames. */ - - if (num_active_streams > 0) { - return 1; - } - - /* If there is no active streams and GOAWAY has been sent or - received, we are done with this session. */ - return (session->goaway_flags & - (NGHTTP2_GOAWAY_SENT | NGHTTP2_GOAWAY_RECV)) == 0; -} - -int nghttp2_session_want_write(nghttp2_session *session) { - /* If these flag is set, we don't want to write any data. The - application should drop the connection. */ - if (session->goaway_flags & NGHTTP2_GOAWAY_TERM_SENT) { - return 0; - } - - /* - * Unless termination GOAWAY is sent or received, we want to write - * frames if there is pending ones. If pending frame is request/push - * response HEADERS and concurrent stream limit is reached, we don't - * want to write them. - */ - return session->aob.item || nghttp2_outbound_queue_top(&session->ob_urgent) || - nghttp2_outbound_queue_top(&session->ob_reg) || - ((!nghttp2_pq_empty(&session->root.obq) || - !session_sched_empty(session)) && - session->remote_window_size > 0) || - (nghttp2_outbound_queue_top(&session->ob_syn) && - !session_is_outgoing_concurrent_streams_max(session)); -} - -int nghttp2_session_add_ping(nghttp2_session *session, uint8_t flags, - const uint8_t *opaque_data) { - int rv; - nghttp2_outbound_item *item; - nghttp2_frame *frame; - nghttp2_mem *mem; - - mem = &session->mem; - - if ((flags & NGHTTP2_FLAG_ACK) && - session->obq_flood_counter_ >= session->max_outbound_ack) { - return NGHTTP2_ERR_FLOODED; - } - - item = nghttp2_mem_malloc(mem, sizeof(nghttp2_outbound_item)); - if (item == NULL) { - return NGHTTP2_ERR_NOMEM; - } - - nghttp2_outbound_item_init(item); - - frame = &item->frame; - - nghttp2_frame_ping_init(&frame->ping, flags, opaque_data); - - rv = nghttp2_session_add_item(session, item); - - if (rv != 0) { - nghttp2_frame_ping_free(&frame->ping); - nghttp2_mem_free(mem, item); - return rv; - } - - if (flags & NGHTTP2_FLAG_ACK) { - ++session->obq_flood_counter_; - } - - return 0; -} - -int nghttp2_session_add_goaway(nghttp2_session *session, int32_t last_stream_id, - uint32_t error_code, const uint8_t *opaque_data, - size_t opaque_data_len, uint8_t aux_flags) { - int rv; - nghttp2_outbound_item *item; - nghttp2_frame *frame; - uint8_t *opaque_data_copy = NULL; - nghttp2_goaway_aux_data *aux_data; - nghttp2_mem *mem; - - mem = &session->mem; - - if (nghttp2_session_is_my_stream_id(session, last_stream_id)) { - return NGHTTP2_ERR_INVALID_ARGUMENT; - } - - if (opaque_data_len) { - if (opaque_data_len + 8 > NGHTTP2_MAX_PAYLOADLEN) { - return NGHTTP2_ERR_INVALID_ARGUMENT; - } - opaque_data_copy = nghttp2_mem_malloc(mem, opaque_data_len); - if (opaque_data_copy == NULL) { - return NGHTTP2_ERR_NOMEM; - } - memcpy(opaque_data_copy, opaque_data, opaque_data_len); - } - - item = nghttp2_mem_malloc(mem, sizeof(nghttp2_outbound_item)); - if (item == NULL) { - nghttp2_mem_free(mem, opaque_data_copy); - return NGHTTP2_ERR_NOMEM; - } - - nghttp2_outbound_item_init(item); - - frame = &item->frame; - - /* last_stream_id must not be increased from the value previously - sent */ - last_stream_id = - nghttp2_min_int32(last_stream_id, session->local_last_stream_id); - - nghttp2_frame_goaway_init(&frame->goaway, last_stream_id, error_code, - opaque_data_copy, opaque_data_len); - - aux_data = &item->aux_data.goaway; - aux_data->flags = aux_flags; - - rv = nghttp2_session_add_item(session, item); - if (rv != 0) { - nghttp2_frame_goaway_free(&frame->goaway, mem); - nghttp2_mem_free(mem, item); - return rv; - } - - session->goaway_flags |= NGHTTP2_GOAWAY_SUBMITTED; - - return 0; -} - -int nghttp2_session_add_window_update(nghttp2_session *session, uint8_t flags, - int32_t stream_id, - int32_t window_size_increment) { - int rv; - nghttp2_outbound_item *item; - nghttp2_frame *frame; - nghttp2_mem *mem; - - mem = &session->mem; - item = nghttp2_mem_malloc(mem, sizeof(nghttp2_outbound_item)); - if (item == NULL) { - return NGHTTP2_ERR_NOMEM; - } - - nghttp2_outbound_item_init(item); - - frame = &item->frame; - - nghttp2_frame_window_update_init(&frame->window_update, flags, stream_id, - window_size_increment); - - rv = nghttp2_session_add_item(session, item); - - if (rv != 0) { - nghttp2_frame_window_update_free(&frame->window_update); - nghttp2_mem_free(mem, item); - return rv; - } - return 0; -} - -static void -session_append_inflight_settings(nghttp2_session *session, - nghttp2_inflight_settings *settings) { - nghttp2_inflight_settings **i; - - for (i = &session->inflight_settings_head; *i; i = &(*i)->next) - ; - - *i = settings; -} - -int nghttp2_session_add_settings(nghttp2_session *session, uint8_t flags, - const nghttp2_settings_entry *iv, size_t niv) { - nghttp2_outbound_item *item; - nghttp2_frame *frame; - nghttp2_settings_entry *iv_copy; - size_t i; - int rv; - nghttp2_mem *mem; - nghttp2_inflight_settings *inflight_settings = NULL; - uint8_t no_rfc7540_pri = session->pending_no_rfc7540_priorities; - - mem = &session->mem; - - if (flags & NGHTTP2_FLAG_ACK) { - if (niv != 0) { - return NGHTTP2_ERR_INVALID_ARGUMENT; - } - - if (session->obq_flood_counter_ >= session->max_outbound_ack) { - return NGHTTP2_ERR_FLOODED; - } - } - - if (!nghttp2_iv_check(iv, niv)) { - return NGHTTP2_ERR_INVALID_ARGUMENT; - } - - for (i = 0; i < niv; ++i) { - if (iv[i].settings_id != NGHTTP2_SETTINGS_NO_RFC7540_PRIORITIES) { - continue; - } - - if (no_rfc7540_pri == UINT8_MAX) { - no_rfc7540_pri = (uint8_t)iv[i].value; - continue; - } - - if (iv[i].value != (uint32_t)no_rfc7540_pri) { - return NGHTTP2_ERR_INVALID_ARGUMENT; - } - } - - item = nghttp2_mem_malloc(mem, sizeof(nghttp2_outbound_item)); - if (item == NULL) { - return NGHTTP2_ERR_NOMEM; - } - - if (niv > 0) { - iv_copy = nghttp2_frame_iv_copy(iv, niv, mem); - if (iv_copy == NULL) { - nghttp2_mem_free(mem, item); - return NGHTTP2_ERR_NOMEM; - } - } else { - iv_copy = NULL; - } - - if ((flags & NGHTTP2_FLAG_ACK) == 0) { - rv = inflight_settings_new(&inflight_settings, iv, niv, mem); - if (rv != 0) { - assert(nghttp2_is_fatal(rv)); - nghttp2_mem_free(mem, iv_copy); - nghttp2_mem_free(mem, item); - return rv; - } - } - - nghttp2_outbound_item_init(item); - - frame = &item->frame; - - nghttp2_frame_settings_init(&frame->settings, flags, iv_copy, niv); - rv = nghttp2_session_add_item(session, item); - if (rv != 0) { - /* The only expected error is fatal one */ - assert(nghttp2_is_fatal(rv)); - - inflight_settings_del(inflight_settings, mem); - - nghttp2_frame_settings_free(&frame->settings, mem); - nghttp2_mem_free(mem, item); - - return rv; - } - - if (flags & NGHTTP2_FLAG_ACK) { - ++session->obq_flood_counter_; - } else { - session_append_inflight_settings(session, inflight_settings); - } - - /* Extract NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS and ENABLE_PUSH - here. We use it to refuse the incoming stream and PUSH_PROMISE - with RST_STREAM. */ - - for (i = niv; i > 0; --i) { - if (iv[i - 1].settings_id == NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS) { - session->pending_local_max_concurrent_stream = iv[i - 1].value; - break; - } - } - - for (i = niv; i > 0; --i) { - if (iv[i - 1].settings_id == NGHTTP2_SETTINGS_ENABLE_PUSH) { - session->pending_enable_push = (uint8_t)iv[i - 1].value; - break; - } - } - - for (i = niv; i > 0; --i) { - if (iv[i - 1].settings_id == NGHTTP2_SETTINGS_ENABLE_CONNECT_PROTOCOL) { - session->pending_enable_connect_protocol = (uint8_t)iv[i - 1].value; - break; - } - } - - if (no_rfc7540_pri == UINT8_MAX) { - session->pending_no_rfc7540_priorities = 0; - } else { - session->pending_no_rfc7540_priorities = no_rfc7540_pri; - } - - return 0; -} - -int nghttp2_session_pack_data(nghttp2_session *session, nghttp2_bufs *bufs, - size_t datamax, nghttp2_frame *frame, - nghttp2_data_aux_data *aux_data, - nghttp2_stream *stream) { - int rv; - uint32_t data_flags; - nghttp2_ssize payloadlen; - nghttp2_ssize padded_payloadlen; - nghttp2_buf *buf; - size_t max_payloadlen; - - assert(bufs->head == bufs->cur); - - buf = &bufs->cur->buf; - - if (session->callbacks.read_length_callback2 || - session->callbacks.read_length_callback) { - if (session->callbacks.read_length_callback2) { - payloadlen = session->callbacks.read_length_callback2( - session, frame->hd.type, stream->stream_id, session->remote_window_size, - stream->remote_window_size, session->remote_settings.max_frame_size, - session->user_data); - } else { - payloadlen = (nghttp2_ssize)session->callbacks.read_length_callback( - session, frame->hd.type, stream->stream_id, session->remote_window_size, - stream->remote_window_size, session->remote_settings.max_frame_size, - session->user_data); - } - - DEBUGF("send: read_length_callback=%td\n", payloadlen); - - payloadlen = - nghttp2_session_enforce_flow_control_limits(session, stream, payloadlen); - - DEBUGF("send: read_length_callback after flow control=%td\n", payloadlen); - - if (payloadlen <= 0) { - return NGHTTP2_ERR_CALLBACK_FAILURE; - } - - if ((size_t)payloadlen > nghttp2_buf_avail(buf)) { - /* Resize the current buffer(s). The reason why we do +1 for - buffer size is for possible padding field. */ - rv = nghttp2_bufs_realloc(&session->aob.framebufs, - (size_t)(NGHTTP2_FRAME_HDLEN + 1 + payloadlen)); - - if (rv != 0) { - DEBUGF("send: realloc buffer failed rv=%d", rv); - /* If reallocation failed, old buffers are still in tact. So - use safe limit. */ - payloadlen = (nghttp2_ssize)datamax; - - DEBUGF("send: use safe limit payloadlen=%td", payloadlen); - } else { - assert(&session->aob.framebufs == bufs); - - buf = &bufs->cur->buf; - } - } - datamax = (size_t)payloadlen; - } - - /* Current max DATA length is less then buffer chunk size */ - assert(nghttp2_buf_avail(buf) >= datamax); - - data_flags = NGHTTP2_DATA_FLAG_NONE; - switch (aux_data->dpw.version) { - case NGHTTP2_DATA_PROVIDER_V1: - payloadlen = (nghttp2_ssize)aux_data->dpw.data_prd.v1.read_callback( - session, frame->hd.stream_id, buf->pos, datamax, &data_flags, - &aux_data->dpw.data_prd.source, session->user_data); - - break; - case NGHTTP2_DATA_PROVIDER_V2: - payloadlen = aux_data->dpw.data_prd.v2.read_callback( - session, frame->hd.stream_id, buf->pos, datamax, &data_flags, - &aux_data->dpw.data_prd.source, session->user_data); - - break; - default: - assert(0); - abort(); - } - - if (payloadlen == NGHTTP2_ERR_DEFERRED || - payloadlen == NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE || - payloadlen == NGHTTP2_ERR_PAUSE) { - DEBUGF("send: DATA postponed due to %s\n", - nghttp2_strerror((int)payloadlen)); - - return (int)payloadlen; - } - - if (payloadlen < 0 || datamax < (size_t)payloadlen) { - /* This is the error code when callback is failed. */ - return NGHTTP2_ERR_CALLBACK_FAILURE; - } - - buf->last = buf->pos + payloadlen; - buf->pos -= NGHTTP2_FRAME_HDLEN; - - /* Clear flags, because this may contain previous flags of previous - DATA */ - frame->hd.flags = NGHTTP2_FLAG_NONE; - - if (data_flags & NGHTTP2_DATA_FLAG_EOF) { - aux_data->eof = 1; - /* If NGHTTP2_DATA_FLAG_NO_END_STREAM is set, don't set - NGHTTP2_FLAG_END_STREAM */ - if ((aux_data->flags & NGHTTP2_FLAG_END_STREAM) && - (data_flags & NGHTTP2_DATA_FLAG_NO_END_STREAM) == 0) { - frame->hd.flags |= NGHTTP2_FLAG_END_STREAM; - } - } - - if (data_flags & NGHTTP2_DATA_FLAG_NO_COPY) { - if (session->callbacks.send_data_callback == NULL) { - DEBUGF("NGHTTP2_DATA_FLAG_NO_COPY requires send_data_callback set\n"); - - return NGHTTP2_ERR_CALLBACK_FAILURE; - } - aux_data->no_copy = 1; - } - - frame->hd.length = (size_t)payloadlen; - frame->data.padlen = 0; - - max_payloadlen = - nghttp2_min_size(datamax, frame->hd.length + NGHTTP2_MAX_PADLEN); - - padded_payloadlen = - session_call_select_padding(session, frame, max_payloadlen); - - if (nghttp2_is_fatal((int)padded_payloadlen)) { - return (int)padded_payloadlen; - } - - frame->data.padlen = (size_t)(padded_payloadlen - payloadlen); - - nghttp2_frame_pack_frame_hd(buf->pos, &frame->hd); - - nghttp2_frame_add_pad(bufs, &frame->hd, frame->data.padlen, - aux_data->no_copy); - - session_reschedule_stream(session, stream); - - if (frame->hd.length == 0 && (data_flags & NGHTTP2_DATA_FLAG_EOF) && - (data_flags & NGHTTP2_DATA_FLAG_NO_END_STREAM)) { - /* DATA payload length is 0, and DATA frame does not bear - END_STREAM. In this case, there is no point to send 0 length - DATA frame. */ - return NGHTTP2_ERR_CANCEL; - } - - return 0; -} - -void *nghttp2_session_get_stream_user_data(nghttp2_session *session, - int32_t stream_id) { - nghttp2_stream *stream; - stream = nghttp2_session_get_stream(session, stream_id); - if (stream) { - return stream->stream_user_data; - } else { - return NULL; - } -} - -int nghttp2_session_set_stream_user_data(nghttp2_session *session, - int32_t stream_id, - void *stream_user_data) { - nghttp2_stream *stream; - nghttp2_frame *frame; - nghttp2_outbound_item *item; - - stream = nghttp2_session_get_stream(session, stream_id); - if (stream) { - stream->stream_user_data = stream_user_data; - return 0; - } - - if (session->server || !nghttp2_session_is_my_stream_id(session, stream_id) || - !nghttp2_outbound_queue_top(&session->ob_syn)) { - return NGHTTP2_ERR_INVALID_ARGUMENT; - } - - frame = &nghttp2_outbound_queue_top(&session->ob_syn)->frame; - assert(frame->hd.type == NGHTTP2_HEADERS); - - if (frame->hd.stream_id > stream_id || - (uint32_t)stream_id >= session->next_stream_id) { - return NGHTTP2_ERR_INVALID_ARGUMENT; - } - - for (item = session->ob_syn.head; item; item = item->qnext) { - if (item->frame.hd.stream_id < stream_id) { - continue; - } - - if (item->frame.hd.stream_id > stream_id) { - break; - } - - item->aux_data.headers.stream_user_data = stream_user_data; - return 0; - } - - return NGHTTP2_ERR_INVALID_ARGUMENT; -} - -int nghttp2_session_resume_data(nghttp2_session *session, int32_t stream_id) { - int rv; - nghttp2_stream *stream; - stream = nghttp2_session_get_stream(session, stream_id); - if (stream == NULL || !nghttp2_stream_check_deferred_item(stream)) { - return NGHTTP2_ERR_INVALID_ARGUMENT; - } - - rv = session_resume_deferred_stream_item(session, stream, - NGHTTP2_STREAM_FLAG_DEFERRED_USER); - - if (nghttp2_is_fatal(rv)) { - return rv; - } - - return 0; -} - -size_t nghttp2_session_get_outbound_queue_size(nghttp2_session *session) { - return nghttp2_outbound_queue_size(&session->ob_urgent) + - nghttp2_outbound_queue_size(&session->ob_reg) + - nghttp2_outbound_queue_size(&session->ob_syn); - /* TODO account for item attached to stream */ -} - -int32_t -nghttp2_session_get_stream_effective_recv_data_length(nghttp2_session *session, - int32_t stream_id) { - nghttp2_stream *stream; - stream = nghttp2_session_get_stream(session, stream_id); - if (stream == NULL) { - return -1; - } - return stream->recv_window_size < 0 ? 0 : stream->recv_window_size; -} - -int32_t -nghttp2_session_get_stream_effective_local_window_size(nghttp2_session *session, - int32_t stream_id) { - nghttp2_stream *stream; - stream = nghttp2_session_get_stream(session, stream_id); - if (stream == NULL) { - return -1; - } - return stream->local_window_size; -} - -int32_t nghttp2_session_get_stream_local_window_size(nghttp2_session *session, - int32_t stream_id) { - nghttp2_stream *stream; - int32_t size; - stream = nghttp2_session_get_stream(session, stream_id); - if (stream == NULL) { - return -1; - } - - size = stream->local_window_size - stream->recv_window_size; - - /* size could be negative if local endpoint reduced - SETTINGS_INITIAL_WINDOW_SIZE */ - if (size < 0) { - return 0; - } - - return size; -} - -int32_t -nghttp2_session_get_effective_recv_data_length(nghttp2_session *session) { - return session->recv_window_size < 0 ? 0 : session->recv_window_size; -} - -int32_t -nghttp2_session_get_effective_local_window_size(nghttp2_session *session) { - return session->local_window_size; -} - -int32_t nghttp2_session_get_local_window_size(nghttp2_session *session) { - return session->local_window_size - session->recv_window_size; -} - -int32_t nghttp2_session_get_stream_remote_window_size(nghttp2_session *session, - int32_t stream_id) { - nghttp2_stream *stream; - - stream = nghttp2_session_get_stream(session, stream_id); - if (stream == NULL) { - return -1; - } - - /* stream->remote_window_size can be negative when - SETTINGS_INITIAL_WINDOW_SIZE is changed. */ - return nghttp2_max_int32(0, stream->remote_window_size); -} - -int32_t nghttp2_session_get_remote_window_size(nghttp2_session *session) { - return session->remote_window_size; -} - -uint32_t nghttp2_session_get_remote_settings(nghttp2_session *session, - nghttp2_settings_id id) { - switch (id) { - case NGHTTP2_SETTINGS_HEADER_TABLE_SIZE: - return session->remote_settings.header_table_size; - case NGHTTP2_SETTINGS_ENABLE_PUSH: - return session->remote_settings.enable_push; - case NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS: - return session->remote_settings.max_concurrent_streams; - case NGHTTP2_SETTINGS_INITIAL_WINDOW_SIZE: - return session->remote_settings.initial_window_size; - case NGHTTP2_SETTINGS_MAX_FRAME_SIZE: - return session->remote_settings.max_frame_size; - case NGHTTP2_SETTINGS_MAX_HEADER_LIST_SIZE: - return session->remote_settings.max_header_list_size; - case NGHTTP2_SETTINGS_ENABLE_CONNECT_PROTOCOL: - return session->remote_settings.enable_connect_protocol; - case NGHTTP2_SETTINGS_NO_RFC7540_PRIORITIES: - return session->remote_settings.no_rfc7540_priorities; - } - - assert(0); - abort(); /* if NDEBUG is set */ -} - -uint32_t nghttp2_session_get_local_settings(nghttp2_session *session, - nghttp2_settings_id id) { - switch (id) { - case NGHTTP2_SETTINGS_HEADER_TABLE_SIZE: - return session->local_settings.header_table_size; - case NGHTTP2_SETTINGS_ENABLE_PUSH: - return session->local_settings.enable_push; - case NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS: - return session->local_settings.max_concurrent_streams; - case NGHTTP2_SETTINGS_INITIAL_WINDOW_SIZE: - return session->local_settings.initial_window_size; - case NGHTTP2_SETTINGS_MAX_FRAME_SIZE: - return session->local_settings.max_frame_size; - case NGHTTP2_SETTINGS_MAX_HEADER_LIST_SIZE: - return session->local_settings.max_header_list_size; - case NGHTTP2_SETTINGS_ENABLE_CONNECT_PROTOCOL: - return session->local_settings.enable_connect_protocol; - case NGHTTP2_SETTINGS_NO_RFC7540_PRIORITIES: - return session->local_settings.no_rfc7540_priorities; - } - - assert(0); - abort(); /* if NDEBUG is set */ -} - -static int nghttp2_session_upgrade_internal(nghttp2_session *session, - const uint8_t *settings_payload, - size_t settings_payloadlen, - void *stream_user_data) { - nghttp2_stream *stream; - nghttp2_frame frame; - nghttp2_settings_entry *iv; - size_t niv; - int rv; - nghttp2_priority_spec pri_spec; - nghttp2_mem *mem; - - mem = &session->mem; - - if ((!session->server && session->next_stream_id != 1) || - (session->server && session->last_recv_stream_id >= 1)) { - return NGHTTP2_ERR_PROTO; - } - if (settings_payloadlen % NGHTTP2_FRAME_SETTINGS_ENTRY_LENGTH) { - return NGHTTP2_ERR_INVALID_ARGUMENT; - } - /* SETTINGS frame contains too many settings */ - if (settings_payloadlen / NGHTTP2_FRAME_SETTINGS_ENTRY_LENGTH > - session->max_settings) { - return NGHTTP2_ERR_TOO_MANY_SETTINGS; - } - rv = nghttp2_frame_unpack_settings_payload2(&iv, &niv, settings_payload, - settings_payloadlen, mem); - if (rv != 0) { - return rv; - } - - if (session->server) { - nghttp2_frame_hd_init(&frame.hd, settings_payloadlen, NGHTTP2_SETTINGS, - NGHTTP2_FLAG_NONE, 0); - frame.settings.iv = iv; - frame.settings.niv = niv; - rv = nghttp2_session_on_settings_received(session, &frame, 1 /* No ACK */); - } else { - rv = nghttp2_submit_settings(session, NGHTTP2_FLAG_NONE, iv, niv); - } - nghttp2_mem_free(mem, iv); - if (rv != 0) { - return rv; - } - - nghttp2_priority_spec_default_init(&pri_spec); - - stream = nghttp2_session_open_stream( - session, 1, NGHTTP2_STREAM_FLAG_NONE, &pri_spec, NGHTTP2_STREAM_OPENING, - session->server ? NULL : stream_user_data); - if (stream == NULL) { - return NGHTTP2_ERR_NOMEM; - } - - /* We don't call nghttp2_session_adjust_closed_stream(), since this - should be the first stream open. */ - - if (session->server) { - nghttp2_stream_shutdown(stream, NGHTTP2_SHUT_RD); - session->last_recv_stream_id = 1; - session->last_proc_stream_id = 1; - } else { - nghttp2_stream_shutdown(stream, NGHTTP2_SHUT_WR); - session->last_sent_stream_id = 1; - session->next_stream_id += 2; - } - return 0; -} - -int nghttp2_session_upgrade(nghttp2_session *session, - const uint8_t *settings_payload, - size_t settings_payloadlen, - void *stream_user_data) { - int rv; - nghttp2_stream *stream; - - rv = nghttp2_session_upgrade_internal(session, settings_payload, - settings_payloadlen, stream_user_data); - if (rv != 0) { - return rv; - } - - stream = nghttp2_session_get_stream(session, 1); - assert(stream); - - /* We have no information about request header fields when Upgrade - was happened. So we don't know the request method here. If - request method is HEAD, we have a trouble because we may have - nonzero content-length header field in response headers, and we - will going to check it against the actual DATA frames, but we may - get mismatch because HEAD response body must be empty. Because - of this reason, nghttp2_session_upgrade() was deprecated in favor - of nghttp2_session_upgrade2(), which has |head_request| parameter - to indicate that request method is HEAD or not. */ - stream->http_flags |= NGHTTP2_HTTP_FLAG_METH_UPGRADE_WORKAROUND; - return 0; -} - -int nghttp2_session_upgrade2(nghttp2_session *session, - const uint8_t *settings_payload, - size_t settings_payloadlen, int head_request, - void *stream_user_data) { - int rv; - nghttp2_stream *stream; - - rv = nghttp2_session_upgrade_internal(session, settings_payload, - settings_payloadlen, stream_user_data); - if (rv != 0) { - return rv; - } - - stream = nghttp2_session_get_stream(session, 1); - assert(stream); - - if (head_request) { - stream->http_flags |= NGHTTP2_HTTP_FLAG_METH_HEAD; - } - - return 0; -} - -int nghttp2_session_get_stream_local_close(nghttp2_session *session, - int32_t stream_id) { - nghttp2_stream *stream; - - stream = nghttp2_session_get_stream(session, stream_id); - - if (!stream) { - return -1; - } - - return (stream->shut_flags & NGHTTP2_SHUT_WR) != 0; -} - -int nghttp2_session_get_stream_remote_close(nghttp2_session *session, - int32_t stream_id) { - nghttp2_stream *stream; - - stream = nghttp2_session_get_stream(session, stream_id); - - if (!stream) { - return -1; - } - - return (stream->shut_flags & NGHTTP2_SHUT_RD) != 0; -} - -int nghttp2_session_consume(nghttp2_session *session, int32_t stream_id, - size_t size) { - int rv; - nghttp2_stream *stream; - - if (stream_id == 0) { - return NGHTTP2_ERR_INVALID_ARGUMENT; - } - - if (!(session->opt_flags & NGHTTP2_OPTMASK_NO_AUTO_WINDOW_UPDATE)) { - return NGHTTP2_ERR_INVALID_STATE; - } - - rv = session_update_connection_consumed_size(session, size); - - if (nghttp2_is_fatal(rv)) { - return rv; - } - - stream = nghttp2_session_get_stream(session, stream_id); - - if (!stream) { - return 0; - } - - rv = session_update_stream_consumed_size(session, stream, size); - - if (nghttp2_is_fatal(rv)) { - return rv; - } - - return 0; -} - -int nghttp2_session_consume_connection(nghttp2_session *session, size_t size) { - int rv; - - if (!(session->opt_flags & NGHTTP2_OPTMASK_NO_AUTO_WINDOW_UPDATE)) { - return NGHTTP2_ERR_INVALID_STATE; - } - - rv = session_update_connection_consumed_size(session, size); - - if (nghttp2_is_fatal(rv)) { - return rv; - } - - return 0; -} - -int nghttp2_session_consume_stream(nghttp2_session *session, int32_t stream_id, - size_t size) { - int rv; - nghttp2_stream *stream; - - if (stream_id == 0) { - return NGHTTP2_ERR_INVALID_ARGUMENT; - } - - if (!(session->opt_flags & NGHTTP2_OPTMASK_NO_AUTO_WINDOW_UPDATE)) { - return NGHTTP2_ERR_INVALID_STATE; - } - - stream = nghttp2_session_get_stream(session, stream_id); - - if (!stream) { - return 0; - } - - rv = session_update_stream_consumed_size(session, stream, size); - - if (nghttp2_is_fatal(rv)) { - return rv; - } - - return 0; -} - -int nghttp2_session_set_next_stream_id(nghttp2_session *session, - int32_t next_stream_id) { - if (next_stream_id <= 0 || - session->next_stream_id > (uint32_t)next_stream_id) { - return NGHTTP2_ERR_INVALID_ARGUMENT; - } - - if (session->server) { - if (next_stream_id % 2) { - return NGHTTP2_ERR_INVALID_ARGUMENT; - } - } else if (next_stream_id % 2 == 0) { - return NGHTTP2_ERR_INVALID_ARGUMENT; - } - - session->next_stream_id = (uint32_t)next_stream_id; - return 0; -} - -uint32_t nghttp2_session_get_next_stream_id(nghttp2_session *session) { - return session->next_stream_id; -} - -int32_t nghttp2_session_get_last_proc_stream_id(nghttp2_session *session) { - return session->last_proc_stream_id; -} - -nghttp2_stream *nghttp2_session_find_stream(nghttp2_session *session, - int32_t stream_id) { - if (stream_id == 0) { - return &session->root; - } - - return nghttp2_session_get_stream_raw(session, stream_id); -} - -nghttp2_stream *nghttp2_session_get_root_stream(nghttp2_session *session) { - return &session->root; -} - -int nghttp2_session_check_server_session(nghttp2_session *session) { - return session->server; -} - -int nghttp2_session_change_stream_priority( - nghttp2_session *session, int32_t stream_id, - const nghttp2_priority_spec *pri_spec) { - int rv; - nghttp2_stream *stream; - nghttp2_priority_spec pri_spec_copy; - - if (session->pending_no_rfc7540_priorities == 1) { - return 0; - } - - if (stream_id == 0 || stream_id == pri_spec->stream_id) { - return NGHTTP2_ERR_INVALID_ARGUMENT; - } - - stream = nghttp2_session_get_stream_raw(session, stream_id); - if (!stream) { - return NGHTTP2_ERR_INVALID_ARGUMENT; - } - - pri_spec_copy = *pri_spec; - nghttp2_priority_spec_normalize_weight(&pri_spec_copy); - - rv = nghttp2_session_reprioritize_stream(session, stream, &pri_spec_copy); - - if (nghttp2_is_fatal(rv)) { - return rv; - } - - /* We don't intentionally call nghttp2_session_adjust_idle_stream() - so that idle stream created by this function, and existing ones - are kept for application. We will adjust number of idle stream - in nghttp2_session_mem_send2 or nghttp2_session_mem_recv2 is - called. */ - return 0; -} - -int nghttp2_session_create_idle_stream(nghttp2_session *session, - int32_t stream_id, - const nghttp2_priority_spec *pri_spec) { - nghttp2_stream *stream; - nghttp2_priority_spec pri_spec_copy; - - if (session->pending_no_rfc7540_priorities == 1) { - return 0; - } - - if (stream_id == 0 || stream_id == pri_spec->stream_id || - !session_detect_idle_stream(session, stream_id)) { - return NGHTTP2_ERR_INVALID_ARGUMENT; - } - - stream = nghttp2_session_get_stream_raw(session, stream_id); - if (stream) { - return NGHTTP2_ERR_INVALID_ARGUMENT; - } - - pri_spec_copy = *pri_spec; - nghttp2_priority_spec_normalize_weight(&pri_spec_copy); - - stream = - nghttp2_session_open_stream(session, stream_id, NGHTTP2_STREAM_FLAG_NONE, - &pri_spec_copy, NGHTTP2_STREAM_IDLE, NULL); - if (!stream) { - return NGHTTP2_ERR_NOMEM; - } - - /* We don't intentionally call nghttp2_session_adjust_idle_stream() - so that idle stream created by this function, and existing ones - are kept for application. We will adjust number of idle stream - in nghttp2_session_mem_send2 or nghttp2_session_mem_recv2 is - called. */ - return 0; -} - -size_t -nghttp2_session_get_hd_inflate_dynamic_table_size(nghttp2_session *session) { - return nghttp2_hd_inflate_get_dynamic_table_size(&session->hd_inflater); -} - -size_t -nghttp2_session_get_hd_deflate_dynamic_table_size(nghttp2_session *session) { - return nghttp2_hd_deflate_get_dynamic_table_size(&session->hd_deflater); -} - -void nghttp2_session_set_user_data(nghttp2_session *session, void *user_data) { - session->user_data = user_data; -} - -int nghttp2_session_change_extpri_stream_priority( - nghttp2_session *session, int32_t stream_id, const nghttp2_extpri *extpri_in, - int ignore_client_signal) { - nghttp2_stream *stream; - nghttp2_extpri extpri = *extpri_in; - - if (!session->server) { - return NGHTTP2_ERR_INVALID_STATE; - } - - if (session->pending_no_rfc7540_priorities != 1) { - return 0; - } - - if (stream_id == 0) { - return NGHTTP2_ERR_INVALID_ARGUMENT; - } - - stream = nghttp2_session_get_stream_raw(session, stream_id); - if (!stream) { - return NGHTTP2_ERR_INVALID_ARGUMENT; - } - - if (extpri.urgency > NGHTTP2_EXTPRI_URGENCY_LOW) { - extpri.urgency = NGHTTP2_EXTPRI_URGENCY_LOW; - } - - if (ignore_client_signal) { - stream->flags |= NGHTTP2_STREAM_FLAG_IGNORE_CLIENT_PRIORITIES; - } - - return session_update_stream_priority(session, stream, - nghttp2_extpri_to_uint8(&extpri)); -} - -int nghttp2_session_get_extpri_stream_priority(nghttp2_session *session, - nghttp2_extpri *extpri, - int32_t stream_id) { - nghttp2_stream *stream; - - if (!session->server) { - return NGHTTP2_ERR_INVALID_STATE; - } - - if (session->pending_no_rfc7540_priorities != 1) { - return 0; - } - - if (stream_id == 0) { - return NGHTTP2_ERR_INVALID_ARGUMENT; - } - - stream = nghttp2_session_get_stream_raw(session, stream_id); - if (!stream) { - return NGHTTP2_ERR_INVALID_ARGUMENT; - } - - nghttp2_extpri_from_uint8(extpri, stream->extpri); - - return 0; -} diff --git a/3rdparty/exported/nghttp2/nghttp2_session.h b/3rdparty/exported/nghttp2/nghttp2_session.h deleted file mode 100644 index ef8f7b27d672..000000000000 --- a/3rdparty/exported/nghttp2/nghttp2_session.h +++ /dev/null @@ -1,984 +0,0 @@ -/* - * nghttp2 - HTTP/2 C Library - * - * Copyright (c) 2012 Tatsuhiro Tsujikawa - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE - * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION - * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION - * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ -#ifndef NGHTTP2_SESSION_H -#define NGHTTP2_SESSION_H - -#ifdef HAVE_CONFIG_H -# include -#endif /* HAVE_CONFIG_H */ - -#include -#include "nghttp2_map.h" -#include "nghttp2_frame.h" -#include "nghttp2_hd.h" -#include "nghttp2_stream.h" -#include "nghttp2_outbound_item.h" -#include "nghttp2_int.h" -#include "nghttp2_buf.h" -#include "nghttp2_callbacks.h" -#include "nghttp2_mem.h" -#include "nghttp2_ratelim.h" - -/* The global variable for tests where we want to disable strict - preface handling. */ -extern int nghttp2_enable_strict_preface; - -/* - * Option flags. - */ -typedef enum { - NGHTTP2_OPTMASK_NO_AUTO_WINDOW_UPDATE = 1 << 0, - NGHTTP2_OPTMASK_NO_RECV_CLIENT_MAGIC = 1 << 1, - NGHTTP2_OPTMASK_NO_HTTP_MESSAGING = 1 << 2, - NGHTTP2_OPTMASK_NO_AUTO_PING_ACK = 1 << 3, - NGHTTP2_OPTMASK_NO_CLOSED_STREAMS = 1 << 4, - NGHTTP2_OPTMASK_SERVER_FALLBACK_RFC7540_PRIORITIES = 1 << 5, - NGHTTP2_OPTMASK_NO_RFC9113_LEADING_AND_TRAILING_WS_VALIDATION = 1 << 6, -} nghttp2_optmask; - -/* - * bitmask for built-in type to enable the default handling for that - * type of the frame. - */ -typedef enum { - NGHTTP2_TYPEMASK_NONE = 0, - NGHTTP2_TYPEMASK_ALTSVC = 1 << 0, - NGHTTP2_TYPEMASK_ORIGIN = 1 << 1, - NGHTTP2_TYPEMASK_PRIORITY_UPDATE = 1 << 2 -} nghttp2_typemask; - -typedef enum { - NGHTTP2_OB_POP_ITEM, - NGHTTP2_OB_SEND_DATA, - NGHTTP2_OB_SEND_NO_COPY, - NGHTTP2_OB_SEND_CLIENT_MAGIC -} nghttp2_outbound_state; - -typedef struct { - nghttp2_outbound_item *item; - nghttp2_bufs framebufs; - nghttp2_outbound_state state; -} nghttp2_active_outbound_item; - -/* Buffer length for inbound raw byte stream used in - nghttp2_session_recv(). */ -#define NGHTTP2_INBOUND_BUFFER_LENGTH 16384 - -/* The default maximum number of incoming reserved streams */ -#define NGHTTP2_MAX_INCOMING_RESERVED_STREAMS 200 - -/* Even if we have less SETTINGS_MAX_CONCURRENT_STREAMS than this - number, we keep NGHTTP2_MIN_IDLE_STREAMS streams in idle state */ -#define NGHTTP2_MIN_IDLE_STREAMS 16 - -/* The maximum number of items in outbound queue, which is considered - as flooding caused by peer. All frames are not considered here. - We only consider PING + ACK and SETTINGS + ACK. This is because - they both are response to the frame initiated by peer and peer can - send as many of them as they want. If peer does not read network, - response frames are stacked up, which leads to memory exhaustion. - The value selected here is arbitrary, but safe value and if we have - these frames in this number, it is considered suspicious. */ -#define NGHTTP2_DEFAULT_MAX_OBQ_FLOOD_ITEM 1000 - -/* The default value of maximum number of concurrent streams. */ -#define NGHTTP2_DEFAULT_MAX_CONCURRENT_STREAMS 0xffffffffu - -/* The default values for stream reset rate limiter. */ -#define NGHTTP2_DEFAULT_STREAM_RESET_BURST 1000 -#define NGHTTP2_DEFAULT_STREAM_RESET_RATE 33 - -/* The default max number of CONTINUATION frames following an incoming - HEADER frame. */ -#define NGHTTP2_DEFAULT_MAX_CONTINUATIONS 8 - -/* Internal state when receiving incoming frame */ -typedef enum { - /* Receiving frame header */ - NGHTTP2_IB_READ_CLIENT_MAGIC, - NGHTTP2_IB_READ_FIRST_SETTINGS, - NGHTTP2_IB_READ_HEAD, - NGHTTP2_IB_READ_NBYTE, - NGHTTP2_IB_READ_HEADER_BLOCK, - NGHTTP2_IB_IGN_HEADER_BLOCK, - NGHTTP2_IB_IGN_PAYLOAD, - NGHTTP2_IB_FRAME_SIZE_ERROR, - NGHTTP2_IB_READ_SETTINGS, - NGHTTP2_IB_READ_GOAWAY_DEBUG, - NGHTTP2_IB_EXPECT_CONTINUATION, - NGHTTP2_IB_IGN_CONTINUATION, - NGHTTP2_IB_READ_PAD_DATA, - NGHTTP2_IB_READ_DATA, - NGHTTP2_IB_IGN_DATA, - NGHTTP2_IB_IGN_ALL, - NGHTTP2_IB_READ_ALTSVC_PAYLOAD, - NGHTTP2_IB_READ_ORIGIN_PAYLOAD, - NGHTTP2_IB_READ_EXTENSION_PAYLOAD -} nghttp2_inbound_state; - -typedef struct { - nghttp2_frame frame; - /* Storage for extension frame payload. frame->ext.payload points - to this structure to avoid frequent memory allocation. */ - nghttp2_ext_frame_payload ext_frame_payload; - /* The received SETTINGS entry. For the standard settings entries, - we only keep the last seen value. For - SETTINGS_HEADER_TABLE_SIZE, we also keep minimum value in the - last index. */ - nghttp2_settings_entry *iv; - /* buffer pointers to small buffer, raw_sbuf */ - nghttp2_buf sbuf; - /* buffer pointers to large buffer, raw_lbuf */ - nghttp2_buf lbuf; - /* Large buffer, malloced on demand */ - uint8_t *raw_lbuf; - /* The number of entry filled in |iv| */ - size_t niv; - /* The number of entries |iv| can store. */ - size_t max_niv; - /* How many bytes we still need to receive for current frame */ - size_t payloadleft; - /* padding length for the current frame */ - size_t padlen; - nghttp2_inbound_state state; - /* Small fixed sized buffer. */ - uint8_t raw_sbuf[32]; -} nghttp2_inbound_frame; - -typedef struct { - uint32_t header_table_size; - uint32_t enable_push; - uint32_t max_concurrent_streams; - uint32_t initial_window_size; - uint32_t max_frame_size; - uint32_t max_header_list_size; - uint32_t enable_connect_protocol; - uint32_t no_rfc7540_priorities; -} nghttp2_settings_storage; - -typedef enum { - NGHTTP2_GOAWAY_NONE = 0, - /* Flag means that connection should be terminated after sending GOAWAY. */ - NGHTTP2_GOAWAY_TERM_ON_SEND = 0x1, - /* Flag means GOAWAY to terminate session has been sent */ - NGHTTP2_GOAWAY_TERM_SENT = 0x2, - /* Flag means GOAWAY was sent */ - NGHTTP2_GOAWAY_SENT = 0x4, - /* Flag means GOAWAY was received */ - NGHTTP2_GOAWAY_RECV = 0x8, - /* Flag means GOAWAY has been submitted at least once */ - NGHTTP2_GOAWAY_SUBMITTED = 0x10 -} nghttp2_goaway_flag; - -/* nghttp2_inflight_settings stores the SETTINGS entries which local - endpoint has sent to the remote endpoint, and has not received ACK - yet. */ -struct nghttp2_inflight_settings { - struct nghttp2_inflight_settings *next; - nghttp2_settings_entry *iv; - size_t niv; -}; - -typedef struct nghttp2_inflight_settings nghttp2_inflight_settings; - -struct nghttp2_session { - nghttp2_map /* */ streams; - /* root of dependency tree*/ - nghttp2_stream root; - /* Queue for outbound urgent frames (PING and SETTINGS) */ - nghttp2_outbound_queue ob_urgent; - /* Queue for non-DATA frames */ - nghttp2_outbound_queue ob_reg; - /* Queue for outbound stream-creating HEADERS (request or push - response) frame, which are subject to - SETTINGS_MAX_CONCURRENT_STREAMS limit. */ - nghttp2_outbound_queue ob_syn; - /* Queues for DATA frames which is used when - SETTINGS_NO_RFC7540_PRIORITIES is enabled. This implements RFC - 9218 extensible prioritization scheme. */ - struct { - nghttp2_pq ob_data; - } sched[NGHTTP2_EXTPRI_URGENCY_LEVELS]; - nghttp2_active_outbound_item aob; - nghttp2_inbound_frame iframe; - nghttp2_hd_deflater hd_deflater; - nghttp2_hd_inflater hd_inflater; - nghttp2_session_callbacks callbacks; - /* Memory allocator */ - nghttp2_mem mem; - void *user_data; - /* Points to the latest incoming closed stream. NULL if there is no - closed stream. Only used when session is initialized as - server. */ - nghttp2_stream *closed_stream_head; - /* Points to the oldest incoming closed stream. NULL if there is no - closed stream. Only used when session is initialized as - server. */ - nghttp2_stream *closed_stream_tail; - /* Points to the latest idle stream. NULL if there is no idle - stream. Only used when session is initialized as server .*/ - nghttp2_stream *idle_stream_head; - /* Points to the oldest idle stream. NULL if there is no idle - stream. Only used when session is initialized as erver. */ - nghttp2_stream *idle_stream_tail; - /* Queue of In-flight SETTINGS values. SETTINGS bearing ACK is not - considered as in-flight. */ - nghttp2_inflight_settings *inflight_settings_head; - /* Stream reset rate limiter. If receiving excessive amount of - stream resets, GOAWAY will be sent. */ - nghttp2_ratelim stream_reset_ratelim; - /* Sequential number across all streams to process streams in - FIFO. */ - uint64_t stream_seq; - /* The number of outgoing streams. This will be capped by - remote_settings.max_concurrent_streams. */ - size_t num_outgoing_streams; - /* The number of incoming streams. This will be capped by - local_settings.max_concurrent_streams. */ - size_t num_incoming_streams; - /* The number of incoming reserved streams. This is the number of - streams in reserved (remote) state. RFC 7540 does not limit this - number. nghttp2 offers - nghttp2_option_set_max_reserved_remote_streams() to achieve this. - If it is used, num_incoming_streams is capped by - max_incoming_reserved_streams. Client application should - consider to set this because without that server can send - arbitrary number of PUSH_PROMISE, and exhaust client's memory. */ - size_t num_incoming_reserved_streams; - /* The maximum number of incoming reserved streams (reserved - (remote) state). RST_STREAM will be sent for the pushed stream - which exceeds this limit. */ - size_t max_incoming_reserved_streams; - /* The number of closed streams still kept in |streams| hash. The - closed streams can be accessed through single linked list - |closed_stream_head|. The current implementation only keeps - incoming streams and session is initialized as server. */ - size_t num_closed_streams; - /* The number of idle streams kept in |streams| hash. The idle - streams can be accessed through doubly linked list - |idle_stream_head|. The current implementation only keeps idle - streams if session is initialized as server. */ - size_t num_idle_streams; - /* The number of bytes allocated for nvbuf */ - size_t nvbuflen; - /* Counter for detecting flooding in outbound queue. If it exceeds - max_outbound_ack, session will be closed. */ - size_t obq_flood_counter_; - /* The maximum number of outgoing SETTINGS ACK and PING ACK in - outbound queue. */ - size_t max_outbound_ack; - /* The maximum length of header block to send. Calculated by the - same way as nghttp2_hd_deflate_bound() does. */ - size_t max_send_header_block_length; - /* The maximum number of settings accepted per SETTINGS frame. */ - size_t max_settings; - /* The maximum number of CONTINUATION frames following an incoming - HEADER frame. */ - size_t max_continuations; - /* The number of CONTINUATION frames following an incoming HEADER - frame. This variable is reset when END_HEADERS flag is seen. */ - size_t num_continuations; - /* Next Stream ID. Made unsigned int to detect >= (1 << 31). */ - uint32_t next_stream_id; - /* The last stream ID this session initiated. For client session, - this is the last stream ID it has sent. For server session, it - is the last promised stream ID sent in PUSH_PROMISE. */ - int32_t last_sent_stream_id; - /* The largest stream ID received so far */ - int32_t last_recv_stream_id; - /* The largest stream ID which has been processed in some way. This - value will be used as last-stream-id when sending GOAWAY - frame. */ - int32_t last_proc_stream_id; - /* Counter of unique ID of PING. Wraps when it exceeds - NGHTTP2_MAX_UNIQUE_ID */ - uint32_t next_unique_id; - /* This is the last-stream-ID we have sent in GOAWAY */ - int32_t local_last_stream_id; - /* This is the value in GOAWAY frame received from remote endpoint. */ - int32_t remote_last_stream_id; - /* Current sender window size. This value is computed against the - current initial window size of remote endpoint. */ - int32_t remote_window_size; - /* Keep track of the number of bytes received without - WINDOW_UPDATE. This could be negative after submitting negative - value to WINDOW_UPDATE. */ - int32_t recv_window_size; - /* The number of bytes consumed by the application and now is - subject to WINDOW_UPDATE. This is only used when auto - WINDOW_UPDATE is turned off. */ - int32_t consumed_size; - /* The amount of recv_window_size cut using submitting negative - value to WINDOW_UPDATE */ - int32_t recv_reduction; - /* window size for local flow control. It is initially set to - NGHTTP2_INITIAL_CONNECTION_WINDOW_SIZE and could be - increased/decreased by submitting WINDOW_UPDATE. See - nghttp2_submit_window_update(). */ - int32_t local_window_size; - /* This flag is used to indicate that the local endpoint received initial - SETTINGS frame from the remote endpoint. */ - uint8_t remote_settings_received; - /* Settings value received from the remote endpoint. */ - nghttp2_settings_storage remote_settings; - /* Settings value of the local endpoint. */ - nghttp2_settings_storage local_settings; - /* Option flags. This is bitwise-OR of 0 or more of nghttp2_optmask. */ - uint32_t opt_flags; - /* Unacked local SETTINGS_MAX_CONCURRENT_STREAMS value. We use this - to refuse the incoming stream if it exceeds this value. */ - uint32_t pending_local_max_concurrent_stream; - /* The bitwise OR of zero or more of nghttp2_typemask to indicate - that the default handling of extension frame is enabled. */ - uint32_t builtin_recv_ext_types; - /* Unacked local ENABLE_PUSH value. We use this to refuse - PUSH_PROMISE before SETTINGS ACK is received. */ - uint8_t pending_enable_push; - /* Unacked local ENABLE_CONNECT_PROTOCOL value. We use this to - accept :protocol header field before SETTINGS_ACK is received. */ - uint8_t pending_enable_connect_protocol; - /* Unacked local SETTINGS_NO_RFC7540_PRIORITIES value, which is - effective before it is acknowledged. */ - uint8_t pending_no_rfc7540_priorities; - /* Turn on fallback to RFC 7540 priorities; for server use only. */ - uint8_t fallback_rfc7540_priorities; - /* Nonzero if the session is server side. */ - uint8_t server; - /* Flags indicating GOAWAY is sent and/or received. The flags are - composed by bitwise OR-ing nghttp2_goaway_flag. */ - uint8_t goaway_flags; - /* This flag is used to reduce excessive queuing of WINDOW_UPDATE to - this session. The nonzero does not necessarily mean - WINDOW_UPDATE is not queued. */ - uint8_t window_update_queued; - /* Bitfield of extension frame types that application is willing to - receive. To designate the bit of given frame type i, use - user_recv_ext_types[i / 8] & (1 << (i & 0x7)). First 10 frame - types are standard frame types and not used in this bitfield. If - bit is set, it indicates that incoming frame with that type is - passed to user defined callbacks, otherwise they are ignored. */ - uint8_t user_recv_ext_types[32]; -}; - -/* Struct used when updating initial window size of each active - stream. */ -typedef struct { - nghttp2_session *session; - int32_t new_window_size, old_window_size; -} nghttp2_update_window_size_arg; - -typedef struct { - nghttp2_session *session; - /* linked list of streams to close */ - nghttp2_stream *head; - int32_t last_stream_id; - /* nonzero if GOAWAY is sent to peer, which means we are going to - close incoming streams. zero if GOAWAY is received from peer and - we are going to close outgoing streams. */ - int incoming; -} nghttp2_close_stream_on_goaway_arg; - -/* TODO stream timeout etc */ - -/* - * Returns nonzero value if |stream_id| is initiated by local - * endpoint. - */ -int nghttp2_session_is_my_stream_id(nghttp2_session *session, - int32_t stream_id); - -/* - * Adds |item| to the outbound queue in |session|. When this function - * succeeds, it takes ownership of |item|. So caller must not free it - * on success. - * - * This function returns 0 if it succeeds, or one of the following - * negative error codes: - * - * NGHTTP2_ERR_NOMEM - * Out of memory. - * NGHTTP2_ERR_STREAM_CLOSED - * Stream already closed (DATA and PUSH_PROMISE frame only) - */ -int nghttp2_session_add_item(nghttp2_session *session, - nghttp2_outbound_item *item); - -/* - * Adds RST_STREAM frame for the stream |stream_id| with the error - * code |error_code|. This is a convenient function built on top of - * nghttp2_session_add_frame() to add RST_STREAM easily. - * - * This function simply returns 0 without adding RST_STREAM frame if - * given stream is in NGHTTP2_STREAM_CLOSING state, because multiple - * RST_STREAM for a stream is redundant. - * - * This function returns 0 if it succeeds, or one of the following - * negative error codes: - * - * NGHTTP2_ERR_NOMEM - * Out of memory. - */ -int nghttp2_session_add_rst_stream(nghttp2_session *session, int32_t stream_id, - uint32_t error_code); - -/* - * Adds PING frame. This is a convenient function built on top of - * nghttp2_session_add_frame() to add PING easily. - * - * If the |opaque_data| is not NULL, it must point to 8 bytes memory - * region of data. The data pointed by |opaque_data| is copied. It can - * be NULL. In this case, 8 bytes NULL is used. - * - * This function returns 0 if it succeeds, or one of the following - * negative error codes: - * - * NGHTTP2_ERR_NOMEM - * Out of memory. - * NGHTTP2_ERR_FLOODED - * There are too many items in outbound queue; this only happens - * if NGHTTP2_FLAG_ACK is set in |flags| - */ -int nghttp2_session_add_ping(nghttp2_session *session, uint8_t flags, - const uint8_t *opaque_data); - -/* - * Adds GOAWAY frame with the last-stream-ID |last_stream_id| and the - * error code |error_code|. This is a convenient function built on top - * of nghttp2_session_add_frame() to add GOAWAY easily. The - * |aux_flags| are bitwise-OR of one or more of - * nghttp2_goaway_aux_flag. - * - * This function returns 0 if it succeeds, or one of the following - * negative error codes: - * - * NGHTTP2_ERR_NOMEM - * Out of memory. - * NGHTTP2_ERR_INVALID_ARGUMENT - * The |opaque_data_len| is too large. - */ -int nghttp2_session_add_goaway(nghttp2_session *session, int32_t last_stream_id, - uint32_t error_code, const uint8_t *opaque_data, - size_t opaque_data_len, uint8_t aux_flags); - -/* - * Adds WINDOW_UPDATE frame with stream ID |stream_id| and - * window-size-increment |window_size_increment|. This is a convenient - * function built on top of nghttp2_session_add_frame() to add - * WINDOW_UPDATE easily. - * - * This function returns 0 if it succeeds, or one of the following - * negative error codes: - * - * NGHTTP2_ERR_NOMEM - * Out of memory. - */ -int nghttp2_session_add_window_update(nghttp2_session *session, uint8_t flags, - int32_t stream_id, - int32_t window_size_increment); - -/* - * Adds SETTINGS frame. - * - * This function returns 0 if it succeeds, or one of the following - * negative error codes: - * - * NGHTTP2_ERR_NOMEM - * Out of memory. - * NGHTTP2_ERR_FLOODED - * There are too many items in outbound queue; this only happens - * if NGHTTP2_FLAG_ACK is set in |flags| - */ -int nghttp2_session_add_settings(nghttp2_session *session, uint8_t flags, - const nghttp2_settings_entry *iv, size_t niv); - -/* - * Creates new stream in |session| with stream ID |stream_id|, - * priority |pri_spec| and flags |flags|. The |flags| is bitwise OR - * of nghttp2_stream_flag. Since this function is called when initial - * HEADERS is sent or received, these flags are taken from it. The - * state of stream is set to |initial_state|. The |stream_user_data| - * is a pointer to the arbitrary user supplied data to be associated - * to this stream. - * - * If |initial_state| is NGHTTP2_STREAM_RESERVED, this function sets - * NGHTTP2_STREAM_FLAG_PUSH flag set. - * - * This function returns a pointer to created new stream object, or - * NULL. - * - * This function adjusts neither the number of closed streams or idle - * streams. The caller should manually call - * nghttp2_session_adjust_closed_stream() or - * nghttp2_session_adjust_idle_stream() respectively. - */ -nghttp2_stream *nghttp2_session_open_stream(nghttp2_session *session, - int32_t stream_id, uint8_t flags, - nghttp2_priority_spec *pri_spec, - nghttp2_stream_state initial_state, - void *stream_user_data); - -/* - * Closes stream whose stream ID is |stream_id|. The reason of closure - * is indicated by the |error_code|. When closing the stream, - * on_stream_close_callback will be called. - * - * If the session is initialized as server and |stream| is incoming - * stream, stream is just marked closed and this function calls - * nghttp2_session_keep_closed_stream() with |stream|. Otherwise, - * |stream| will be deleted from memory. - * - * This function returns 0 if it succeeds, or one the following - * negative error codes: - * - * NGHTTP2_ERR_NOMEM - * Out of memory - * NGHTTP2_ERR_INVALID_ARGUMENT - * The specified stream does not exist. - * NGHTTP2_ERR_CALLBACK_FAILURE - * The callback function failed. - */ -int nghttp2_session_close_stream(nghttp2_session *session, int32_t stream_id, - uint32_t error_code); - -/* - * Deletes |stream| from memory. After this function returns, stream - * cannot be accessed. - * - * This function returns 0 if it succeeds, or one the following - * negative error codes: - * - * NGHTTP2_ERR_NOMEM - * Out of memory - */ -int nghttp2_session_destroy_stream(nghttp2_session *session, - nghttp2_stream *stream); - -/* - * Tries to keep incoming closed stream |stream|. Due to the - * limitation of maximum number of streams in memory, |stream| is not - * closed and just deleted from memory (see - * nghttp2_session_destroy_stream). - */ -void nghttp2_session_keep_closed_stream(nghttp2_session *session, - nghttp2_stream *stream); - -/* - * Appends |stream| to linked list |session->idle_stream_head|. We - * apply fixed limit for list size. To fit into that limit, one or - * more oldest streams are removed from list as necessary. - */ -void nghttp2_session_keep_idle_stream(nghttp2_session *session, - nghttp2_stream *stream); - -/* - * Detaches |stream| from idle streams linked list. - */ -void nghttp2_session_detach_idle_stream(nghttp2_session *session, - nghttp2_stream *stream); - -/* - * Deletes closed stream to ensure that number of incoming streams - * including active and closed is in the maximum number of allowed - * stream. - * - * This function returns 0 if it succeeds, or one the following - * negative error codes: - * - * NGHTTP2_ERR_NOMEM - * Out of memory - */ -int nghttp2_session_adjust_closed_stream(nghttp2_session *session); - -/* - * Deletes idle stream to ensure that number of idle streams is in - * certain limit. - * - * This function returns 0 if it succeeds, or one the following - * negative error codes: - * - * NGHTTP2_ERR_NOMEM - * Out of memory - */ -int nghttp2_session_adjust_idle_stream(nghttp2_session *session); - -/* - * If further receptions and transmissions over the stream |stream_id| - * are disallowed, close the stream with error code NGHTTP2_NO_ERROR. - * - * This function returns 0 if it - * succeeds, or one of the following negative error codes: - * - * NGHTTP2_ERR_INVALID_ARGUMENT - * The specified stream does not exist. - */ -int nghttp2_session_close_stream_if_shut_rdwr(nghttp2_session *session, - nghttp2_stream *stream); - -int nghttp2_session_on_request_headers_received(nghttp2_session *session, - nghttp2_frame *frame); - -int nghttp2_session_on_response_headers_received(nghttp2_session *session, - nghttp2_frame *frame, - nghttp2_stream *stream); - -int nghttp2_session_on_push_response_headers_received(nghttp2_session *session, - nghttp2_frame *frame, - nghttp2_stream *stream); - -/* - * Called when HEADERS is received, assuming |frame| is properly - * initialized. This function does first validate received frame and - * then open stream and call callback functions. - * - * This function returns 0 if it succeeds, or one of the following - * negative error codes: - * - * NGHTTP2_ERR_NOMEM - * Out of memory. - * NGHTTP2_ERR_IGN_HEADER_BLOCK - * Frame was rejected and header block must be decoded but - * result must be ignored. - * NGHTTP2_ERR_CALLBACK_FAILURE - * The read_callback failed - */ -int nghttp2_session_on_headers_received(nghttp2_session *session, - nghttp2_frame *frame, - nghttp2_stream *stream); - -/* - * Called when PRIORITY is received, assuming |frame| is properly - * initialized. - * - * This function returns 0 if it succeeds, or one of the following - * negative error codes: - * - * NGHTTP2_ERR_NOMEM - * Out of memory. - * NGHTTP2_ERR_CALLBACK_FAILURE - * The read_callback failed - */ -int nghttp2_session_on_priority_received(nghttp2_session *session, - nghttp2_frame *frame); - -/* - * Called when RST_STREAM is received, assuming |frame| is properly - * initialized. - * - * This function returns 0 if it succeeds, or one the following - * negative error codes: - * - * NGHTTP2_ERR_NOMEM - * Out of memory - * NGHTTP2_ERR_CALLBACK_FAILURE - * The read_callback failed - */ -int nghttp2_session_on_rst_stream_received(nghttp2_session *session, - nghttp2_frame *frame); - -/* - * Called when SETTINGS is received, assuming |frame| is properly - * initialized. If |noack| is non-zero, SETTINGS with ACK will not be - * submitted. If |frame| has NGHTTP2_FLAG_ACK flag set, no SETTINGS - * with ACK will not be submitted regardless of |noack|. - * - * This function returns 0 if it succeeds, or one the following - * negative error codes: - * - * NGHTTP2_ERR_NOMEM - * Out of memory - * NGHTTP2_ERR_CALLBACK_FAILURE - * The read_callback failed - * NGHTTP2_ERR_FLOODED - * There are too many items in outbound queue, and this is most - * likely caused by misbehaviour of peer. - */ -int nghttp2_session_on_settings_received(nghttp2_session *session, - nghttp2_frame *frame, int noack); - -/* - * Called when PUSH_PROMISE is received, assuming |frame| is properly - * initialized. - * - * This function returns 0 if it succeeds, or one of the following - * negative error codes: - * - * NGHTTP2_ERR_NOMEM - * Out of memory. - * NGHTTP2_ERR_IGN_HEADER_BLOCK - * Frame was rejected and header block must be decoded but - * result must be ignored. - * NGHTTP2_ERR_CALLBACK_FAILURE - * The read_callback failed - */ -int nghttp2_session_on_push_promise_received(nghttp2_session *session, - nghttp2_frame *frame); - -/* - * Called when PING is received, assuming |frame| is properly - * initialized. - * - * This function returns 0 if it succeeds, or one of the following - * negative error codes: - * - * NGHTTP2_ERR_NOMEM - * Out of memory. - * NGHTTP2_ERR_CALLBACK_FAILURE - * The callback function failed. - * NGHTTP2_ERR_FLOODED - * There are too many items in outbound queue, and this is most - * likely caused by misbehaviour of peer. - */ -int nghttp2_session_on_ping_received(nghttp2_session *session, - nghttp2_frame *frame); - -/* - * Called when GOAWAY is received, assuming |frame| is properly - * initialized. - * - * This function returns 0 if it succeeds, or one of the following - * negative error codes: - * - * NGHTTP2_ERR_NOMEM - * Out of memory. - * NGHTTP2_ERR_CALLBACK_FAILURE - * The callback function failed. - */ -int nghttp2_session_on_goaway_received(nghttp2_session *session, - nghttp2_frame *frame); - -/* - * Called when WINDOW_UPDATE is received, assuming |frame| is properly - * initialized. - * - * This function returns 0 if it succeeds, or one of the following - * negative error codes: - * - * NGHTTP2_ERR_NOMEM - * Out of memory. - * NGHTTP2_ERR_CALLBACK_FAILURE - * The callback function failed. - */ -int nghttp2_session_on_window_update_received(nghttp2_session *session, - nghttp2_frame *frame); - -/* - * Called when ALTSVC is received, assuming |frame| is properly - * initialized. - * - * This function returns 0 if it succeeds, or one of the following - * negative error codes: - * - * NGHTTP2_ERR_CALLBACK_FAILURE - * The callback function failed. - */ -int nghttp2_session_on_altsvc_received(nghttp2_session *session, - nghttp2_frame *frame); - -/* - * Called when ORIGIN is received, assuming |frame| is properly - * initialized. - * - * This function returns 0 if it succeeds, or one of the following - * negative error codes: - * - * NGHTTP2_ERR_CALLBACK_FAILURE - * The callback function failed. - */ -int nghttp2_session_on_origin_received(nghttp2_session *session, - nghttp2_frame *frame); - -/* - * Called when PRIORITY_UPDATE is received, assuming |frame| is - * properly initialized. - * - * This function returns 0 if it succeeds, or one of the following - * negative error codes: - * - * NGHTTP2_ERR_CALLBACK_FAILURE - * The callback function failed. - */ -int nghttp2_session_on_priority_update_received(nghttp2_session *session, - nghttp2_frame *frame); - -/* - * Called when DATA is received, assuming |frame| is properly - * initialized. - * - * This function returns 0 if it succeeds, or one of the following - * negative error codes: - * - * NGHTTP2_ERR_NOMEM - * Out of memory. - * NGHTTP2_ERR_CALLBACK_FAILURE - * The callback function failed. - */ -int nghttp2_session_on_data_received(nghttp2_session *session, - nghttp2_frame *frame); - -/* - * Returns nghttp2_stream* object whose stream ID is |stream_id|. It - * could be NULL if such stream does not exist. This function returns - * NULL if stream is marked as closed. - */ -nghttp2_stream *nghttp2_session_get_stream(nghttp2_session *session, - int32_t stream_id); - -/* - * This function behaves like nghttp2_session_get_stream(), but it - * returns stream object even if it is marked as closed or in - * NGHTTP2_STREAM_IDLE state. - */ -nghttp2_stream *nghttp2_session_get_stream_raw(nghttp2_session *session, - int32_t stream_id); - -/* - * Packs DATA frame |frame| in wire frame format and stores it in - * |bufs|. Payload will be read using |aux_data->data_prd|. The - * length of payload is at most |datamax| bytes. - * - * This function returns 0 if it succeeds, or one of the following - * negative error codes: - * - * NGHTTP2_ERR_DEFERRED - * The DATA frame is postponed. - * NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE - * The read_callback failed (stream error). - * NGHTTP2_ERR_NOMEM - * Out of memory. - * NGHTTP2_ERR_CALLBACK_FAILURE - * The read_callback failed (session error). - */ -int nghttp2_session_pack_data(nghttp2_session *session, nghttp2_bufs *bufs, - size_t datamax, nghttp2_frame *frame, - nghttp2_data_aux_data *aux_data, - nghttp2_stream *stream); - -/* - * Pops and returns next item to send. If there is no such item, - * returns NULL. This function takes into account max concurrent - * streams. That means if session->ob_syn has item and max concurrent - * streams is reached, the even if other queues contain items, then - * this function returns NULL. - */ -nghttp2_outbound_item * -nghttp2_session_pop_next_ob_item(nghttp2_session *session); - -/* - * Returns next item to send. If there is no such item, this function - * returns NULL. This function takes into account max concurrent - * streams. That means if session->ob_syn has item and max concurrent - * streams is reached, the even if other queues contain items, then - * this function returns NULL. - */ -nghttp2_outbound_item * -nghttp2_session_get_next_ob_item(nghttp2_session *session); - -/* - * Updates local settings with the |iv|. The number of elements in the - * array pointed by the |iv| is given by the |niv|. This function - * assumes that the all settings_id member in |iv| are in range 1 to - * NGHTTP2_SETTINGS_MAX, inclusive. - * - * While updating individual stream's local window size, if the window - * size becomes strictly larger than NGHTTP2_MAX_WINDOW_SIZE, - * RST_STREAM is issued against such a stream. - * - * This function returns 0 if it succeeds, or one of the following - * negative error codes: - * - * NGHTTP2_ERR_NOMEM - * Out of memory - */ -int nghttp2_session_update_local_settings(nghttp2_session *session, - nghttp2_settings_entry *iv, - size_t niv); - -/* - * Re-prioritize |stream|. The new priority specification is - * |pri_spec|. Caller must ensure that stream->hd.stream_id != - * pri_spec->stream_id. - * - * This function does not adjust the number of idle streams. The - * caller should call nghttp2_session_adjust_idle_stream() later. - * - * This function returns 0 if it succeeds, or one of the following - * negative error codes: - * - * NGHTTP2_ERR_NOMEM - * Out of memory - */ -int nghttp2_session_reprioritize_stream(nghttp2_session *session, - nghttp2_stream *stream, - const nghttp2_priority_spec *pri_spec); - -/* - * Terminates current |session| with the |error_code|. The |reason| - * is NULL-terminated debug string. - * - * This function returns 0 if it succeeds, or one of the following - * negative error codes: - * - * NGHTTP2_ERR_NOMEM - * Out of memory. - * NGHTTP2_ERR_INVALID_ARGUMENT - * The |reason| is too long. - */ -int nghttp2_session_terminate_session_with_reason(nghttp2_session *session, - uint32_t error_code, - const char *reason); - -/* - * Accumulates received bytes |delta_size| for connection-level flow - * control and decides whether to send WINDOW_UPDATE to the - * connection. If NGHTTP2_OPT_NO_AUTO_WINDOW_UPDATE is set, - * WINDOW_UPDATE will not be sent. - * - * This function returns 0 if it succeeds, or one of the following - * negative error codes: - * - * NGHTTP2_ERR_NOMEM - * Out of memory. - */ -int nghttp2_session_update_recv_connection_window_size(nghttp2_session *session, - size_t delta_size); - -/* - * Accumulates received bytes |delta_size| for stream-level flow - * control and decides whether to send WINDOW_UPDATE to that stream. - * If NGHTTP2_OPT_NO_AUTO_WINDOW_UPDATE is set, WINDOW_UPDATE will not - * be sent. - * - * This function returns 0 if it succeeds, or one of the following - * negative error codes: - * - * NGHTTP2_ERR_NOMEM - * Out of memory. - */ -int nghttp2_session_update_recv_stream_window_size(nghttp2_session *session, - nghttp2_stream *stream, - size_t delta_size, - int send_window_update); - -#endif /* NGHTTP2_SESSION_H */ diff --git a/3rdparty/exported/nghttp2/nghttp2_stream.c b/3rdparty/exported/nghttp2/nghttp2_stream.c deleted file mode 100644 index f23624479037..000000000000 --- a/3rdparty/exported/nghttp2/nghttp2_stream.c +++ /dev/null @@ -1,1016 +0,0 @@ -/* - * nghttp2 - HTTP/2 C Library - * - * Copyright (c) 2012 Tatsuhiro Tsujikawa - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE - * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION - * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION - * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ -#include "nghttp2_stream.h" - -#include -#include - -#include "nghttp2_session.h" -#include "nghttp2_helper.h" -#include "nghttp2_debug.h" -#include "nghttp2_frame.h" - -/* Maximum distance between any two stream's cycle in the same - priority queue. Imagine stream A's cycle is A, and stream B's - cycle is B, and A < B. The cycle is unsigned 32 bit integer, it - may get overflow. Because of how we calculate the next cycle - value, if B - A is less than or equals to - NGHTTP2_MAX_CYCLE_DISTANCE, A and B are in the same scale, in other - words, B is really greater than or equal to A. Otherwise, A is a - result of overflow, and it is actually A > B if we consider that - fact. */ -#define NGHTTP2_MAX_CYCLE_DISTANCE \ - ((uint64_t)NGHTTP2_MAX_FRAME_SIZE_MAX * 256 + 255) - -static int stream_less(const void *lhsx, const void *rhsx) { - const nghttp2_stream *lhs, *rhs; - - lhs = nghttp2_struct_of(lhsx, nghttp2_stream, pq_entry); - rhs = nghttp2_struct_of(rhsx, nghttp2_stream, pq_entry); - - if (lhs->cycle == rhs->cycle) { - return lhs->seq < rhs->seq; - } - - return rhs->cycle - lhs->cycle <= NGHTTP2_MAX_CYCLE_DISTANCE; -} - -void nghttp2_stream_init(nghttp2_stream *stream, int32_t stream_id, - uint8_t flags, nghttp2_stream_state initial_state, - int32_t weight, int32_t remote_initial_window_size, - int32_t local_initial_window_size, - void *stream_user_data, nghttp2_mem *mem) { - nghttp2_pq_init(&stream->obq, stream_less, mem); - - stream->stream_id = stream_id; - stream->flags = flags; - stream->state = initial_state; - stream->shut_flags = NGHTTP2_SHUT_NONE; - stream->stream_user_data = stream_user_data; - stream->item = NULL; - stream->remote_window_size = remote_initial_window_size; - stream->local_window_size = local_initial_window_size; - stream->recv_window_size = 0; - stream->consumed_size = 0; - stream->recv_reduction = 0; - stream->window_update_queued = 0; - - stream->dep_prev = NULL; - stream->dep_next = NULL; - stream->sib_prev = NULL; - stream->sib_next = NULL; - - stream->closed_prev = NULL; - stream->closed_next = NULL; - - stream->weight = weight; - stream->sum_dep_weight = 0; - - stream->http_flags = NGHTTP2_HTTP_FLAG_NONE; - stream->content_length = -1; - stream->recv_content_length = 0; - stream->status_code = -1; - - stream->queued = 0; - stream->descendant_last_cycle = 0; - stream->cycle = 0; - stream->pending_penalty = 0; - stream->descendant_next_seq = 0; - stream->seq = 0; - stream->last_writelen = 0; - - stream->extpri = stream->http_extpri = NGHTTP2_EXTPRI_DEFAULT_URGENCY; -} - -void nghttp2_stream_free(nghttp2_stream *stream) { - nghttp2_pq_free(&stream->obq); - /* We don't free stream->item. If it is assigned to aob, then - active_outbound_item_reset() will delete it. Otherwise, - nghttp2_stream_close() or session_del() will delete it. */ -} - -void nghttp2_stream_shutdown(nghttp2_stream *stream, nghttp2_shut_flag flag) { - stream->shut_flags = (uint8_t)(stream->shut_flags | flag); -} - -/* - * Returns nonzero if |stream| is active. This function does not take - * into account its descendants. - */ -static int stream_active(nghttp2_stream *stream) { - return stream->item && - (stream->flags & NGHTTP2_STREAM_FLAG_DEFERRED_ALL) == 0; -} - -/* - * Returns nonzero if |stream| or one of its descendants is active - */ -static int stream_subtree_active(nghttp2_stream *stream) { - return stream_active(stream) || !nghttp2_pq_empty(&stream->obq); -} - -/* - * Returns next cycle for |stream|. - */ -static void stream_next_cycle(nghttp2_stream *stream, uint64_t last_cycle) { - uint64_t penalty; - - penalty = (uint64_t)stream->last_writelen * NGHTTP2_MAX_WEIGHT + - stream->pending_penalty; - - stream->cycle = last_cycle + penalty / (uint32_t)stream->weight; - stream->pending_penalty = (uint32_t)(penalty % (uint32_t)stream->weight); -} - -static int stream_obq_push(nghttp2_stream *dep_stream, nghttp2_stream *stream) { - int rv; - - for (; dep_stream && !stream->queued; - stream = dep_stream, dep_stream = dep_stream->dep_prev) { - stream_next_cycle(stream, dep_stream->descendant_last_cycle); - stream->seq = dep_stream->descendant_next_seq++; - - DEBUGF("stream: stream=%d obq push cycle=%lu\n", stream->stream_id, - stream->cycle); - - DEBUGF("stream: push stream %d to stream %d\n", stream->stream_id, - dep_stream->stream_id); - - rv = nghttp2_pq_push(&dep_stream->obq, &stream->pq_entry); - if (rv != 0) { - return rv; - } - stream->queued = 1; - } - - return 0; -} - -/* - * Removes |stream| from parent's obq. If removal of |stream| makes - * parent's obq empty, and parent is not active, then parent is also - * removed. This process is repeated recursively. - */ -static void stream_obq_remove(nghttp2_stream *stream) { - nghttp2_stream *dep_stream; - - dep_stream = stream->dep_prev; - - if (!stream->queued) { - return; - } - - for (; dep_stream; stream = dep_stream, dep_stream = dep_stream->dep_prev) { - DEBUGF("stream: remove stream %d from stream %d\n", stream->stream_id, - dep_stream->stream_id); - - nghttp2_pq_remove(&dep_stream->obq, &stream->pq_entry); - - assert(stream->queued); - - stream->queued = 0; - stream->cycle = 0; - stream->pending_penalty = 0; - stream->descendant_last_cycle = 0; - stream->last_writelen = 0; - - if (stream_subtree_active(dep_stream)) { - return; - } - } -} - -/* - * Moves |stream| from |src|'s obq to |dest|'s obq. Removal from - * |src|'s obq is just done calling nghttp2_pq_remove(), so it does - * not recursively remove |src| and ancestors, like - * stream_obq_remove(). - */ -static int stream_obq_move(nghttp2_stream *dest, nghttp2_stream *src, - nghttp2_stream *stream) { - if (!stream->queued) { - return 0; - } - - DEBUGF("stream: remove stream %d from stream %d (move)\n", stream->stream_id, - src->stream_id); - - nghttp2_pq_remove(&src->obq, &stream->pq_entry); - stream->queued = 0; - - return stream_obq_push(dest, stream); -} - -void nghttp2_stream_reschedule(nghttp2_stream *stream) { - nghttp2_stream *dep_stream; - - assert(stream->queued); - - dep_stream = stream->dep_prev; - - for (; dep_stream; stream = dep_stream, dep_stream = dep_stream->dep_prev) { - nghttp2_pq_remove(&dep_stream->obq, &stream->pq_entry); - - stream_next_cycle(stream, dep_stream->descendant_last_cycle); - stream->seq = dep_stream->descendant_next_seq++; - - nghttp2_pq_push(&dep_stream->obq, &stream->pq_entry); - - DEBUGF("stream: stream=%d obq resched cycle=%lu\n", stream->stream_id, - stream->cycle); - - dep_stream->last_writelen = stream->last_writelen; - } -} - -void nghttp2_stream_change_weight(nghttp2_stream *stream, int32_t weight) { - nghttp2_stream *dep_stream; - uint64_t last_cycle; - int32_t old_weight; - uint64_t wlen_penalty; - - if (stream->weight == weight) { - return; - } - - old_weight = stream->weight; - stream->weight = weight; - - dep_stream = stream->dep_prev; - - if (!dep_stream) { - return; - } - - dep_stream->sum_dep_weight += weight - old_weight; - - if (!stream->queued) { - return; - } - - nghttp2_pq_remove(&dep_stream->obq, &stream->pq_entry); - - wlen_penalty = (uint64_t)stream->last_writelen * NGHTTP2_MAX_WEIGHT; - - /* Compute old stream->pending_penalty we used to calculate - stream->cycle */ - stream->pending_penalty = - (uint32_t)((stream->pending_penalty + (uint32_t)old_weight - - (wlen_penalty % (uint32_t)old_weight)) % - (uint32_t)old_weight); - - last_cycle = stream->cycle - - (wlen_penalty + stream->pending_penalty) / (uint32_t)old_weight; - - /* Now we have old stream->pending_penalty and new stream->weight in - place */ - stream_next_cycle(stream, last_cycle); - - if (dep_stream->descendant_last_cycle - stream->cycle <= - NGHTTP2_MAX_CYCLE_DISTANCE) { - stream->cycle = dep_stream->descendant_last_cycle; - } - - /* Continue to use same stream->seq */ - - nghttp2_pq_push(&dep_stream->obq, &stream->pq_entry); - - DEBUGF("stream: stream=%d obq resched cycle=%lu\n", stream->stream_id, - stream->cycle); -} - -static nghttp2_stream *stream_last_sib(nghttp2_stream *stream) { - for (; stream->sib_next; stream = stream->sib_next) - ; - - return stream; -} - -int32_t nghttp2_stream_dep_distributed_weight(nghttp2_stream *stream, - int32_t weight) { - weight = stream->weight * weight / stream->sum_dep_weight; - - return nghttp2_max_int32(1, weight); -} - -#ifdef STREAM_DEP_DEBUG - -static void ensure_inactive(nghttp2_stream *stream) { - nghttp2_stream *si; - - if (stream->queued) { - fprintf(stderr, "stream(%p)=%d, stream->queued = 1; want 0\n", stream, - stream->stream_id); - assert(0); - } - - if (stream_active(stream)) { - fprintf(stderr, "stream(%p)=%d, stream_active(stream) = 1; want 0\n", - stream, stream->stream_id); - assert(0); - } - - if (!nghttp2_pq_empty(&stream->obq)) { - fprintf(stderr, "stream(%p)=%d, nghttp2_pq_size() = %zu; want 0\n", stream, - stream->stream_id, nghttp2_pq_size(&stream->obq)); - assert(0); - } - - for (si = stream->dep_next; si; si = si->sib_next) { - ensure_inactive(si); - } -} - -static void check_queued(nghttp2_stream *stream) { - nghttp2_stream *si; - int queued; - - if (stream->queued) { - if (!stream_subtree_active(stream)) { - fprintf(stderr, - "stream(%p)=%d, stream->queued == 1, but " - "stream_active() == %d and nghttp2_pq_size(&stream->obq) = %zu\n", - stream, stream->stream_id, stream_active(stream), - nghttp2_pq_size(&stream->obq)); - assert(0); - } - if (!stream_active(stream)) { - queued = 0; - for (si = stream->dep_next; si; si = si->sib_next) { - if (si->queued) { - ++queued; - } - } - if (queued == 0) { - fprintf(stderr, - "stream(%p)=%d, stream->queued == 1, and " - "!stream_active(), but no descendants is queued\n", - stream, stream->stream_id); - assert(0); - } - } - - for (si = stream->dep_next; si; si = si->sib_next) { - check_queued(si); - } - } else { - if (stream_active(stream) || !nghttp2_pq_empty(&stream->obq)) { - fprintf(stderr, - "stream(%p) = %d, stream->queued == 0, but " - "stream_active(stream) == %d and " - "nghttp2_pq_size(&stream->obq) = %zu\n", - stream, stream->stream_id, stream_active(stream), - nghttp2_pq_size(&stream->obq)); - assert(0); - } - for (si = stream->dep_next; si; si = si->sib_next) { - ensure_inactive(si); - } - } -} - -static void check_sum_dep(nghttp2_stream *stream) { - nghttp2_stream *si; - int32_t n = 0; - for (si = stream->dep_next; si; si = si->sib_next) { - n += si->weight; - } - if (n != stream->sum_dep_weight) { - fprintf(stderr, "stream(%p)=%d, sum_dep_weight = %d; want %d\n", stream, - stream->stream_id, n, stream->sum_dep_weight); - assert(0); - } - for (si = stream->dep_next; si; si = si->sib_next) { - check_sum_dep(si); - } -} - -static void check_dep_prev(nghttp2_stream *stream) { - nghttp2_stream *si; - for (si = stream->dep_next; si; si = si->sib_next) { - if (si->dep_prev != stream) { - fprintf(stderr, "si->dep_prev = %p; want %p\n", si->dep_prev, stream); - assert(0); - } - check_dep_prev(si); - } -} - -#endif /* STREAM_DEP_DEBUG */ - -#ifdef STREAM_DEP_DEBUG -static void validate_tree(nghttp2_stream *stream) { - nghttp2_stream *si; - - if (!stream) { - return; - } - - for (; stream->dep_prev; stream = stream->dep_prev) - ; - - assert(stream->stream_id == 0); - assert(!stream->queued); - - fprintf(stderr, "checking...\n"); - if (nghttp2_pq_empty(&stream->obq)) { - fprintf(stderr, "root obq empty\n"); - for (si = stream->dep_next; si; si = si->sib_next) { - ensure_inactive(si); - } - } else { - for (si = stream->dep_next; si; si = si->sib_next) { - check_queued(si); - } - } - - check_sum_dep(stream); - check_dep_prev(stream); -} -#else /* !STREAM_DEP_DEBUG */ -static void validate_tree(nghttp2_stream *stream) { (void)stream; } -#endif /* !STREAM_DEP_DEBUG*/ - -static int stream_update_dep_on_attach_item(nghttp2_stream *stream) { - int rv; - - rv = stream_obq_push(stream->dep_prev, stream); - if (rv != 0) { - return rv; - } - - validate_tree(stream); - return 0; -} - -static void stream_update_dep_on_detach_item(nghttp2_stream *stream) { - if (nghttp2_pq_empty(&stream->obq)) { - stream_obq_remove(stream); - } - - validate_tree(stream); -} - -int nghttp2_stream_attach_item(nghttp2_stream *stream, - nghttp2_outbound_item *item) { - int rv; - - assert((stream->flags & NGHTTP2_STREAM_FLAG_DEFERRED_ALL) == 0); - assert(stream->item == NULL); - - DEBUGF("stream: stream=%d attach item=%p\n", stream->stream_id, item); - - stream->item = item; - - if (stream->flags & NGHTTP2_STREAM_FLAG_NO_RFC7540_PRIORITIES) { - return 0; - } - - rv = stream_update_dep_on_attach_item(stream); - if (rv != 0) { - /* This may relave stream->queued == 1, but stream->item == NULL. - But only consequence of this error is fatal one, and session - destruction. In that execution path, these inconsistency does - not matter. */ - stream->item = NULL; - return rv; - } - - return 0; -} - -void nghttp2_stream_detach_item(nghttp2_stream *stream) { - DEBUGF("stream: stream=%d detach item=%p\n", stream->stream_id, stream->item); - - stream->item = NULL; - stream->flags = (uint8_t)(stream->flags & ~NGHTTP2_STREAM_FLAG_DEFERRED_ALL); - - if (stream->flags & NGHTTP2_STREAM_FLAG_NO_RFC7540_PRIORITIES) { - return; - } - - stream_update_dep_on_detach_item(stream); -} - -void nghttp2_stream_defer_item(nghttp2_stream *stream, uint8_t flags) { - assert(stream->item); - - DEBUGF("stream: stream=%d defer item=%p cause=%02x\n", stream->stream_id, - stream->item, flags); - - stream->flags |= flags; - - if (stream->flags & NGHTTP2_STREAM_FLAG_NO_RFC7540_PRIORITIES) { - return; - } - - stream_update_dep_on_detach_item(stream); -} - -int nghttp2_stream_resume_deferred_item(nghttp2_stream *stream, uint8_t flags) { - assert(stream->item); - - DEBUGF("stream: stream=%d resume item=%p flags=%02x\n", stream->stream_id, - stream->item, flags); - - stream->flags = (uint8_t)(stream->flags & ~flags); - - if (stream->flags & NGHTTP2_STREAM_FLAG_DEFERRED_ALL) { - return 0; - } - - if (stream->flags & NGHTTP2_STREAM_FLAG_NO_RFC7540_PRIORITIES) { - return 0; - } - - return stream_update_dep_on_attach_item(stream); -} - -int nghttp2_stream_check_deferred_item(nghttp2_stream *stream) { - return stream->item && (stream->flags & NGHTTP2_STREAM_FLAG_DEFERRED_ALL); -} - -int nghttp2_stream_check_deferred_by_flow_control(nghttp2_stream *stream) { - return stream->item && - (stream->flags & NGHTTP2_STREAM_FLAG_DEFERRED_FLOW_CONTROL); -} - -static int update_initial_window_size(int32_t *window_size_ptr, - int32_t new_initial_window_size, - int32_t old_initial_window_size) { - int64_t new_window_size = (int64_t)(*window_size_ptr) + - new_initial_window_size - old_initial_window_size; - if (INT32_MIN > new_window_size || - new_window_size > NGHTTP2_MAX_WINDOW_SIZE) { - return -1; - } - *window_size_ptr = (int32_t)new_window_size; - return 0; -} - -int nghttp2_stream_update_remote_initial_window_size( - nghttp2_stream *stream, int32_t new_initial_window_size, - int32_t old_initial_window_size) { - return update_initial_window_size(&stream->remote_window_size, - new_initial_window_size, - old_initial_window_size); -} - -int nghttp2_stream_update_local_initial_window_size( - nghttp2_stream *stream, int32_t new_initial_window_size, - int32_t old_initial_window_size) { - return update_initial_window_size(&stream->local_window_size, - new_initial_window_size, - old_initial_window_size); -} - -void nghttp2_stream_promise_fulfilled(nghttp2_stream *stream) { - stream->state = NGHTTP2_STREAM_OPENED; - stream->flags = (uint8_t)(stream->flags & ~NGHTTP2_STREAM_FLAG_PUSH); -} - -int nghttp2_stream_dep_find_ancestor(nghttp2_stream *stream, - nghttp2_stream *target) { - for (; stream; stream = stream->dep_prev) { - if (stream == target) { - return 1; - } - } - return 0; -} - -int nghttp2_stream_dep_insert(nghttp2_stream *dep_stream, - nghttp2_stream *stream) { - nghttp2_stream *si; - int rv; - - DEBUGF("stream: dep_insert dep_stream(%p)=%d, stream(%p)=%d\n", dep_stream, - dep_stream->stream_id, stream, stream->stream_id); - - stream->sum_dep_weight = dep_stream->sum_dep_weight; - dep_stream->sum_dep_weight = stream->weight; - - if (dep_stream->dep_next) { - for (si = dep_stream->dep_next; si; si = si->sib_next) { - si->dep_prev = stream; - if (si->queued) { - rv = stream_obq_move(stream, dep_stream, si); - if (rv != 0) { - return rv; - } - } - } - - if (stream_subtree_active(stream)) { - rv = stream_obq_push(dep_stream, stream); - if (rv != 0) { - return rv; - } - } - - stream->dep_next = dep_stream->dep_next; - } - - dep_stream->dep_next = stream; - stream->dep_prev = dep_stream; - - validate_tree(stream); - - return 0; -} - -static void set_dep_prev(nghttp2_stream *stream, nghttp2_stream *dep) { - for (; stream; stream = stream->sib_next) { - stream->dep_prev = dep; - } -} - -static void link_dep(nghttp2_stream *dep_stream, nghttp2_stream *stream) { - dep_stream->dep_next = stream; - if (stream) { - stream->dep_prev = dep_stream; - } -} - -static void link_sib(nghttp2_stream *a, nghttp2_stream *b) { - a->sib_next = b; - if (b) { - b->sib_prev = a; - } -} - -static void insert_link_dep(nghttp2_stream *dep_stream, - nghttp2_stream *stream) { - nghttp2_stream *sib_next; - - assert(stream->sib_prev == NULL); - - sib_next = dep_stream->dep_next; - - link_sib(stream, sib_next); - - link_dep(dep_stream, stream); -} - -static void unlink_sib(nghttp2_stream *stream) { - nghttp2_stream *prev, *next, *dep_next; - - prev = stream->sib_prev; - dep_next = stream->dep_next; - - assert(prev); - - if (dep_next) { - /* - * prev--stream(--sib_next--...) - * | - * dep_next - */ - - link_sib(prev, dep_next); - - set_dep_prev(dep_next, stream->dep_prev); - - if (stream->sib_next) { - link_sib(stream_last_sib(dep_next), stream->sib_next); - } - } else { - /* - * prev--stream(--sib_next--...) - */ - next = stream->sib_next; - - prev->sib_next = next; - - if (next) { - next->sib_prev = prev; - } - } -} - -static void unlink_dep(nghttp2_stream *stream) { - nghttp2_stream *prev, *next, *dep_next; - - prev = stream->dep_prev; - dep_next = stream->dep_next; - - assert(prev); - - if (dep_next) { - /* - * prev - * | - * stream(--sib_next--...) - * | - * dep_next - */ - link_dep(prev, dep_next); - - set_dep_prev(dep_next, stream->dep_prev); - - if (stream->sib_next) { - link_sib(stream_last_sib(dep_next), stream->sib_next); - } - - } else if (stream->sib_next) { - /* - * prev - * | - * stream--sib_next - */ - next = stream->sib_next; - - next->sib_prev = NULL; - - link_dep(prev, next); - } else { - prev->dep_next = NULL; - } -} - -void nghttp2_stream_dep_add(nghttp2_stream *dep_stream, - nghttp2_stream *stream) { - DEBUGF("stream: dep_add dep_stream(%p)=%d, stream(%p)=%d\n", dep_stream, - dep_stream->stream_id, stream, stream->stream_id); - - dep_stream->sum_dep_weight += stream->weight; - - if (dep_stream->dep_next == NULL) { - link_dep(dep_stream, stream); - } else { - insert_link_dep(dep_stream, stream); - } - - validate_tree(stream); -} - -int nghttp2_stream_dep_remove(nghttp2_stream *stream) { - nghttp2_stream *dep_prev, *si; - int32_t sum_dep_weight_delta; - int rv; - - DEBUGF("stream: dep_remove stream(%p)=%d\n", stream, stream->stream_id); - - /* Distribute weight of |stream| to direct descendants */ - sum_dep_weight_delta = -stream->weight; - - for (si = stream->dep_next; si; si = si->sib_next) { - si->weight = nghttp2_stream_dep_distributed_weight(stream, si->weight); - - sum_dep_weight_delta += si->weight; - - if (si->queued) { - rv = stream_obq_move(stream->dep_prev, stream, si); - if (rv != 0) { - return rv; - } - } - } - - assert(stream->dep_prev); - - dep_prev = stream->dep_prev; - - dep_prev->sum_dep_weight += sum_dep_weight_delta; - - if (stream->queued) { - stream_obq_remove(stream); - } - - if (stream->sib_prev) { - unlink_sib(stream); - } else { - unlink_dep(stream); - } - - stream->sum_dep_weight = 0; - - stream->dep_prev = NULL; - stream->dep_next = NULL; - stream->sib_prev = NULL; - stream->sib_next = NULL; - - validate_tree(dep_prev); - - return 0; -} - -int nghttp2_stream_dep_insert_subtree(nghttp2_stream *dep_stream, - nghttp2_stream *stream) { - nghttp2_stream *last_sib; - nghttp2_stream *dep_next; - nghttp2_stream *si; - int rv; - - DEBUGF("stream: dep_insert_subtree dep_stream(%p)=%d stream(%p)=%d\n", - dep_stream, dep_stream->stream_id, stream, stream->stream_id); - - stream->sum_dep_weight += dep_stream->sum_dep_weight; - dep_stream->sum_dep_weight = stream->weight; - - if (dep_stream->dep_next) { - dep_next = dep_stream->dep_next; - - link_dep(dep_stream, stream); - - if (stream->dep_next) { - last_sib = stream_last_sib(stream->dep_next); - - link_sib(last_sib, dep_next); - } else { - link_dep(stream, dep_next); - } - - for (si = dep_next; si; si = si->sib_next) { - si->dep_prev = stream; - if (si->queued) { - rv = stream_obq_move(stream, dep_stream, si); - if (rv != 0) { - return rv; - } - } - } - } else { - link_dep(dep_stream, stream); - } - - if (stream_subtree_active(stream)) { - rv = stream_obq_push(dep_stream, stream); - if (rv != 0) { - return rv; - } - } - - validate_tree(dep_stream); - - return 0; -} - -int nghttp2_stream_dep_add_subtree(nghttp2_stream *dep_stream, - nghttp2_stream *stream) { - int rv; - - DEBUGF("stream: dep_add_subtree dep_stream(%p)=%d stream(%p)=%d\n", - dep_stream, dep_stream->stream_id, stream, stream->stream_id); - - dep_stream->sum_dep_weight += stream->weight; - - if (dep_stream->dep_next) { - insert_link_dep(dep_stream, stream); - } else { - link_dep(dep_stream, stream); - } - - if (stream_subtree_active(stream)) { - rv = stream_obq_push(dep_stream, stream); - if (rv != 0) { - return rv; - } - } - - validate_tree(dep_stream); - - return 0; -} - -void nghttp2_stream_dep_remove_subtree(nghttp2_stream *stream) { - nghttp2_stream *next, *dep_prev; - - DEBUGF("stream: dep_remove_subtree stream(%p)=%d\n", stream, - stream->stream_id); - - assert(stream->dep_prev); - - dep_prev = stream->dep_prev; - - if (stream->sib_prev) { - link_sib(stream->sib_prev, stream->sib_next); - } else { - next = stream->sib_next; - - link_dep(dep_prev, next); - - if (next) { - next->sib_prev = NULL; - } - } - - dep_prev->sum_dep_weight -= stream->weight; - - if (stream->queued) { - stream_obq_remove(stream); - } - - validate_tree(dep_prev); - - stream->sib_prev = NULL; - stream->sib_next = NULL; - stream->dep_prev = NULL; -} - -int nghttp2_stream_in_dep_tree(nghttp2_stream *stream) { - return stream->dep_prev || stream->dep_next || stream->sib_prev || - stream->sib_next; -} - -nghttp2_outbound_item * -nghttp2_stream_next_outbound_item(nghttp2_stream *stream) { - nghttp2_pq_entry *ent; - nghttp2_stream *si; - - for (;;) { - if (stream_active(stream)) { - /* Update ascendant's descendant_last_cycle here, so that we can - assure that new stream is scheduled based on it. */ - for (si = stream; si->dep_prev; si = si->dep_prev) { - si->dep_prev->descendant_last_cycle = si->cycle; - } - return stream->item; - } - ent = nghttp2_pq_top(&stream->obq); - if (!ent) { - return NULL; - } - stream = nghttp2_struct_of(ent, nghttp2_stream, pq_entry); - } -} - -nghttp2_stream_proto_state nghttp2_stream_get_state(nghttp2_stream *stream) { - if (stream->flags & NGHTTP2_STREAM_FLAG_CLOSED) { - return NGHTTP2_STREAM_STATE_CLOSED; - } - - if (stream->flags & NGHTTP2_STREAM_FLAG_PUSH) { - if (stream->shut_flags & NGHTTP2_SHUT_RD) { - return NGHTTP2_STREAM_STATE_RESERVED_LOCAL; - } - - if (stream->shut_flags & NGHTTP2_SHUT_WR) { - return NGHTTP2_STREAM_STATE_RESERVED_REMOTE; - } - } - - if (stream->shut_flags & NGHTTP2_SHUT_RD) { - return NGHTTP2_STREAM_STATE_HALF_CLOSED_REMOTE; - } - - if (stream->shut_flags & NGHTTP2_SHUT_WR) { - return NGHTTP2_STREAM_STATE_HALF_CLOSED_LOCAL; - } - - if (stream->state == NGHTTP2_STREAM_IDLE) { - return NGHTTP2_STREAM_STATE_IDLE; - } - - return NGHTTP2_STREAM_STATE_OPEN; -} - -nghttp2_stream *nghttp2_stream_get_parent(nghttp2_stream *stream) { - return stream->dep_prev; -} - -nghttp2_stream *nghttp2_stream_get_next_sibling(nghttp2_stream *stream) { - return stream->sib_next; -} - -nghttp2_stream *nghttp2_stream_get_previous_sibling(nghttp2_stream *stream) { - return stream->sib_prev; -} - -nghttp2_stream *nghttp2_stream_get_first_child(nghttp2_stream *stream) { - return stream->dep_next; -} - -int32_t nghttp2_stream_get_weight(nghttp2_stream *stream) { - return stream->weight; -} - -int32_t nghttp2_stream_get_sum_dependency_weight(nghttp2_stream *stream) { - return stream->sum_dep_weight; -} - -int32_t nghttp2_stream_get_stream_id(nghttp2_stream *stream) { - return stream->stream_id; -} diff --git a/3rdparty/exported/nghttp2/nghttp2_stream.h b/3rdparty/exported/nghttp2/nghttp2_stream.h deleted file mode 100644 index 28add165469d..000000000000 --- a/3rdparty/exported/nghttp2/nghttp2_stream.h +++ /dev/null @@ -1,440 +0,0 @@ -/* - * nghttp2 - HTTP/2 C Library - * - * Copyright (c) 2012 Tatsuhiro Tsujikawa - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE - * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION - * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION - * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ -#ifndef NGHTTP2_STREAM_H -#define NGHTTP2_STREAM_H - -#ifdef HAVE_CONFIG_H -# include -#endif /* HAVE_CONFIG_H */ - -#include -#include "nghttp2_outbound_item.h" -#include "nghttp2_map.h" -#include "nghttp2_pq.h" -#include "nghttp2_int.h" - -/* - * If local peer is stream initiator: - * NGHTTP2_STREAM_OPENING : upon sending request HEADERS - * NGHTTP2_STREAM_OPENED : upon receiving response HEADERS - * NGHTTP2_STREAM_CLOSING : upon queuing RST_STREAM - * - * If remote peer is stream initiator: - * NGHTTP2_STREAM_OPENING : upon receiving request HEADERS - * NGHTTP2_STREAM_OPENED : upon sending response HEADERS - * NGHTTP2_STREAM_CLOSING : upon queuing RST_STREAM - */ -typedef enum { - /* Initial state */ - NGHTTP2_STREAM_INITIAL, - /* For stream initiator: request HEADERS has been sent, but response - HEADERS has not been received yet. For receiver: request HEADERS - has been received, but it does not send response HEADERS yet. */ - NGHTTP2_STREAM_OPENING, - /* For stream initiator: response HEADERS is received. For receiver: - response HEADERS is sent. */ - NGHTTP2_STREAM_OPENED, - /* RST_STREAM is received, but somehow we need to keep stream in - memory. */ - NGHTTP2_STREAM_CLOSING, - /* PUSH_PROMISE is received or sent */ - NGHTTP2_STREAM_RESERVED, - /* Stream is created in this state if it is used as anchor in - dependency tree. */ - NGHTTP2_STREAM_IDLE -} nghttp2_stream_state; - -typedef enum { - NGHTTP2_SHUT_NONE = 0, - /* Indicates further receptions will be disallowed. */ - NGHTTP2_SHUT_RD = 0x01, - /* Indicates further transmissions will be disallowed. */ - NGHTTP2_SHUT_WR = 0x02, - /* Indicates both further receptions and transmissions will be - disallowed. */ - NGHTTP2_SHUT_RDWR = NGHTTP2_SHUT_RD | NGHTTP2_SHUT_WR -} nghttp2_shut_flag; - -typedef enum { - NGHTTP2_STREAM_FLAG_NONE = 0, - /* Indicates that this stream is pushed stream and not opened - yet. */ - NGHTTP2_STREAM_FLAG_PUSH = 0x01, - /* Indicates that this stream was closed */ - NGHTTP2_STREAM_FLAG_CLOSED = 0x02, - /* Indicates the item is deferred due to flow control. */ - NGHTTP2_STREAM_FLAG_DEFERRED_FLOW_CONTROL = 0x04, - /* Indicates the item is deferred by user callback */ - NGHTTP2_STREAM_FLAG_DEFERRED_USER = 0x08, - /* bitwise OR of NGHTTP2_STREAM_FLAG_DEFERRED_FLOW_CONTROL and - NGHTTP2_STREAM_FLAG_DEFERRED_USER. */ - NGHTTP2_STREAM_FLAG_DEFERRED_ALL = 0x0c, - /* Indicates that this stream is not subject to RFC7540 - priorities scheme. */ - NGHTTP2_STREAM_FLAG_NO_RFC7540_PRIORITIES = 0x10, - /* Ignore client RFC 9218 priority signal. */ - NGHTTP2_STREAM_FLAG_IGNORE_CLIENT_PRIORITIES = 0x20, - /* Indicates that RFC 9113 leading and trailing white spaces - validation against a field value is not performed. */ - NGHTTP2_STREAM_FLAG_NO_RFC9113_LEADING_AND_TRAILING_WS_VALIDATION = 0x40, -} nghttp2_stream_flag; - -/* HTTP related flags to enforce HTTP semantics */ -typedef enum { - NGHTTP2_HTTP_FLAG_NONE = 0, - /* header field seen so far */ - NGHTTP2_HTTP_FLAG__AUTHORITY = 1, - NGHTTP2_HTTP_FLAG__PATH = 1 << 1, - NGHTTP2_HTTP_FLAG__METHOD = 1 << 2, - NGHTTP2_HTTP_FLAG__SCHEME = 1 << 3, - /* host is not pseudo header, but we require either host or - :authority */ - NGHTTP2_HTTP_FLAG_HOST = 1 << 4, - NGHTTP2_HTTP_FLAG__STATUS = 1 << 5, - /* required header fields for HTTP request except for CONNECT - method. */ - NGHTTP2_HTTP_FLAG_REQ_HEADERS = NGHTTP2_HTTP_FLAG__METHOD | - NGHTTP2_HTTP_FLAG__PATH | - NGHTTP2_HTTP_FLAG__SCHEME, - NGHTTP2_HTTP_FLAG_PSEUDO_HEADER_DISALLOWED = 1 << 6, - /* HTTP method flags */ - NGHTTP2_HTTP_FLAG_METH_CONNECT = 1 << 7, - NGHTTP2_HTTP_FLAG_METH_HEAD = 1 << 8, - NGHTTP2_HTTP_FLAG_METH_OPTIONS = 1 << 9, - NGHTTP2_HTTP_FLAG_METH_UPGRADE_WORKAROUND = 1 << 10, - NGHTTP2_HTTP_FLAG_METH_ALL = - NGHTTP2_HTTP_FLAG_METH_CONNECT | NGHTTP2_HTTP_FLAG_METH_HEAD | - NGHTTP2_HTTP_FLAG_METH_OPTIONS | NGHTTP2_HTTP_FLAG_METH_UPGRADE_WORKAROUND, - /* :path category */ - /* path starts with "/" */ - NGHTTP2_HTTP_FLAG_PATH_REGULAR = 1 << 11, - /* path "*" */ - NGHTTP2_HTTP_FLAG_PATH_ASTERISK = 1 << 12, - /* scheme */ - /* "http" or "https" scheme */ - NGHTTP2_HTTP_FLAG_SCHEME_HTTP = 1 << 13, - /* set if final response is expected */ - NGHTTP2_HTTP_FLAG_EXPECT_FINAL_RESPONSE = 1 << 14, - NGHTTP2_HTTP_FLAG__PROTOCOL = 1 << 15, - /* set if priority header field is received */ - NGHTTP2_HTTP_FLAG_PRIORITY = 1 << 16, - /* set if an error is encountered while parsing priority header - field */ - NGHTTP2_HTTP_FLAG_BAD_PRIORITY = 1 << 17, -} nghttp2_http_flag; - -struct nghttp2_stream { - /* Entry for dep_prev->obq */ - nghttp2_pq_entry pq_entry; - /* Priority Queue storing direct descendant (nghttp2_stream). Only - streams which itself has some data to send, or has a descendant - which has some data to sent. */ - nghttp2_pq obq; - /* Content-Length of request/response body. -1 if unknown. */ - int64_t content_length; - /* Received body so far */ - int64_t recv_content_length; - /* Base last_cycle for direct descendent streams. */ - uint64_t descendant_last_cycle; - /* Next scheduled time to sent item */ - uint64_t cycle; - /* Next seq used for direct descendant streams */ - uint64_t descendant_next_seq; - /* Secondary key for prioritization to break a tie for cycle. This - value is monotonically increased for single parent stream. */ - uint64_t seq; - /* pointers to form dependency tree. If multiple streams depend on - a stream, only one stream (left most) has non-NULL dep_prev which - points to the stream it depends on. The remaining streams are - linked using sib_prev and sib_next. The stream which has - non-NULL dep_prev always NULL sib_prev. The right most stream - has NULL sib_next. If this stream is a root of dependency tree, - dep_prev and sib_prev are NULL. */ - nghttp2_stream *dep_prev, *dep_next; - nghttp2_stream *sib_prev, *sib_next; - /* When stream is kept after closure, it may be kept in doubly - linked list pointed by nghttp2_session closed_stream_head. - closed_next points to the next stream object if it is the element - of the list. */ - nghttp2_stream *closed_prev, *closed_next; - /* The arbitrary data provided by user for this stream. */ - void *stream_user_data; - /* Item to send */ - nghttp2_outbound_item *item; - /* Last written length of frame payload */ - size_t last_writelen; - /* stream ID */ - int32_t stream_id; - /* Current remote window size. This value is computed against the - current initial window size of remote endpoint. */ - int32_t remote_window_size; - /* Keep track of the number of bytes received without - WINDOW_UPDATE. This could be negative after submitting negative - value to WINDOW_UPDATE */ - int32_t recv_window_size; - /* The number of bytes consumed by the application and now is - subject to WINDOW_UPDATE. This is only used when auto - WINDOW_UPDATE is turned off. */ - int32_t consumed_size; - /* The amount of recv_window_size cut using submitting negative - value to WINDOW_UPDATE */ - int32_t recv_reduction; - /* window size for local flow control. It is initially set to - NGHTTP2_INITIAL_WINDOW_SIZE and could be increased/decreased by - submitting WINDOW_UPDATE. See nghttp2_submit_window_update(). */ - int32_t local_window_size; - /* weight of this stream */ - int32_t weight; - /* This is unpaid penalty (offset) when calculating cycle. */ - uint32_t pending_penalty; - /* sum of weight of direct descendants */ - int32_t sum_dep_weight; - nghttp2_stream_state state; - /* status code from remote server */ - int16_t status_code; - /* Bitwise OR of zero or more nghttp2_http_flag values */ - uint32_t http_flags; - /* This is bitwise-OR of 0 or more of nghttp2_stream_flag. */ - uint8_t flags; - /* Bitwise OR of zero or more nghttp2_shut_flag values */ - uint8_t shut_flags; - /* Nonzero if this stream has been queued to stream pointed by - dep_prev. We maintain the invariant that if a stream is queued, - then its ancestors, except for root, are also queued. This - invariant may break in fatal error condition. */ - uint8_t queued; - /* This flag is used to reduce excessive queuing of WINDOW_UPDATE to - this stream. The nonzero does not necessarily mean WINDOW_UPDATE - is not queued. */ - uint8_t window_update_queued; - /* extpri is a stream priority produced by nghttp2_extpri_to_uint8 - used by RFC 9218 extensible priorities. */ - uint8_t extpri; - /* http_extpri is a stream priority received in HTTP request header - fields and produced by nghttp2_extpri_to_uint8. */ - uint8_t http_extpri; -}; - -void nghttp2_stream_init(nghttp2_stream *stream, int32_t stream_id, - uint8_t flags, nghttp2_stream_state initial_state, - int32_t weight, int32_t remote_initial_window_size, - int32_t local_initial_window_size, - void *stream_user_data, nghttp2_mem *mem); - -void nghttp2_stream_free(nghttp2_stream *stream); - -/* - * Disallow either further receptions or transmissions, or both. - * |flag| is bitwise OR of one or more of nghttp2_shut_flag. - */ -void nghttp2_stream_shutdown(nghttp2_stream *stream, nghttp2_shut_flag flag); - -/* - * Defer |stream->item|. We won't call this function in the situation - * where |stream->item| == NULL. The |flags| is bitwise OR of zero or - * more of NGHTTP2_STREAM_FLAG_DEFERRED_USER and - * NGHTTP2_STREAM_FLAG_DEFERRED_FLOW_CONTROL. The |flags| indicates - * the reason of this action. - */ -void nghttp2_stream_defer_item(nghttp2_stream *stream, uint8_t flags); - -/* - * Put back deferred data in this stream to active state. The |flags| - * are one or more of bitwise OR of the following values: - * NGHTTP2_STREAM_FLAG_DEFERRED_USER and - * NGHTTP2_STREAM_FLAG_DEFERRED_FLOW_CONTROL and given masks are - * cleared if they are set. So even if this function is called, if - * one of flag is still set, data does not become active. - * - * This function returns 0 if it succeeds, or one of the following - * negative error codes: - * - * NGHTTP2_ERR_NOMEM - * Out of memory - */ -int nghttp2_stream_resume_deferred_item(nghttp2_stream *stream, uint8_t flags); - -/* - * Returns nonzero if item is deferred by whatever reason. - */ -int nghttp2_stream_check_deferred_item(nghttp2_stream *stream); - -/* - * Returns nonzero if item is deferred by flow control. - */ -int nghttp2_stream_check_deferred_by_flow_control(nghttp2_stream *stream); - -/* - * Updates the remote window size with the new value - * |new_initial_window_size|. The |old_initial_window_size| is used to - * calculate the current window size. - * - * This function returns 0 if it succeeds or -1. The failure is due to - * overflow. - */ -int nghttp2_stream_update_remote_initial_window_size( - nghttp2_stream *stream, int32_t new_initial_window_size, - int32_t old_initial_window_size); - -/* - * Updates the local window size with the new value - * |new_initial_window_size|. The |old_initial_window_size| is used to - * calculate the current window size. - * - * This function returns 0 if it succeeds or -1. The failure is due to - * overflow. - */ -int nghttp2_stream_update_local_initial_window_size( - nghttp2_stream *stream, int32_t new_initial_window_size, - int32_t old_initial_window_size); - -/* - * Call this function if promised stream |stream| is replied with - * HEADERS. This function makes the state of the |stream| to - * NGHTTP2_STREAM_OPENED. - */ -void nghttp2_stream_promise_fulfilled(nghttp2_stream *stream); - -/* - * Returns nonzero if |target| is an ancestor of |stream|. - */ -int nghttp2_stream_dep_find_ancestor(nghttp2_stream *stream, - nghttp2_stream *target); - -/* - * Computes distributed weight of a stream of the |weight| under the - * |stream| if |stream| is removed from a dependency tree. - */ -int32_t nghttp2_stream_dep_distributed_weight(nghttp2_stream *stream, - int32_t weight); - -/* - * Makes the |stream| depend on the |dep_stream|. This dependency is - * exclusive. All existing direct descendants of |dep_stream| become - * the descendants of the |stream|. This function assumes - * |stream->item| is NULL. - * - * This function returns 0 if it succeeds, or one of the following - * negative error codes: - * - * NGHTTP2_ERR_NOMEM - * Out of memory - */ -int nghttp2_stream_dep_insert(nghttp2_stream *dep_stream, - nghttp2_stream *stream); - -/* - * Makes the |stream| depend on the |dep_stream|. This dependency is - * not exclusive. This function assumes |stream->item| is NULL. - */ -void nghttp2_stream_dep_add(nghttp2_stream *dep_stream, nghttp2_stream *stream); - -/* - * Removes the |stream| from the current dependency tree. This - * function assumes |stream->item| is NULL. - */ -int nghttp2_stream_dep_remove(nghttp2_stream *stream); - -/* - * Attaches |item| to |stream|. - * - * This function returns 0 if it succeeds, or one of the following - * negative error codes: - * - * NGHTTP2_ERR_NOMEM - * Out of memory - */ -int nghttp2_stream_attach_item(nghttp2_stream *stream, - nghttp2_outbound_item *item); - -/* - * Detaches |stream->item|. This function does not free - * |stream->item|. The caller must free it. - */ -void nghttp2_stream_detach_item(nghttp2_stream *stream); - -/* - * Makes the |stream| depend on the |dep_stream|. This dependency is - * exclusive. - * - * This function returns 0 if it succeeds, or one of the following - * negative error codes: - * - * NGHTTP2_ERR_NOMEM - * Out of memory - */ -int nghttp2_stream_dep_insert_subtree(nghttp2_stream *dep_stream, - nghttp2_stream *stream); - -/* - * Makes the |stream| depend on the |dep_stream|. This dependency is - * not exclusive. - * - * This function returns 0 if it succeeds, or one of the following - * negative error codes: - * - * NGHTTP2_ERR_NOMEM - * Out of memory - */ -int nghttp2_stream_dep_add_subtree(nghttp2_stream *dep_stream, - nghttp2_stream *stream); - -/* - * Removes subtree whose root stream is |stream|. The - * effective_weight of streams in removed subtree is not updated. - * - * This function returns 0 if it succeeds, or one of the following - * negative error codes: - * - * NGHTTP2_ERR_NOMEM - * Out of memory - */ -void nghttp2_stream_dep_remove_subtree(nghttp2_stream *stream); - -/* - * Returns nonzero if |stream| is in any dependency tree. - */ -int nghttp2_stream_in_dep_tree(nghttp2_stream *stream); - -/* - * Schedules transmission of |stream|'s item, assuming stream->item is - * attached, and stream->last_writelen was updated. - */ -void nghttp2_stream_reschedule(nghttp2_stream *stream); - -/* - * Changes |stream|'s weight to |weight|. If |stream| is queued, it - * will be rescheduled based on new weight. - */ -void nghttp2_stream_change_weight(nghttp2_stream *stream, int32_t weight); - -/* - * Returns a stream which has highest priority, updating - * descendant_last_cycle of selected stream's ancestors. - */ -nghttp2_outbound_item * -nghttp2_stream_next_outbound_item(nghttp2_stream *stream); - -#endif /* NGHTTP2_STREAM */ diff --git a/3rdparty/exported/nghttp2/nghttp2_submit.c b/3rdparty/exported/nghttp2/nghttp2_submit.c deleted file mode 100644 index 81c1ab7046bc..000000000000 --- a/3rdparty/exported/nghttp2/nghttp2_submit.c +++ /dev/null @@ -1,970 +0,0 @@ -/* - * nghttp2 - HTTP/2 C Library - * - * Copyright (c) 2012, 2013 Tatsuhiro Tsujikawa - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE - * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION - * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION - * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ -#include "nghttp2_submit.h" - -#include -#include - -#include "nghttp2_session.h" -#include "nghttp2_frame.h" -#include "nghttp2_helper.h" -#include "nghttp2_priority_spec.h" - -/* - * Detects the dependency error, that is stream attempted to depend on - * itself. If |stream_id| is -1, we use session->next_stream_id as - * stream ID. - * - * This function returns 0 if it succeeds, or one of the following - * error codes: - * - * NGHTTP2_ERR_INVALID_ARGUMENT - * Stream attempted to depend on itself. - */ -static int detect_self_dependency(nghttp2_session *session, int32_t stream_id, - const nghttp2_priority_spec *pri_spec) { - assert(pri_spec); - - if (stream_id == -1) { - if ((int32_t)session->next_stream_id == pri_spec->stream_id) { - return NGHTTP2_ERR_INVALID_ARGUMENT; - } - return 0; - } - - if (stream_id == pri_spec->stream_id) { - return NGHTTP2_ERR_INVALID_ARGUMENT; - } - - return 0; -} - -/* This function takes ownership of |nva_copy|. Regardless of the - return value, the caller must not free |nva_copy| after this - function returns. */ -static int32_t submit_headers_shared(nghttp2_session *session, uint8_t flags, - int32_t stream_id, - const nghttp2_priority_spec *pri_spec, - nghttp2_nv *nva_copy, size_t nvlen, - const nghttp2_data_provider_wrap *dpw, - void *stream_user_data) { - int rv; - uint8_t flags_copy; - nghttp2_outbound_item *item = NULL; - nghttp2_frame *frame = NULL; - nghttp2_headers_category hcat; - nghttp2_mem *mem; - - mem = &session->mem; - - item = nghttp2_mem_malloc(mem, sizeof(nghttp2_outbound_item)); - if (item == NULL) { - rv = NGHTTP2_ERR_NOMEM; - goto fail; - } - - nghttp2_outbound_item_init(item); - - if (dpw != NULL && dpw->data_prd.read_callback != NULL) { - item->aux_data.headers.dpw = *dpw; - } - - item->aux_data.headers.stream_user_data = stream_user_data; - - flags_copy = - (uint8_t)((flags & (NGHTTP2_FLAG_END_STREAM | NGHTTP2_FLAG_PRIORITY)) | - NGHTTP2_FLAG_END_HEADERS); - - if (stream_id == -1) { - if (session->next_stream_id > INT32_MAX) { - rv = NGHTTP2_ERR_STREAM_ID_NOT_AVAILABLE; - goto fail; - } - - stream_id = (int32_t)session->next_stream_id; - session->next_stream_id += 2; - - hcat = NGHTTP2_HCAT_REQUEST; - } else { - /* More specific categorization will be done later. */ - hcat = NGHTTP2_HCAT_HEADERS; - } - - frame = &item->frame; - - nghttp2_frame_headers_init(&frame->headers, flags_copy, stream_id, hcat, - pri_spec, nva_copy, nvlen); - - rv = nghttp2_session_add_item(session, item); - - if (rv != 0) { - nghttp2_frame_headers_free(&frame->headers, mem); - goto fail2; - } - - if (hcat == NGHTTP2_HCAT_REQUEST) { - return stream_id; - } - - return 0; - -fail: - /* nghttp2_frame_headers_init() takes ownership of nva_copy. */ - nghttp2_nv_array_del(nva_copy, mem); -fail2: - nghttp2_mem_free(mem, item); - - return rv; -} - -static int32_t submit_headers_shared_nva(nghttp2_session *session, - uint8_t flags, int32_t stream_id, - const nghttp2_priority_spec *pri_spec, - const nghttp2_nv *nva, size_t nvlen, - const nghttp2_data_provider_wrap *dpw, - void *stream_user_data) { - int rv; - nghttp2_nv *nva_copy; - nghttp2_priority_spec copy_pri_spec; - nghttp2_mem *mem; - - mem = &session->mem; - - if (pri_spec) { - copy_pri_spec = *pri_spec; - nghttp2_priority_spec_normalize_weight(©_pri_spec); - } else { - nghttp2_priority_spec_default_init(©_pri_spec); - } - - rv = nghttp2_nv_array_copy(&nva_copy, nva, nvlen, mem); - if (rv < 0) { - return rv; - } - - return submit_headers_shared(session, flags, stream_id, ©_pri_spec, - nva_copy, nvlen, dpw, stream_user_data); -} - -int nghttp2_submit_trailer(nghttp2_session *session, int32_t stream_id, - const nghttp2_nv *nva, size_t nvlen) { - if (stream_id <= 0) { - return NGHTTP2_ERR_INVALID_ARGUMENT; - } - - return (int)submit_headers_shared_nva( - session, NGHTTP2_FLAG_END_STREAM, stream_id, NULL, nva, nvlen, NULL, NULL); -} - -int32_t nghttp2_submit_headers(nghttp2_session *session, uint8_t flags, - int32_t stream_id, - const nghttp2_priority_spec *pri_spec, - const nghttp2_nv *nva, size_t nvlen, - void *stream_user_data) { - int rv; - - if (stream_id == -1) { - if (session->server) { - return NGHTTP2_ERR_PROTO; - } - } else if (stream_id <= 0) { - return NGHTTP2_ERR_INVALID_ARGUMENT; - } - - flags &= NGHTTP2_FLAG_END_STREAM; - - if (pri_spec && !nghttp2_priority_spec_check_default(pri_spec) && - session->remote_settings.no_rfc7540_priorities != 1) { - rv = detect_self_dependency(session, stream_id, pri_spec); - if (rv != 0) { - return rv; - } - - flags |= NGHTTP2_FLAG_PRIORITY; - } else { - pri_spec = NULL; - } - - return submit_headers_shared_nva(session, flags, stream_id, pri_spec, nva, - nvlen, NULL, stream_user_data); -} - -int nghttp2_submit_ping(nghttp2_session *session, uint8_t flags, - const uint8_t *opaque_data) { - flags &= NGHTTP2_FLAG_ACK; - return nghttp2_session_add_ping(session, flags, opaque_data); -} - -int nghttp2_submit_priority(nghttp2_session *session, uint8_t flags, - int32_t stream_id, - const nghttp2_priority_spec *pri_spec) { - int rv; - nghttp2_outbound_item *item; - nghttp2_frame *frame; - nghttp2_priority_spec copy_pri_spec; - nghttp2_mem *mem; - (void)flags; - - mem = &session->mem; - - if (session->remote_settings.no_rfc7540_priorities == 1) { - return 0; - } - - if (stream_id == 0 || pri_spec == NULL) { - return NGHTTP2_ERR_INVALID_ARGUMENT; - } - - if (stream_id == pri_spec->stream_id) { - return NGHTTP2_ERR_INVALID_ARGUMENT; - } - - copy_pri_spec = *pri_spec; - - nghttp2_priority_spec_normalize_weight(©_pri_spec); - - item = nghttp2_mem_malloc(mem, sizeof(nghttp2_outbound_item)); - - if (item == NULL) { - return NGHTTP2_ERR_NOMEM; - } - - nghttp2_outbound_item_init(item); - - frame = &item->frame; - - nghttp2_frame_priority_init(&frame->priority, stream_id, ©_pri_spec); - - rv = nghttp2_session_add_item(session, item); - - if (rv != 0) { - nghttp2_frame_priority_free(&frame->priority); - nghttp2_mem_free(mem, item); - - return rv; - } - - return 0; -} - -int nghttp2_submit_rst_stream(nghttp2_session *session, uint8_t flags, - int32_t stream_id, uint32_t error_code) { - (void)flags; - - if (stream_id == 0) { - return NGHTTP2_ERR_INVALID_ARGUMENT; - } - - return nghttp2_session_add_rst_stream(session, stream_id, error_code); -} - -int nghttp2_submit_goaway(nghttp2_session *session, uint8_t flags, - int32_t last_stream_id, uint32_t error_code, - const uint8_t *opaque_data, size_t opaque_data_len) { - (void)flags; - - if (session->goaway_flags & NGHTTP2_GOAWAY_TERM_ON_SEND) { - return 0; - } - return nghttp2_session_add_goaway(session, last_stream_id, error_code, - opaque_data, opaque_data_len, - NGHTTP2_GOAWAY_AUX_NONE); -} - -int nghttp2_submit_shutdown_notice(nghttp2_session *session) { - if (!session->server) { - return NGHTTP2_ERR_INVALID_STATE; - } - if (session->goaway_flags) { - return 0; - } - return nghttp2_session_add_goaway(session, (1u << 31) - 1, NGHTTP2_NO_ERROR, - NULL, 0, - NGHTTP2_GOAWAY_AUX_SHUTDOWN_NOTICE); -} - -int nghttp2_submit_settings(nghttp2_session *session, uint8_t flags, - const nghttp2_settings_entry *iv, size_t niv) { - (void)flags; - return nghttp2_session_add_settings(session, NGHTTP2_FLAG_NONE, iv, niv); -} - -int32_t nghttp2_submit_push_promise(nghttp2_session *session, uint8_t flags, - int32_t stream_id, const nghttp2_nv *nva, - size_t nvlen, - void *promised_stream_user_data) { - nghttp2_outbound_item *item; - nghttp2_frame *frame; - nghttp2_nv *nva_copy; - uint8_t flags_copy; - int32_t promised_stream_id; - int rv; - nghttp2_mem *mem; - (void)flags; - - mem = &session->mem; - - if (stream_id <= 0 || nghttp2_session_is_my_stream_id(session, stream_id)) { - return NGHTTP2_ERR_INVALID_ARGUMENT; - } - - if (!session->server) { - return NGHTTP2_ERR_PROTO; - } - - /* All 32bit signed stream IDs are spent. */ - if (session->next_stream_id > INT32_MAX) { - return NGHTTP2_ERR_STREAM_ID_NOT_AVAILABLE; - } - - item = nghttp2_mem_malloc(mem, sizeof(nghttp2_outbound_item)); - if (item == NULL) { - return NGHTTP2_ERR_NOMEM; - } - - nghttp2_outbound_item_init(item); - - item->aux_data.headers.stream_user_data = promised_stream_user_data; - - frame = &item->frame; - - rv = nghttp2_nv_array_copy(&nva_copy, nva, nvlen, mem); - if (rv < 0) { - nghttp2_mem_free(mem, item); - return rv; - } - - flags_copy = NGHTTP2_FLAG_END_HEADERS; - - promised_stream_id = (int32_t)session->next_stream_id; - session->next_stream_id += 2; - - nghttp2_frame_push_promise_init(&frame->push_promise, flags_copy, stream_id, - promised_stream_id, nva_copy, nvlen); - - rv = nghttp2_session_add_item(session, item); - - if (rv != 0) { - nghttp2_frame_push_promise_free(&frame->push_promise, mem); - nghttp2_mem_free(mem, item); - - return rv; - } - - return promised_stream_id; -} - -int nghttp2_submit_window_update(nghttp2_session *session, uint8_t flags, - int32_t stream_id, - int32_t window_size_increment) { - int rv; - nghttp2_stream *stream = 0; - (void)flags; - - if (window_size_increment == 0) { - return 0; - } - if (stream_id == 0) { - rv = nghttp2_adjust_local_window_size( - &session->local_window_size, &session->recv_window_size, - &session->recv_reduction, &window_size_increment); - if (rv != 0) { - return rv; - } - } else { - stream = nghttp2_session_get_stream(session, stream_id); - if (!stream) { - return 0; - } - - rv = nghttp2_adjust_local_window_size( - &stream->local_window_size, &stream->recv_window_size, - &stream->recv_reduction, &window_size_increment); - if (rv != 0) { - return rv; - } - } - - if (window_size_increment > 0) { - if (stream_id == 0) { - session->consumed_size = - nghttp2_max_int32(0, session->consumed_size - window_size_increment); - } else { - stream->consumed_size = - nghttp2_max_int32(0, stream->consumed_size - window_size_increment); - } - - return nghttp2_session_add_window_update(session, 0, stream_id, - window_size_increment); - } - return 0; -} - -int nghttp2_session_set_local_window_size(nghttp2_session *session, - uint8_t flags, int32_t stream_id, - int32_t window_size) { - int32_t window_size_increment; - nghttp2_stream *stream; - int rv; - (void)flags; - - if (window_size < 0) { - return NGHTTP2_ERR_INVALID_ARGUMENT; - } - - if (stream_id == 0) { - window_size_increment = window_size - session->local_window_size; - - if (window_size_increment == 0) { - return 0; - } - - if (window_size_increment < 0) { - return nghttp2_adjust_local_window_size( - &session->local_window_size, &session->recv_window_size, - &session->recv_reduction, &window_size_increment); - } - - rv = nghttp2_increase_local_window_size( - &session->local_window_size, &session->recv_window_size, - &session->recv_reduction, &window_size_increment); - - if (rv != 0) { - return rv; - } - - if (window_size_increment > 0) { - return nghttp2_session_add_window_update(session, 0, stream_id, - window_size_increment); - } - - return nghttp2_session_update_recv_connection_window_size(session, 0); - } else { - stream = nghttp2_session_get_stream(session, stream_id); - - if (stream == NULL) { - return 0; - } - - window_size_increment = window_size - stream->local_window_size; - - if (window_size_increment == 0) { - return 0; - } - - if (window_size_increment < 0) { - return nghttp2_adjust_local_window_size( - &stream->local_window_size, &stream->recv_window_size, - &stream->recv_reduction, &window_size_increment); - } - - rv = nghttp2_increase_local_window_size( - &stream->local_window_size, &stream->recv_window_size, - &stream->recv_reduction, &window_size_increment); - - if (rv != 0) { - return rv; - } - - if (window_size_increment > 0) { - return nghttp2_session_add_window_update(session, 0, stream_id, - window_size_increment); - } - - return nghttp2_session_update_recv_stream_window_size(session, stream, 0, - 1); - } -} - -int nghttp2_submit_altsvc(nghttp2_session *session, uint8_t flags, - int32_t stream_id, const uint8_t *origin, - size_t origin_len, const uint8_t *field_value, - size_t field_value_len) { - nghttp2_mem *mem; - uint8_t *buf, *p; - uint8_t *origin_copy; - uint8_t *field_value_copy; - nghttp2_outbound_item *item; - nghttp2_frame *frame; - nghttp2_ext_altsvc *altsvc; - int rv; - (void)flags; - - mem = &session->mem; - - if (!session->server) { - return NGHTTP2_ERR_INVALID_STATE; - } - - if (2 + origin_len + field_value_len > NGHTTP2_MAX_PAYLOADLEN) { - return NGHTTP2_ERR_INVALID_ARGUMENT; - } - - if (stream_id == 0) { - if (origin_len == 0) { - return NGHTTP2_ERR_INVALID_ARGUMENT; - } - } else if (origin_len != 0) { - return NGHTTP2_ERR_INVALID_ARGUMENT; - } - - buf = nghttp2_mem_malloc(mem, origin_len + field_value_len + 2); - if (buf == NULL) { - return NGHTTP2_ERR_NOMEM; - } - - p = buf; - - origin_copy = p; - if (origin_len) { - p = nghttp2_cpymem(p, origin, origin_len); - } - *p++ = '\0'; - - field_value_copy = p; - if (field_value_len) { - p = nghttp2_cpymem(p, field_value, field_value_len); - } - *p++ = '\0'; - - item = nghttp2_mem_malloc(mem, sizeof(nghttp2_outbound_item)); - if (item == NULL) { - rv = NGHTTP2_ERR_NOMEM; - goto fail_item_malloc; - } - - nghttp2_outbound_item_init(item); - - item->aux_data.ext.builtin = 1; - - altsvc = &item->ext_frame_payload.altsvc; - - frame = &item->frame; - frame->ext.payload = altsvc; - - nghttp2_frame_altsvc_init(&frame->ext, stream_id, origin_copy, origin_len, - field_value_copy, field_value_len); - - rv = nghttp2_session_add_item(session, item); - if (rv != 0) { - nghttp2_frame_altsvc_free(&frame->ext, mem); - nghttp2_mem_free(mem, item); - - return rv; - } - - return 0; - -fail_item_malloc: - free(buf); - - return rv; -} - -int nghttp2_submit_origin(nghttp2_session *session, uint8_t flags, - const nghttp2_origin_entry *ov, size_t nov) { - nghttp2_mem *mem; - uint8_t *p; - nghttp2_outbound_item *item; - nghttp2_frame *frame; - nghttp2_ext_origin *origin; - nghttp2_origin_entry *ov_copy; - size_t len = 0; - size_t i; - int rv; - (void)flags; - - mem = &session->mem; - - if (!session->server) { - return NGHTTP2_ERR_INVALID_STATE; - } - - if (nov) { - for (i = 0; i < nov; ++i) { - len += ov[i].origin_len; - } - - if (2 * nov + len > NGHTTP2_MAX_PAYLOADLEN) { - return NGHTTP2_ERR_INVALID_ARGUMENT; - } - - /* The last nov is added for terminal NULL character. */ - ov_copy = - nghttp2_mem_malloc(mem, nov * sizeof(nghttp2_origin_entry) + len + nov); - if (ov_copy == NULL) { - return NGHTTP2_ERR_NOMEM; - } - - p = (uint8_t *)ov_copy + nov * sizeof(nghttp2_origin_entry); - - for (i = 0; i < nov; ++i) { - ov_copy[i].origin = p; - ov_copy[i].origin_len = ov[i].origin_len; - p = nghttp2_cpymem(p, ov[i].origin, ov[i].origin_len); - *p++ = '\0'; - } - - assert((size_t)(p - (uint8_t *)ov_copy) == - nov * sizeof(nghttp2_origin_entry) + len + nov); - } else { - ov_copy = NULL; - } - - item = nghttp2_mem_malloc(mem, sizeof(nghttp2_outbound_item)); - if (item == NULL) { - rv = NGHTTP2_ERR_NOMEM; - goto fail_item_malloc; - } - - nghttp2_outbound_item_init(item); - - item->aux_data.ext.builtin = 1; - - origin = &item->ext_frame_payload.origin; - - frame = &item->frame; - frame->ext.payload = origin; - - nghttp2_frame_origin_init(&frame->ext, ov_copy, nov); - - rv = nghttp2_session_add_item(session, item); - if (rv != 0) { - nghttp2_frame_origin_free(&frame->ext, mem); - nghttp2_mem_free(mem, item); - - return rv; - } - - return 0; - -fail_item_malloc: - free(ov_copy); - - return rv; -} - -int nghttp2_submit_priority_update(nghttp2_session *session, uint8_t flags, - int32_t stream_id, - const uint8_t *field_value, - size_t field_value_len) { - nghttp2_mem *mem; - uint8_t *buf, *p; - nghttp2_outbound_item *item; - nghttp2_frame *frame; - nghttp2_ext_priority_update *priority_update; - int rv; - (void)flags; - - mem = &session->mem; - - if (session->server) { - return NGHTTP2_ERR_INVALID_STATE; - } - - if (session->remote_settings.no_rfc7540_priorities == 0) { - return 0; - } - - if (stream_id == 0 || 4 + field_value_len > NGHTTP2_MAX_PAYLOADLEN) { - return NGHTTP2_ERR_INVALID_ARGUMENT; - } - - if (field_value_len) { - buf = nghttp2_mem_malloc(mem, field_value_len + 1); - if (buf == NULL) { - return NGHTTP2_ERR_NOMEM; - } - - p = nghttp2_cpymem(buf, field_value, field_value_len); - *p = '\0'; - } else { - buf = NULL; - } - - item = nghttp2_mem_malloc(mem, sizeof(nghttp2_outbound_item)); - if (item == NULL) { - rv = NGHTTP2_ERR_NOMEM; - goto fail_item_malloc; - } - - nghttp2_outbound_item_init(item); - - item->aux_data.ext.builtin = 1; - - priority_update = &item->ext_frame_payload.priority_update; - - frame = &item->frame; - frame->ext.payload = priority_update; - - nghttp2_frame_priority_update_init(&frame->ext, stream_id, buf, - field_value_len); - - rv = nghttp2_session_add_item(session, item); - if (rv != 0) { - nghttp2_frame_priority_update_free(&frame->ext, mem); - nghttp2_mem_free(mem, item); - - return rv; - } - - return 0; - -fail_item_malloc: - free(buf); - - return rv; -} - -static uint8_t set_request_flags(const nghttp2_priority_spec *pri_spec, - const nghttp2_data_provider_wrap *dpw) { - uint8_t flags = NGHTTP2_FLAG_NONE; - if (dpw == NULL || dpw->data_prd.read_callback == NULL) { - flags |= NGHTTP2_FLAG_END_STREAM; - } - - if (pri_spec) { - flags |= NGHTTP2_FLAG_PRIORITY; - } - - return flags; -} - -static int32_t submit_request_shared(nghttp2_session *session, - const nghttp2_priority_spec *pri_spec, - const nghttp2_nv *nva, size_t nvlen, - const nghttp2_data_provider_wrap *dpw, - void *stream_user_data) { - uint8_t flags; - int rv; - - if (session->server) { - return NGHTTP2_ERR_PROTO; - } - - if (pri_spec && !nghttp2_priority_spec_check_default(pri_spec) && - session->remote_settings.no_rfc7540_priorities != 1) { - rv = detect_self_dependency(session, -1, pri_spec); - if (rv != 0) { - return rv; - } - } else { - pri_spec = NULL; - } - - flags = set_request_flags(pri_spec, dpw); - - return submit_headers_shared_nva(session, flags, -1, pri_spec, nva, nvlen, - dpw, stream_user_data); -} - -int32_t nghttp2_submit_request(nghttp2_session *session, - const nghttp2_priority_spec *pri_spec, - const nghttp2_nv *nva, size_t nvlen, - const nghttp2_data_provider *data_prd, - void *stream_user_data) { - nghttp2_data_provider_wrap dpw; - - return submit_request_shared(session, pri_spec, nva, nvlen, - nghttp2_data_provider_wrap_v1(&dpw, data_prd), - stream_user_data); -} - -int32_t nghttp2_submit_request2(nghttp2_session *session, - const nghttp2_priority_spec *pri_spec, - const nghttp2_nv *nva, size_t nvlen, - const nghttp2_data_provider2 *data_prd, - void *stream_user_data) { - nghttp2_data_provider_wrap dpw; - - return submit_request_shared(session, pri_spec, nva, nvlen, - nghttp2_data_provider_wrap_v2(&dpw, data_prd), - stream_user_data); -} - -static uint8_t set_response_flags(const nghttp2_data_provider_wrap *dpw) { - uint8_t flags = NGHTTP2_FLAG_NONE; - if (dpw == NULL || dpw->data_prd.read_callback == NULL) { - flags |= NGHTTP2_FLAG_END_STREAM; - } - return flags; -} - -static int submit_response_shared(nghttp2_session *session, int32_t stream_id, - const nghttp2_nv *nva, size_t nvlen, - const nghttp2_data_provider_wrap *dpw) { - uint8_t flags; - - if (stream_id <= 0) { - return NGHTTP2_ERR_INVALID_ARGUMENT; - } - - if (!session->server) { - return NGHTTP2_ERR_PROTO; - } - - flags = set_response_flags(dpw); - return submit_headers_shared_nva(session, flags, stream_id, NULL, nva, nvlen, - dpw, NULL); -} - -int nghttp2_submit_response(nghttp2_session *session, int32_t stream_id, - const nghttp2_nv *nva, size_t nvlen, - const nghttp2_data_provider *data_prd) { - nghttp2_data_provider_wrap dpw; - - return submit_response_shared(session, stream_id, nva, nvlen, - nghttp2_data_provider_wrap_v1(&dpw, data_prd)); -} - -int nghttp2_submit_response2(nghttp2_session *session, int32_t stream_id, - const nghttp2_nv *nva, size_t nvlen, - const nghttp2_data_provider2 *data_prd) { - nghttp2_data_provider_wrap dpw; - - return submit_response_shared(session, stream_id, nva, nvlen, - nghttp2_data_provider_wrap_v2(&dpw, data_prd)); -} - -int nghttp2_submit_data_shared(nghttp2_session *session, uint8_t flags, - int32_t stream_id, - const nghttp2_data_provider_wrap *dpw) { - int rv; - nghttp2_outbound_item *item; - nghttp2_frame *frame; - nghttp2_data_aux_data *aux_data; - uint8_t nflags = flags & NGHTTP2_FLAG_END_STREAM; - nghttp2_mem *mem; - - mem = &session->mem; - - if (stream_id == 0) { - return NGHTTP2_ERR_INVALID_ARGUMENT; - } - - item = nghttp2_mem_malloc(mem, sizeof(nghttp2_outbound_item)); - if (item == NULL) { - return NGHTTP2_ERR_NOMEM; - } - - nghttp2_outbound_item_init(item); - - frame = &item->frame; - aux_data = &item->aux_data.data; - aux_data->dpw = *dpw; - aux_data->eof = 0; - aux_data->flags = nflags; - - /* flags are sent on transmission */ - nghttp2_frame_data_init(&frame->data, NGHTTP2_FLAG_NONE, stream_id); - - rv = nghttp2_session_add_item(session, item); - if (rv != 0) { - nghttp2_frame_data_free(&frame->data); - nghttp2_mem_free(mem, item); - return rv; - } - return 0; -} - -int nghttp2_submit_data(nghttp2_session *session, uint8_t flags, - int32_t stream_id, - const nghttp2_data_provider *data_prd) { - nghttp2_data_provider_wrap dpw; - - assert(data_prd); - - return nghttp2_submit_data_shared( - session, flags, stream_id, nghttp2_data_provider_wrap_v1(&dpw, data_prd)); -} - -int nghttp2_submit_data2(nghttp2_session *session, uint8_t flags, - int32_t stream_id, - const nghttp2_data_provider2 *data_prd) { - nghttp2_data_provider_wrap dpw; - - assert(data_prd); - - return nghttp2_submit_data_shared( - session, flags, stream_id, nghttp2_data_provider_wrap_v2(&dpw, data_prd)); -} - -ssize_t nghttp2_pack_settings_payload(uint8_t *buf, size_t buflen, - const nghttp2_settings_entry *iv, - size_t niv) { - return (ssize_t)nghttp2_pack_settings_payload2(buf, buflen, iv, niv); -} - -nghttp2_ssize nghttp2_pack_settings_payload2(uint8_t *buf, size_t buflen, - const nghttp2_settings_entry *iv, - size_t niv) { - if (!nghttp2_iv_check(iv, niv)) { - return NGHTTP2_ERR_INVALID_ARGUMENT; - } - - if (buflen < (niv * NGHTTP2_FRAME_SETTINGS_ENTRY_LENGTH)) { - return NGHTTP2_ERR_INSUFF_BUFSIZE; - } - - return (nghttp2_ssize)nghttp2_frame_pack_settings_payload(buf, iv, niv); -} - -int nghttp2_submit_extension(nghttp2_session *session, uint8_t type, - uint8_t flags, int32_t stream_id, void *payload) { - int rv; - nghttp2_outbound_item *item; - nghttp2_frame *frame; - nghttp2_mem *mem; - - mem = &session->mem; - - if (type <= NGHTTP2_CONTINUATION) { - return NGHTTP2_ERR_INVALID_ARGUMENT; - } - - if (!session->callbacks.pack_extension_callback2 && - !session->callbacks.pack_extension_callback) { - return NGHTTP2_ERR_INVALID_STATE; - } - - item = nghttp2_mem_malloc(mem, sizeof(nghttp2_outbound_item)); - if (item == NULL) { - return NGHTTP2_ERR_NOMEM; - } - - nghttp2_outbound_item_init(item); - - frame = &item->frame; - nghttp2_frame_extension_init(&frame->ext, type, flags, stream_id, payload); - - rv = nghttp2_session_add_item(session, item); - if (rv != 0) { - nghttp2_frame_extension_free(&frame->ext); - nghttp2_mem_free(mem, item); - return rv; - } - - return 0; -} diff --git a/3rdparty/exported/nghttp2/nghttp2_submit.h b/3rdparty/exported/nghttp2/nghttp2_submit.h deleted file mode 100644 index 350ee0227590..000000000000 --- a/3rdparty/exported/nghttp2/nghttp2_submit.h +++ /dev/null @@ -1,40 +0,0 @@ -/* - * nghttp2 - HTTP/2 C Library - * - * Copyright (c) 2012 Tatsuhiro Tsujikawa - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE - * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION - * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION - * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ -#ifndef NGHTTP2_SUBMIT_H -#define NGHTTP2_SUBMIT_H - -#ifdef HAVE_CONFIG_H -# include -#endif /* HAVE_CONFIG_H */ - -#include - -#include "nghttp2_outbound_item.h" - -int nghttp2_submit_data_shared(nghttp2_session *session, uint8_t flags, - int32_t stream_id, - const nghttp2_data_provider_wrap *dpw); - -#endif /* NGHTTP2_SUBMIT_H */ diff --git a/3rdparty/exported/nghttp2/nghttp2_time.c b/3rdparty/exported/nghttp2/nghttp2_time.c deleted file mode 100644 index 148ccfdce81c..000000000000 --- a/3rdparty/exported/nghttp2/nghttp2_time.c +++ /dev/null @@ -1,63 +0,0 @@ -/* - * nghttp2 - HTTP/2 C Library - * - * Copyright (c) 2023 nghttp2 contributors - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE - * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION - * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION - * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ -#include "nghttp2_time.h" - -#ifdef HAVE_WINDOWS_H -# include -#endif /* HAVE_WINDOWS_H */ - -#include - -#if !defined(HAVE_GETTICKCOUNT64) || defined(__CYGWIN__) -static uint64_t time_now_sec(void) { - time_t t = time(NULL); - - if (t == -1) { - return 0; - } - - return (uint64_t)t; -} -#endif /* !HAVE_GETTICKCOUNT64 || __CYGWIN__ */ - -#if defined(HAVE_GETTICKCOUNT64) && !defined(__CYGWIN__) -uint64_t nghttp2_time_now_sec(void) { return GetTickCount64() / 1000; } -#elif defined(HAVE_CLOCK_GETTIME) && defined(HAVE_DECL_CLOCK_MONOTONIC) && \ - HAVE_DECL_CLOCK_MONOTONIC -uint64_t nghttp2_time_now_sec(void) { - struct timespec tp; - int rv = clock_gettime(CLOCK_MONOTONIC, &tp); - - if (rv == -1) { - return time_now_sec(); - } - - return (uint64_t)tp.tv_sec; -} -#else /* (!HAVE_CLOCK_GETTIME || !HAVE_DECL_CLOCK_MONOTONIC) && \ - (!HAVE_GETTICKCOUNT64 || __CYGWIN__)) */ -uint64_t nghttp2_time_now_sec(void) { return time_now_sec(); } -#endif /* (!HAVE_CLOCK_GETTIME || !HAVE_DECL_CLOCK_MONOTONIC) && \ - (!HAVE_GETTICKCOUNT64 || __CYGWIN__)) */ diff --git a/3rdparty/exported/nghttp2/nghttp2_time.h b/3rdparty/exported/nghttp2/nghttp2_time.h deleted file mode 100644 index 03c0bbe944ee..000000000000 --- a/3rdparty/exported/nghttp2/nghttp2_time.h +++ /dev/null @@ -1,38 +0,0 @@ -/* - * nghttp2 - HTTP/2 C Library - * - * Copyright (c) 2023 nghttp2 contributors - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE - * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION - * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION - * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ -#ifndef NGHTTP2_TIME_H -#define NGHTTP2_TIME_H - -#ifdef HAVE_CONFIG_H -# include -#endif /* HAVE_CONFIG_H */ - -#include - -/* nghttp2_time_now_sec returns seconds from implementation-specific - timepoint. If it is unable to get seconds, it returns 0. */ -uint64_t nghttp2_time_now_sec(void); - -#endif /* NGHTTP2_TIME_H */ diff --git a/3rdparty/exported/nghttp2/nghttp2_version.c b/3rdparty/exported/nghttp2/nghttp2_version.c deleted file mode 100644 index 4211f2cf8f62..000000000000 --- a/3rdparty/exported/nghttp2/nghttp2_version.c +++ /dev/null @@ -1,38 +0,0 @@ -/* - * nghttp2 - HTTP/2 C Library - * - * Copyright (c) 2012, 2013 Tatsuhiro Tsujikawa - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE - * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION - * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION - * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ -#ifdef HAVE_CONFIG_H -# include -#endif /* HAVE_CONFIG_H */ - -#include - -static nghttp2_info version = {NGHTTP2_VERSION_AGE, NGHTTP2_VERSION_NUM, - NGHTTP2_VERSION, NGHTTP2_PROTO_VERSION_ID}; - -nghttp2_info *nghttp2_version(int least_version) { - if (least_version > NGHTTP2_VERSION_NUM) - return NULL; - return &version; -} diff --git a/3rdparty/exported/nghttp2/sfparse.c b/3rdparty/exported/nghttp2/sfparse.c deleted file mode 100644 index b5e94cc28153..000000000000 --- a/3rdparty/exported/nghttp2/sfparse.c +++ /dev/null @@ -1,1145 +0,0 @@ -/* - * sfparse - * - * Copyright (c) 2023 sfparse contributors - * Copyright (c) 2019 nghttp3 contributors - * Copyright (c) 2015 nghttp2 contributors - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE - * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION - * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION - * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ -#include "sfparse.h" - -#include -#include -#include - -#define SF_STATE_DICT 0x08u -#define SF_STATE_LIST 0x10u -#define SF_STATE_ITEM 0x18u - -#define SF_STATE_INNER_LIST 0x04u - -#define SF_STATE_BEFORE 0x00u -#define SF_STATE_BEFORE_PARAMS 0x01u -#define SF_STATE_PARAMS 0x02u -#define SF_STATE_AFTER 0x03u - -#define SF_STATE_OP_MASK 0x03u - -#define SF_SET_STATE_AFTER(NAME) (SF_STATE_##NAME | SF_STATE_AFTER) -#define SF_SET_STATE_BEFORE_PARAMS(NAME) \ - (SF_STATE_##NAME | SF_STATE_BEFORE_PARAMS) -#define SF_SET_STATE_INNER_LIST_BEFORE(NAME) \ - (SF_STATE_##NAME | SF_STATE_INNER_LIST | SF_STATE_BEFORE) - -#define SF_STATE_DICT_AFTER SF_SET_STATE_AFTER(DICT) -#define SF_STATE_DICT_BEFORE_PARAMS SF_SET_STATE_BEFORE_PARAMS(DICT) -#define SF_STATE_DICT_INNER_LIST_BEFORE SF_SET_STATE_INNER_LIST_BEFORE(DICT) - -#define SF_STATE_LIST_AFTER SF_SET_STATE_AFTER(LIST) -#define SF_STATE_LIST_BEFORE_PARAMS SF_SET_STATE_BEFORE_PARAMS(LIST) -#define SF_STATE_LIST_INNER_LIST_BEFORE SF_SET_STATE_INNER_LIST_BEFORE(LIST) - -#define SF_STATE_ITEM_AFTER SF_SET_STATE_AFTER(ITEM) -#define SF_STATE_ITEM_BEFORE_PARAMS SF_SET_STATE_BEFORE_PARAMS(ITEM) -#define SF_STATE_ITEM_INNER_LIST_BEFORE SF_SET_STATE_INNER_LIST_BEFORE(ITEM) - -#define SF_STATE_INITIAL 0x00u - -#define DIGIT_CASES \ - case '0': \ - case '1': \ - case '2': \ - case '3': \ - case '4': \ - case '5': \ - case '6': \ - case '7': \ - case '8': \ - case '9' - -#define LCALPHA_CASES \ - case 'a': \ - case 'b': \ - case 'c': \ - case 'd': \ - case 'e': \ - case 'f': \ - case 'g': \ - case 'h': \ - case 'i': \ - case 'j': \ - case 'k': \ - case 'l': \ - case 'm': \ - case 'n': \ - case 'o': \ - case 'p': \ - case 'q': \ - case 'r': \ - case 's': \ - case 't': \ - case 'u': \ - case 'v': \ - case 'w': \ - case 'x': \ - case 'y': \ - case 'z' - -#define UCALPHA_CASES \ - case 'A': \ - case 'B': \ - case 'C': \ - case 'D': \ - case 'E': \ - case 'F': \ - case 'G': \ - case 'H': \ - case 'I': \ - case 'J': \ - case 'K': \ - case 'L': \ - case 'M': \ - case 'N': \ - case 'O': \ - case 'P': \ - case 'Q': \ - case 'R': \ - case 'S': \ - case 'T': \ - case 'U': \ - case 'V': \ - case 'W': \ - case 'X': \ - case 'Y': \ - case 'Z' - -#define ALPHA_CASES \ - UCALPHA_CASES: \ - LCALPHA_CASES - -#define X20_21_CASES \ - case ' ': \ - case '!' - -#define X23_5B_CASES \ - case '#': \ - case '$': \ - case '%': \ - case '&': \ - case '\'': \ - case '(': \ - case ')': \ - case '*': \ - case '+': \ - case ',': \ - case '-': \ - case '.': \ - case '/': \ - DIGIT_CASES: \ - case ':': \ - case ';': \ - case '<': \ - case '=': \ - case '>': \ - case '?': \ - case '@': \ - UCALPHA_CASES: \ - case '[' - -#define X5D_7E_CASES \ - case ']': \ - case '^': \ - case '_': \ - case '`': \ - LCALPHA_CASES: \ - case '{': \ - case '|': \ - case '}': \ - case '~' - -static int is_ws(uint8_t c) { - switch (c) { - case ' ': - case '\t': - return 1; - default: - return 0; - } -} - -static int parser_eof(sf_parser *sfp) { return sfp->pos == sfp->end; } - -static void parser_discard_ows(sf_parser *sfp) { - for (; !parser_eof(sfp) && is_ws(*sfp->pos); ++sfp->pos) - ; -} - -static void parser_discard_sp(sf_parser *sfp) { - for (; !parser_eof(sfp) && *sfp->pos == ' '; ++sfp->pos) - ; -} - -static void parser_set_op_state(sf_parser *sfp, uint32_t op) { - sfp->state &= ~SF_STATE_OP_MASK; - sfp->state |= op; -} - -static void parser_unset_inner_list_state(sf_parser *sfp) { - sfp->state &= ~SF_STATE_INNER_LIST; -} - -static int parser_key(sf_parser *sfp, sf_vec *dest) { - const uint8_t *base; - - switch (*sfp->pos) { - case '*': - LCALPHA_CASES: - break; - default: - return SF_ERR_PARSE_ERROR; - } - - base = sfp->pos++; - - for (; !parser_eof(sfp); ++sfp->pos) { - switch (*sfp->pos) { - case '_': - case '-': - case '.': - case '*': - DIGIT_CASES: - LCALPHA_CASES: - continue; - } - - break; - } - - if (dest) { - dest->base = (uint8_t *)base; - dest->len = (size_t)(sfp->pos - dest->base); - } - - return 0; -} - -static int parser_number(sf_parser *sfp, sf_value *dest) { - int sign = 1; - int64_t value = 0; - size_t len = 0; - size_t fpos = 0; - - if (*sfp->pos == '-') { - ++sfp->pos; - if (parser_eof(sfp)) { - return SF_ERR_PARSE_ERROR; - } - - sign = -1; - } - - assert(!parser_eof(sfp)); - - for (; !parser_eof(sfp); ++sfp->pos) { - switch (*sfp->pos) { - DIGIT_CASES: - if (++len > 15) { - return SF_ERR_PARSE_ERROR; - } - - value *= 10; - value += *sfp->pos - '0'; - - continue; - } - - break; - } - - if (len == 0) { - return SF_ERR_PARSE_ERROR; - } - - if (parser_eof(sfp) || *sfp->pos != '.') { - if (dest) { - dest->type = SF_TYPE_INTEGER; - dest->flags = SF_VALUE_FLAG_NONE; - dest->integer = value * sign; - } - - return 0; - } - - /* decimal */ - - if (len > 12) { - return SF_ERR_PARSE_ERROR; - } - - fpos = len; - - ++sfp->pos; - - for (; !parser_eof(sfp); ++sfp->pos) { - switch (*sfp->pos) { - DIGIT_CASES: - if (++len > 15) { - return SF_ERR_PARSE_ERROR; - } - - value *= 10; - value += *sfp->pos - '0'; - - continue; - } - - break; - } - - if (fpos == len || len - fpos > 3) { - return SF_ERR_PARSE_ERROR; - } - - if (dest) { - dest->type = SF_TYPE_DECIMAL; - dest->flags = SF_VALUE_FLAG_NONE; - dest->decimal.numer = value * sign; - - switch (len - fpos) { - case 1: - dest->decimal.denom = 10; - - break; - case 2: - dest->decimal.denom = 100; - - break; - case 3: - dest->decimal.denom = 1000; - - break; - } - } - - return 0; -} - -static int parser_date(sf_parser *sfp, sf_value *dest) { - int rv; - sf_value val; - - /* The first byte has already been validated by the caller. */ - assert('@' == *sfp->pos); - - ++sfp->pos; - - if (parser_eof(sfp)) { - return SF_ERR_PARSE_ERROR; - } - - rv = parser_number(sfp, &val); - if (rv != 0) { - return rv; - } - - if (val.type != SF_TYPE_INTEGER) { - return SF_ERR_PARSE_ERROR; - } - - if (dest) { - *dest = val; - dest->type = SF_TYPE_DATE; - } - - return 0; -} - -static int parser_string(sf_parser *sfp, sf_value *dest) { - const uint8_t *base; - uint32_t flags = SF_VALUE_FLAG_NONE; - - /* The first byte has already been validated by the caller. */ - assert('"' == *sfp->pos); - - base = ++sfp->pos; - - for (; !parser_eof(sfp); ++sfp->pos) { - switch (*sfp->pos) { - X20_21_CASES: - X23_5B_CASES: - X5D_7E_CASES: - break; - case '\\': - ++sfp->pos; - if (parser_eof(sfp)) { - return SF_ERR_PARSE_ERROR; - } - - switch (*sfp->pos) { - case '"': - case '\\': - flags = SF_VALUE_FLAG_ESCAPED_STRING; - - break; - default: - return SF_ERR_PARSE_ERROR; - } - - break; - case '"': - if (dest) { - dest->type = SF_TYPE_STRING; - dest->flags = flags; - dest->vec.len = (size_t)(sfp->pos - base); - dest->vec.base = dest->vec.len == 0 ? NULL : (uint8_t *)base; - } - - ++sfp->pos; - - return 0; - default: - return SF_ERR_PARSE_ERROR; - } - } - - return SF_ERR_PARSE_ERROR; -} - -static int parser_token(sf_parser *sfp, sf_value *dest) { - const uint8_t *base; - - /* The first byte has already been validated by the caller. */ - base = sfp->pos++; - - for (; !parser_eof(sfp); ++sfp->pos) { - switch (*sfp->pos) { - case '!': - case '#': - case '$': - case '%': - case '&': - case '\'': - case '*': - case '+': - case '-': - case '.': - case '^': - case '_': - case '`': - case '|': - case '~': - case ':': - case '/': - DIGIT_CASES: - ALPHA_CASES: - continue; - } - - break; - } - - if (dest) { - dest->type = SF_TYPE_TOKEN; - dest->flags = SF_VALUE_FLAG_NONE; - dest->vec.base = (uint8_t *)base; - dest->vec.len = (size_t)(sfp->pos - base); - } - - return 0; -} - -static int parser_byteseq(sf_parser *sfp, sf_value *dest) { - const uint8_t *base; - - /* The first byte has already been validated by the caller. */ - assert(':' == *sfp->pos); - - base = ++sfp->pos; - - for (; !parser_eof(sfp); ++sfp->pos) { - switch (*sfp->pos) { - case '+': - case '/': - DIGIT_CASES: - ALPHA_CASES: - continue; - case '=': - switch ((sfp->pos - base) & 0x3) { - case 0: - case 1: - return SF_ERR_PARSE_ERROR; - case 2: - switch (*(sfp->pos - 1)) { - case 'A': - case 'Q': - case 'g': - case 'w': - break; - default: - return SF_ERR_PARSE_ERROR; - } - - ++sfp->pos; - - if (parser_eof(sfp) || *sfp->pos != '=') { - return SF_ERR_PARSE_ERROR; - } - - break; - case 3: - switch (*(sfp->pos - 1)) { - case 'A': - case 'E': - case 'I': - case 'M': - case 'Q': - case 'U': - case 'Y': - case 'c': - case 'g': - case 'k': - case 'o': - case 's': - case 'w': - case '0': - case '4': - case '8': - break; - default: - return SF_ERR_PARSE_ERROR; - } - - break; - } - - ++sfp->pos; - - if (parser_eof(sfp) || *sfp->pos != ':') { - return SF_ERR_PARSE_ERROR; - } - - goto fin; - case ':': - if ((sfp->pos - base) & 0x3) { - return SF_ERR_PARSE_ERROR; - } - - goto fin; - default: - return SF_ERR_PARSE_ERROR; - } - } - - return SF_ERR_PARSE_ERROR; - -fin: - if (dest) { - dest->type = SF_TYPE_BYTESEQ; - dest->flags = SF_VALUE_FLAG_NONE; - dest->vec.len = (size_t)(sfp->pos - base); - dest->vec.base = dest->vec.len == 0 ? NULL : (uint8_t *)base; - } - - ++sfp->pos; - - return 0; -} - -static int parser_boolean(sf_parser *sfp, sf_value *dest) { - int b; - - /* The first byte has already been validated by the caller. */ - assert('?' == *sfp->pos); - - ++sfp->pos; - - if (parser_eof(sfp)) { - return SF_ERR_PARSE_ERROR; - } - - switch (*sfp->pos) { - case '0': - b = 0; - - break; - case '1': - b = 1; - - break; - default: - return SF_ERR_PARSE_ERROR; - } - - ++sfp->pos; - - if (dest) { - dest->type = SF_TYPE_BOOLEAN; - dest->flags = SF_VALUE_FLAG_NONE; - dest->boolean = b; - } - - return 0; -} - -static int parser_bare_item(sf_parser *sfp, sf_value *dest) { - switch (*sfp->pos) { - case '"': - return parser_string(sfp, dest); - case '-': - DIGIT_CASES: - return parser_number(sfp, dest); - case '@': - return parser_date(sfp, dest); - case ':': - return parser_byteseq(sfp, dest); - case '?': - return parser_boolean(sfp, dest); - case '*': - ALPHA_CASES: - return parser_token(sfp, dest); - default: - return SF_ERR_PARSE_ERROR; - } -} - -static int parser_skip_inner_list(sf_parser *sfp); - -int sf_parser_param(sf_parser *sfp, sf_vec *dest_key, sf_value *dest_value) { - int rv; - - switch (sfp->state & SF_STATE_OP_MASK) { - case SF_STATE_BEFORE: - rv = parser_skip_inner_list(sfp); - if (rv != 0) { - return rv; - } - - /* fall through */ - case SF_STATE_BEFORE_PARAMS: - parser_set_op_state(sfp, SF_STATE_PARAMS); - - break; - case SF_STATE_PARAMS: - break; - default: - assert(0); - abort(); - } - - if (parser_eof(sfp) || *sfp->pos != ';') { - parser_set_op_state(sfp, SF_STATE_AFTER); - - return SF_ERR_EOF; - } - - ++sfp->pos; - - parser_discard_sp(sfp); - if (parser_eof(sfp)) { - return SF_ERR_PARSE_ERROR; - } - - rv = parser_key(sfp, dest_key); - if (rv != 0) { - return rv; - } - - if (parser_eof(sfp) || *sfp->pos != '=') { - if (dest_value) { - dest_value->type = SF_TYPE_BOOLEAN; - dest_value->flags = SF_VALUE_FLAG_NONE; - dest_value->boolean = 1; - } - - return 0; - } - - ++sfp->pos; - - if (parser_eof(sfp)) { - return SF_ERR_PARSE_ERROR; - } - - return parser_bare_item(sfp, dest_value); -} - -static int parser_skip_params(sf_parser *sfp) { - int rv; - - for (;;) { - rv = sf_parser_param(sfp, NULL, NULL); - switch (rv) { - case 0: - break; - case SF_ERR_EOF: - return 0; - case SF_ERR_PARSE_ERROR: - return rv; - default: - assert(0); - abort(); - } - } -} - -int sf_parser_inner_list(sf_parser *sfp, sf_value *dest) { - int rv; - - switch (sfp->state & SF_STATE_OP_MASK) { - case SF_STATE_BEFORE: - parser_discard_sp(sfp); - if (parser_eof(sfp)) { - return SF_ERR_PARSE_ERROR; - } - - break; - case SF_STATE_BEFORE_PARAMS: - rv = parser_skip_params(sfp); - if (rv != 0) { - return rv; - } - - /* Technically, we are entering SF_STATE_AFTER, but we will set - another state without reading the state. */ - /* parser_set_op_state(sfp, SF_STATE_AFTER); */ - - /* fall through */ - case SF_STATE_AFTER: - if (parser_eof(sfp)) { - return SF_ERR_PARSE_ERROR; - } - - switch (*sfp->pos) { - case ' ': - parser_discard_sp(sfp); - if (parser_eof(sfp)) { - return SF_ERR_PARSE_ERROR; - } - - break; - case ')': - break; - default: - return SF_ERR_PARSE_ERROR; - } - - break; - default: - assert(0); - abort(); - } - - if (*sfp->pos == ')') { - ++sfp->pos; - - parser_unset_inner_list_state(sfp); - parser_set_op_state(sfp, SF_STATE_BEFORE_PARAMS); - - return SF_ERR_EOF; - } - - rv = parser_bare_item(sfp, dest); - if (rv != 0) { - return rv; - } - - parser_set_op_state(sfp, SF_STATE_BEFORE_PARAMS); - - return 0; -} - -static int parser_skip_inner_list(sf_parser *sfp) { - int rv; - - for (;;) { - rv = sf_parser_inner_list(sfp, NULL); - switch (rv) { - case 0: - break; - case SF_ERR_EOF: - return 0; - case SF_ERR_PARSE_ERROR: - return rv; - default: - assert(0); - abort(); - } - } -} - -static int parser_next_key_or_item(sf_parser *sfp) { - parser_discard_ows(sfp); - - if (parser_eof(sfp)) { - return SF_ERR_EOF; - } - - if (*sfp->pos != ',') { - return SF_ERR_PARSE_ERROR; - } - - ++sfp->pos; - - parser_discard_ows(sfp); - if (parser_eof(sfp)) { - return SF_ERR_PARSE_ERROR; - } - - return 0; -} - -static int parser_dict_value(sf_parser *sfp, sf_value *dest) { - int rv; - - if (parser_eof(sfp) || *(sfp->pos) != '=') { - /* Boolean true */ - if (dest) { - dest->type = SF_TYPE_BOOLEAN; - dest->flags = SF_VALUE_FLAG_NONE; - dest->boolean = 1; - } - - sfp->state = SF_STATE_DICT_BEFORE_PARAMS; - - return 0; - } - - ++sfp->pos; - - if (parser_eof(sfp)) { - return SF_ERR_PARSE_ERROR; - } - - if (*sfp->pos == '(') { - if (dest) { - dest->type = SF_TYPE_INNER_LIST; - dest->flags = SF_VALUE_FLAG_NONE; - } - - ++sfp->pos; - - sfp->state = SF_STATE_DICT_INNER_LIST_BEFORE; - - return 0; - } - - rv = parser_bare_item(sfp, dest); - if (rv != 0) { - return rv; - } - - sfp->state = SF_STATE_DICT_BEFORE_PARAMS; - - return 0; -} - -int sf_parser_dict(sf_parser *sfp, sf_vec *dest_key, sf_value *dest_value) { - int rv; - - switch (sfp->state) { - case SF_STATE_DICT_INNER_LIST_BEFORE: - rv = parser_skip_inner_list(sfp); - if (rv != 0) { - return rv; - } - - /* fall through */ - case SF_STATE_DICT_BEFORE_PARAMS: - rv = parser_skip_params(sfp); - if (rv != 0) { - return rv; - } - - /* fall through */ - case SF_STATE_DICT_AFTER: - rv = parser_next_key_or_item(sfp); - if (rv != 0) { - return rv; - } - - break; - case SF_STATE_INITIAL: - parser_discard_sp(sfp); - - if (parser_eof(sfp)) { - return SF_ERR_EOF; - } - - break; - default: - assert(0); - abort(); - } - - rv = parser_key(sfp, dest_key); - if (rv != 0) { - return rv; - } - - return parser_dict_value(sfp, dest_value); -} - -int sf_parser_list(sf_parser *sfp, sf_value *dest) { - int rv; - - switch (sfp->state) { - case SF_STATE_LIST_INNER_LIST_BEFORE: - rv = parser_skip_inner_list(sfp); - if (rv != 0) { - return rv; - } - - /* fall through */ - case SF_STATE_LIST_BEFORE_PARAMS: - rv = parser_skip_params(sfp); - if (rv != 0) { - return rv; - } - - /* fall through */ - case SF_STATE_LIST_AFTER: - rv = parser_next_key_or_item(sfp); - if (rv != 0) { - return rv; - } - - break; - case SF_STATE_INITIAL: - parser_discard_sp(sfp); - - if (parser_eof(sfp)) { - return SF_ERR_EOF; - } - - break; - default: - assert(0); - abort(); - } - - if (*sfp->pos == '(') { - if (dest) { - dest->type = SF_TYPE_INNER_LIST; - dest->flags = SF_VALUE_FLAG_NONE; - } - - ++sfp->pos; - - sfp->state = SF_STATE_LIST_INNER_LIST_BEFORE; - - return 0; - } - - rv = parser_bare_item(sfp, dest); - if (rv != 0) { - return rv; - } - - sfp->state = SF_STATE_LIST_BEFORE_PARAMS; - - return 0; -} - -int sf_parser_item(sf_parser *sfp, sf_value *dest) { - int rv; - - switch (sfp->state) { - case SF_STATE_INITIAL: - parser_discard_sp(sfp); - - if (parser_eof(sfp)) { - return SF_ERR_PARSE_ERROR; - } - - break; - case SF_STATE_ITEM_INNER_LIST_BEFORE: - rv = parser_skip_inner_list(sfp); - if (rv != 0) { - return rv; - } - - /* fall through */ - case SF_STATE_ITEM_BEFORE_PARAMS: - rv = parser_skip_params(sfp); - if (rv != 0) { - return rv; - } - - /* fall through */ - case SF_STATE_ITEM_AFTER: - parser_discard_sp(sfp); - - if (!parser_eof(sfp)) { - return SF_ERR_PARSE_ERROR; - } - - return SF_ERR_EOF; - default: - assert(0); - abort(); - } - - if (*sfp->pos == '(') { - if (dest) { - dest->type = SF_TYPE_INNER_LIST; - dest->flags = SF_VALUE_FLAG_NONE; - } - - ++sfp->pos; - - sfp->state = SF_STATE_ITEM_INNER_LIST_BEFORE; - - return 0; - } - - rv = parser_bare_item(sfp, dest); - if (rv != 0) { - return rv; - } - - sfp->state = SF_STATE_ITEM_BEFORE_PARAMS; - - return 0; -} - -void sf_parser_init(sf_parser *sfp, const uint8_t *data, size_t datalen) { - if (datalen == 0) { - sfp->pos = sfp->end = NULL; - } else { - sfp->pos = data; - sfp->end = data + datalen; - } - - sfp->state = SF_STATE_INITIAL; -} - -void sf_unescape(sf_vec *dest, const sf_vec *src) { - const uint8_t *p, *q; - uint8_t *o; - size_t len, slen; - - if (src->len == 0) { - *dest = *src; - - return; - } - - o = dest->base; - p = src->base; - len = src->len; - - for (;;) { - q = memchr(p, '\\', len); - if (q == NULL) { - if (len == src->len) { - *dest = *src; - - return; - } - - memcpy(o, p, len); - o += len; - - break; - } - - slen = (size_t)(q - p); - memcpy(o, p, slen); - o += slen; - - p = q + 1; - *o++ = *p++; - len -= slen + 2; - } - - dest->len = (size_t)(o - dest->base); -} - -void sf_base64decode(sf_vec *dest, const sf_vec *src) { - static const int index_tbl[] = { - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, 62, -1, -1, -1, 63, 52, 53, 54, 55, 56, 57, 58, 59, 60, - 61, -1, -1, -1, -1, -1, -1, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, - 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, - -1, -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, - 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1}; - uint8_t *o; - const uint8_t *p, *end; - uint32_t n; - size_t i; - int idx; - - assert((src->len & 0x3) == 0); - - if (src->len == 0) { - *dest = *src; - - return; - } - - o = dest->base; - p = src->base; - end = src->base + src->len; - - for (; p != end;) { - n = 0; - - for (i = 1; i <= 4; ++i, ++p) { - idx = index_tbl[*p]; - - if (idx == -1) { - assert(i > 2); - - if (i == 3) { - assert(*p == '=' && *(p + 1) == '=' && p + 2 == end); - - *o++ = (uint8_t)(n >> 16); - - goto fin; - } - - assert(*p == '=' && p + 1 == end); - - *o++ = (uint8_t)(n >> 16); - *o++ = (n >> 8) & 0xffu; - - goto fin; - } - - n += (uint32_t)(idx << (24 - i * 6)); - } - - *o++ = (uint8_t)(n >> 16); - *o++ = (n >> 8) & 0xffu; - *o++ = n & 0xffu; - } - -fin: - dest->len = (size_t)(o - dest->base); -} diff --git a/3rdparty/exported/nghttp2/sfparse.h b/3rdparty/exported/nghttp2/sfparse.h deleted file mode 100644 index 1474db1429ac..000000000000 --- a/3rdparty/exported/nghttp2/sfparse.h +++ /dev/null @@ -1,409 +0,0 @@ -/* - * sfparse - * - * Copyright (c) 2023 sfparse contributors - * Copyright (c) 2019 nghttp3 contributors - * Copyright (c) 2015 nghttp2 contributors - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE - * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION - * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION - * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ -#ifndef SFPARSE_H -#define SFPARSE_H - -/* Define WIN32 when build target is Win32 API (borrowed from - libcurl) */ -#if (defined(_WIN32) || defined(__WIN32__)) && !defined(WIN32) -# define WIN32 -#endif - -#ifdef __cplusplus -extern "C" { -#endif - -#if defined(_MSC_VER) && (_MSC_VER < 1800) -/* MSVC < 2013 does not have inttypes.h because it is not C99 - compliant. See compiler macros and version number in - https://sourceforge.net/p/predef/wiki/Compilers/ */ -# include -#else /* !defined(_MSC_VER) || (_MSC_VER >= 1800) */ -# include -#endif /* !defined(_MSC_VER) || (_MSC_VER >= 1800) */ -#include -#include - -/** - * @enum - * - * :type:`sf_type` defines value type. - */ -typedef enum sf_type { - /** - * :enum:`SF_TYPE_BOOLEAN` indicates boolean type. - */ - SF_TYPE_BOOLEAN, - /** - * :enum:`SF_TYPE_INTEGER` indicates integer type. - */ - SF_TYPE_INTEGER, - /** - * :enum:`SF_TYPE_DECIMAL` indicates decimal type. - */ - SF_TYPE_DECIMAL, - /** - * :enum:`SF_TYPE_STRING` indicates string type. - */ - SF_TYPE_STRING, - /** - * :enum:`SF_TYPE_TOKEN` indicates token type. - */ - SF_TYPE_TOKEN, - /** - * :enum:`SF_TYPE_BYTESEQ` indicates byte sequence type. - */ - SF_TYPE_BYTESEQ, - /** - * :enum:`SF_TYPE_INNER_LIST` indicates inner list type. - */ - SF_TYPE_INNER_LIST, - /** - * :enum:`SF_TYPE_DATE` indicates date type. - */ - SF_TYPE_DATE -} sf_type; - -/** - * @macro - * - * :macro:`SF_ERR_PARSE_ERROR` indicates fatal parse error has - * occurred, and it is not possible to continue the processing. - */ -#define SF_ERR_PARSE_ERROR -1 - -/** - * @macro - * - * :macro:`SF_ERR_EOF` indicates that there is nothing left to read. - * The context of this error varies depending on the function that - * returns this error code. - */ -#define SF_ERR_EOF -2 - -/** - * @struct - * - * :type:`sf_vec` stores sequence of bytes. - */ -typedef struct sf_vec { - /** - * :member:`base` points to the beginning of the sequence of bytes. - */ - uint8_t *base; - /** - * :member:`len` is the number of bytes contained in this sequence. - */ - size_t len; -} sf_vec; - -/** - * @macro - * - * :macro:`SF_VALUE_FLAG_NONE` indicates no flag set. - */ -#define SF_VALUE_FLAG_NONE 0x0u - -/** - * @macro - * - * :macro:`SF_VALUE_FLAG_ESCAPED_STRING` indicates that a string - * contains escaped character(s). - */ -#define SF_VALUE_FLAG_ESCAPED_STRING 0x1u - -/** - * @struct - * - * :type:`sf_decimal` contains decimal value. - */ -typedef struct sf_decimal { - /** - * :member:`numer` contains numerator of the decimal value. - */ - int64_t numer; - /** - * :member:`denom` contains denominator of the decimal value. - */ - int64_t denom; -} sf_decimal; - -/** - * @struct - * - * :type:`sf_value` stores a Structured Field item. For Inner List, - * only type is set to :enum:`sf_type.SF_TYPE_INNER_LIST`. In order - * to read the items contained in an inner list, call - * `sf_parser_inner_list`. - */ -typedef struct sf_value { - /** - * :member:`type` is the type of the value contained in this - * particular object. - */ - sf_type type; - /** - * :member:`flags` is bitwise OR of one or more of - * :macro:`SF_VALUE_FLAG_* `. - */ - uint32_t flags; - /** - * @anonunion_start - * - * @sf_value_value - */ - union { - /** - * :member:`boolean` contains boolean value if :member:`type` == - * :enum:`sf_type.SF_TYPE_BOOLEAN`. 1 indicates true, and 0 - * indicates false. - */ - int boolean; - /** - * :member:`integer` contains integer value if :member:`type` is - * either :enum:`sf_type.SF_TYPE_INTEGER` or - * :enum:`sf_type.SF_TYPE_DATE`. - */ - int64_t integer; - /** - * :member:`decimal` contains decimal value if :member:`type` == - * :enum:`sf_type.SF_TYPE_DECIMAL`. - */ - sf_decimal decimal; - /** - * :member:`vec` contains sequence of bytes if :member:`type` is - * either :enum:`sf_type.SF_TYPE_STRING`, - * :enum:`sf_type.SF_TYPE_TOKEN`, or - * :enum:`sf_type.SF_TYPE_BYTESEQ`. - * - * For :enum:`sf_type.SF_TYPE_STRING`, this field contains one or - * more escaped characters if :member:`flags` has - * :macro:`SF_VALUE_FLAG_ESCAPED_STRING` set. To unescape the - * string, use `sf_unescape`. - * - * For :enum:`sf_type.SF_TYPE_BYTESEQ`, this field contains base64 - * encoded string. To decode this byte string, use - * `sf_base64decode`. - * - * If :member:`vec.len ` == 0, :member:`vec.base - * ` is guaranteed to be NULL. - */ - sf_vec vec; - /** - * @anonunion_end - */ - }; -} sf_value; - -/** - * @struct - * - * :type:`sf_parser` is the Structured Field Values parser. Use - * `sf_parser_init` to initialize it. - */ -typedef struct sf_parser { - /* all fields are private */ - const uint8_t *pos; - const uint8_t *end; - uint32_t state; -} sf_parser; - -/** - * @function - * - * `sf_parser_init` initializes |sfp| with the given buffer pointed by - * |data| of length |datalen|. - */ -void sf_parser_init(sf_parser *sfp, const uint8_t *data, size_t datalen); - -/** - * @function - * - * `sf_parser_param` reads a parameter. If this function returns 0, - * it stores parameter key and value in |dest_key| and |dest_value| - * respectively, if they are not NULL. - * - * This function does no effort to find duplicated keys. Same key may - * be reported more than once. - * - * Caller should keep calling this function until it returns negative - * error code. If it returns :macro:`SF_ERR_EOF`, all parameters have - * read, and caller can continue to read rest of the values. If it - * returns :macro:`SF_ERR_PARSE_ERROR`, it encountered fatal error - * while parsing field value. - */ -int sf_parser_param(sf_parser *sfp, sf_vec *dest_key, sf_value *dest_value); - -/** - * @function - * - * `sf_parser_dict` reads the next dictionary key and value pair. If - * this function returns 0, it stores the key and value in |dest_key| - * and |dest_value| respectively, if they are not NULL. - * - * Caller can optionally read parameters attached to the pair by - * calling `sf_parser_param`. - * - * This function does no effort to find duplicated keys. Same key may - * be reported more than once. - * - * Caller should keep calling this function until it returns negative - * error code. If it returns :macro:`SF_ERR_EOF`, all key and value - * pairs have been read, and there is nothing left to read. - * - * This function returns 0 if it succeeds, or one of the following - * negative error codes: - * - * :macro:`SF_ERR_EOF` - * All values in the dictionary have read. - * :macro:`SF_ERR_PARSE_ERROR` - * It encountered fatal error while parsing field value. - */ -int sf_parser_dict(sf_parser *sfp, sf_vec *dest_key, sf_value *dest_value); - -/** - * @function - * - * `sf_parser_list` reads the next list item. If this function - * returns 0, it stores the item in |dest| if it is not NULL. - * - * Caller can optionally read parameters attached to the item by - * calling `sf_parser_param`. - * - * Caller should keep calling this function until it returns negative - * error code. If it returns :macro:`SF_ERR_EOF`, all values in the - * list have been read, and there is nothing left to read. - * - * This function returns 0 if it succeeds, or one of the following - * negative error codes: - * - * :macro:`SF_ERR_EOF` - * All values in the list have read. - * :macro:`SF_ERR_PARSE_ERROR` - * It encountered fatal error while parsing field value. - */ -int sf_parser_list(sf_parser *sfp, sf_value *dest); - -/** - * @function - * - * `sf_parser_item` reads a single item. If this function returns 0, - * it stores the item in |dest| if it is not NULL. - * - * This function is only used for the field value that consists of a - * single item. - * - * Caller can optionally read parameters attached to the item by - * calling `sf_parser_param`. - * - * Caller should call this function again to make sure that there is - * nothing left to read. If this 2nd function call returns - * :macro:`SF_ERR_EOF`, all data have been processed successfully. - * - * This function returns 0 if it succeeds, or one of the following - * negative error codes: - * - * :macro:`SF_ERR_EOF` - * There is nothing left to read. - * :macro:`SF_ERR_PARSE_ERROR` - * It encountered fatal error while parsing field value. - */ -int sf_parser_item(sf_parser *sfp, sf_value *dest); - -/** - * @function - * - * `sf_parser_inner_list` reads the next inner list item. If this - * function returns 0, it stores the item in |dest| if it is not NULL. - * - * Caller can optionally read parameters attached to the item by - * calling `sf_parser_param`. - * - * Caller should keep calling this function until it returns negative - * error code. If it returns :macro:`SF_ERR_EOF`, all values in this - * inner list have been read, and caller can optionally read - * parameters attached to this inner list by calling - * `sf_parser_param`. Then caller can continue to read rest of the - * values. - * - * This function returns 0 if it succeeds, or one of the following - * negative error codes: - * - * :macro:`SF_ERR_EOF` - * All values in the inner list have read. - * :macro:`SF_ERR_PARSE_ERROR` - * It encountered fatal error while parsing field value. - */ -int sf_parser_inner_list(sf_parser *sfp, sf_value *dest); - -/** - * @function - * - * `sf_unescape` copies |src| to |dest| by removing escapes (``\``). - * |src| should be the pointer to :member:`sf_value.vec` of type - * :enum:`sf_type.SF_TYPE_STRING` produced by either `sf_parser_dict`, - * `sf_parser_list`, `sf_parser_inner_list`, `sf_parser_item`, or - * `sf_parser_param`, otherwise the behavior is undefined. - * - * :member:`dest->base ` must point to the buffer that - * has sufficient space to store the unescaped string. - * - * If there is no escape character in |src|, |*src| is assigned to - * |*dest|. This includes the case that :member:`src->len - * ` == 0. - * - * This function sets the length of unescaped string to - * :member:`dest->len `. - */ -void sf_unescape(sf_vec *dest, const sf_vec *src); - -/** - * @function - * - * `sf_base64decode` decodes Base64 encoded string |src| and writes - * the result into |dest|. |src| should be the pointer to - * :member:`sf_value.vec` of type :enum:`sf_type.SF_TYPE_BYTESEQ` - * produced by either `sf_parser_dict`, `sf_parser_list`, - * `sf_parser_inner_list`, `sf_parser_item`, or `sf_parser_param`, - * otherwise the behavior is undefined. - * - * :member:`dest->base ` must point to the buffer that - * has sufficient space to store the decoded byte string. - * - * If :member:`src->len ` == 0, |*src| is assigned to - * |*dest|. - * - * This function sets the length of decoded byte string to - * :member:`dest->len `. - */ -void sf_base64decode(sf_vec *dest, const sf_vec *src); - -#ifdef __cplusplus -} -#endif - -#endif /* SFPARSE_H */ diff --git a/3rdparty/exported/nghttp2/version.rc.in b/3rdparty/exported/nghttp2/version.rc.in deleted file mode 100644 index 4edfa7a49f99..000000000000 --- a/3rdparty/exported/nghttp2/version.rc.in +++ /dev/null @@ -1,40 +0,0 @@ -#include - -VS_VERSION_INFO VERSIONINFO - -FILEVERSION @PROJECT_VERSION_MAJOR@, @PROJECT_VERSION_MINOR@, @PROJECT_VERSION_PATCH@, 0 -PRODUCTVERSION @PROJECT_VERSION_MAJOR@, @PROJECT_VERSION_MINOR@, @PROJECT_VERSION_PATCH@, 0 -FILEFLAGSMASK 0x3fL -FILEOS 0x40004L -FILETYPE 0x2L -FILESUBTYPE 0x0L -#ifdef _DEBUG - #define VER_STR "@PROJECT_VERSION@.0 (MSVC debug)" - #define DBG "d" - FILEFLAGS 0x1L -#else - #define VER_STR "@PROJECT_VERSION@.0 (MSVC release)" - #define DBG "" - FILEFLAGS 0x0L -#endif -BEGIN -BLOCK "StringFileInfo" -BEGIN - BLOCK "040904b0" - BEGIN - VALUE "CompanyName", "https://nghttp2.org/" - VALUE "FileDescription", "nghttp2; HTTP/2 C library" - VALUE "FileVersion", VER_STR - VALUE "InternalName", "nghttp2" DBG - VALUE "LegalCopyright", "The MIT License" - VALUE "LegalTrademarks", "" - VALUE "OriginalFilename", "nghttp2" DBG ".dll" - VALUE "ProductName", "NGHTTP2." - VALUE "ProductVersion", VER_STR - END -END -BLOCK "VarFileInfo" -BEGIN -VALUE "Translation", 0x409, 1200 -END -END diff --git a/CMakeLists.txt b/CMakeLists.txt index 6640fec8ca50..4cbe3559e194 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -216,7 +216,6 @@ set(CCF_ENDPOINTS_SOURCES include(${CCF_DIR}/cmake/crypto.cmake) include(${CCF_DIR}/cmake/quickjs.cmake) -include(${CCF_DIR}/cmake/nghttp2.cmake) include(${CCF_DIR}/cmake/qcbor.cmake) include(${CCF_DIR}/cmake/t_cose.cmake) @@ -536,7 +535,7 @@ if(COMPILE_TARGET STREQUAL "snp") ccf_endpoints.snp ccfcrypto.snp ccf_kv.snp - nghttp2.snp + nghttp2 ${CMAKE_THREAD_LIBS_INIT} ) @@ -585,7 +584,7 @@ elseif(COMPILE_TARGET STREQUAL "virtual") ccf_endpoints.host ccfcrypto.host ccf_kv.host - nghttp2.host + nghttp2 ${CMAKE_THREAD_LIBS_INIT} ) diff --git a/cgmanifest.json b/cgmanifest.json index e448c442b7a6..1d6d643d57f8 100644 --- a/cgmanifest.json +++ b/cgmanifest.json @@ -100,15 +100,6 @@ } } }, - { - "component": { - "type": "git", - "git": { - "repositoryUrl": "https://github.com/nghttp2/nghttp2", - "commitHash": "781057e15626bf403c8739c25166ad123aa17ff3" - } - } - }, { "component": { "type": "git", diff --git a/cmake/cpack_settings.cmake b/cmake/cpack_settings.cmake index d3d57e0bd6e9..5feafa25d3fc 100644 --- a/cmake/cpack_settings.cmake +++ b/cmake/cpack_settings.cmake @@ -21,7 +21,9 @@ message(STATUS "Debian package version: ${CPACK_DEBIAN_PACKAGE_VERSION}") # Note: On Ubuntu, the most up-to-date version of the OpenSSL deb package is # 1.1.1f, which corresponds to the OpenSSL 1.1.1t release (latest security # patches). -set(CCF_DEB_BASE_DEPENDENCIES "libuv1 (>= 1.34.2);openssl (>=1.1.1f)") +set(CCF_DEB_BASE_DEPENDENCIES + "libuv1 (>= 1.34.2);openssl (>=1.1.1f);libnghttp2-14 (>=1.40.0)" +) set(CCF_DEB_DEPENDENCIES ${CCF_DEB_BASE_DEPENDENCIES}) list(APPEND CCF_DEB_DEPENDENCIES "libc++1-15;libc++abi1-15") diff --git a/cmake/nghttp2.cmake b/cmake/nghttp2.cmake deleted file mode 100644 index b2397a572fdb..000000000000 --- a/cmake/nghttp2.cmake +++ /dev/null @@ -1,74 +0,0 @@ -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the Apache 2.0 License. - -set(NGHTTP2_PREFIX - ${CCF_3RD_PARTY_EXPORTED_DIR}/nghttp2 - CACHE PATH "Prefix to NGHTTP2 library" -) - -set(NGHTTP2_SRCS - ${NGHTTP2_PREFIX}/nghttp2_buf.c - ${NGHTTP2_PREFIX}/nghttp2_callbacks.c - ${NGHTTP2_PREFIX}/nghttp2_debug.c - ${NGHTTP2_PREFIX}/nghttp2_frame.c - ${NGHTTP2_PREFIX}/nghttp2_hd.c - ${NGHTTP2_PREFIX}/nghttp2_hd_huffman.c - ${NGHTTP2_PREFIX}/nghttp2_hd_huffman_data.c - ${NGHTTP2_PREFIX}/nghttp2_helper.c - ${NGHTTP2_PREFIX}/nghttp2_http.c - ${NGHTTP2_PREFIX}/nghttp2_map.c - ${NGHTTP2_PREFIX}/nghttp2_mem.c - ${NGHTTP2_PREFIX}/nghttp2_alpn.c - ${NGHTTP2_PREFIX}/nghttp2_option.c - ${NGHTTP2_PREFIX}/nghttp2_outbound_item.c - ${NGHTTP2_PREFIX}/nghttp2_pq.c - ${NGHTTP2_PREFIX}/nghttp2_priority_spec.c - ${NGHTTP2_PREFIX}/nghttp2_queue.c - ${NGHTTP2_PREFIX}/nghttp2_rcbuf.c - ${NGHTTP2_PREFIX}/nghttp2_extpri.c - ${NGHTTP2_PREFIX}/nghttp2_session.c - ${NGHTTP2_PREFIX}/nghttp2_stream.c - ${NGHTTP2_PREFIX}/nghttp2_submit.c - ${NGHTTP2_PREFIX}/nghttp2_version.c - ${NGHTTP2_PREFIX}/nghttp2_ratelim.c - ${NGHTTP2_PREFIX}/nghttp2_time.c - ${NGHTTP2_PREFIX}/sfparse.c -) - -if(COMPILE_TARGET STREQUAL "snp") - add_library(nghttp2.snp STATIC ${NGHTTP2_SRCS}) - target_include_directories( - nghttp2.snp PUBLIC $ - $ - ) - target_compile_definitions( - nghttp2.snp PUBLIC -DNGHTTP2_STATICLIB -DHAVE_ARPA_INET_H=1 - ) - add_san(nghttp2.snp) - set_property(TARGET nghttp2.snp PROPERTY POSITION_INDEPENDENT_CODE ON) - - install( - TARGETS nghttp2.snp - EXPORT ccf - DESTINATION lib - ) -endif() - -add_library(nghttp2.host STATIC ${NGHTTP2_SRCS}) -target_include_directories( - nghttp2.host PUBLIC $ - $ -) -target_compile_definitions( - nghttp2.host PUBLIC -DNGHTTP2_STATICLIB -DHAVE_ARPA_INET_H=1 -) -add_san(nghttp2.host) -set_property(TARGET nghttp2.host PROPERTY POSITION_INDEPENDENT_CODE ON) - -if(INSTALL_VIRTUAL_LIBRARIES) - install( - TARGETS nghttp2.host - EXPORT ccf - DESTINATION lib - ) -endif() diff --git a/docker/ccf_ci_built b/docker/ccf_ci_built index c1ddb865c3bc..0b030d074876 100644 --- a/docker/ccf_ci_built +++ b/docker/ccf_ci_built @@ -3,7 +3,7 @@ # Also contains CCF source and build directory # Latest image as of this change -ARG base=ghcr.io/microsoft/ccf/ci/default:build-08-01-2025-1 +ARG base=ghcr.io/microsoft/ccf/ci/default:build-08-01-2025-2 FROM ${base} # SSH. Note that this could (should) be done in the base ccf_ci image instead From f5cb0a7835b2a5841cd4a1561633919b6f75c526 Mon Sep 17 00:00:00 2001 From: Amaury Chamayou Date: Thu, 9 Jan 2025 09:56:50 +0000 Subject: [PATCH 2/2] Upgrade QCBOR from 1.2 to 1.5 and t_cose from 1.1 to 1.1.3 (#6744) Co-authored-by: Max --- 3rdparty/exported/QCBOR/CMakeLists.txt | 23 +- 3rdparty/exported/QCBOR/Makefile | 2 +- .../QCBOR/QCBOR.xcodeproj/project.pbxproj | 6 +- 3rdparty/exported/QCBOR/README.md | 78 +- 3rdparty/exported/QCBOR/cmd_line_main.c | 4 +- 3rdparty/exported/QCBOR/doc/Tagging.md | 2 + 3rdparty/exported/QCBOR/example.c | 18 +- 3rdparty/exported/QCBOR/example.h | 2 +- 3rdparty/exported/QCBOR/qcbor/UsefulBuf.h | 183 +- 3rdparty/exported/QCBOR/qcbor/qcbor_common.h | 612 +- 3rdparty/exported/QCBOR/qcbor/qcbor_decode.h | 684 +- 3rdparty/exported/QCBOR/qcbor/qcbor_encode.h | 5034 +++--- 3rdparty/exported/QCBOR/qcbor/qcbor_private.h | 450 +- .../QCBOR/qcbor/qcbor_spiffy_decode.h | 3876 +++-- 3rdparty/exported/QCBOR/src/UsefulBuf.c | 367 +- 3rdparty/exported/QCBOR/src/ieee754.c | 914 +- 3rdparty/exported/QCBOR/src/ieee754.h | 219 +- 3rdparty/exported/QCBOR/src/qcbor_decode.c | 4094 +++-- 3rdparty/exported/QCBOR/src/qcbor_encode.c | 759 +- .../exported/QCBOR/src/qcbor_err_to_str.c | 147 +- .../exported/QCBOR/test/UsefulBuf_Tests.c | 275 +- .../exported/QCBOR/test/UsefulBuf_Tests.h | 66 +- 3rdparty/exported/QCBOR/test/float_tests.c | 1170 +- 3rdparty/exported/QCBOR/test/float_tests.h | 33 +- .../QCBOR/test/half_to_double_from_rfc7049.c | 2 +- .../QCBOR/test/half_to_double_from_rfc7049.h | 4 +- .../QCBOR/test/not_well_formed_cbor.h | 9 +- .../exported/QCBOR/test/qcbor_decode_tests.c | 13733 +++++++++------- .../exported/QCBOR/test/qcbor_decode_tests.h | 15 +- .../exported/QCBOR/test/qcbor_encode_tests.c | 385 +- .../exported/QCBOR/test/qcbor_encode_tests.h | 9 +- 3rdparty/exported/QCBOR/test/run_tests.c | 37 +- 3rdparty/exported/QCBOR/test/run_tests.h | 4 +- 3rdparty/exported/QCBOR/ub-example.c | 2 +- 3rdparty/exported/QCBOR/ub-example.h | 2 +- 3rdparty/exported/t_cose/CMakeLists.txt | 2 +- 3rdparty/exported/t_cose/CONTRIBUTING.md | 107 +- 3rdparty/exported/t_cose/Makefile.ossl | 4 +- 3rdparty/exported/t_cose/Makefile.psa | 4 +- 3rdparty/exported/t_cose/Makefile.test | 10 +- 3rdparty/exported/t_cose/README.md | 22 +- .../t_cose/inc/t_cose/t_cose_common.h | 10 +- 3rdparty/exported/t_cose/mainpage.dox | 18 + .../exported/t_cose/src/t_cose_sign1_sign.c | 8 +- .../exported/t_cose/src/t_cose_sign1_verify.c | 7 +- .../t_cose/t_cose.xcodeproj/project.pbxproj | 4 +- cgmanifest.json | 4 +- 47 files changed, 19513 insertions(+), 13907 deletions(-) create mode 100644 3rdparty/exported/t_cose/mainpage.dox diff --git a/3rdparty/exported/QCBOR/CMakeLists.txt b/3rdparty/exported/QCBOR/CMakeLists.txt index 486946ce9e65..1c7e081f9937 100644 --- a/3rdparty/exported/QCBOR/CMakeLists.txt +++ b/3rdparty/exported/QCBOR/CMakeLists.txt @@ -11,7 +11,7 @@ cmake_minimum_required(VERSION 3.15) project(qcbor DESCRIPTION "QCBOR" LANGUAGES C - VERSION 1.1.0 + VERSION 1.5.0 ) set(BUILD_QCBOR_TEST "OFF" CACHE STRING "Build QCBOR test suite [OFF, LIB, APP]") @@ -72,6 +72,27 @@ if (CMAKE_C_COMPILER_ID STREQUAL "GNU") ) endif() +set(HEADERS + inc/qcbor/qcbor.h + inc/qcbor/qcbor_common.h + inc/qcbor/qcbor_private.h + inc/qcbor/qcbor_encode.h + inc/qcbor/qcbor_decode.h + inc/qcbor/qcbor_spiffy_decode.h + inc/qcbor/UsefulBuf.h +) +set_target_properties( + qcbor PROPERTIES + VERSION ${PROJECT_VERSION} + SOVERSION ${PROJECT_VERSION_MAJOR} + PUBLIC_HEADER "${HEADERS}" +) +include(GNUInstallDirs) +install( + TARGETS qcbor + PUBLIC_HEADER DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/qcbor" +) + if (NOT BUILD_QCBOR_TEST STREQUAL "OFF") add_subdirectory(test) endif() diff --git a/3rdparty/exported/QCBOR/Makefile b/3rdparty/exported/QCBOR/Makefile index d5d359b7121c..defcb720d08b 100644 --- a/3rdparty/exported/QCBOR/Makefile +++ b/3rdparty/exported/QCBOR/Makefile @@ -45,7 +45,7 @@ libqcbor.a: $(QCBOR_OBJ) # run "make warn" as a handy way to compile with the warning flags # used in the QCBOR release process. See CFLAGS above. warn: - make CMD_LINE="-Wall -Wextra -Wpedantic -Wshadow -Wconversion -Wcast-qual" + make CMD_LINE="$(CMD_LINE) -Wall -Wextra -Wpedantic -Wshadow -Wconversion -Wcast-qual" # The shared library is not made by default because of platform diff --git a/3rdparty/exported/QCBOR/QCBOR.xcodeproj/project.pbxproj b/3rdparty/exported/QCBOR/QCBOR.xcodeproj/project.pbxproj index c1e6cd710ed0..e43bf040f119 100644 --- a/3rdparty/exported/QCBOR/QCBOR.xcodeproj/project.pbxproj +++ b/3rdparty/exported/QCBOR/QCBOR.xcodeproj/project.pbxproj @@ -150,8 +150,8 @@ 0FA9BEB9216DC7AD00BA646B /* qcbor_encode_tests.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = qcbor_encode_tests.h; path = test/qcbor_encode_tests.h; sourceTree = ""; }; 0FA9BEBB216DE31700BA646B /* UsefulBuf_Tests.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = UsefulBuf_Tests.h; path = test/UsefulBuf_Tests.h; sourceTree = ""; }; 0FA9BEBC216DE31700BA646B /* UsefulBuf_Tests.c */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 3; lastKnownFileType = sourcecode.c.c; name = UsefulBuf_Tests.c; path = test/UsefulBuf_Tests.c; sourceTree = ""; tabWidth = 3; }; - E73B57572161CA680080D658 /* ieee754.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ieee754.h; path = src/ieee754.h; sourceTree = ""; }; - E73B57582161CA690080D658 /* ieee754.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = ieee754.c; path = src/ieee754.c; sourceTree = ""; }; + E73B57572161CA680080D658 /* ieee754.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 3; lastKnownFileType = sourcecode.c.h; name = ieee754.h; path = src/ieee754.h; sourceTree = ""; tabWidth = 3; }; + E73B57582161CA690080D658 /* ieee754.c */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 3; lastKnownFileType = sourcecode.c.c; name = ieee754.c; path = src/ieee754.c; sourceTree = ""; tabWidth = 3; }; E73B575A2161CA7C0080D658 /* float_tests.c */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 3; lastKnownFileType = sourcecode.c.c; name = float_tests.c; path = test/float_tests.c; sourceTree = ""; tabWidth = 3; }; E73B575B2161CA7C0080D658 /* half_to_double_from_rfc7049.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = half_to_double_from_rfc7049.h; path = test/half_to_double_from_rfc7049.h; sourceTree = ""; }; E73B575C2161CA7C0080D658 /* float_tests.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = float_tests.h; path = test/float_tests.h; sourceTree = ""; }; @@ -173,7 +173,7 @@ E776E094214AE09700E67947 /* UsefulBuf.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 3; lastKnownFileType = sourcecode.c.h; name = UsefulBuf.h; path = inc/UsefulBuf.h; sourceTree = ""; tabWidth = 3; }; E776E096214AE0C700E67947 /* cmd_line_main.c */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 3; lastKnownFileType = sourcecode.c.c; path = cmd_line_main.c; sourceTree = ""; tabWidth = 3; }; E776E161214EE19C00E67947 /* README.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = ""; }; - E7864765252CE63100A0C11B /* qcbor_err_to_str.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = qcbor_err_to_str.c; path = src/qcbor_err_to_str.c; sourceTree = ""; }; + E7864765252CE63100A0C11B /* qcbor_err_to_str.c */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 3; lastKnownFileType = sourcecode.c.c; name = qcbor_err_to_str.c; path = src/qcbor_err_to_str.c; sourceTree = ""; tabWidth = 3; }; E78C91DE240C90C100F4CECE /* qcbor_decode.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 3; lastKnownFileType = sourcecode.c.h; name = qcbor_decode.h; path = inc/qcbor/qcbor_decode.h; sourceTree = ""; tabWidth = 3; }; E78C91DF240C90C100F4CECE /* qcbor_common.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 3; lastKnownFileType = sourcecode.c.h; name = qcbor_common.h; path = inc/qcbor/qcbor_common.h; sourceTree = ""; tabWidth = 3; }; E78C91E0240C90C100F4CECE /* qcbor_private.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 3; lastKnownFileType = sourcecode.c.h; name = qcbor_private.h; path = inc/qcbor/qcbor_private.h; sourceTree = ""; tabWidth = 3; }; diff --git a/3rdparty/exported/QCBOR/README.md b/3rdparty/exported/QCBOR/README.md index 673e940e1469..46148806cc65 100644 --- a/3rdparty/exported/QCBOR/README.md +++ b/3rdparty/exported/QCBOR/README.md @@ -1,9 +1,9 @@ ![QCBOR Logo](https://github.com/laurencelundblade/qdv/blob/master/logo.png?raw=true) -**QCBOR** is a powerful, commercial-quality CBOR encoder/decoder that +**QCBOR** is a powerful, commercial-quality CBOR encoder-decoder that implements these RFCs: -* [RFC8949](https://tools.ietf.org/html/rfc8949) The CBOR Standard. (Everything +* [RFC8949](https://tools.ietf.org/html/rfc8949) The CBOR Standard. (Nearly everything except sorting of encoded maps) * [RFC7049](https://tools.ietf.org/html/rfc7049) The previous CBOR standard. Replaced by RFC 8949. @@ -88,9 +88,9 @@ implementations as seen in the following example. /* Encode */ QCBOREncode_Init(&EncodeCtx, Buffer); QCBOREncode_OpenMap(&EncodeCtx); - QCBOREncode_AddTextToMap(&EncodeCtx, "Manufacturer", pE->Manufacturer); - QCBOREncode_AddInt64ToMap(&EncodeCtx, "Displacement", pE->uDisplacement); - QCBOREncode_AddInt64ToMap(&EncodeCtx, "Horsepower", pE->uHorsePower); + QCBOREncode_AddTextToMapSZ(&EncodeCtx, "Manufacturer", pE->Manufacturer); + QCBOREncode_AddInt64ToMapSZ(&EncodeCtx, "Displacement", pE->uDisplacement); + QCBOREncode_AddInt64ToMapSZ(&EncodeCtx, "Horsepower", pE->uHorsePower); QCBOREncode_CloseMap(&EncodeCtx); uErr = QCBOREncode_Finish(&EncodeCtx, &EncodedEngine); @@ -168,11 +168,14 @@ QCBOR. ## Code Status -The current version is v1.1, a small feature addition and bug fix -release over QCBOR 1.0. +The official current release is version 1.5 Changes over the last few +years have been only minor bug fixes, minor feature additions and +documentation improvements. QCBOR 1.x is highly stable. -Code has been stable for over a year. The last major change was in -fall of 2020. +Work on some larger feature additions is ongoing in "dev" branch. +This includes more explicit support for preferred serialization and +CDE (CBOR Deterministic Encoding). It will eventually be release as +QCBOR 2.x. QCBOR was originally developed by Qualcomm. It was [open sourced through CAF](https://source.codeaurora.org/quic/QCBOR/QCBOR/) with a @@ -375,17 +378,21 @@ available options and the associated #defines. ## Code Size These are approximate sizes on a 64-bit x86 CPU with the -Os optimization. +All QCBOR_DISABLE_XXX are set and compiler stack frame checking is disabled +for smallest but not for largest. Smallest is the library functions for a +protocol with strings, integers, arrays, maps and Booleans, but not floats +and standard tag types. | | smallest | largest | |---------------|----------|---------| - | encode only | 900 | 2100 | + | encode only | 850 | 2200 | | decode only | 1550 | 13300 | - | combined | 2450 | 15500 | + | combined | 2500 | 15500 | From the table above, one can see that the amount of code pulled in from the QCBOR library varies a lot, ranging from 1KB to 15KB. The - main factor is in this is the number of QCBOR functions called and - which ones they are. QCBOR is constructed with less internal + main factor is the number of QCBOR functions called and + which ones they are. QCBOR minimizes internal interdependency so only code necessary for the called functions is brought in. @@ -436,6 +443,7 @@ code. The amount saved is an approximation. | QCBOR_DISABLE_PREFERRED_FLOAT | 900 | | QCBOR_DISABLE_FLOAT_HW_USE | 50 | | QCBOR_DISABLE_TAGS | 400 | + | QCBOR_DISABLE_NON_INTEGER_LABELS | 140 | | USEFULBUF_DISABLE_ALL_FLOAT | 950 | QCBOR_DISABLE_ENCODE_USAGE_GUARDS affects encoding only. It doesn't @@ -475,6 +483,12 @@ a single tag, the error is unrecoverable so it is suitable only for protocols th have no tags. "Borrowed" tag content formats (e.g. an epoch-based date without the tag number), can still be processed. +QCBOR_DISABLE_NON_INTEGER_LABELS causes any label that doesn't +fit in an int64_t to result in a QCBOR_ERR_MAP_LABEL_TYPE error. +This also disables QCBOR_DECODE_MODE_MAP_AS_ARRAY and +QCBOR_DECODE_MODE_MAP_STRINGS_ONLY. It is fairly common for CBOR-based +protocols to use only small integers as labels. + See the discussion above on floating-point. ### Size of spiffy decode @@ -524,44 +538,8 @@ EAT and CWT. * Máté Tóth-Pál for float-point disabling and other * Dave Thaler for portability to Windows -## Copyright and License - -QCBOR is available under what is essentially the 3-Clause BSD License. - -Files created inside Qualcomm and open-sourced through CAF (The Code -Aurora Forum) have a slightly modified 3-Clause BSD License. The -modification additionally disclaims NON-INFRINGEMENT. - -Files created after release to CAF use the standard 3-Clause BSD -License with no modification. These files have the SPDX license -identifier, "SPDX-License-Identifier: BSD-3-Clause" in them. - -### BSD-3-Clause license - -* Redistributions of source code must retain the above copyright -notice, this list of conditions and the following disclaimer. - -* Redistributions in binary form must reproduce the above copyright -notice, this list of conditions and the following disclaimer in the -documentation and/or other materials provided with the distribution. - -* Neither the name of the copyright holder nor the names of its -contributors may be used to endorse or promote products derived from -this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ### Copyright for this README -Copyright (c) 2018-2021, Laurence Lundblade. All rights reserved. +Copyright (c) 2018-2024, Laurence Lundblade. All rights reserved. Copyright (c) 2021-2023, Arm Limited. All rights reserved. diff --git a/3rdparty/exported/QCBOR/cmd_line_main.c b/3rdparty/exported/QCBOR/cmd_line_main.c index 59ceb3a7c7c1..da5d0711cba4 100644 --- a/3rdparty/exported/QCBOR/cmd_line_main.c +++ b/3rdparty/exported/QCBOR/cmd_line_main.c @@ -1,11 +1,11 @@ /*============================================================================== - cmd_line_mainc.c -- Runs tests for QCBOR encoder / decoder + cmd_line_mainc.c -- Runs tests for QCBOR encoder-decoder Copyright (c) 2018-2020, Laurence Lundblade. All rights reserved. SPDX-License-Identifier: BSD-3-Clause - See BSD-3-Clause license in README.md + See BSD-3-Clause license in file named "LICENSE" Created on 9/13/18 =============================================================================*/ diff --git a/3rdparty/exported/QCBOR/doc/Tagging.md b/3rdparty/exported/QCBOR/doc/Tagging.md index 7d6518518ddc..9d9538285596 100644 --- a/3rdparty/exported/QCBOR/doc/Tagging.md +++ b/3rdparty/exported/QCBOR/doc/Tagging.md @@ -1,3 +1,5 @@ +@file Tagging.md + @anchor CBORTags # Types and Tagging in CBOR diff --git a/3rdparty/exported/QCBOR/example.c b/3rdparty/exported/QCBOR/example.c index d580c78f0056..c489ad61e61e 100644 --- a/3rdparty/exported/QCBOR/example.c +++ b/3rdparty/exported/QCBOR/example.c @@ -6,7 +6,7 @@ SPDX-License-Identifier: BSD-3-Clause - See BSD-3-Clause license in README.md + See BSD-3-Clause license in file named "LICENSE" Created on 6/30/2020 ========================================================================== */ @@ -130,7 +130,7 @@ static bool EngineCompare(const CarEngine *pE1, const CarEngine *pE2) * @return The pointer and length of the encoded CBOR or * @ref NULLUsefulBufC on error. * - * This encodes the input structure \c pEngine as a CBOR map of + * This encodes the input structure @c pEngine as a CBOR map of * label-value pairs. An array of float is one of the items in the * map. * @@ -162,14 +162,14 @@ UsefulBufC EncodeEngine(const CarEngine *pEngine, UsefulBuf Buffer) /* Proceed to output all the items, letting the internal error * tracking do its work */ QCBOREncode_OpenMap(&EncodeCtx); - QCBOREncode_AddTextToMap(&EncodeCtx, "Manufacturer", pEngine->Manufacturer); - QCBOREncode_AddInt64ToMap(&EncodeCtx, "NumCylinders", pEngine->uNumCylinders); - QCBOREncode_AddInt64ToMap(&EncodeCtx, "Displacement", pEngine->uDisplacement); - QCBOREncode_AddInt64ToMap(&EncodeCtx, "Horsepower", pEngine->uHorsePower); + QCBOREncode_AddTextToMapSZ(&EncodeCtx, "Manufacturer", pEngine->Manufacturer); + QCBOREncode_AddInt64ToMapSZ(&EncodeCtx, "NumCylinders", pEngine->uNumCylinders); + QCBOREncode_AddInt64ToMapSZ(&EncodeCtx, "Displacement", pEngine->uDisplacement); + QCBOREncode_AddInt64ToMapSZ(&EncodeCtx, "Horsepower", pEngine->uHorsePower); #ifndef USEFULBUF_DISABLE_ALL_FLOAT - QCBOREncode_AddDoubleToMap(&EncodeCtx, "DesignedCompression", pEngine->dDesignedCompresion); + QCBOREncode_AddDoubleToMapSZ(&EncodeCtx, "DesignedCompression", pEngine->dDesignedCompresion); #endif /* USEFULBUF_DISABLE_ALL_FLOAT */ - QCBOREncode_OpenArrayInMap(&EncodeCtx, "Cylinders"); + QCBOREncode_OpenArrayInMapSZ(&EncodeCtx, "Cylinders"); #ifndef USEFULBUF_DISABLE_ALL_FLOAT for(int64_t i = 0 ; i < pEngine->uNumCylinders; i++) { QCBOREncode_AddDouble(&EncodeCtx, @@ -177,7 +177,7 @@ UsefulBufC EncodeEngine(const CarEngine *pEngine, UsefulBuf Buffer) } #endif /* USEFULBUF_DISABLE_ALL_FLOAT */ QCBOREncode_CloseArray(&EncodeCtx); - QCBOREncode_AddBoolToMap(&EncodeCtx, "Turbo", pEngine->bTurboCharged); + QCBOREncode_AddBoolToMapSZ(&EncodeCtx, "Turbo", pEngine->bTurboCharged); QCBOREncode_CloseMap(&EncodeCtx); /* Get the pointer and length of the encoded output. If there was diff --git a/3rdparty/exported/QCBOR/example.h b/3rdparty/exported/QCBOR/example.h index b5bcf4bccf26..903b3f505b6c 100644 --- a/3rdparty/exported/QCBOR/example.h +++ b/3rdparty/exported/QCBOR/example.h @@ -5,7 +5,7 @@ SPDX-License-Identifier: BSD-3-Clause - See BSD-3-Clause license in README.md + See BSD-3-Clause license in file named "LICENSE" Created on 6/30/20 =============================================================================*/ diff --git a/3rdparty/exported/QCBOR/qcbor/UsefulBuf.h b/3rdparty/exported/QCBOR/qcbor/UsefulBuf.h index aa245070299a..0a6e823c19b7 100644 --- a/3rdparty/exported/QCBOR/qcbor/UsefulBuf.h +++ b/3rdparty/exported/QCBOR/qcbor/UsefulBuf.h @@ -1,34 +1,35 @@ -/*============================================================================ - Copyright (c) 2016-2018, The Linux Foundation. - Copyright (c) 2018-2022, Laurence Lundblade. - Copyright (c) 2021, Arm Limited. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following - disclaimer in the documentation and/or other materials provided - with the distribution. - * Neither the name of The Linux Foundation nor the names of its - contributors, nor the name "Laurence Lundblade" may be used to - endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED -WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT -ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS -BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR -BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, -WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE -OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN -IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - =============================================================================*/ +/* ========================================================================= + * Copyright (c) 2016-2018, The Linux Foundation. + * Copyright (c) 2018-2024, Laurence Lundblade. + * Copyright (c) 2021, Arm Limited. All rights reserved. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * * Neither the name of The Linux Foundation nor the names of its + * contributors, nor the name "Laurence Lundblade" may be used to + * endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ========================================================================= */ /*============================================================================ FILE: UsefulBuf.h @@ -42,6 +43,10 @@ IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. when who what, where, why -------- ---- -------------------------------------------------- + 08/14/2024 llundblade Add UsefulOutBuf_RetrieveOutputStorage(). + 08/13/2024 llundblade Add UsefulInputBuf_RetrieveUndecodedInput(). + 08/08/2024 llundblade Add UsefulOutBuf_SubString(). + 10/05/2024 llundblade Add Xxx_OffsetToPointer. 19/12/2022 llundblade Document that adding empty data is allowed. 4/11/2022 llundblade Add GetOutPlace and Advance to UsefulOutBuf. 9/21/2021 llundbla Clarify UsefulOutBuf size calculation mode @@ -646,16 +651,27 @@ size_t UsefulBuf_FindBytes(UsefulBufC BytesToSearch, UsefulBufC BytesToFind); /** - @brief Convert a pointer to an offset with bounds checking. - - @param[in] UB Pointer to the UsefulInputBuf. - @param[in] p Pointer to convert to offset. - - @return SIZE_MAX if @c p is out of range, the byte offset if not. + * @brief Convert a pointer to an offset with bounds checking. + * + * @param[in] UB A UsefulBuf. + * @param[in] p Pointer to convert to offset. + * + * @return SIZE_MAX if @c p is out of range, the byte offset if not. */ static inline size_t UsefulBuf_PointerToOffset(UsefulBufC UB, const void *p); +/** + * @brief Convert an offset to a pointer with bounds checking. + * + * @param[in] UB A UsefulBuf. + * @param[in] uOffset Offset in @c pUInBuf. + * + * @return @c NULL if @c uOffset is out of range, a pointer into the buffer if not. + */ +static inline const void *UsefulBuf_OffsetToPointer(UsefulBufC UB, size_t uOffset); + + #ifndef USEFULBUF_DISABLE_DEPRECATED /** Deprecated macro; use @ref UsefulBuf_FROM_SZ_LITERAL instead */ #define SZLiteralToUsefulBufC(szString) UsefulBuf_FROM_SZ_LITERAL(szString) @@ -674,7 +690,7 @@ static inline UsefulBuf UsefulBufC_Unconst(const UsefulBufC UBC) { UsefulBuf UB; - // See UsefulBuf_Unconst() implementation for comment + /* See UsefulBuf_Unconst() implementation for comment */ UB.ptr = (void *)(uintptr_t)UBC.ptr; UB.len = UBC.len; @@ -1323,8 +1339,8 @@ UsefulOutBuf_GetOutPlace(UsefulOutBuf *pUOutBuf); * @param[in] uAmount The amount to advance. * * This advances the position in the output buffer - * by \c uAmount. This assumes that the - * caller has written \c uAmount to the pointer obtained + * by @c uAmount. This assumes that the + * caller has written @c uAmount to the pointer obtained * with UsefulOutBuf_GetOutPlace(). * * Warning: this bypasses the buffer safety provided by @@ -1368,6 +1384,35 @@ UsefulBufC UsefulOutBuf_OutUBuf(UsefulOutBuf *pUOutBuf); UsefulBufC UsefulOutBuf_CopyOut(UsefulOutBuf *pUOutBuf, UsefulBuf Dest); +/** + * @beief Return a substring of the output data. + * + * @param[in] pUOutBuf Pointer to the @ref UsefulOutBuf. + * @param[in] uStart Offset of start of substring. + * @param[in] uLen Length of substring. + * + * This is the same as UsefulOutBuf_OutUBuf(), but returns a + * substring. @c NULLUsefulBufC is returned if the requested substring + * is off the end of the output bytes or if in error state. + */ +UsefulBufC UsefulOutBuf_SubString(UsefulOutBuf *pUOutBuf, + const size_t uStart, + const size_t uLen); + + +/** + * @brief Retrieve the storage buffer passed in to UsefulOutBuf_Init(). + * + * @param[in] pUOutBuf The encoding context. + * + * @return The output storage buffer passed to UsefulOutBuf_Init(). + * + * This doesn't give any information about how much has been encoded + * or the error state. It just returns the exact @ref UsefulOutBuf given + * to UsefulOutBuf_Init(). + */ +static UsefulBuf UsefulOutBuf_RetrieveOutputStorage(UsefulOutBuf *pUOutBuf); + /** @@ -1490,7 +1535,18 @@ static int UsefulInputBuf_BytesAvailable(UsefulInputBuf *pUInBuf, size_t uLen); * * @return SIZE_MAX if @c p is out of range, the byte offset if not. */ -static inline size_t UsefulInputBuf_PointerToOffset(UsefulInputBuf *pUInBuf, const void *p); +static size_t UsefulInputBuf_PointerToOffset(UsefulInputBuf *pUInBuf, const void *p); + + +/** + * @brief Convert an offset to a pointer with bounds checking. + * + * @param[in] pUInBuf Pointer to the @ref UsefulInputBuf. + * @param[in] uOffset Offset in @c pUInBuf. + * + * @return @c NULL if @c uOffset is out of range, a pointer into the buffer if not. + */ +static const void *UsefulInputBuf_OffsetToPointer(UsefulInputBuf *pUInBuf, size_t uOffset); /** @@ -1700,6 +1756,16 @@ static inline size_t UsefulInputBuf_GetBufferLength(UsefulInputBuf *pUInBuf); static void UsefulInputBuf_SetBufferLength(UsefulInputBuf *pUInBuf, size_t uNewLen); +/** + * @brief Retrieve the undecoded input buffer. + * + * @param[in] pUInBuf Pointer to the @ref UsefulInputBuf. + * + * @return The input that was given to UsefulInputBuf_Init(). + * + * A simple convenience method, should it be useful to get the original input back. + */ +static UsefulBufC UsefulInputBuf_RetrieveUndecodedInput(UsefulInputBuf *pUInBuf); /*---------------------------------------------------------- @@ -1844,7 +1910,7 @@ static inline size_t UsefulBuf_PointerToOffset(UsefulBufC UB, const void *p) return SIZE_MAX; } - // Cast to size_t (from ptrdiff_t) is OK because of check above + /* Cast to size_t (from ptrdiff_t) is OK because of check above */ const size_t uOffset = (size_t)((const uint8_t *)p - (const uint8_t *)UB.ptr); if(uOffset >= UB.len) { @@ -1856,6 +1922,18 @@ static inline size_t UsefulBuf_PointerToOffset(UsefulBufC UB, const void *p) } +static inline const void *UsefulBuf_OffsetToPointer(UsefulBufC UB, size_t uOffset) +{ + if(UsefulBuf_IsNULLC(UB) || uOffset >= UB.len) { + return NULL; + } + + return (const uint8_t *)UB.ptr + uOffset; +} + + + + #ifndef USEFULBUF_DISABLE_ALL_FLOAT static inline uint32_t UsefulBufUtil_CopyFloatToUint32(float f) { @@ -2192,6 +2270,12 @@ static inline UsefulBuf UsefulOutBuf_GetOutPlace(UsefulOutBuf *pUOutBuf) } +static inline UsefulBuf UsefulOutBuf_RetrieveOutputStorage(UsefulOutBuf *pMe) +{ + return pMe->UB; +} + + static inline void UsefulInputBuf_Init(UsefulInputBuf *pMe, UsefulBufC UB) @@ -2237,9 +2321,9 @@ static inline size_t UsefulInputBuf_BytesUnconsumed(UsefulInputBuf *pMe) /* The cursor is off the end of the input buffer given. * Presuming there are no bugs in this code, this should never happen. - * If it so, the struct was corrupted. The check is retained as + * If it is so, the struct was corrupted. The check is retained as * as a defense in case there is a bug in this code or the struct is - * corrupted. + * corrupted by an attacker or accidentally. */ if(pMe->cursor > pMe->UB.len) { return 0; @@ -2262,6 +2346,12 @@ static inline size_t UsefulInputBuf_PointerToOffset(UsefulInputBuf *pUInBuf, con } +static inline const void *UsefulInputBuf_OffsetToPointer(UsefulInputBuf *pUInBuf, size_t uOffset) + { + return UsefulBuf_OffsetToPointer(pUInBuf->UB, uOffset); + } + + static inline UsefulBufC UsefulInputBuf_GetUsefulBuf(UsefulInputBuf *pMe, size_t uNum) { const void *pResult = UsefulInputBuf_GetBytes(pMe, uNum); @@ -2454,6 +2544,11 @@ static inline void UsefulInputBuf_SetBufferLength(UsefulInputBuf *pMe, size_t uN pMe->UB.len = uNewLen; } +static inline UsefulBufC UsefulInputBuf_RetrieveUndecodedInput(UsefulInputBuf *pMe) +{ + return pMe->UB; +} + #ifdef __cplusplus } diff --git a/3rdparty/exported/QCBOR/qcbor/qcbor_common.h b/3rdparty/exported/QCBOR/qcbor/qcbor_common.h index 127537d85322..0027cf9554dc 100644 --- a/3rdparty/exported/QCBOR/qcbor/qcbor_common.h +++ b/3rdparty/exported/QCBOR/qcbor/qcbor_common.h @@ -1,110 +1,99 @@ -/*============================================================================== - Copyright (c) 2016-2018, The Linux Foundation. - Copyright (c) 2018-2022, Laurence Lundblade. - Copyright (c) 2021, Arm Limited. - All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following - disclaimer in the documentation and/or other materials provided - with the distribution. - * Neither the name of The Linux Foundation nor the names of its - contributors, nor the name "Laurence Lundblade" may be used to - endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED -WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT -ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS -BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR -BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, -WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE -OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN -IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - =============================================================================*/ - - +/* ========================================================================== + * Copyright (c) 2016-2018, The Linux Foundation. + * Copyright (c) 2018-2024, Laurence Lundblade. + * Copyright (c) 2021, Arm Limited. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * * Neither the name of The Linux Foundation nor the names of its + * contributors, nor the name "Laurence Lundblade" may be used to + * endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ========================================================================= */ #ifndef qcbor_common_h #define qcbor_common_h +#ifdef __cplusplus +extern "C" { +#if 0 +} // Keep editor indention formatting happy +#endif +#endif + /** - @file qcbor_common.h - - Types and defines common to QCBOR encoding and decoding. -*/ + * @file qcbor_common.h + * + * Constant values for types, error codes and such that are common to + * encoding and decoding. + */ /** - * This define indicates QCBOR v1.1. - * - * There are no backwards compatibiliy issues with QCBOR 1.0. + * Semantic versioning for QCBOR x.y.z from 1.3.0 on * - * The only new API is QCBOREncode_OpenBytes() and related. + * Note: + * - QCBOR 1.2 is indicated by the #define QCBOR_1_2 + * - QCBOR 1.1 is indicated by the #define QCBOR_1_1 + * - QCBOR 1.0 is indicated by the absence of all the above */ -#define QCBOR_1_1 +#define QCBOR_VERSION_MAJOR 1 +#define QCBOR_VERSION_MINOR 5 +#define QCBOR_VERSION_PATCH 0 /** - This define indicates a version of QCBOR that supports spiffy decode, - the decode functions found in qcbor_spiffy_decode.h. - - Versions of QCBOR that support spiffy decode are backwards compatible - with previous versions, but there are a few minor exceptions such as - some aspects of tag handling that are different. This define can be - used handle these variances. -*/ + * This define indicates a version of QCBOR that supports spiffy + * decode, the decode functions found in qcbor_spiffy_decode.h. + * + * Versions of QCBOR that support spiffy decode are backwards + * compatible with previous versions, but there are a few minor + * exceptions such as some aspects of tag handling that are + * different. This define can be used to handle these variances. + */ #define QCBOR_SPIFFY_DECODE -/* It was originally defined as QCBOR_CONFIG_DISABLE_EXP_AND_MANTISSA, - * but this is incosistent with all the other QCBOR_DISABLE_ - * #defines, so the name was changed and this was added for backwards - * compatibility - */ -#ifdef QCBOR_CONFIG_DISABLE_EXP_AND_MANTISSA -#define QCBOR_DISABLE_EXP_AND_MANTISSA -#endif -/* If USEFULBUF_DISABLE_ALL_FLOATis defined then define - * QCBOR_DISABLE_FLOAT_HW_USE and QCBOR_DISABLE_PREFERRED_FLOAT - */ -#ifdef USEFULBUF_DISABLE_ALL_FLOAT -#ifndef QCBOR_DISABLE_FLOAT_HW_USE -#define QCBOR_DISABLE_FLOAT_HW_USE -#endif /* QCBOR_DISABLE_FLOAT_HW_USE */ -#ifndef QCBOR_DISABLE_PREFERRED_FLOAT -#define QCBOR_DISABLE_PREFERRED_FLOAT -#endif /* QCBOR_DISABLE_PREFERRED_FLOAT */ -#endif /* USEFULBUF_DISABLE_ALL_FLOAT */ - -/* Standard CBOR Major type for positive integers of various lengths */ +/* Standard CBOR Major type for positive integers of various lengths. */ #define CBOR_MAJOR_TYPE_POSITIVE_INT 0 -/* Standard CBOR Major type for negative integer of various lengths */ +/* Standard CBOR Major type for negative integer of various lengths. */ #define CBOR_MAJOR_TYPE_NEGATIVE_INT 1 /* Standard CBOR Major type for an array of arbitrary 8-bit bytes. */ #define CBOR_MAJOR_TYPE_BYTE_STRING 2 /* Standard CBOR Major type for a UTF-8 string. Note this is true 8-bit UTF8 - with no encoding and no NULL termination */ + * with no encoding and no NULL termination. */ #define CBOR_MAJOR_TYPE_TEXT_STRING 3 -/* Standard CBOR Major type for an ordered array of other CBOR data items */ +/* Standard CBOR Major type for an ordered array of other CBOR data items. */ #define CBOR_MAJOR_TYPE_ARRAY 4 /* Standard CBOR Major type for CBOR MAP. Maps an array of pairs. The - first item in the pair is the "label" (key, name or identfier) and the second - item is the value. */ + * first item in the pair is the "label" (key, name or identfier) and the second + * item is the value. */ #define CBOR_MAJOR_TYPE_MAP 5 /* Standard CBOR major type for a tag number. This creates a CBOR "tag" that @@ -117,142 +106,121 @@ IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #define CBOR_MAJOR_TYPE_TAG 6 #define CBOR_MAJOR_TYPE_OPTIONAL 6 -/* Standard CBOR extra simple types like floats and the values true and false */ +/* Standard CBOR simple types like float, the values true, false, null... */ #define CBOR_MAJOR_TYPE_SIMPLE 7 -/* - These are special values for the AdditionalInfo bits that are part of - the first byte. Mostly they encode the length of the data item. - */ -#define LEN_IS_ONE_BYTE 24 -#define LEN_IS_TWO_BYTES 25 -#define LEN_IS_FOUR_BYTES 26 -#define LEN_IS_EIGHT_BYTES 27 -#define ADDINFO_RESERVED1 28 -#define ADDINFO_RESERVED2 29 -#define ADDINFO_RESERVED3 30 -#define LEN_IS_INDEFINITE 31 /* - 24 is a special number for CBOR. Integers and lengths - less than it are encoded in the same byte as the major type. + * Tags that are used with CBOR_MAJOR_TYPE_OPTIONAL. These + * are types defined in RFC 8949 and some additional ones + * in the IANA CBOR tags registry. */ -#define CBOR_TWENTY_FOUR 24 - - -/* - Tags that are used with CBOR_MAJOR_TYPE_OPTIONAL. These - are types defined in RFC 8949 and some additional ones - in the IANA CBOR tags registry. - */ -/** See QCBOREncode_AddDateString(). */ +/** See QCBOREncode_AddTDateString(). */ #define CBOR_TAG_DATE_STRING 0 -/** See QCBOREncode_AddDateEpoch(). */ +/** See QCBOREncode_AddTDateEpoch(). */ #define CBOR_TAG_DATE_EPOCH 1 -/** See QCBOREncode_AddPositiveBignum(). */ +/** See QCBOREncode_AddTPositiveBignum(). */ #define CBOR_TAG_POS_BIGNUM 2 -/** See QCBOREncode_AddNegativeBignum(). */ +/** See QCBOREncode_AddTNegativeBignum(). */ #define CBOR_TAG_NEG_BIGNUM 3 /** CBOR tag for a two-element array representing a fraction with a - mantissa and base-10 scaling factor. See QCBOREncode_AddDecimalFraction() - and @ref expAndMantissa. - */ + * mantissa and base-10 scaling factor. See + * QCBOREncode_AddTDecimalFraction() and @ref expAndMantissa. */ #define CBOR_TAG_DECIMAL_FRACTION 4 /** CBOR tag for a two-element array representing a fraction with a - mantissa and base-2 scaling factor. See QCBOREncode_AddBigFloat() - and @ref expAndMantissa. */ + * mantissa and base-2 scaling factor. See QCBOREncode_AddTBigFloat() + * and @ref expAndMantissa. */ #define CBOR_TAG_BIGFLOAT 5 -/** Not Decoded by QCBOR. Tag for COSE format encryption with no recipient - identification. See [RFC 8152, COSE] - (https://tools.ietf.org/html/rfc8152). No API is provided for this - tag. */ +/** Not Decoded by QCBOR. Tag for COSE format encryption with no + * recipient identification. See [RFC 9052, COSE] + * (https://www.rfc-editor.org/rfc/rfc9052.html). No API is provided + * for this tag. */ #define CBOR_TAG_COSE_ENCRYPT0 16 #define CBOR_TAG_COSE_ENCRYPTO 16 -/** Not Decoded by QCBOR. Tag for COSE format MAC'd data with no recipient - identification. See [RFC 8152, COSE] - (https://tools.ietf.org/html/rfc8152). No API is provided for this - tag.*/ +/** Not Decoded by QCBOR. Tag for COSE format MAC'd data with no + * recipient identification. See [RFC 9052, COSE] + * (https://www.rfc-editor.org/rfc/rfc9052.html). No API is provided for this + * tag. */ #define CBOR_TAG_COSE_MAC0 17 /** Tag for COSE format single signature signing. No API is provided - for this tag. See [RFC 8152, COSE] - (https://tools.ietf.org/html/rfc8152). */ + * for this tag. See [RFC 9052, COSE] + * (https://www.rfc-editor.org/rfc/rfc9052.html). */ #define CBOR_TAG_COSE_SIGN1 18 /** A hint that the following byte string should be encoded in - Base64URL when converting to JSON or similar text-based - representations. Call @c - QCBOREncode_AddTag(pCtx,CBOR_TAG_ENC_AS_B64URL) before the call to - QCBOREncode_AddBytes(). */ + * Base64URL when converting to JSON or similar text-based + * representations. Call @c + * QCBOREncode_AddTag(pCtx,CBOR_TAG_ENC_AS_B64URL) before the call to + * QCBOREncode_AddBytes(). */ #define CBOR_TAG_ENC_AS_B64URL 21 /** A hint that the following byte string should be encoded in Base64 - when converting to JSON or similar text-based - representations. Call @c - QCBOREncode_AddTag(pCtx,CBOR_TAG_ENC_AS_B64) before the call to - QCBOREncode_AddBytes(). */ + * when converting to JSON or similar text-based + * representations. Call @c + * QCBOREncode_AddTag(pCtx,CBOR_TAG_ENC_AS_B64) before the call to + * QCBOREncode_AddBytes(). */ #define CBOR_TAG_ENC_AS_B64 22 /** A hint that the following byte string should be encoded in base-16 - format per [RFC 4648] (https://tools.ietf.org/html/rfc4648) when - converting to JSON or similar text-based - representations. Essentially, Base-16 encoding is the standard - case- insensitive hex encoding and may be referred to as - "hex". Call @c QCBOREncode_AddTag(pCtx,CBOR_TAG_ENC_AS_B16) before - the call to QCBOREncode_AddBytes(). */ + * format per [RFC 4648] + * (https://www.rfc-editor.org/rfc/rfc4648.html) when converting to + * JSON or similar text-based representations. Essentially, Base-16 + * encoding is the standard case- insensitive hex encoding and may be + * referred to as "hex". Call @c QCBOREncode_AddTag(pCtx,CBOR_TAG_ENC_AS_B16) + * before the call to QCBOREncode_AddBytes(). */ #define CBOR_TAG_ENC_AS_B16 23 /** See QCBORDecode_EnterBstrWrapped()). */ #define CBOR_TAG_CBOR 24 -/** See QCBOREncode_AddURI(). */ +/** See QCBOREncode_AddTURI(). */ #define CBOR_TAG_URI 32 -/** See QCBOREncode_AddB64URLText(). */ +/** See QCBOREncode_AddTB64URLText(). */ #define CBOR_TAG_B64URL 33 /** See QCBOREncode_AddB64Text(). */ #define CBOR_TAG_B64 34 -/** See QCBOREncode_AddRegex(). */ +/** See QCBOREncode_AddTRegex(). */ #define CBOR_TAG_REGEX 35 /** See QCBOREncode_AddMIMEData(). */ #define CBOR_TAG_MIME 36 -/** See QCBOREncode_AddBinaryUUID(). */ +/** See QCBOREncode_AddTBinaryUUID(). */ #define CBOR_TAG_BIN_UUID 37 /** The data is a CBOR Web Token per [RFC 8392] - (https://tools.ietf.org/html/rfc8932). No API is provided for this - tag. */ + * (https://www.rfc-editor.org/rfc/rfc8392.html). No API is provided for this + * tag. */ #define CBOR_TAG_CWT 61 -/** Tag for COSE format encryption. See [RFC 8152, COSE] - (https://tools.ietf.org/html/rfc8152). No API is provided for this - tag. */ +/** Tag for COSE format encryption. See [RFC 9052, COSE] + * (https://www.rfc-editor.org/rfc/rfc9052.html). No API is provided for this + * tag. */ #define CBOR_TAG_CBOR_SEQUENCE 63 -/** Not Decoded by QCBOR. Tag for COSE format encryption with recipient - identification. See [RFC 8152, COSE] - (https://tools.ietf.org/html/rfc8152). No API is provided for this - tag. */ +/** Not Decoded by QCBOR. Tag for COSE format encrypt. See [RFC 9052, COSE] + * (https://www.rfc-editor.org/rfc/rfc9052.html). No API is provided for this + * tag. */ #define CBOR_TAG_COSE_ENCRYPT 96 #define CBOR_TAG_ENCRYPT 96 -/** Not Decoded by QCBOR. Tag for COSE format MAC. See [RFC 8152, COSE] - (https://tools.ietf.org/html/rfc8152). No API is provided for this +/** Not Decoded by QCBOR. Tag for COSE format MAC. See [RFC 9052, COSE] + * (https://www.rfc-editor.org/rfc/rfc9052.html). No API is provided for this tag. */ #define CBOR_TAG_COSE_MAC 97 #define CBOR_TAG_MAC 97 -/** Not Decoded by QCBOR. Tag for COSE format signed data. See [RFC 8152, COSE] - (https://tools.ietf.org/html/rfc8152). No API is provided for this +/** Not Decoded by QCBOR. Tag for COSE format signed data. See [RFC 9052, COSE] + * (https://www.rfc-editor.org/rfc/rfc9052.html). No API is provided for this tag. */ #define CBOR_TAG_COSE_SIGN 98 #define CBOR_TAG_SIGN 98 /** Tag for date counted by days from Jan 1 1970 per [RFC 8943] - (https://tools.ietf.org/html/rfc8943). See - QCBOREncode_AddTDaysEpoch(). */ + * (https://www.rfc-editor.org/rfc/rfc8943.html). See + * QCBOREncode_AddTDaysEpoch(). */ #define CBOR_TAG_DAYS_EPOCH 100 /** Not Decoded by QCBOR. World geographic coordinates. See ISO 6709, [RFC 5870] - (https://tools.ietf.org/html/rfc5870) and WGS-84. No API is - provided for this tag. */ + * (https://www.rfc-editor.org/rfc/rfc5870.html) and WGS-84. No API is + * provided for this tag. */ #define CBOR_TAG_GEO_COORD 103 /** Binary MIME.*/ #define CBOR_TAG_BINARY_MIME 257 /** Tag for date string without time or time zone per [RFC 8943] - (https://tools.ietf.org/html/rfc8943). See - QCBOREncode_AddTDaysString(). */ + * (https://www.rfc-editor.org/rfc/rfc8943.html). See + * QCBOREncode_AddTDaysString(). */ #define CBOR_TAG_DAYS_STRING 1004 /** The magic number, self-described CBOR. No API is provided for this - tag. */ + * tag. */ #define CBOR_TAG_CBOR_MAGIC 55799 /** The 16-bit invalid tag from the CBOR tags registry */ @@ -264,28 +232,11 @@ IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -/* - Values for the 5 bits for items of major type 7 - */ -#define CBOR_SIMPLEV_FALSE 20 -#define CBOR_SIMPLEV_TRUE 21 -#define CBOR_SIMPLEV_NULL 22 -#define CBOR_SIMPLEV_UNDEF 23 -#define CBOR_SIMPLEV_ONEBYTE 24 -#define HALF_PREC_FLOAT 25 -#define SINGLE_PREC_FLOAT 26 -#define DOUBLE_PREC_FLOAT 27 -#define CBOR_SIMPLE_BREAK 31 -#define CBOR_SIMPLEV_RESERVED_START CBOR_SIMPLEV_ONEBYTE -#define CBOR_SIMPLEV_RESERVED_END CBOR_SIMPLE_BREAK - - - /** - * Error codes returned by QCBOR Encoder and Decoder. + * Error codes returned by QCBOR Encoder-Decoder. * - * The errors are grouped to keep the code size of + * They are grouped to keep the code size of * QCBORDecode_IsNotWellFormedError() and * QCBORDecode_IsUnrecoverableError() minimal. * @@ -299,307 +250,338 @@ IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * added for new QCBOR features. */ typedef enum { - /** The encode or decode completely correctly. */ + /** The encode or decode completed correctly. */ QCBOR_SUCCESS = 0, /** The buffer provided for the encoded output when doing encoding - was too small and the encoded output will not fit. */ + * was too small and the encoded output will not fit. */ QCBOR_ERR_BUFFER_TOO_SMALL = 1, /** During encoding, an attempt to create simple value between 24 - and 31. */ + * and 31. */ QCBOR_ERR_ENCODE_UNSUPPORTED = 2, /** During encoding, the length of the encoded CBOR exceeded - QCBOR_MAX_ARRAY_OFFSET, which is slightly less than - @c UINT32_MAX. */ + * @ref QCBOR_MAX_ARRAY_OFFSET, which is slightly less than + * @c UINT32_MAX. */ QCBOR_ERR_BUFFER_TOO_LARGE = 3, /** During encoding, the array or map nesting was deeper than this - implementation can handle. Note that in the interest of code - size and memory use, this implementation has a hard limit on - array nesting. The limit is defined as the constant @ref - QCBOR_MAX_ARRAY_NESTING. */ + * implementation can handle. Note that in the interest of code + * size and memory use, QCBOR has a hard limit on array + * nesting. The limit is defined as the constant + * @ref QCBOR_MAX_ARRAY_NESTING. */ QCBOR_ERR_ARRAY_NESTING_TOO_DEEP = 4, - /** During encoding, @c QCBOREncode_CloseXxx() called with a - different type than is currently open. */ + /** During encoding, @c QCBOREncode_CloseXxx() called for a + * different type than is currently open. */ QCBOR_ERR_CLOSE_MISMATCH = 5, - /** During encoding, the array or map had too many items in it. - This limit @ref QCBOR_MAX_ITEMS_IN_ARRAY, typically 65,535. */ + /** During encoding, the array or map had too many items in it. The + * limits are @ref QCBOR_MAX_ITEMS_IN_ARRAY and + * @ref QCBOR_MAX_ITEMS_IN_MAP. */ QCBOR_ERR_ARRAY_TOO_LONG = 6, /** During encoding, more arrays or maps were closed than - opened. This is a coding error on the part of the caller of the - encoder. */ + * opened. This is a coding error on the part of the caller of the + * encoder. */ QCBOR_ERR_TOO_MANY_CLOSES = 7, - /** During encoding the number of array or map opens was not - matched by the number of closes. Also occurs with opened - byte strings that are not closed. */ + /** During encoding, the number of array or map opens was not + * matched by the number of closes. Also occurs with opened byte + * strings that are not closed. */ QCBOR_ERR_ARRAY_OR_MAP_STILL_OPEN = 8, - /** During encode, opening a byte string while a byte string is open - is not allowed. . */ + /** During encoding, opening a byte string while a byte string is + * open is not allowed. */ QCBOR_ERR_OPEN_BYTE_STRING = 9, /** Trying to cancel a byte string wrapping after items have been - added to it. */ + * added to it. */ QCBOR_ERR_CANNOT_CANCEL = 10, #define QCBOR_START_OF_NOT_WELL_FORMED_ERRORS 20 /** During decoding, the CBOR is not well-formed because a simple - value between 0 and 31 is encoded in a two-byte integer rather - than one. */ + * value between 0 and 31 is encoded in a two-byte integer rather + * than one. */ QCBOR_ERR_BAD_TYPE_7 = 20, /** During decoding, returned by QCBORDecode_Finish() if all the - inputs bytes have not been consumed. This is considered not - well-formed. */ + * inputs bytes have not been consumed. This is considered not + * well-formed. */ QCBOR_ERR_EXTRA_BYTES = 21, /** During decoding, some CBOR construct was encountered that this - decoder doesn't support, primarily this is the reserved - additional info values, 28 through 30. The CBOR is not - well-formed.*/ + * decoder doesn't support, primarily this is the reserved + * additional info values, 28 through 30. The CBOR is not + * well-formed. + */ QCBOR_ERR_UNSUPPORTED = 22, /** During decoding, the an array or map was not fully consumed. - Returned by QCBORDecode_Finish(). The CBOR is not - well-formed. */ + * Returned by QCBORDecode_Finish(). The CBOR is not + * well-formed. */ QCBOR_ERR_ARRAY_OR_MAP_UNCONSUMED = 23, /** During decoding, an integer type is encoded with a bad length - (that of an indefinite length string). The CBOR is not-well - formed. */ + * (that of an indefinite length string). The CBOR is not-well + * formed. */ QCBOR_ERR_BAD_INT = 24, #define QCBOR_START_OF_UNRECOVERABLE_DECODE_ERRORS 30 /** During decoding, one of the chunks in an indefinite-length - string is not of the type of the start of the string. The CBOR - is not well-formed. This error makes no further decoding - possible. */ + * string is not of the type of the start of the string. The CBOR + * is not well-formed. This error makes no further decoding + * possible. */ QCBOR_ERR_INDEFINITE_STRING_CHUNK = 30, /** During decoding, hit the end of the given data to decode. For - example, a byte string of 100 bytes was expected, but the end - of the input was hit before finding those 100 bytes. Corrupted - CBOR input will often result in this error. See also @ref - QCBOR_ERR_NO_MORE_ITEMS. The CBOR is not well-formed. This - error makes no further decoding possible. */ + * example, a byte string of 100 bytes was expected, but the end + * of the input was hit before finding those 100 bytes. Corrupted + * CBOR input will often result in this error. See also + * @ref QCBOR_ERR_NO_MORE_ITEMS. The CBOR is not well-formed. + * This error makes no further decoding possible. */ QCBOR_ERR_HIT_END = 31, /** During decoding, a break occurred outside an indefinite-length - item. The CBOR is not well-formed. This error makes no further - decoding possible. */ + * item. The CBOR is not well-formed. This error makes no further + * decoding possible. */ QCBOR_ERR_BAD_BREAK = 32, #define QCBOR_END_OF_NOT_WELL_FORMED_ERRORS 39 /** During decoding, the input is too large. It is greater than - QCBOR_MAX_DECODE_INPUT_SIZE. This is an implementation limit. - This error makes no further decoding possible. */ + * QCBOR_MAX_DECODE_INPUT_SIZE. This is an implementation limit. + * This error makes no further decoding possible. */ QCBOR_ERR_INPUT_TOO_LARGE = 40, /** During decoding, the array or map nesting was deeper than this - implementation can handle. Note that in the interest of code - size and memory use, this implementation has a hard limit on - array nesting. The limit is defined as the constant @ref - QCBOR_MAX_ARRAY_NESTING. This error makes no further decoding - possible. */ + * implementation can handle. Note that in the interest of code + * size and memory use, QCBOR has a hard limit on array + * nesting. The limit is defined as the constant + * @ref QCBOR_MAX_ARRAY_NESTING. This error makes no further + * decoding possible. */ QCBOR_ERR_ARRAY_DECODE_NESTING_TOO_DEEP = 41, /** During decoding, the array or map had too many items in it. - This limit @ref QCBOR_MAX_ITEMS_IN_ARRAY, typically 65,534, - UINT16_MAX - 1. This error makes no further decoding - possible. */ + * This limit is @ref QCBOR_MAX_ITEMS_IN_ARRAY (65,534) for + * arrays and @ref QCBOR_MAX_ITEMS_IN_MAP (32,767) for maps. This + * error makes no further decoding possible. */ QCBOR_ERR_ARRAY_DECODE_TOO_LONG = 42, /** When decoding, a string's size is greater than what a size_t - can hold less 4. In all but some very strange situations this - is because of corrupt input CBOR and should be treated as - such. The strange situation is a CPU with a very small size_t - (e.g., a 16-bit CPU) and a large string (e.g., > 65KB). This - error makes no further decoding possible. */ + * can hold less 4. In all but some very strange situations this + * is because of corrupt input CBOR and should be treated as + * such. The strange situation is a CPU with a very small size_t + * (e.g., a 16-bit CPU) and a large string (e.g., > 65KB). This + * error makes no further decoding possible. */ QCBOR_ERR_STRING_TOO_LONG = 43, /** Something is wrong with a decimal fraction or bigfloat such as - it not consisting of an array with two integers. This error - makes no further decoding possible. */ + * it not consisting of an array with two integers. This error + * makes no further decoding possible. */ QCBOR_ERR_BAD_EXP_AND_MANTISSA = 44, /** Unable to decode an indefinite-length string because no string - allocator was configured. See QCBORDecode_SetMemPool() or - QCBORDecode_SetUpAllocator(). This error makes no further - decoding possible. */ + * allocator was configured. See QCBORDecode_SetMemPool() or + * QCBORDecode_SetUpAllocator(). This error makes no further + * decoding possible.*/ QCBOR_ERR_NO_STRING_ALLOCATOR = 45, - /** Error allocating space for a string, usually for an - indefinite-length string. This error makes no further decoding - possible. */ + /** Error allocating memory for a string, usually out of memory. + * This primarily occurs decoding indefinite-length strings. This + * error makes no further decoding possible. */ QCBOR_ERR_STRING_ALLOCATE = 46, /** During decoding, the type of the label for a map entry is not - one that can be handled in the current decoding mode. Typically - this is because a label is not an intger or a string. This is - an implemation limit. */ + * one that can be handled in the current decoding mode. Typically + * this is because a label is not an integer or a string. This is + * an implementation limit. */ QCBOR_ERR_MAP_LABEL_TYPE = 47, /** When the built-in tag decoding encounters an unexpected type, - this error is returned. This error is unrecoverable because the - built-in tag decoding doesn't try to consume the unexpected - type. In previous versions of QCBOR this was considered a - recoverable error hence QCBOR_ERR_BAD_TAG_CONTENT. Going back - further, RFC 7049 use the name "optional tags". That name is no - longer used because "optional" was causing confusion. See - also @ref QCBOR_ERR_RECOVERABLE_BAD_TAG_CONTENT. */ + * this error is returned. This error is unrecoverable because the + * built-in tag decoding doesn't try to consume the unexpected + * type. In previous versions of QCBOR this was considered a + * recoverable error hence QCBOR_ERR_BAD_TAG_CONTENT. Going + * back further, RFC 7049 use the name "optional tags". That name + * is no longer used because "optional" was causing confusion. */ QCBOR_ERR_UNRECOVERABLE_TAG_CONTENT = 48, QCBOR_ERR_BAD_TAG_CONTENT = 48, QCBOR_ERR_BAD_OPT_TAG = 48, /** Indefinite length string handling is disabled and there is an - indefinite length string in the input CBOR. */ + * indefinite length string in the input CBOR. */ QCBOR_ERR_INDEF_LEN_STRINGS_DISABLED = 49, - /** Indefinite length arrays and maps handling are disabled and there is an - indefinite length map or array in the input CBOR. */ + /** Indefinite length arrays and maps handling are disabled and + * there is an indefinite length map or array in the input + * CBOR. */ QCBOR_ERR_INDEF_LEN_ARRAYS_DISABLED = 50, /** All decoding of tags (major type 6) has been disabled and a tag - occurred in the decode input. */ + * occurred in the decode input. */ QCBOR_ERR_TAGS_DISABLED = 51, #define QCBOR_END_OF_UNRECOVERABLE_DECODE_ERRORS 59 /** More than @ref QCBOR_MAX_TAGS_PER_ITEM tags encountered for a - CBOR ITEM. @ref QCBOR_MAX_TAGS_PER_ITEM is a limit of this - implementation. During decoding, too many tags in the - caller-configured tag list, or not enough space in @ref - QCBORTagListOut. This error makes no further decoding - possible. */ + * CBOR ITEM. @ref QCBOR_MAX_TAGS_PER_ITEM is a limit of this + * implementation. During decoding, too many tags in the + * caller-configured tag list, or not enough space in + * @ref QCBORTagListOut. This error makes no further decoding + * possible. */ QCBOR_ERR_TOO_MANY_TAGS = 60, - /** When decoding for a specific type, the type was not was - expected. */ + /** When decoding for a specific type, the type was not expected. */ QCBOR_ERR_UNEXPECTED_TYPE = 61, - /** Duplicate label in map detected. */ + /** Duplicate label detected in a map. */ QCBOR_ERR_DUPLICATE_LABEL = 62, /** During decoding, the buffer given to QCBORDecode_SetMemPool() - is either too small, smaller than - QCBOR_DECODE_MIN_MEM_POOL_SIZE or too large, larger than - UINT32_MAX. */ + * is either too small, smaller than + * @ref QCBOR_DECODE_MIN_MEM_POOL_SIZE or too large, larger than + * UINT32_MAX. */ QCBOR_ERR_MEM_POOL_SIZE = 63, /** During decoding, an integer smaller than INT64_MIN was received - (CBOR can represent integers smaller than INT64_MIN, but C - cannot). */ + * (CBOR can represent integers smaller than INT64_MIN, but C + * cannot). */ QCBOR_ERR_INT_OVERFLOW = 64, /** During decoding, a date greater than +- 292 billion years from - Jan 1 1970 encountered during parsing. This is an - implementation limit. */ + * Jan 1 1970 encountered during parsing. This is an + * implementation limit. */ QCBOR_ERR_DATE_OVERFLOW = 65, /** During decoding, @c QCBORDecode_ExitXxx() was called for a - different type than @c QCBORDecode_EnterXxx(). */ + * different type than @c QCBORDecode_EnterXxx(). */ QCBOR_ERR_EXIT_MISMATCH = 66, /** All well-formed data items have been consumed and there are no - more. If parsing a CBOR stream this indicates the non-error end - of the stream. If not parsing a CBOR stream / sequence, this - probably indicates that some data items expected are not - present. See also @ref QCBOR_ERR_HIT_END. */ + * more. If parsing a CBOR stream this indicates the non-error end + * of the stream. If not parsing a CBOR stream/sequence, this + * probably indicates that some data items expected are not + * present. See also @ref QCBOR_ERR_HIT_END. */ QCBOR_ERR_NO_MORE_ITEMS = 67, /** When finding an item by label, an item with the requested label - was not found. */ + * was not found. */ QCBOR_ERR_LABEL_NOT_FOUND = 68, /** Number conversion failed because of sign. For example a - negative int64_t can't be converted to a uint64_t */ + * negative int64_t can't be converted to a uint64_t */ QCBOR_ERR_NUMBER_SIGN_CONVERSION = 69, - /** When converting a decoded number, the value is too large or to - small for the conversion target */ + /** When converting a decoded number, the value is too large or too + * small for the conversion target. */ QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW = 70, /** Trying to get an item by label when a map has not been - entered. */ + * entered. */ QCBOR_ERR_MAP_NOT_ENTERED = 71, - /** A @ref QCBORItemCallback callback indicates processing should not - continue for some non-CBOR reason. */ + /** A callback indicates processing should not continue for some + * non-CBOR reason. */ QCBOR_ERR_CALLBACK_FAIL = 72, /** This error code is deprecated. Instead, - @ref QCBOR_ERR_HALF_PRECISION_DISABLED, - @ref QCBOR_ERR_HW_FLOAT_DISABLED or @ref QCBOR_ERR_ALL_FLOAT_DISABLED - is returned depending on the specific floating-point functionality - that is disabled and the type of floating-point input. */ + * @ref QCBOR_ERR_HALF_PRECISION_DISABLED, + * @ref QCBOR_ERR_HW_FLOAT_DISABLED or @ref QCBOR_ERR_ALL_FLOAT_DISABLED + * is returned depending on the specific floating-point functionality + * that is disabled and the type of floating-point input. */ QCBOR_ERR_FLOAT_DATE_DISABLED = 73, /** Support for half-precision float decoding is disabled. */ QCBOR_ERR_HALF_PRECISION_DISABLED = 74, /** Use of floating-point HW is disabled. This affects all type - conversions to and from double and float types. */ + * conversions to and from double and float types. */ QCBOR_ERR_HW_FLOAT_DISABLED = 75, /** Unable to complete operation because a floating-point value - that is a NaN (not a number), that is too large, too small, - infinity or -infinity was encountered in encoded CBOR. Usually - this because conversion of the float-point value was being - attempted. */ + * that is a NaN (not a number), that is too large, too small, + * infinity or -infinity was encountered in encoded CBOR. Usually + * this because conversion of the float-point value was being + * attempted. */ QCBOR_ERR_FLOAT_EXCEPTION = 76, - /** Floating point support is completely turned off, encoding/decoding - floating point numbers is not possible. */ + /** Floating point support is completely turned off, + * encoding/decoding floating point numbers is not possible. */ QCBOR_ERR_ALL_FLOAT_DISABLED = 77, /** Like @ref QCBOR_ERR_UNRECOVERABLE_TAG_CONTENT, but recoverable. - If an implementation decodes a tag and can and does consume the - whole tag contents when it is not the correct tag content, this - error can be returned. None of the built-in tag decoders do - this (to save object code). */ - QCBOR_ERR_RECOVERABLE_BAD_TAG_CONTENT = 78 + * If an implementation decodes a tag and can and does consume the + * whole tag contents when it is not the correct tag content, this + * error can be returned. None of the built-in tag decoders do this + * (to save object code). */ + QCBOR_ERR_RECOVERABLE_BAD_TAG_CONTENT = 78, - /* This is stored in uint8_t; never add values > 255 */ -} QCBORError; + /** QCBORDecode_EnterBstrWrapped() cannot be used on + * indefinite-length strings because they exist in memory pool for + * a @ref QCBORStringAllocate. */ + QCBOR_ERR_CANNOT_ENTER_ALLOCATED_STRING = 79, + /** A range of error codes that can be made use of by the + * caller. QCBOR internally does nothing with these except notice + * that they are not QCBOR_SUCCESS. See QCBORDecode_SetError(). */ + QCBOR_ERR_FIRST_USER_DEFINED = 128, -/* Function for getting an error string from an error code */ -const char *qcbor_err_to_str(QCBORError err); + /** See @ref QCBOR_ERR_FIRST_USER_DEFINED */ + QCBOR_ERR_LAST_USER_DEFINED = 255 + /* This is stored in uint8_t; never add values > 255 */ +} QCBORError; /** - The maximum nesting of arrays and maps when encoding or decoding. The - error @ref QCBOR_ERR_ARRAY_NESTING_TOO_DEEP will be returned on - encoding or QCBOR_ERR_ARRAY_DECODE_NESTING_TOO_DEEP on decoding if it is exceeded. + * @brief Get string describing an error code. + * + * @param[in] uErr The error code. + * + * @return NULL-terminated string describing error or "Unidentified + * error" if the error is not known. + * + * This is not thread-safe because it uses a static buffer + * for formatting, but this is only a diagnostic and the only + * consequence is the wrong description. */ -#define QCBOR_MAX_ARRAY_NESTING QCBOR_MAX_ARRAY_NESTING1 +const char * +qcbor_err_to_str(QCBORError uErr); + + /** - * The maximum number of items in a single array or map when encoding of decoding. + * The maximum nesting of arrays and maps when encoding or + * decoding. The error @ref QCBOR_ERR_ARRAY_NESTING_TOO_DEEP will be + * returned on encoding or @ref QCBOR_ERR_ARRAY_DECODE_NESTING_TOO_DEEP on + * decoding if it is exceeded. Do not increase this over 255. */ -/* -1 because the value UINT16_MAX is used to track indefinite-length arrays */ -#define QCBOR_MAX_ITEMS_IN_ARRAY (UINT16_MAX-1) +#define QCBOR_MAX_ARRAY_NESTING 15 /** - This is deprecated. See QCBORDecode_GetNthTag() and QCBORDecode_GetNthTagOfLast() - for tag handling. - - The maximum number of tags that can be in @ref QCBORTagListIn and passed to - QCBORDecode_SetCallerConfiguredTagList() + * The maximum number of items in a single array when encoding or + * decoding. See also @ref QCBOR_MAX_ITEMS_IN_MAP. + */ +#define QCBOR_MAX_ITEMS_IN_ARRAY (UINT16_MAX-1) /* -1 is because the + * value UINT16_MAX is + * used to indicate + * indefinite-length. + */ +/** + * The maximum number of items in a single map when encoding or + * decoding. See also @ref QCBOR_MAX_ITEMS_IN_ARRAY. */ -#define QCBOR_MAX_CUSTOM_TAGS 16 +#define QCBOR_MAX_ITEMS_IN_MAP (QCBOR_MAX_ITEMS_IN_ARRAY/2) +#ifdef __cplusplus +} +#endif + #endif /* qcbor_common_h */ diff --git a/3rdparty/exported/QCBOR/qcbor/qcbor_decode.h b/3rdparty/exported/QCBOR/qcbor/qcbor_decode.h index bf30e6ded32d..8c7a44c2f4ac 100644 --- a/3rdparty/exported/QCBOR/qcbor/qcbor_decode.h +++ b/3rdparty/exported/QCBOR/qcbor/qcbor_decode.h @@ -1,35 +1,35 @@ -/*============================================================================== - Copyright (c) 2016-2018, The Linux Foundation. - Copyright (c) 2018-2022, Laurence Lundblade. - Copyright (c) 2021, Arm Limited. - All rights reserved. - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are - met: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following - disclaimer in the documentation and/or other materials provided - with the distribution. - * Neither the name of The Linux Foundation nor the names of its - contributors, nor the name "Laurence Lundblade" may be used to - endorse or promote products derived from this software without - specific prior written permission. - - THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED - WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT - ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS - BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR - BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE - OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN - IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - =============================================================================*/ +/* =========================================================================== + * Copyright (c) 2016-2018, The Linux Foundation. + * Copyright (c) 2018-2024, Laurence Lundblade. + * Copyright (c) 2021, Arm Limited. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * * Neither the name of The Linux Foundation nor the names of its + * contributors, nor the name "Laurence Lundblade" may be used to + * endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ========================================================================= */ #ifndef qcbor_decode_h @@ -56,7 +56,7 @@ extern "C" { * # QCBOR Basic Decode * * This section discusses decoding assuming familiarity with the - * general description of this encoder / decoder in section @ref + * general description of this encoder-decoder in section @ref * Overview. * * Encoded CBOR has a tree structure where the leaf nodes are @@ -64,9 +64,9 @@ extern "C" { * nodes are either arrays or maps. Fundamentally, CBOR decoding is a * pre-order traversal of this tree with CBOR sequences a minor * exception. Calling QCBORDecode_GetNext() repeatedly will perform - * this. It is possible to decode any CBOR by only calling - * QCBORDecode_GetNext(), though this doesn't take advantage of many - * QCBOR features. + * this. QCBOR maintains an internal traversal cursor. It is possible + * to decode any CBOR by only calling QCBORDecode_GetNext(), though + * this doesn't take advantage of many QCBOR features. * * QCBORDecode_GetNext() returns a 56 byte structure called * @ref QCBORItem that describes the decoded item including: @@ -121,8 +121,11 @@ extern "C" { * call QCBORDecode_GetError() to know the earlier items were * successfully decoded before examining their value or type. * - * The internal decode error state is reset only by re initializing the - * decoder or calling QCBORDecode_GetErrorAndReset(). + * The internal decode error state can be reset by reinitializing the + * decoder or calling QCBORDecode_GetErrorAndReset(). Code calling + * QCBOR may take advantage of the internal error state to halt + * futher decoding and propagate errors it detects using + * QCBORDecode_SetError(). * * It is only useful to reset the error state by calling * QCBORDecode_GetErrorAndReset() on recoverable errors. Examples of @@ -175,7 +178,7 @@ extern "C" { * Decode functions like QCBORDecode_GetEpochDate() and * QCBORDecode_GetDecimalFraction() that can decode the tag content * even if the tag number is absent are still available. Typically - * they won't be linked in because of dead stripping. The + * they won't be linked in because of dead stripping. The * @c uTagRequirement parameter has no effect, but if it is * @ref QCBOR_TAG_REQUIREMENT_TAG, @ref QCBOR_ERR_TAGS_DISABLED * will be set. @@ -195,8 +198,8 @@ typedef enum { } QCBORDecodeMode; /** - * The maximum size of input to the decoder. Slightly less than UINT32_MAX - * to make room for some special indicator values. + * The maximum size of input to the decoder. Slightly less than + * @c UINT32_MAX to make room for some special indicator values. */ #define QCBOR_MAX_DECODE_INPUT_SIZE (UINT32_MAX - 2) @@ -211,134 +214,156 @@ typedef enum { /* Do not renumber these. Code depends on some of these values. */ /** The data type is unknown, unset or invalid. */ #define QCBOR_TYPE_NONE 0 + /** Never used in QCBORItem. Used by functions that match QCBOR types. */ #define QCBOR_TYPE_ANY 1 /** Type for an integer that decoded either between @c INT64_MIN and - @c INT32_MIN or @c INT32_MAX and @c INT64_MAX. Data is in member - @c val.int64. */ + * @c INT32_MIN or @c INT32_MAX and @c INT64_MAX. Data is in member + * @c val.int64. */ #define QCBOR_TYPE_INT64 2 + /** Type for an integer that decoded to a more than @c INT64_MAX and - @c UINT64_MAX. Data is in member @c val.uint64. */ + * @c UINT64_MAX. Data is in member @c val.uint64. */ #define QCBOR_TYPE_UINT64 3 + /** Type for an array. See comments on @c val.uCount. */ #define QCBOR_TYPE_ARRAY 4 + /** Type for a map. See comments on @c val.uCount. */ #define QCBOR_TYPE_MAP 5 + /** Type for a buffer full of bytes. Data is in @c val.string. */ #define QCBOR_TYPE_BYTE_STRING 6 + /** Type for a UTF-8 string. It is not NULL-terminated. See - QCBOREncode_AddText() for a discussion of line endings in CBOR. Data - is in @c val.string. */ + * QCBOREncode_AddText() for a discussion of line endings in CBOR. Data + * is in @c val.string. */ #define QCBOR_TYPE_TEXT_STRING 7 + /** Type for a positive big number. Data is in @c val.bignum, a - pointer and a length. */ + * pointer and a length. */ #define QCBOR_TYPE_POSBIGNUM 9 + /** Type for a negative big number. Data is in @c val.bignum, a - pointer and a length. */ + * pointer and a length. */ #define QCBOR_TYPE_NEGBIGNUM 10 + /** Type for [RFC 3339] (https://tools.ietf.org/html/rfc3339) date - string, possibly with time zone. Data is in @c val.string . Note this - was previously in @c val.dateString, however this is the same as - val.string being the same type in same union. */ + * string, possibly with time zone. Data is in @c val.string . Note this + * was previously in @c val.dateString, however this is the same as + * val.string being the same type in same union. val.dateString will + * be deprecated.. */ #define QCBOR_TYPE_DATE_STRING 11 + /** Type for integer seconds since Jan 1970 + floating-point - fraction. Data is in @c val.epochDate */ + * fraction. Data is in @c val.epochDate */ #define QCBOR_TYPE_DATE_EPOCH 12 -/** A simple type that this CBOR implementation doesn't know about; - Type is in @c val.uSimple. */ + +/** The CBOR major type "simple" has a small integer value indicating + * what it is. The standard CBOR simples are true, false, null, undef + * (values 20-23) and float-point numbers (values 25-27). The values + * 0-19 and 32-255 are unassigned and may be used if registered with + * in the IANA Simple Values Registry. If these unassigned simple + * values occur in the input they will be decoded as this. The value + * is in @c val.uSimple. */ #define QCBOR_TYPE_UKNOWN_SIMPLE 13 /** A decimal fraction made of decimal exponent and integer mantissa. - See @ref expAndMantissa and QCBOREncode_AddDecimalFraction(). */ + * See @ref expAndMantissa and QCBOREncode_AddTDecimalFraction(). */ #define QCBOR_TYPE_DECIMAL_FRACTION 14 /** A decimal fraction made of decimal exponent and positive big - number mantissa. See @ref expAndMantissa and - QCBOREncode_AddDecimalFractionBigNum(). */ + * number mantissa. See @ref expAndMantissa and + * QCBOREncode_AddTDecimalFractionBigNum(). */ #define QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM 15 /** A decimal fraction made of decimal exponent and negative big - number mantissa. See @ref expAndMantissa and - QCBOREncode_AddDecimalFractionBigNum(). */ + * number mantissa. See @ref expAndMantissa and + * QCBOREncode_AddTDecimalFractionBigNum(). */ #define QCBOR_TYPE_DECIMAL_FRACTION_NEG_BIGNUM 16 /** A floating-point number made of base-2 exponent and integer - mantissa. See @ref expAndMantissa and - QCBOREncode_AddBigFloat(). */ + * mantissa. See @ref expAndMantissa and + * QCBOREncode_AddTBigFloat(). */ #define QCBOR_TYPE_BIGFLOAT 17 /** A floating-point number made of base-2 exponent and positive big - number mantissa. See @ref expAndMantissa and - QCBOREncode_AddBigFloatBigNum(). */ + * number mantissa. See @ref expAndMantissa and + * QCBOREncode_AddTBigFloatBigNum(). */ #define QCBOR_TYPE_BIGFLOAT_POS_BIGNUM 18 /** A floating-point number made of base-2 exponent and negative big - number mantissa. See @ref expAndMantissa and - QCBOREncode_AddBigFloatBigNum(). */ + * number mantissa. See @ref expAndMantissa and + * QCBOREncode_AddTBigFloatBigNum(). */ #define QCBOR_TYPE_BIGFLOAT_NEG_BIGNUM 19 -/** Type for the value false. */ +/** Type for the simple value false. */ #define QCBOR_TYPE_FALSE 20 -/** Type for the value true. */ + +/** Type for the simple value true. */ #define QCBOR_TYPE_TRUE 21 -/** Type for the value null. */ + +/** Type for the simple value null. */ #define QCBOR_TYPE_NULL 22 -/** Type for the value undef. */ + +/** Type for the simple value undef. */ #define QCBOR_TYPE_UNDEF 23 -/** Type for a floating-point number. Data is in @c val.float. */ + +/** Type for a floating-point number. Data is in @c val.fnum. */ #define QCBOR_TYPE_FLOAT 26 -/** Type for a double floating-point number. Data is in @c val.double. */ + +/** Type for a double floating-point number. Data is in @c val.dfnum. */ #define QCBOR_TYPE_DOUBLE 27 #define QCBOR_TYPE_BREAK 31 /* Used internally; never returned */ /** For @ref QCBOR_DECODE_MODE_MAP_AS_ARRAY decode mode, a map that is - being traversed as an array. See QCBORDecode_Init() */ + * being traversed as an array. See QCBORDecode_Init() */ #define QCBOR_TYPE_MAP_AS_ARRAY 32 /** Encoded CBOR that is wrapped in a byte string. Often used when the - CBOR is to be hashed for signing or HMAC. See also @ref - QBCOR_TYPE_WRAPPED_CBOR_SEQUENCE. Data is in @c val.string. */ + * CBOR is to be hashed for signing or HMAC. See also @ref + * QBCOR_TYPE_WRAPPED_CBOR_SEQUENCE. Data is in @c val.string. */ #define QBCOR_TYPE_WRAPPED_CBOR 36 /** A URI as defined in RFC 3986. Data is in @c val.string. */ #define QCBOR_TYPE_URI 44 /** Text is base64 URL encoded in RFC 4648. The base64 encoding is - NOT removed. Data is in @c val.string. */ + * NOT removed. Data is in @c val.string. */ #define QCBOR_TYPE_BASE64URL 45 /** Text is base64 encoded in RFC 4648. The base64 encoding is NOT - removed. Data is in @c val.string. */ + * removed. Data is in @c val.string. */ #define QCBOR_TYPE_BASE64 46 /** PERL-compatible regular expression. Data is in @c val.string. */ #define QCBOR_TYPE_REGEX 47 /** Non-binary MIME per RFC 2045. See also @ref - QCBOR_TYPE_BINARY_MIME. Data is in @c val.string. */ + * QCBOR_TYPE_BINARY_MIME. Data is in @c val.string. */ #define QCBOR_TYPE_MIME 48 /** Binary UUID per RFC 4122. Data is in @c val.string. */ #define QCBOR_TYPE_UUID 49 /** A CBOR sequence per RFC 8742. See also @ ref - QBCOR_TYPE_WRAPPED_CBOR. Data is in @c val.string. */ + * QBCOR_TYPE_WRAPPED_CBOR. Data is in @c val.string. */ #define QBCOR_TYPE_WRAPPED_CBOR_SEQUENCE 75 /** Binary MIME per RFC 2045. See also @ref QCBOR_TYPE_MIME. Data is - in @c val.string. */ + * in @c val.string. */ #define QCBOR_TYPE_BINARY_MIME 76 /** Type for [RFC 8943](https://tools.ietf.org/html/rfc8943) date - string, a date with no time or time zone info. Data is in - @c val.string */ + * string, a date with no time or time zone info. Data is in + * @c val.string */ #define QCBOR_TYPE_DAYS_STRING 77 /** Type for integer days since Jan 1 1970 described in - [RFC 8943](https://tools.ietf.org/html/rfc8943). Data is in - @c val.epochDays */ + * [RFC 8943](https://tools.ietf.org/html/rfc8943). Data is in + * @c val.epochDays */ #define QCBOR_TYPE_DAYS_EPOCH 78 #define QCBOR_TYPE_TAG 254 /* Used internally; never returned */ @@ -354,6 +379,49 @@ typedef enum { #define QCBOR_LAST_UNMAPPED_TAG (CBOR_TAG_INVALID16 - QCBOR_NUM_MAPPED_TAGS - 1) +/** + * @anchor expAndMantissa + * + * This holds the value for big floats and decimal fractions, as an + * exponent and mantissa. For big floats the base for exponentiation + * is 2. For decimal fractions it is 10. Whether an instance is a big + * float or decimal fraction is known by context, usually by @c uDataType + * in @ref QCBORItem which might be @ref QCBOR_TYPE_DECIMAL_FRACTION, + * @ref QCBOR_TYPE_BIGFLOAT, ... + * + * The mantissa may be an @c int64_t or a big number. This is again + * determined by context, usually @c uDataType in @ref QCBORItem which + * might be @ref QCBOR_TYPE_DECIMAL_FRACTION, + * @ref QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM, ... The sign of the + * big number also comes from the context + * (@ref QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM, + * @ref QCBOR_TYPE_DECIMAL_FRACTION_NEG_BIGNUM,...). + * + * @c bigNum is big endian or network byte order. The most significant + * byte is first. + * + * When @c Mantissa is @c int64_t, it represents the true value of the + * mantissa with the offset of 1 for CBOR negative values + * applied. When it is a negative big number + * (@ref QCBOR_TYPE_DECIMAL_FRACTION_NEG_BIGNUM or + * @ref QCBOR_TYPE_BIGFLOAT_NEG_BIGNUM), the offset of 1 has NOT been + * applied (doing so requires somewhat complex big number arithmetic + * and may increase the length of the big number). To get the correct + * value @c bigNum must be incremented by one before use. + * + * Also see QCBOREncode_AddTDecimalFraction(), + * QCBOREncode_AddTBigFloat(), QCBOREncode_AddTDecimalFractionBigNum() + * and QCBOREncode_AddTBigFloatBigNum(). + */ +typedef struct { + int64_t nExponent; + union { + int64_t nInt; + UsefulBufC bigNum; + } Mantissa; +} QCBORExpAndMantissa; + + /** * This holds a decoded data item. It is returned by the * QCBORDecode_GetNext(), the principle decoding function. @@ -438,64 +506,32 @@ typedef struct _QCBORItem { /** The value for @c uDataType @ref QCBOR_TYPE_DAYS_EPOCH -- the * number of days before or after Jan 1, 1970. */ int64_t epochDays; - /** No longer used. Was the value for @ref QCBOR_TYPE_DATE_STRING, - * but now that value is in @c string. TODO: finish writing this.*/ + * but now that value is in @c string. This will be removed in QCBOR 2.0. */ UsefulBufC dateString; - /** The value for @c uDataType @ref QCBOR_TYPE_POSBIGNUM and - @ref QCBOR_TYPE_NEGBIGNUM. TODO: change to string*/ + * @ref QCBOR_TYPE_NEGBIGNUM. */ UsefulBufC bigNum; - /** The integer value for unknown simple types. TODO: doc this better. */ + /** See @ref QCBOR_TYPE_UKNOWN_SIMPLE */ uint8_t uSimple; #ifndef QCBOR_DISABLE_EXP_AND_MANTISSA - /** - * @anchor expAndMantissa - * - * This holds the value for big floats and decimal fractions. - * The use of the fields in this structure depends on @c - * uDataType. - * - * When @c uDataType indicates a decimal fraction, the - * @c nExponent is base 10. When it indicates a big float, it - * is base 2. - * - * When @c uDataType indicates a big number, then the @c bigNum - * member of @c Mantissa is valid. Otherwise the @c nInt member - * of @c Mantissa is valid. - * - * See @ref QCBOR_TYPE_DECIMAL_FRACTION, - * @ref QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM, - * @ref QCBOR_TYPE_DECIMAL_FRACTION_NEG_BIGNUM, - * @ref QCBOR_TYPE_BIGFLOAT, @ref QCBOR_TYPE_BIGFLOAT_POS_BIGNUM, - * and @ref QCBOR_TYPE_BIGFLOAT_NEG_BIGNUM. - * - * Also see QCBOREncode_AddTDecimalFraction(), - * QCBOREncode_AddTBigFloat(), - * QCBOREncode_AddTDecimalFractionBigNum() and - * QCBOREncode_AddTBigFloatBigNum(). - */ - struct { - int64_t nExponent; - union { - int64_t nInt; - UsefulBufC bigNum; - } Mantissa; - } expAndMantissa; -#endif /* QCBOR_DISABLE_EXP_AND_MANTISSA */ + QCBORExpAndMantissa expAndMantissa; +#endif /* ! QCBOR_DISABLE_EXP_AND_MANTISSA */ uint64_t uTagV; /* Used internally during decoding */ } val; /** Union holding the different label types selected based on @c uLabelType */ union { - /** The label for @c uLabelType @ref QCBOR_TYPE_BYTE_STRING and - * @ref QCBOR_TYPE_TEXT_STRING */ - UsefulBufC string; /** The label for @c uLabelType for @ref QCBOR_TYPE_INT64 */ int64_t int64; +#ifndef QCBOR_DISABLE_NON_INTEGER_LABELS /** The label for @c uLabelType for @ref QCBOR_TYPE_UINT64 */ uint64_t uint64; + /** The label for @c uLabelType @ref QCBOR_TYPE_BYTE_STRING and + * @ref QCBOR_TYPE_TEXT_STRING */ + UsefulBufC string; +#endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */ } label; #ifndef QCBOR_DISABLE_TAGS @@ -590,7 +626,9 @@ typedef struct _QCBORItem { * strings will have to free them. How they free them, depends on the * design of the string allocator. */ -typedef UsefulBuf (* QCBORStringAllocate)(void *pAllocateCxt, void *pOldMem, size_t uNewSize); +typedef UsefulBuf (* QCBORStringAllocate)(void *pAllocateCxt, + void *pOldMem, + size_t uNewSize); /** @@ -654,7 +692,8 @@ typedef struct _QCBORDecodeContext QCBORDecodeContext; * that are not integers or text strings, but the caller must manage * much of the map decoding. */ -void QCBORDecode_Init(QCBORDecodeContext *pCtx, UsefulBufC EncodedCBOR, QCBORDecodeMode nMode); +void +QCBORDecode_Init(QCBORDecodeContext *pCtx, UsefulBufC EncodedCBOR, QCBORDecodeMode nMode); /** @@ -703,7 +742,10 @@ void QCBORDecode_Init(QCBORDecodeContext *pCtx, UsefulBufC EncodedCBOR, QCBORDec * See also QCBORDecode_SetUpAllocator() to set up a custom allocator * if this one isn't sufficient. */ -QCBORError QCBORDecode_SetMemPool(QCBORDecodeContext *pCtx, UsefulBuf MemPool, bool bAllStrings); +QCBORError +QCBORDecode_SetMemPool(QCBORDecodeContext *pCtx, + UsefulBuf MemPool, + bool bAllStrings); /** @@ -739,10 +781,11 @@ QCBORError QCBORDecode_SetMemPool(QCBORDecodeContext *pCtx, UsefulBuf MemPool, b * @c uLabelAlloc @c == @c 1 in @ref QCBORItem. Note this is in a * separate GitHub repository. */ -void QCBORDecode_SetUpAllocator(QCBORDecodeContext *pCtx, - QCBORStringAllocate pfAllocateFunction, - void *pAllocateContext, - bool bAllStrings); +void +QCBORDecode_SetUpAllocator(QCBORDecodeContext *pCtx, + QCBORStringAllocate pfAllocateFunction, + void *pAllocateContext, + bool bAllStrings); /** @@ -865,9 +908,10 @@ void QCBORDecode_SetUpAllocator(QCBORDecodeContext *pCtx, * * See [Decode Error Overview](#Decode-Errors-Overview). * - * If a decoding error occurs, \c uDataType and \c uLabelType will be set - * to @ref QCBOR_TYPE_NONE. If there is no need to know the specific - * error, it is sufficient to check for @ref QCBOR_TYPE_NONE. + * If a decoding error occurs or previously occured, @c uDataType and + * @c uLabelType will be set to @ref QCBOR_TYPE_NONE. If there is no + * need to know the specific error, it is sufficient to check for @ref + * QCBOR_TYPE_NONE. * * Errors fall in several categories: * @@ -905,7 +949,7 @@ void QCBORDecode_SetUpAllocator(QCBORDecodeContext *pCtx, * | __Invalid CBOR__ || * | @ref QCBOR_ERR_NO_MORE_ITEMS | Need more input data items to decode | * | @ref QCBOR_ERR_BAD_EXP_AND_MANTISSA | The structure of a big float or big number is invalid | - * | @ref QCBOR_ERR_BAD_TAG_CONTENT | The content of a tag is of the wrong type | + * | @ref QCBOR_ERR_UNRECOVERABLE_TAG_CONTENT | The content of a tag is of the wrong type | * | __Implementation Limits__ || * | @ref QCBOR_ERR_INT_OVERFLOW | Input integer smaller than INT64_MIN | * | @ref QCBOR_ERR_ARRAY_DECODE_TOO_LONG | Array or map has more elements than can be handled | @@ -916,14 +960,15 @@ void QCBORDecode_SetUpAllocator(QCBORDecodeContext *pCtx, * | __Configuration errors__ || * | @ref QCBOR_ERR_NO_STRING_ALLOCATOR | Encountered indefinite-length string with no allocator configured | * | @ref QCBOR_ERR_MAP_LABEL_TYPE | A map label that is not a string on an integer | - * | @ref QCBOR_ERR_HALF_PRECISION_DISABLED | Library compiled with half-precision disabled and half-precision input encountered | - * | @ref QCBOR_ERR_INDEF_LEN_ARRAYS_DISABLED | Library compiled with indefinite maps and arrays disabled and indefinite map or array encountered | - * | @ref QCBOR_ERR_INDEF_LEN_STRINGS_DISABLED | Library compiled with indefinite strings disabled and indefinite string encountered | + * | @ref QCBOR_ERR_HALF_PRECISION_DISABLED | Half-precision input, but disabled in QCBOR library | + * | @ref QCBOR_ERR_INDEF_LEN_ARRAYS_DISABLED | Indefinite-length input, but disabled in QCBOR library | + * | @ref QCBOR_ERR_INDEF_LEN_STRINGS_DISABLED | Indefinite-length input, but disabled in QCBOR library | * | @ref QCBOR_ERR_ALL_FLOAT_DISABLED | Library compiled with floating-point support turned off. | * | __Resource exhaustion errors__ || * | @ref QCBOR_ERR_STRING_ALLOCATE | The string allocator is unable to allocate more memory | */ -void QCBORDecode_VGetNext(QCBORDecodeContext *pCtx, QCBORItem *pDecodedItem); +void +QCBORDecode_VGetNext(QCBORDecodeContext *pCtx, QCBORItem *pDecodedItem); /** @@ -939,7 +984,8 @@ void QCBORDecode_VGetNext(QCBORDecodeContext *pCtx, QCBORItem *pDecodedItem); * doesn't set the internal decoding error and will attempt to decode * even if the decoder is in the error state. */ -QCBORError QCBORDecode_GetNext(QCBORDecodeContext *pCtx, QCBORItem *pDecodedItem); +QCBORError +QCBORDecode_GetNext(QCBORDecodeContext *pCtx, QCBORItem *pDecodedItem); /** @@ -948,14 +994,24 @@ QCBORError QCBORDecode_GetNext(QCBORDecodeContext *pCtx, QCBORItem *pDecodedItem * @param[in] pCtx The decoder context. * @param[out] pDecodedItem The decoded CBOR item. * - * This is the same as QCBORDecode_VGetNext() but the contents of the - * entire map or array will be consumed if the item is a map or array. + * @c pItem returned is the same as QCBORDecode_VGetNext(). If the + * item is an array or map, the entire contents of the array or map + * will be consumed leaving the cursor after the array or map. + * + * If an array or map is being consumed by this, an error will occur + * if any of the items in the array or map are in error. * - * In order to go back to decode the contents of a map or array + * If the item is a tag the contents of which is an array or map, like + * a big float, @c pItem will identify it as such and the contents + * will be consumed, but the validity of the tag won't be checked + * other than for being well-formed. + * + * In order to go back to decode the contents of an array or map * consumed by this, the decoder must be rewound using * QCBORDecode_Rewind(). */ -void QCBORDecode_VGetNextConsume(QCBORDecodeContext *pCtx, QCBORItem *pDecodedItem); +void +QCBORDecode_VGetNextConsume(QCBORDecodeContext *pCtx, QCBORItem *pDecodedItem); /** @@ -1000,6 +1056,68 @@ QCBORError QCBORDecode_PeekNext(QCBORDecodeContext *pCtx, QCBORItem *pDecodedItem); +/** + * @brief Get the current traversal cursort offset in the input CBOR. + * + * @param[in] pCtx The decoder context. + * + * @returns The traversal cursor offset or @c UINT32_MAX. + + * The position returned is always the start of the next item that + * would be next decoded with QCBORDecode_VGetNext(). The cursor + * returned may be at the end of the input in which case the next call + * to QCBORDecode_VGetNext() will result in the @ref + * QCBOR_ERR_NO_MORE_ITEMS. See also QCBORDecode_AtEnd(). + * + * If the decoder is in error state from previous decoding, + * @c UINT32_MAX is returned. + * + * When decoding map items, the position returned is always of the + * label, never the value. + * + * For indefinite-length arrays and maps, the break byte is consumed + * when the last item in the array or map is consumed so the cursor is + * at the next item to be decoded as expected. + * + * There are some special rules for the traversal cursor when fetching + * map items by label. See the description of @SpiffyDecode. + * + * When traversal is bounded because an array or map has been entered + * (e.g., QCBORDecode_EnterMap()) and all items in the array or map + * have been consumed, the position returned will be of the item + * outside of the array or map. The array or map must be exited before + * QCBORDecode_VGetNext() will decode it. + * + * In many cases the position returned will be in the middle of + * an array or map. It will not be possible to start decoding at + * that location with another instance of the decoder and go to + * the end. It is not valid CBOR. If the input is a CBOR sequence + * and the position is not in the moddle of an array or map + * then it is possible to decode to the end. + * + * There is no corresponding seek method because it is too complicated + * to restore the internal decoder state that tracks nesting. + */ +static uint32_t +QCBORDecode_Tell(QCBORDecodeContext *pCtx); + + +/** + * @brief Tell whether cursor is at end of the input. + * + * @param[in] pCtx The decoder context. + * + * @returns Error code possibly indicating end of input. + * + * This returns the same as QCBORDecode_GetError() except that @ref + * QCBOR_ERR_NO_MORE_ITEMS is returned if the travseral cursor is at + * the end of the CBOR input bytes (not the end of an entered array or + * map). + */ +QCBORError +QCBORDecode_EndCheck(QCBORDecodeContext *pCtx); + + /** * @brief Returns the tag numbers for an item. * @@ -1014,44 +1132,50 @@ QCBORDecode_PeekNext(QCBORDecodeContext *pCtx, QCBORItem *pDecodedItem); * in the QCBORItem. * * Tags nest. Here the tag with index 0 has the data item as its content. The - * tag with index 1 has the tag at index 0 has its content and so forth. + * tag with index 1 has the tag at index 0 has its content and so forth. * * Deep tag nesting is rare so this implementation imposes a limit of * @ref QCBOR_MAX_TAGS_PER_ITEM on nesting and returns @ref * QCBOR_ERR_TOO_MANY_TAGS if there are more. This is a limit of this - * imple* mentation, not of CBOR. (To be able to handle deeper + * implementation, not of CBOR. (To be able to handle deeper * nesting, the constant can be increased and the library * recompiled. It will use more memory). * * See also @ref CBORTags, @ref Tag-Usage and @ref Tags-Overview. * * To reduce memory used by a QCBORItem, tag numbers larger than - * UINT16_MAX are mapped so the tag numbers in @c uTags should be + * @c UINT16_MAX are mapped so the tag numbers in @c uTags should be * accessed with this function rather than directly. * * This returns @ref CBOR_TAG_INVALID64 if any error occurred when * getting the item. This is also returned if there are no tags on the * item or no tag at @c uIndex. */ -uint64_t QCBORDecode_GetNthTag(QCBORDecodeContext *pCtx, const QCBORItem *pItem, uint32_t uIndex); +uint64_t +QCBORDecode_GetNthTag(QCBORDecodeContext *pCtx, const QCBORItem *pItem, uint32_t uIndex); /** - * @brief Returns the tag numbers for last-fetched item. + * @brief Returns the tag numbers for last-decoded item. * * @param[in] pCtx The decoder context. * @param[in] uIndex The index of the tag to get. * - * @returns The actual nth tag value or CBOR_TAG_INVALID64. + * @returns The nth tag number or CBOR_TAG_INVALID64. + * + * This returns tags of the most recently decoded item. See + * QCBORDecode_GetNthTag(). This is particularly of use for spiffy + * decode functions that don't return a @ref QCBORItem. * - * See QCBORDecode_GetNthTag(). This is the same but works with spiffy - * decoding functions that do not return a QCBORItem with a - * list of recorded tag numbers. This gets the tags for the most - * recently decoded item. + * This does not work for QCBORDecode_GetNext(), + * QCBORDecode_PeekNext(), QCBORDecode_VPeekNext() or + * QCBORDecode_VGetNextConsume() but these all return a + * @ref QCBORItem, so it is not necessary. * - * If a decoding error set then this returns CBOR_TAG_INVALID64. + * If a decoding error is set, then this returns CBOR_TAG_INVALID64. */ -uint64_t QCBORDecode_GetNthTagOfLast(const QCBORDecodeContext *pCtx, uint32_t uIndex); +uint64_t +QCBORDecode_GetNthTagOfLast(const QCBORDecodeContext *pCtx, uint32_t uIndex); /** @@ -1092,7 +1216,8 @@ uint64_t QCBORDecode_GetNthTagOfLast(const QCBORDecodeContext *pCtx, uint32_t uI * QCBOR_ERR_EXTRA_BYTES will be returned. This can be considered a * successful decode. See also QCBORDecode_PartialFinish(). */ -QCBORError QCBORDecode_Finish(QCBORDecodeContext *pCtx); +QCBORError +QCBORDecode_Finish(QCBORDecodeContext *pCtx); /** @@ -1124,6 +1249,19 @@ QCBORError QCBORDecode_PartialFinish(QCBORDecodeContext *pCtx, size_t *puConsumed); +/** + * @brief Retrieve the undecoded input buffer. + * + * @param[in] pCtx The decode context. + * + * @return The input that was given to QCBORDecode_Init(). + * + * A simple convenience method, should it be useful to get the original input back. + */ +static UsefulBufC +QCBORDecode_RetrieveUndecodedInput(QCBORDecodeContext *pCtx); + + /** * @brief Get the decoding error. * @@ -1151,7 +1289,8 @@ QCBORDecode_PartialFinish(QCBORDecodeContext *pCtx, size_t *puConsumed); * QCBORDecode_GetAndResetError() may be called after these data items * are fetched. */ -static QCBORError QCBORDecode_GetError(QCBORDecodeContext *pCtx); +static QCBORError +QCBORDecode_GetError(QCBORDecodeContext *pCtx); /** @@ -1163,22 +1302,24 @@ static QCBORError QCBORDecode_GetError(QCBORDecodeContext *pCtx); * This returns the same as QCBORDecode_GetError() and also resets the * error state to @ref QCBOR_SUCCESS. */ -static QCBORError QCBORDecode_GetAndResetError(QCBORDecodeContext *pCtx); +static QCBORError +QCBORDecode_GetAndResetError(QCBORDecodeContext *pCtx); /** * @brief Whether an error indicates non-well-formed CBOR. * - * @param[in] uErr The decoder context. + * @param[in] uErr The QCBOR error code. * @return @c true if the error code indicates non-well-formed CBOR. */ -static bool QCBORDecode_IsNotWellFormedError(QCBORError uErr); +static bool +QCBORDecode_IsNotWellFormedError(QCBORError uErr); /** * @brief Whether a decoding error is recoverable. * - * @param[in] uErr The decoder context. + * @param[in] uErr The QCBOR error code. * @return @c true if the error code indicates and uncrecoverable error. * * When an error is unrecoverable, no further decoding of the input is @@ -1194,55 +1335,81 @@ static bool QCBORDecode_IsNotWellFormedError(QCBORError uErr); * The unrecoverable errors are a range of the errors in * @ref QCBORError. */ -static bool QCBORDecode_IsUnrecoverableError(QCBORError uErr); +static bool +QCBORDecode_IsUnrecoverableError(QCBORError uErr); + + +/** + * @brief Manually set error condition, or set user-defined error. + * + * @param[in] pCtx The decoder context. + * @param[in] uError The error code to set. + * + * Once set, none of the QCBORDecode methods will do anything and the + * error code set will stay until cleared with + * QCBORDecode_GetAndResetError(). A user-defined error can be set + * deep in some decoding layers to short-circuit further decoding + * and propagate up. + * + * When the error condition is set, QCBORDecode_VGetNext() will always + * return an item with data and label type as @ref QCBOR_TYPE_NONE. + * + * The main intent of this is to set a user-defined error code in the + * range of @ref QCBOR_ERR_FIRST_USER_DEFINED to + * @ref QCBOR_ERR_LAST_USER_DEFINED, but it is OK to set QCBOR-defined + * error codes too. + */ +static void +QCBORDecode_SetError(QCBORDecodeContext *pCtx, QCBORError uError); /** - @brief Convert int64_t to smaller integers safely. - - @param [in] src An @c int64_t. - @param [out] dest A smaller sized integer to convert to. - - @return 0 on success -1 if not - - When decoding an integer, the CBOR decoder will return the value as - an int64_t unless the integer is in the range of @c INT64_MAX and @c - UINT64_MAX. That is, unless the value is so large that it can only be - represented as a @c uint64_t, it will be an @c int64_t. - - CBOR itself doesn't size the individual integers it carries at - all. The only limits it puts on the major integer types is that they - are 8 bytes or less in length. Then encoders like this one use the - smallest number of 1, 2, 4 or 8 bytes to represent the integer based - on its value. There is thus no notion that one data item in CBOR is - a 1-byte integer and another is a 4-byte integer. - - The interface to this CBOR encoder only uses 64-bit integers. Some - CBOR protocols or implementations of CBOR protocols may not want to - work with something smaller than a 64-bit integer. Perhaps an array - of 1000 integers needs to be sent and none has a value larger than - 50,000 and are represented as @c uint16_t. - - The sending / encoding side is easy. Integers are temporarily widened - to 64-bits as a parameter passing through QCBOREncode_AddInt64() and - encoded in the smallest way possible for their value, possibly in - less than an @c uint16_t. - - On the decoding side the integers will be returned at @c int64_t even if - they are small and were represented by only 1 or 2 bytes in the - encoded CBOR. The functions here will convert integers to a small - representation with an overflow check. - - (The decoder could have support 8 different integer types and - represented the integer with the smallest type automatically, but - this would have made the decoder more complex and code calling the - decoder more complex in most use cases. In most use cases on 64-bit - machines it is no burden to carry around even small integers as - 64-bit values). + * @brief Convert int64_t to smaller integers safely. + * + * @param [in] src An @c int64_t. + * @param [out] dest A smaller sized integer to convert to. + * + * @return 0 on success -1 if not + * + * When decoding an integer, the CBOR decoder will return the value as + * an int64_t unless the integer is in the range of @c INT64_MAX and + * @c UINT64_MAX. That is, unless the value is so large that it can only be + * represented as a @c uint64_t, it will be an @c int64_t. + * + * CBOR itself doesn't size the individual integers it carries at + * all. The only limits it puts on the major integer types is that they + * are 8 bytes or less in length. Then encoders like this one use the + * smallest number of 1, 2, 4 or 8 bytes to represent the integer based + * on its value. There is thus no notion that one data item in CBOR is + * a 1-byte integer and another is a 4-byte integer. + * + * The interface to this CBOR encoder only uses 64-bit integers. Some + * CBOR protocols or implementations of CBOR protocols may not want to + * work with something smaller than a 64-bit integer. Perhaps an array + * of 1,000 integers needs to be sent and none has a value larger than + * 50,000 and are represented as @c uint16_t. + * + * The sending / encoding side is easy. Integers are temporarily widened + * to 64-bits as a parameter passing through QCBOREncode_AddInt64() and + * encoded in the smallest way possible for their value, possibly in + * less than an @c uint16_t. + * + * On the decoding side the integers will be returned at @c int64_t even if + * they are small and were represented by only 1 or 2 bytes in the + * encoded CBOR. The functions here will convert integers to a small + * representation with an overflow check. + * + * (The decoder could have support 8 different integer types and + * represented the integer with the smallest type automatically, but + * this would have made the decoder more complex and code calling the + * decoder more complex in most use cases. In most use cases on 64-bit + * machines it is no burden to carry around even small integers as + * 64-bit values). */ -static inline int QCBOR_Int64ToInt32(int64_t src, int32_t *dest) +static inline int +QCBOR_Int64ToInt32(int64_t src, int32_t *dest) { if(src > INT32_MAX || src < INT32_MIN) { return -1; @@ -1252,7 +1419,8 @@ static inline int QCBOR_Int64ToInt32(int64_t src, int32_t *dest) return 0; } -static inline int QCBOR_Int64ToInt16(int64_t src, int16_t *dest) +static inline int +QCBOR_Int64ToInt16(int64_t src, int16_t *dest) { if(src > INT16_MAX || src < INT16_MIN) { return -1; @@ -1262,7 +1430,8 @@ static inline int QCBOR_Int64ToInt16(int64_t src, int16_t *dest) return 0; } -static inline int QCBOR_Int64ToInt8(int64_t src, int8_t *dest) +static inline int +QCBOR_Int64ToInt8(int64_t src, int8_t *dest) { if(src > INT8_MAX || src < INT8_MIN) { return -1; @@ -1272,7 +1441,8 @@ static inline int QCBOR_Int64ToInt8(int64_t src, int8_t *dest) return 0; } -static inline int QCBOR_Int64ToUInt32(int64_t src, uint32_t *dest) +static inline int +QCBOR_Int64ToUInt32(int64_t src, uint32_t *dest) { if(src > UINT32_MAX || src < 0) { return -1; @@ -1282,7 +1452,14 @@ static inline int QCBOR_Int64ToUInt32(int64_t src, uint32_t *dest) return 0; } -static inline int QCBOR_Int64UToInt16(int64_t src, uint16_t *dest) +/** + * https://github.com/laurencelundblade/QCBOR/pull/243 + * For backwards compatibility + */ +#define QCBOR_Int64UToInt16 QCBOR_Int64ToUInt16 + +static inline int +QCBOR_Int64ToUInt16(int64_t src, uint16_t *dest) { if(src > UINT16_MAX || src < 0) { return -1; @@ -1292,7 +1469,8 @@ static inline int QCBOR_Int64UToInt16(int64_t src, uint16_t *dest) return 0; } -static inline int QCBOR_Int64ToUInt8(int64_t src, uint8_t *dest) +static inline int +QCBOR_Int64ToUInt8(int64_t src, uint8_t *dest) { if(src > UINT8_MAX || src < 0) { return -1; @@ -1302,7 +1480,8 @@ static inline int QCBOR_Int64ToUInt8(int64_t src, uint8_t *dest) return 0; } -static inline int QCBOR_Int64ToUInt64(int64_t src, uint64_t *dest) +static inline int +QCBOR_Int64ToUInt64(int64_t src, uint64_t *dest) { if(src < 0) { return -1; @@ -1315,11 +1494,12 @@ static inline int QCBOR_Int64ToUInt64(int64_t src, uint64_t *dest) -/* ------------------------------------------------------------------------ - * Deprecated functions retained for backwards compatibility. Their use is - * not recommended. - * ---- */ - +/* ========================================================================= * + * BEGINNING OF DEPRECATED FUNCTIONS * + * * + * There is no plan to remove these in future versions. * + * They just have been replaced by something better. * + * ========================================================================= */ /** * Deprecated -- Tag handling has been revised and this is no longer @@ -1360,7 +1540,9 @@ typedef struct { * Tag handling has been revised and it is no longer ncessary to use * this. See QCBORDecode_GetNthTag(). */ -void QCBORDecode_SetCallerConfiguredTagList(QCBORDecodeContext *pCtx, const QCBORTagListIn *pTagList); +void +QCBORDecode_SetCallerConfiguredTagList(QCBORDecodeContext *pCtx, + const QCBORTagListIn *pTagList); /** @@ -1388,7 +1570,10 @@ void QCBORDecode_SetCallerConfiguredTagList(QCBORDecodeContext *pCtx, const QCBO * add new tags to the internal list so they can be checked for with * this function. */ -bool QCBORDecode_IsTagged(QCBORDecodeContext *pCtx, const QCBORItem *pItem, uint64_t uTag); +bool +QCBORDecode_IsTagged(QCBORDecodeContext *pCtx, + const QCBORItem *pItem, + uint64_t uTag); /** @@ -1409,12 +1594,12 @@ bool QCBORDecode_IsTagged(QCBORDecodeContext *pCtx, const QCBORItem *pItem, uint * been decoded. * * This is not backwards compatibile in two ways. First, it is limited - * to \ref QCBOR_MAX_TAGS_PER_ITEM items whereas previously it was + * to @ref QCBOR_MAX_TAGS_PER_ITEM items whereas previously it was * unlimited. Second, it will not inlucde the tags that QCBOR decodes * internally. * * This works the same as QCBORDecode_GetNext() except that it also - * returns the list of tags for the data item in \c pTagList. + * returns the list of tags for the data item in @c pTagList. * * The 0th tag returned here is the one furthest from the data * item. This is opposite the order for QCBORDecode_GetNthTag(). @@ -1425,28 +1610,56 @@ bool QCBORDecode_IsTagged(QCBORDecodeContext *pCtx, const QCBORItem *pItem, uint * QCBOR_ERR_TOO_MANY_TAGS if the array in @c pTagList is too small to * hold all the tags for the item. */ -QCBORError QCBORDecode_GetNextWithTags(QCBORDecodeContext *pCtx, QCBORItem *pDecodedItem, QCBORTagListOut *pTagList); +QCBORError +QCBORDecode_GetNextWithTags(QCBORDecodeContext *pCtx, + QCBORItem *pDecodedItem, + QCBORTagListOut *pTagList); + +/* ========================================================================= * + * END OF DEPRECATED FUNCTIONS * + * ========================================================================= */ -/* ------------------------------------------------------------------------ - * Inline implementations of public functions defined above. - * ---- */ -static inline QCBORError QCBORDecode_GetError(QCBORDecodeContext *pMe) +/* ========================================================================= * + * BEGINNING OF PRIVATE INLINE IMPLEMENTATION * + * ========================================================================= */ + +static inline uint32_t +QCBORDecode_Tell(QCBORDecodeContext *pMe) +{ + if(pMe->uLastError) { + return UINT32_MAX; + } + + /* Cast is safe because decoder input size is restricted. */ + return (uint32_t)UsefulInputBuf_Tell(&(pMe->InBuf)); +} + +static inline UsefulBufC +QCBORDecode_RetrieveUndecodedInput(QCBORDecodeContext *pMe) +{ + return UsefulInputBuf_RetrieveUndecodedInput(&(pMe->InBuf)); +} + +static inline QCBORError +QCBORDecode_GetError(QCBORDecodeContext *pMe) { return (QCBORError)pMe->uLastError; } -static inline QCBORError QCBORDecode_GetAndResetError(QCBORDecodeContext *pMe) +static inline QCBORError +QCBORDecode_GetAndResetError(QCBORDecodeContext *pMe) { const QCBORError uReturn = (QCBORError)pMe->uLastError; pMe->uLastError = QCBOR_SUCCESS; return uReturn; } -static inline bool QCBORDecode_IsNotWellFormedError(QCBORError uErr) +static inline bool +QCBORDecode_IsNotWellFormedError(const QCBORError uErr) { if(uErr >= QCBOR_START_OF_NOT_WELL_FORMED_ERRORS && uErr <= QCBOR_END_OF_NOT_WELL_FORMED_ERRORS) { @@ -1456,7 +1669,8 @@ static inline bool QCBORDecode_IsNotWellFormedError(QCBORError uErr) } } -static inline bool QCBORDecode_IsUnrecoverableError(QCBORError uErr) +static inline bool +QCBORDecode_IsUnrecoverableError(const QCBORError uErr) { if(uErr >= QCBOR_START_OF_UNRECOVERABLE_DECODE_ERRORS && uErr <= QCBOR_END_OF_UNRECOVERABLE_DECODE_ERRORS) { @@ -1466,6 +1680,18 @@ static inline bool QCBORDecode_IsUnrecoverableError(QCBORError uErr) } } + +static inline void +QCBORDecode_SetError(QCBORDecodeContext *pMe, QCBORError uError) +{ + pMe->uLastError = (uint8_t)uError; +} + +/* ======================================================================== * + * END OF PRIVATE INLINE IMPLEMENTATION * + * ======================================================================== */ + + /* A few cross checks on size constants and special value lengths */ #if QCBOR_MAP_OFFSET_CACHE_INVALID < QCBOR_MAX_DECODE_INPUT_SIZE #error QCBOR_MAP_OFFSET_CACHE_INVALID is too large diff --git a/3rdparty/exported/QCBOR/qcbor/qcbor_encode.h b/3rdparty/exported/QCBOR/qcbor/qcbor_encode.h index 8b2ed90ab680..cf88754f255b 100644 --- a/3rdparty/exported/QCBOR/qcbor/qcbor_encode.h +++ b/3rdparty/exported/QCBOR/qcbor/qcbor_encode.h @@ -1,35 +1,35 @@ -/*============================================================================== - Copyright (c) 2016-2018, The Linux Foundation. - Copyright (c) 2018-2021, Laurence Lundblade. - Copyright (c) 2021, Arm Limited. - All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following - disclaimer in the documentation and/or other materials provided - with the distribution. - * Neither the name of The Linux Foundation nor the names of its - contributors, nor the name "Laurence Lundblade" may be used to - endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED -WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT -ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS -BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR -BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, -WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE -OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN -IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - =============================================================================*/ +/* =========================================================================== + * Copyright (c) 2016-2018, The Linux Foundation. + * Copyright (c) 2018-2024, Laurence Lundblade. + * Copyright (c) 2021, Arm Limited. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * * Neither the name of The Linux Foundation nor the names of its + * contributors, nor the name "Laurence Lundblade" may be used to + * endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ========================================================================= */ #ifndef qcbor_encode_h @@ -50,2186 +50,2673 @@ extern "C" { /** - @file qcbor_encode.h - - @anchor Overview - - # QCBOR Overview - - This implements CBOR -- Concise Binary Object Representation as - defined in [RFC 8949] (https://tools.ietf.org/html/rfc8949). More - information is at http://cbor.io. This is a near-complete implementation of - the specification. [RFC 8742] (https://tools.ietf.org/html/rfc8742) CBOR - Sequences is also supported. Limitations are listed further down. - - See @ref Encoding for general discussion on encoding, - @ref BasicDecode for general discussion on the basic decode features - and @ref SpiffyDecode for general discussion on the easier-to-use - decoder functions. - - CBOR is intentionally designed to be translatable to JSON, but not - all CBOR can convert to JSON. See RFC 8949 for more info on how to - construct CBOR that is the most JSON friendly. - - The memory model for encoding and decoding is that encoded CBOR must - be in a contiguous buffer in memory. During encoding the caller must - supply an output buffer and if the encoding would go off the end of - the buffer an error is returned. During decoding the caller supplies - the encoded CBOR in a contiguous buffer and the decoder returns - pointers and lengths into that buffer for strings. - - This implementation does not require malloc. All data structures - passed in/out of the APIs can fit on the stack. - - Decoding of indefinite-length strings is a special case that requires - a "string allocator" to allocate memory into which the segments of - the string are coalesced. Without this, decoding will error out if an - indefinite-length string is encountered (indefinite-length maps and - arrays do not require the string allocator). A simple string - allocator called MemPool is built-in and will work if supplied with a - block of memory to allocate. The string allocator can optionally use - malloc() or some other custom scheme. - - Here are some terms and definitions: - - - "Item", "Data Item": An integer or string or such. The basic "thing" that - CBOR is about. An array is an item itself that contains some items. - - - "Array": An ordered sequence of items, the same as JSON. - - - "Map": A collection of label/value pairs. Each pair is a data - item. A JSON "object" is the same as a CBOR "map". - - - "Label": The data item in a pair in a map that names or identifies - the pair, not the value. This implementation refers to it as a - "label". JSON refers to it as the "name". The CBOR RFC refers to it - this as a "key". This implementation chooses label instead because - key is too easily confused with a cryptographic key. The COSE - standard, which uses CBOR, has also chosen to use the term "label" - rather than "key" for this same reason. - - - "Key": See "Label" above. - - - "Tag": A data item that is an explicitly labeled new data - type made up of the tagging integer and the tag content. - See @ref Tags-Overview and @ref Tag-Usage. - - - "Initial Byte": The first byte of an encoded item. Encoding and - decoding of this byte is taken care of by the implementation. - - - "Additional Info": In addition to the major type, all data items - have some other info. This is usually the length of the data but can - be several other things. Encoding and decoding of this is taken care - of by the implementation. - - CBOR has two mechanisms for tagging and labeling the data values like - integers and strings. For example, an integer that represents - someone's birthday in epoch seconds since Jan 1, 1970 could be - encoded like this: - - - First it is CBOR_MAJOR_TYPE_POSITIVE_INT (@ref QCBOR_TYPE_INT64), - the primitive positive integer. - - - Next it has a "tag" @ref CBOR_TAG_DATE_EPOCH indicating the integer - represents a date in the form of the number of seconds since Jan 1, - 1970. - - - Last it has a string "label" like "BirthDate" indicating the - meaning of the data. - - The encoded binary looks like this: - - a1 # Map of 1 item - 69 # Indicates text string of 9 bytes - 426972746844617465 # The text "BirthDate" - c1 # Tags next integer as epoch date - 1a # Indicates a 4-byte integer - 580d4172 # unsigned integer date 1477263730 - - Implementors using this API will primarily work with - labels. Generally, tags are only needed for making up new data - types. This implementation covers most of the data types defined in - the RFC using tags. It also, allows for the use of custom tags if - necessary. - - This implementation explicitly supports labels that are text strings - and integers. Text strings translate nicely into JSON objects and are - very readable. Integer labels are much less readable but can be very - compact. If they are in the range of 0 to 23, they take up only one - byte. - - CBOR allows a label to be any type of data including an array or a - map. It is possible to use this API to construct and parse such - labels, but it is not explicitly supported. - - @anchor Encoding - - ## Encoding - - A common encoding usage mode is to invoke the encoding twice. First - with the output buffer as @ref SizeCalculateUsefulBuf to compute the - length of the needed output buffer. The correct sized output buffer - is allocated. The encoder is invoked a second time with the allocated - output buffer. - - The double invocation is not required if the maximum output buffer - size can be predicted. This is usually possible for simple CBOR - structures. - - If a buffer too small to hold the encoded output is given, the error - @ref QCBOR_ERR_BUFFER_TOO_SMALL will be returned. Data will never be - written off the end of the output buffer no matter which functions - here are called or what parameters are passed to them. - - The encoding error handling is simple. The only possible errors are - trying to encode structures that are too large or too complex. There - are no internal malloc calls so there will be no failures for out of - memory. The error state is tracked internally, so there is no need - to check for errors when encoding. Only the return code from - QCBOREncode_Finish() need be checked as once an error happens, the - encoder goes into an error state and calls to it to add more data - will do nothing. An error check is not needed after every data item - is added. - - Encoding generally proceeds by calling QCBOREncode_Init(), calling - lots of @c QCBOREncode_AddXxx() functions and calling - QCBOREncode_Finish(). There are many @c QCBOREncode_AddXxx() - functions for various data types. The input buffers need only to be - valid during the @c QCBOREncode_AddXxx() calls as the data is copied - into the output buffer. - - There are three `Add` functions for each data type. The first / main - one for the type is for adding the data item to an array. The second - one's name ends in `ToMap`, is used for adding data items to maps and - takes a string argument that is its label in the map. The third one - ends in `ToMapN`, is also used for adding data items to maps, and - takes an integer argument that is its label in the map. - - The simplest aggregate type is an array, which is a simple ordered - set of items without labels the same as JSON arrays. Call - QCBOREncode_OpenArray() to open a new array, then various @c - QCBOREncode_AddXxx() functions to put items in the array and then - QCBOREncode_CloseArray(). Nesting to the limit @ref - QCBOR_MAX_ARRAY_NESTING is allowed. All opens must be matched by - closes or an encoding error will be returned. - - The other aggregate type is a map which does use labels. The `Add` - functions that end in `ToMap` and `ToMapN` are convenient ways to add - labeled data items to a map. You can also call any type of `Add` - function once to add a label of any time and then call any type of - `Add` again to add its value. - - Note that when you nest arrays or maps in a map, the nested array or - map has a label. - - Many CBOR-based protocols start with an array or map. This makes them - self-delimiting. No external length or end marker is needed to know - the end. It is also possible not start this way, in which case this - it is usually called a CBOR sequence which is described in - [RFC 8742] (https://tools.ietf.org/html/rfc8742). This encoder supports - either just by whether the first item added is an array, map or other. - - If QCBOR is compiled with QCBOR_DISABLE_ENCODE_USAGE_GUARDS defined, - the errors QCBOR_ERR_CLOSE_MISMATCH, QCBOR_ERR_ARRAY_TOO_LONG, - QCBOR_ERR_TOO_MANY_CLOSES, QCBOR_ERR_ARRAY_OR_MAP_STILL_OPEN, and - QCBOR_ERR_ENCODE_UNSUPPORTED will never be returned. It is up to the - caller to make sure that opened maps, arrays and byte-string wrapping - is closed correctly and that QCBOREncode_AddType7() is called - correctly. With this defined, it is easier to make a mistake when - authoring the encoding of a protocol that will output not well formed - CBOR, but as long as the calling code is correct, it is safe to - disable these checks. Bounds checking that prevents security issues - in the code is still enforced. This define reduces the size of - encoding object code by about 150 bytes. - - @anchor Tags-Overview - - ## Tags Overview - - Any CBOR data item can be made into a tag to add semantics, define a - new data type or such. Some tags are fully standardized and some are - just registered. Others are not registered and used in a proprietary - way. - - Encoding and decoding of many of the registered tags is fully - implemented by QCBOR. It is also possible to encode and decode tags - that are not directly supported. For many use cases the built-in tag - support should be adequate. - - For example, the registered epoch date tag is supported in encoding - by QCBOREncode_AddDateEpoch() and in decoding by @ref - QCBOR_TYPE_DATE_EPOCH and the @c epochDate member of @ref - QCBORItem. This is typical of the built-in tag support. There is an - API to encode data for it and a @c QCBOR_TYPE_XXX when it is decoded. - - Tags are registered in the [IANA CBOR Tags Registry] - (https://www.iana.org/assignments/cbor-tags/cbor-tags.xhtml). There - are roughly three options to create a new tag. First, a public - specification can be created and the new tag registered with IANA. - This is the most formal. Second, the new tag can be registered with - IANA with just a short description rather than a full specification. - These tags must be greater than 256. Third, a tag can be used without - any IANA registration, though the registry should be checked to see - that the new value doesn't collide with one that is registered. The - value of these tags must be 256 or larger. - - See also @ref CBORTags and @ref Tag-Usage - - The encoding side of tags not built-in is handled by - QCBOREncode_AddTag() and is relatively simple. Tag decoding is more - complex and mainly handled by QCBORDecode_GetNext(). Decoding of the - structure of tagged data not built-in (if there is any) has to be - implemented by the caller. - - @anchor Floating-Point - - ## Floating-Point - - By default QCBOR fully supports IEEE 754 floating-point: - - Encode/decode of double, single and half-precision - - CBOR preferred serialization of floating-point - - Floating-point epoch dates - - For the most part, the type double is used in the interface for - floating-point values. In the default configuration, all decoded - floating-point values are returned as a double. - - With CBOR preferred serialization, the encoder outputs the smallest - representation of the double or float that preserves precision. Zero, - NaN and infinity are always output as a half-precision, each taking - just 2 bytes. This reduces the number of bytes needed to encode - double and single-precision, especially if zero, NaN and infinity are - frequently used. - - To avoid use of preferred serialization in the standard configuration - when encoding, use QCBOREncode_AddDoubleNoPreferred() or - QCBOREncode_AddFloatNoPreferred(). - - This implementation of preferred floating-point serialization and - half-precision does not depend on the CPU having floating-point HW or - the compiler bringing in a (sometimes large) library to compensate - for lack of CPU support. This implementation uses shifts and masks - rather than floating-point functions. - - To reduce overall object code by about 900 bytes, define - QCBOR_DISABLE_PREFERRED_FLOAT. This will eliminate all support for - preferred serialization and half-precision. An error will be returned - when attempting to decode half-precision. A float will always be - encoded and decoded as 32-bits and a double will always be encoded - and decoded as 64 bits. - - Note that even if QCBOR_DISABLE_PREFERRED_FLOAT is not defined all - the float-point encoding object code can be avoided by never calling - any functions that encode double or float. Just not calling - floating-point functions will reduce object code by about 500 bytes. - - On CPUs that have no floating-point hardware, - QCBOR_DISABLE_FLOAT_HW_USE should be defined in most cases. If it is - not, then the compiler will bring in possibly large software - libraries to compensate. Defining QCBOR_DISABLE_FLOAT_HW_USE reduces - object code size on CPUs with floating-point hardware by a tiny - amount and eliminates the need for - - When QCBOR_DISABLE_FLOAT_HW_USE is defined, trying to decoding - floating-point dates will give error - @ref QCBOR_ERR_FLOAT_DATE_DISABLED and decoded single-precision - numbers will be returned as @ref QCBOR_TYPE_FLOAT instead of - converting them to double as usual. - - If both QCBOR_DISABLE_FLOAT_HW_USE and QCBOR_DISABLE_PREFERRED_FLOAT - are defined, then the only thing QCBOR can do is encode/decode a C - float type as 32-bits and a C double type as 64-bits. Floating-point - epoch dates will be unsupported. - - If USEFULBUF_DISABLE_ALL_FLOATis defined, then floating point support is - completely disabled. Decoding functions return @ref QCBOR_ERR_ALL_FLOAT_DISABLED - if a floating point value is encountered during decoding. Functions that are - encoding floating point values are not available. - - ## Limitations - - Summary Limits of this implementation: - - The entire encoded CBOR must fit into contiguous memory. - - Max size of encoded / decoded CBOR data is a few bytes less than @c UINT32_MAX (4GB). - - Max array / map nesting level when encoding / decoding is - @ref QCBOR_MAX_ARRAY_NESTING (this is typically 15). - - Max items in an array or map when encoding / decoding is - @ref QCBOR_MAX_ITEMS_IN_ARRAY (typically 65,536). - - Does not directly support labels in maps other than text strings & integers. - - Does not directly support integer labels greater than @c INT64_MAX. - - Epoch dates limited to @c INT64_MAX (+/- 292 billion years). - - Exponents for bigfloats and decimal integers are limited to @c INT64_MAX. - - Tags on labels are ignored during decoding. - - The maximum tag nesting is @c QCBOR_MAX_TAGS_PER_ITEM (typically 4). - - Works only on 32- and 64-bit CPUs (modifications could make it work - on 16-bit CPUs). - - The public interface uses @c size_t for all lengths. Internally the - implementation uses 32-bit lengths by design to use less memory and - fit structures on the stack. This limits the encoded CBOR it can work - with to size @c UINT32_MAX (4GB) which should be enough. - - This implementation assumes two's compliment integer machines. @c - also requires this. It is possible to modify this - implementation for another integer representation, but all modern - machines seem to be two's compliment. + * @file qcbor_encode.h + * + * @anchor Overview + * + * # QCBOR Overview + * + * This implements CBOR -- Concise Binary Object Representation as + * defined in [RFC 8949] (https://www.rfc-editor.org/rfc/rfc8949.html). + * More information is at http://cbor.io. This is a near-complete + * implementation of the specification. [RFC 8742] + * (https://www.rfc-editor.org/rfc/rfc8742.html) CBOR Sequences is + * also supported. Limitations are listed further down. + * + * See @ref Encoding for general discussion on encoding, + * @ref BasicDecode for general discussion on the basic decode features + * and @ref SpiffyDecode for general discussion on the easier-to-use + * decoder functions. + * + * CBOR is intentionally designed to be translatable to JSON, but not + * all CBOR can convert to JSON. See RFC 8949 for more info on how to + * construct CBOR that is the most JSON friendly. + * + * The memory model for encoding and decoding is that encoded CBOR must + * be in a contiguous buffer in memory. During encoding the caller must + * supply an output buffer and if the encoding would go off the end of + * the buffer an error is returned. During decoding the caller supplies + * the encoded CBOR in a contiguous buffer and the decoder returns + * pointers and lengths into that buffer for strings. + * + * This implementation does not require malloc. All data structures + * passed in/out of the APIs can fit on the stack. + * + * Decoding of indefinite-length strings is a special case that requires + * a "string allocator" to allocate memory into which the segments of + * the string are coalesced. Without this, decoding will error out if an + * indefinite-length string is encountered (indefinite-length maps and + * arrays do not require the string allocator). A simple string + * allocator called MemPool is built-in and will work if supplied with a + * block of memory to allocate. The string allocator can optionally use + * malloc() or some other custom scheme. + * + * Here are some terms and definitions: + * + * - "Item", "Data Item": An integer or string or such. The basic "thing" that + * CBOR is about. An array is an item itself that contains some items. + * + * - "Array": An ordered sequence of items, the same as JSON. + * + * - "Map": A collection of label/value pairs. Each pair is a data + * item. A JSON "object" is the same as a CBOR "map". + * + * - "Label": The data item in a pair in a map that names or identifies + * the pair, not the value. This implementation refers to it as a + * "label". JSON refers to it as the "name". The CBOR RFC refers to it + * this as a "key". This implementation chooses label instead because + * key is too easily confused with a cryptographic key. The COSE + * standard, which uses CBOR, has also chosen to use the term "label" + * rather than "key" for this same reason. + * + * - "Key": See "Label" above. + * + * - "Tag": A data item that is an explicitly labeled new data + * type made up of the tagging integer and the tag content. + * See @ref Tags-Overview and @ref Tag-Usage. + * + * - "Initial Byte": The first byte of an encoded item. Encoding and + * decoding of this byte is taken care of by the implementation. + * + * - "Additional Info": In addition to the major type, all data items + * have some other info. This is usually the length of the data but can + * be several other things. Encoding and decoding of this is taken care + * of by the implementation. + * + * CBOR has two mechanisms for tagging and labeling the data values like + * integers and strings. For example, an integer that represents + * someone's birthday in epoch seconds since Jan 1, 1970 could be + * encoded like this: + * + * - First it is CBOR_MAJOR_TYPE_POSITIVE_INT (@ref QCBOR_TYPE_INT64), + * the primitive positive integer. + * + * - Next it has a "tag" @ref CBOR_TAG_DATE_EPOCH indicating the integer + * represents a date in the form of the number of seconds since Jan 1, + * 1970. + * + * - Last it has a string "label" like "BirthDate" indicating the + * meaning of the data. + * + * The encoded binary looks like this: + * + * a1 # Map of 1 item + * 69 # Indicates text string of 9 bytes + * 426972746844617465 # The text "BirthDate" + * c1 # Tags next integer as epoch date + * 1a # Indicates a 4-byte integer + * 580d4172 # unsigned integer date 1477263730 + * + * Implementors using this API will primarily work with + * labels. Generally, tags are only needed for making up new data + * types. This implementation covers most of the data types defined in + * the RFC using tags. It also, allows for the use of custom tags if + * necessary. + * + * This implementation explicitly supports labels that are text strings + * and integers. Text strings translate nicely into JSON objects and are + * very readable. Integer labels are much less readable but can be very + * compact. If they are in the range of 0 to 23, they take up only one + * byte. + * + * CBOR allows a label to be any type of data including an array or a + * map. It is possible to use this API to construct and parse such + * labels, but it is not explicitly supported. + * + * @anchor Encoding + * + * ## Encoding + * + * A common encoding usage mode is to invoke the encoding twice. First + * with the output buffer as @ref SizeCalculateUsefulBuf to compute the + * length of the needed output buffer. The correct sized output buffer + * is allocated. The encoder is invoked a second time with the allocated + * output buffer. + * + * The double invocation is not required if the maximum output buffer + * size can be predicted. This is usually possible for simple CBOR + * structures. + * + * If a buffer too small to hold the encoded output is given, the error + * @ref QCBOR_ERR_BUFFER_TOO_SMALL will be returned. Data will never be + * written off the end of the output buffer no matter which functions + * here are called or what parameters are passed to them. + * + * The encoding error handling is simple. The only possible errors are + * trying to encode structures that are too large or too complex. There + * are no internal malloc calls so there will be no failures for out of + * memory. The error state is tracked internally, so there is no need + * to check for errors when encoding. Only the return code from + * QCBOREncode_Finish() need be checked as once an error happens, the + * encoder goes into an error state and calls to it to add more data + * will do nothing. An error check is not needed after every data item + * is added. + * + * Encoding generally proceeds by calling QCBOREncode_Init(), calling + * lots of @c QCBOREncode_AddXxx() functions and calling + * QCBOREncode_Finish(). There are many @c QCBOREncode_AddXxx() + * functions for various data types. The input buffers need only to be + * valid during the @c QCBOREncode_AddXxx() calls as the data is copied + * into the output buffer. + * + * There are three `Add` functions for each data type. The first / main + * one for the type is for adding the data item to an array. The second + * one's name ends in `ToMap`, is used for adding data items to maps and + * takes a string argument that is its label in the map. The third one + * ends in `ToMapN`, is also used for adding data items to maps, and + * takes an integer argument that is its label in the map. + * + * The simplest aggregate type is an array, which is a simple ordered + * set of items without labels the same as JSON arrays. Call + * QCBOREncode_OpenArray() to open a new array, then various @c + * QCBOREncode_AddXxx() functions to put items in the array and then + * QCBOREncode_CloseArray(). Nesting to the limit @ref + * QCBOR_MAX_ARRAY_NESTING is allowed. All opens must be matched by + * closes or an encoding error will be returned. + * + * The other aggregate type is a map which does use labels. The `Add` + * functions that end in `ToMap` and `ToMapN` are convenient ways to add + * labeled data items to a map. You can also call any type of `Add` + * function once to add a label of any type and then call any type of + * `Add` again to add its value. + * + * Note that when you nest arrays or maps in a map, the nested array or + * map has a label. + * + * Many CBOR-based protocols start with an array or map. This makes + * them self-delimiting. No external length or end marker is needed to + * know the end. It is also possible not start this way, in which case + * this it is usually called a CBOR sequence which is described in + * [RFC 8742] (https://www.rfc-editor.org/rfc/rfc8742.html). This + * encoder supports either just by whether the first item added is an + * array, map or other. + * + * If QCBOR is compiled with QCBOR_DISABLE_ENCODE_USAGE_GUARDS defined, + * the errors QCBOR_ERR_CLOSE_MISMATCH, QCBOR_ERR_ARRAY_TOO_LONG, + * QCBOR_ERR_TOO_MANY_CLOSES, QCBOR_ERR_ARRAY_OR_MAP_STILL_OPEN, and + * QCBOR_ERR_ENCODE_UNSUPPORTED will never be returned. It is up to the + * caller to make sure that opened maps, arrays and byte-string wrapping + * is closed correctly and that QCBOREncode_AddType7() is called + * correctly. With this defined, it is easier to make a mistake when + * authoring the encoding of a protocol that will output not well formed + * CBOR, but as long as the calling code is correct, it is safe to + * disable these checks. Bounds checking that prevents security issues + * in the code is still enforced. This define reduces the size of + * encoding object code by about 150 bytes. + * + * @anchor Tags-Overview + * + * ## Tags Overview + * + * Any CBOR data item can be made into a tag to add semantics, define a + * new data type or such. Some tags are fully standardized and some are + * just registered. Others are not registered and used in a proprietary + * way. + * + * Encoding and decoding of many of the registered tags is fully + * implemented by QCBOR. It is also possible to encode and decode tags + * that are not directly supported. For many use cases the built-in tag + * support should be adequate. + * + * For example, the registered epoch date tag is supported in encoding + * by QCBOREncode_AddTDateEpoch() and in decoding by @ref + * QCBOR_TYPE_DATE_EPOCH and the @c epochDate member of @ref + * QCBORItem. This is typical of the built-in tag support. There is an + * API to encode data for it and a @c QCBOR_TYPE_XXX when it is decoded. + * + * Tags are registered in the [IANA CBOR Tags Registry] + * (https://www.iana.org/assignments/cbor-tags/cbor-tags.xhtml). There + * are roughly three options to create a new tag. First, a public + * specification can be created and the new tag registered with IANA. + * This is the most formal. Second, the new tag can be registered with + * IANA with just a short description rather than a full specification. + * These tags must be greater than 256. Third, a tag can be used without + * any IANA registration, though the registry should be checked to see + * that the new value doesn't collide with one that is registered. The + * value of these tags must be 256 or larger. + * + * See also @ref CBORTags and @ref Tag-Usage + * + * The encoding side of tags not built-in is handled by + * QCBOREncode_AddTag() and is relatively simple. Tag decoding is more + * complex and mainly handled by QCBORDecode_GetNext(). Decoding of the + * structure of tagged data not built-in (if there is any) has to be + * implemented by the caller. + * + * @anchor Floating-Point + * + * ## Floating-Point + * + * By default QCBOR fully supports IEEE 754 floating-point: + * - Encode/decode of double, single and half-precision + * - CBOR preferred serialization of floating-point + * - Floating-point epoch dates + * + * For the most part, the type double is used in the interface for + * floating-point values. In the default configuration, all decoded + * floating-point values are returned as a double. + * + * With CBOR preferred serialization, the encoder outputs the smallest + * representation of the double or float that preserves precision. Zero, + * NaN and infinity are always output as a half-precision, each taking + * just 2 bytes. This reduces the number of bytes needed to encode + * double and single-precision, especially if zero, NaN and infinity are + * frequently used. + * + * To avoid use of preferred serialization in the standard configuration + * when encoding, use QCBOREncode_AddDoubleNoPreferred() or + * QCBOREncode_AddFloatNoPreferred(). + * + * This implementation of preferred floating-point serialization and + * half-precision does not depend on the CPU having floating-point HW or + * the compiler bringing in a (sometimes large) library to compensate + * for lack of CPU support. This implementation uses shifts and masks + * rather than floating-point functions. + * + * To reduce overall object code by about 900 bytes, define + * QCBOR_DISABLE_PREFERRED_FLOAT. This will eliminate all support for + * preferred serialization and half-precision. An error will be returned + * when attempting to decode half-precision. A float will always be + * encoded and decoded as 32-bits and a double will always be encoded + * and decoded as 64 bits. + * + * Note that even if QCBOR_DISABLE_PREFERRED_FLOAT is not defined all + * the float-point encoding object code can be avoided by never calling + * any functions that encode double or float. Just not calling + * floating-point functions will reduce object code by about 500 bytes. + * + * On CPUs that have no floating-point hardware, + * QCBOR_DISABLE_FLOAT_HW_USE should be defined in most cases. If it is + * not, then the compiler will bring in possibly large software + * libraries to compensate. Defining QCBOR_DISABLE_FLOAT_HW_USE reduces + * object code size on CPUs with floating-point hardware by a tiny + * amount and eliminates the need for + * + * When QCBOR_DISABLE_FLOAT_HW_USE is defined, trying to decoding + * floating-point dates will give error + * @ref QCBOR_ERR_FLOAT_DATE_DISABLED and decoded single-precision + * numbers will be returned as @ref QCBOR_TYPE_FLOAT instead of + * converting them to double as usual. + * + * If both QCBOR_DISABLE_FLOAT_HW_USE and QCBOR_DISABLE_PREFERRED_FLOAT + * are defined, then the only thing QCBOR can do is encode/decode a C + * float type as 32-bits and a C double type as 64-bits. Floating-point + * epoch dates will be unsupported. + * + * If USEFULBUF_DISABLE_ALL_FLOAT is defined, then floating point + * support is completely disabled. Decoding functions return + * @ref QCBOR_ERR_ALL_FLOAT_DISABLED if a floating point value is + * encountered during decoding. Functions that are encoding floating + * point values are not available. + * + * ## Limitations + * + * Summary limitations: + * - The entire encoded CBOR must fit into contiguous memory. + * - Max size of encoded CBOR data is a few bytes less than + * @c UINT32_MAX (4GB). + * - Max array / map nesting level when encoding or decoding is + * @ref QCBOR_MAX_ARRAY_NESTING (this is typically 15). + * - Max items in an array or map when encoding or decoding is + * @ref QCBOR_MAX_ITEMS_IN_ARRAY (typically 65,536). + * - Does not directly support labels in maps other than text strings & integers. + * - Does not directly support integer labels beyond whats fits in @c int64_t + * or @c uint64_t. + * - Epoch dates limited to @c INT64_MAX (+/- 292 billion years). + * - Exponents for bigfloats and decimal integers are limited to whats fits in + * @c int64_t. + * - Tags on labels are ignored during decoding. + * - The maximum tag nesting is @c QCBOR_MAX_TAGS_PER_ITEM (typically 4). + * - Works only on 32- and 64-bit CPUs. + * - QCBORDecode_EnterBstrWrapped() doesn't work on indefinite-length strings. + * - Numeric reduction of big numbers to integers for preferred + * serialization is not performed. + * + * The public interface uses @c size_t for all lengths. Internally the + * implementation uses 32-bit lengths by design to use less memory and + * fit structures on the stack. This limits the encoded CBOR it can + * work with to size @c UINT32_MAX (4GB). + * + * This implementation requires two's compliment integers. While + * C doesn't require two's compliment, does. Other + * parts of this implementation may also require two's compliment. */ /** - The size of the buffer to be passed to QCBOREncode_EncodeHead(). It is one - byte larger than sizeof(uint64_t) + 1, the actual maximum size of the - head of a CBOR data item because QCBOREncode_EncodeHead() needs - one extra byte to work. + * The size of the buffer to be passed to QCBOREncode_EncodeHead(). It + * is one byte larger than sizeof(uint64_t) + 1, the actual maximum + * size of the head of a CBOR data item because + * QCBOREncode_EncodeHead() needs one extra byte to work. */ #define QCBOR_HEAD_BUFFER_SIZE (sizeof(uint64_t) + 2) /** - Output the full CBOR tag. See @ref CBORTags, @ref Tag-Usage and - @ref Tags-Overview. + * Output the full CBOR tag. See @ref CBORTags, @ref Tag-Usage and + * @ref Tags-Overview. */ #define QCBOR_ENCODE_AS_TAG 0 /** - Output only the 'borrowed' content format for the relevant tag. - See @ref CBORTags, @ref Tag-Usage and @ref Tags-Overview. + * Output only the 'borrowed' content format for the relevant tag. + * See @ref CBORTags, @ref Tag-Usage and @ref Tags-Overview. */ #define QCBOR_ENCODE_AS_BORROWED 1 /** - QCBOREncodeContext is the data type that holds context for all the - encoding functions. It is less than 200 bytes, so it can go on the - stack. The contents are opaque, and the caller should not access - internal members. A context may be re used serially as long as it is - re initialized. + * QCBOREncodeContext is the data type that holds context for all the + * encoding functions. It is less than 200 bytes, so it can go on the + * stack. The contents are opaque, and the caller should not access + * internal members. A context may be re used serially as long as it is + * re initialized. */ typedef struct _QCBOREncodeContext QCBOREncodeContext; /** - Initialize the encoder to prepare to encode some CBOR. - - @param[in,out] pCtx The encoder context to initialize. - @param[in] Storage The buffer into which the encoded result - will be written. - - Call this once at the start of an encoding of some CBOR. Then call - the many functions like QCBOREncode_AddInt64() and - QCBOREncode_AddText() to add the different data items. Finally, call - QCBOREncode_Finish() to get the pointer and length of the encoded - result. - - The primary purpose of this function is to give the pointer and - length of the output buffer into which the encoded CBOR will be - written. This is done with a @ref UsefulBuf structure, which is just - a pointer and length (it is equivalent to two parameters, one a - pointer and one a length, but a little prettier). - - The output buffer can be allocated any way (malloc, stack, - static). It is just some memory that QCBOR writes to. The length must - be the length of the allocated buffer. QCBOR will never write past - that length, but might write up to that length. If the buffer is too - small, encoding will go into an error state and not write anything - further. - - If allocating on the stack the convenience macro - UsefulBuf_MAKE_STACK_UB() can be used, but its use is not required. - - Since there is no reallocation or such, the output buffer must be - correctly sized when passed in here. It is OK, but wasteful if it is - too large. One way to pick the size is to figure out the maximum size - that will ever be needed and hard code a buffer of that size. - - Another way to do it is to have QCBOR calculate it for you. To do - this, pass @ref SizeCalculateUsefulBuf for @c Storage. - Then call all the functions to add the CBOR exactly as if - encoding for real. Finally, call QCBOREncode_FinishGetSize(). - Once the length is obtained, allocate a buffer of that - size, call QCBOREncode_Init() again with the real buffer. Call all - the add functions again and finally, QCBOREncode_Finish() to obtain - the final result. This uses twice the CPU time, but that is - usually not an issue. - - See QCBOREncode_Finish() for how the pointer and length for the - encoded CBOR is returned. - - For practical purposes QCBOR can't output encoded CBOR larger than - @c UINT32_MAX (4GB) even on 64-bit CPUs because the internal offsets - used to track the start of an array/map are 32 bits to reduce the - size of the encoding context. - - A @ref QCBOREncodeContext can be reused over and over as long as - QCBOREncode_Init() is called before each use. + * Initialize the encoder. + * + * @param[in,out] pCtx The encoder context to initialize. + * @param[in] Storage The buffer into which the encoded result + * will be written. + * + * Call this once at the start of an encoding of some CBOR. Then call + * the many functions like QCBOREncode_AddInt64() and + * QCBOREncode_AddText() to add the different data items. Finally, + * call QCBOREncode_Finish() to get the pointer and length of the + * encoded result. + * + * The primary purpose of this function is to give the pointer and + * length of the output buffer into which the encoded CBOR will be + * written. This is done with a @ref UsefulBuf structure, which is + * just a pointer and length (it is equivalent to two parameters, one + * a pointer and one a length, but a little prettier). + * + * The output buffer can be allocated any way (malloc, stack, + * static). It is just some memory that QCBOR writes to. The length + * must be the length of the allocated buffer. QCBOR will never write + * past that length, but might write up to that length. If the buffer + * is too small, encoding will go into an error state and not write + * anything further. + * + * If allocating on the stack the convenience macro + * UsefulBuf_MAKE_STACK_UB() can be used, but its use is not required. + * + * Since there is no reallocation or such, the output buffer must be + * correctly sized when passed in here. It is OK, but wasteful if it + * is too large. One way to pick the size is to figure out the maximum + * size that will ever be needed and hard code a buffer of that size. + * + * Another way to do it is to have QCBOR calculate it for you. To do + * this, pass @ref SizeCalculateUsefulBuf for @c Storage. Then call + * all the functions to add the CBOR exactly as if encoding for + * real. Finally, call QCBOREncode_FinishGetSize(). Once the length + * is obtained, allocate a buffer of that size, call + * QCBOREncode_Init() again with the real buffer. Call all the add + * functions again and finally, QCBOREncode_Finish() to obtain the + * final result. This uses twice the CPU time, but that is usually not + * an issue. + * + * See QCBOREncode_Finish() for how the pointer and length for the + * encoded CBOR is returned. + * + * For practical purposes QCBOR can't output encoded CBOR larger than + * @c UINT32_MAX (4GB) even on 64-bit CPUs because the internal + * offsets used to track the start of an array/map are 32 bits to + * reduce the size of the encoding context. + * + * A @ref QCBOREncodeContext can be reused over and over as long as + * QCBOREncode_Init() is called before each use. */ -void QCBOREncode_Init(QCBOREncodeContext *pCtx, UsefulBuf Storage); +void +QCBOREncode_Init(QCBOREncodeContext *pCtx, UsefulBuf Storage); /** - @brief Add a signed 64-bit integer to the encoded output. - - @param[in] pCtx The encoding context to add the integer to. - @param[in] nNum The integer to add. - - The integer will be encoded and added to the CBOR output. - - This function figures out the size and the sign and encodes in the - correct minimal CBOR. Specifically, it will select CBOR major type 0 - or 1 based on sign and will encode to 1, 2, 4 or 8 bytes depending on - the value of the integer. Values less than 24 effectively encode to - one byte because they are encoded in with the CBOR major type. This - is a neat and efficient characteristic of CBOR that can be taken - advantage of when designing CBOR-based protocols. If integers like - tags can be kept between -23 and 23 they will be encoded in one byte - including the major type. - - If you pass a smaller int, say an @c int16_t or a small value, say - 100, the encoding will still be CBOR's most compact that can - represent the value. For example, CBOR always encodes the value 0 as - one byte, 0x00. The representation as 0x00 includes identification of - the type as an integer too as the major type for an integer is 0. See - [RFC 8949] (https://tools.ietf.org/html/rfc8949) Appendix A for more - examples of CBOR encoding. This compact encoding is also preferred - serialization CBOR as per section 34.1 in RFC 8949. - - There are no functions to add @c int16_t or @c int32_t because they - are not necessary because this always encodes to the smallest number - of bytes based on the value (If this code is running on a 32-bit - machine having a way to add 32-bit integers would reduce code size - some). - - If the encoding context is in an error state, this will do - nothing. If an error occurs when adding this integer, the internal - error flag will be set, and the error will be returned when - QCBOREncode_Finish() is called. - - See also QCBOREncode_AddUInt64(). + * @brief Add a signed 64-bit integer to the encoded output. + * + * @param[in] pCtx The encoding context to add the integer to. + * @param[in] nNum The integer to add. + * + * The integer will be encoded and added to the CBOR output. + * + * This function figures out the size and the sign and encodes in the + * correct minimal CBOR. Specifically, it will select CBOR major type + * 0 or 1 based on sign and will encode to 1, 2, 4 or 8 bytes + * depending on the value of the integer. Values less than 24 + * effectively encode to one byte because they are encoded in with the + * CBOR major type. This is a neat and efficient characteristic of + * CBOR that can be taken advantage of when designing CBOR-based + * protocols. If integers like tags can be kept between -23 and 23 + * they will be encoded in one byte including the major type. + * + * If you pass a smaller integer, like @c int16_t or a small value, + * like 100, the encoding will still be CBOR's most compact that can + * represent the value. For example, CBOR always encodes the value 0 + * as one byte, 0x00. The representation as 0x00 includes + * identification of the type as an integer too as the major type for + * an integer is 0. See [RFC 8949 Appendix A] + * (https://www.rfc-editor.org/rfc/rfc8949.html#section-appendix.a) + * for more examples of CBOR encoding. This compact encoding is + * preferred serialization CBOR as per [RFC 8949 section 4.1] + * (https://www.rfc-editor.org/rfc/rfc8949.html#section-4.1) + * + * There are no functions to add @c int16_t or @c int32_t because they + * are not necessary because this always encodes to the smallest + * number of bytes based on the value. + * + * If the encoding context is in an error state, this will do + * nothing. If an error occurs when adding this integer, the internal + * error flag will be set, and the error will be returned when + * QCBOREncode_Finish() is called. + * + * See also QCBOREncode_AddUInt64(). */ -void QCBOREncode_AddInt64(QCBOREncodeContext *pCtx, int64_t nNum); +void +QCBOREncode_AddInt64(QCBOREncodeContext *pCtx, int64_t nNum); -static void QCBOREncode_AddInt64ToMap(QCBOREncodeContext *pCtx, const char *szLabel, int64_t uNum); +static void +QCBOREncode_AddInt64ToMapSZ(QCBOREncodeContext *pCtx, const char *szLabel, int64_t nNum); -static void QCBOREncode_AddInt64ToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, int64_t uNum); +static void +QCBOREncode_AddInt64ToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, int64_t nNum); /** - @brief Add an unsigned 64-bit integer to the encoded output. - - @param[in] pCtx The encoding context to add the integer to. - @param[in] uNum The integer to add. - - The integer will be encoded and added to the CBOR output. - - The only reason so use this function is for integers larger than @c - INT64_MAX and smaller than @c UINT64_MAX. Otherwise - QCBOREncode_AddInt64() will work fine. - - Error handling is the same as for QCBOREncode_AddInt64(). + * @brief Add an unsigned 64-bit integer to the encoded output. + * + * @param[in] pCtx The encoding context to add the integer to. + * @param[in] uNum The integer to add. + * + * The integer will be encoded and added to the CBOR output. + * + * The only reason so use this function is for integers larger than + * @c INT64_MAX and smaller than @c UINT64_MAX. Otherwise + * QCBOREncode_AddInt64() will work fine. + * + * Error handling is the same as for QCBOREncode_AddInt64(). */ -void QCBOREncode_AddUInt64(QCBOREncodeContext *pCtx, uint64_t uNum); +static void +QCBOREncode_AddUInt64(QCBOREncodeContext *pCtx, uint64_t uNum); -static void QCBOREncode_AddUInt64ToMap(QCBOREncodeContext *pCtx, const char *szLabel, uint64_t uNum); +static void +QCBOREncode_AddUInt64ToMapSZ(QCBOREncodeContext *pCtx, const char *szLabel, uint64_t uNum); -static void QCBOREncode_AddUInt64ToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, uint64_t uNum); +static void +QCBOREncode_AddUInt64ToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, uint64_t uNum); /** - @brief Add a UTF-8 text string to the encoded output. - - @param[in] pCtx The encoding context to add the text to. - @param[in] Text Pointer and length of text to add. + * @brief Add a UTF-8 text string to the encoded output. + * + * @param[in] pCtx The encoding context to add the text to. + * @param[in] Text Pointer and length of text to add. + * + * The text passed in must be unencoded UTF-8 according to + * [RFC 3629] (https://www.rfc-editor.org/rfc/rfc3629.html). There is + * no NULL termination. The text is added as CBOR major type 3. + * + * If called with @c nBytesLen equal to 0, an empty string will be + * added. When @c nBytesLen is 0, @c pBytes may be @c NULL. + * + * Note that the restriction of the buffer length to a @c uint32_t is + * entirely intentional as this encoder is not capable of encoding + * lengths greater. This limit to 4GB for a text string should not be + * a problem. + * + * Text lines in Internet protocols (on the wire) are delimited by + * either a CRLF or just an LF. Officially many protocols specify + * CRLF, but implementations often work with either. CBOR type 3 text + * can be either line ending, even a mixture of both. + * + * Operating systems usually have a line end convention. Windows uses + * CRLF. Linux and MacOS use LF. Some applications on a given OS may + * work with either and some may not. + * + * The majority of use cases and CBOR protocols using type 3 text will + * work with either line ending. However, some use cases or protocols + * may not work with either in which case translation to and/or from + * the local line end convention, typically that of the OS, is + * necessary. + * + * QCBOR does no line ending translation for type 3 text when encoding + * and decoding. + * + * Error handling is the same as QCBOREncode_AddInt64(). + */ +static void +QCBOREncode_AddText(QCBOREncodeContext *pCtx, UsefulBufC Text); - The text passed in must be unencoded UTF-8 according to [RFC 3629] - (https://tools.ietf.org/html/rfc3629). There is no NULL - termination. The text is added as CBOR major type 3. +static void +QCBOREncode_AddTextToMapSZ(QCBOREncodeContext *pCtx, const char *szLabel, UsefulBufC Text); - If called with @c nBytesLen equal to 0, an empty string will be - added. When @c nBytesLen is 0, @c pBytes may be @c NULL. +static void +QCBOREncode_AddTextToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, UsefulBufC Text); - Note that the restriction of the buffer length to a @c uint32_t is - entirely intentional as this encoder is not capable of encoding - lengths greater. This limit to 4GB for a text string should not be a - problem. - Text lines in Internet protocols (on the wire) are delimited by - either a CRLF or just an LF. Officially many protocols specify CRLF, - but implementations often work with either. CBOR type 3 text can be - either line ending, even a mixture of both. +/** + * @brief Add a UTF-8 text string to the encoded output. + * + * @param[in] pCtx The encoding context to add the text to. + * @param[in] szString Null-terminated text to add. + * + * This works the same as QCBOREncode_AddText(). + */ +static void +QCBOREncode_AddSZString(QCBOREncodeContext *pCtx, const char *szString); - Operating systems usually have a line end convention. Windows uses - CRLF. Linux and MacOS use LF. Some applications on a given OS may - work with either and some may not. +static void +QCBOREncode_AddSZStringToMapSZ(QCBOREncodeContext *pCtx, const char *szLabel, const char *szString); - The majority of use cases and CBOR protocols using type 3 text will - work with either line ending. However, some use cases or protocols - may not work with either in which case translation to and/or from the - local line end convention, typically that of the OS, is necessary. +static void +QCBOREncode_AddSZStringToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, const char *szString); - QCBOR does no line ending translation for type 3 text when encoding - and decoding. - Error handling is the same as QCBOREncode_AddInt64(). +#ifndef USEFULBUF_DISABLE_ALL_FLOAT +/** + * @brief Add a double-precision floating-point number to the encoded output. + * + * @param[in] pCtx The encoding context to add the double to. + * @param[in] dNum The double-precision number to add. + * + * This encodes and outputs a double-precision floating-point + * number. CBOR major type 7 is used. + * + * This implements preferred serialization, selectively encoding the + * double-precision floating-point number as either double-precision, + * single-precision or half-precision. Infinity, NaN and zero are + * always encoded as half-precision. If no precision will be lost in + * the conversion to half-precision, then it will be converted and + * encoded. If not and no precision will be lost in conversion to + * single-precision, then it will be converted and encoded. If not, + * then no conversion is performed, and it encoded as a + * double-precision. + * + * Half-precision floating-point numbers take up two bytes, half that + * of single-precision, one quarter of double-precision. Preferred + * serialization can therefore reduce message size down to one quarter + * of the original if most of the values are zero, infinity or NaN. + * + * When decoded, QCBOR returns these values as double-precision even + * if they were encoded as single or half-precision. + * + * It is possible to disable preferred serialization when compiling + * QCBOR. In that case, this operates the same as + * QCBOREncode_AddDoubleNoPreferred(). + * + * Error handling is the same as QCBOREncode_AddInt64(). + * + * See also QCBOREncode_AddDoubleNoPreferred(), QCBOREncode_AddFloat() + * and QCBOREncode_AddFloatNoPreferred() and @ref Floating-Point. */ -static void QCBOREncode_AddText(QCBOREncodeContext *pCtx, UsefulBufC Text); +static void +QCBOREncode_AddDouble(QCBOREncodeContext *pCtx, double dNum); -static void QCBOREncode_AddTextToMap(QCBOREncodeContext *pCtx, const char *szLabel, UsefulBufC Text); +static void +QCBOREncode_AddDoubleToMapSZ(QCBOREncodeContext *pCtx, const char *szLabel, double dNum); -static void QCBOREncode_AddTextToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, UsefulBufC Text); +static void +QCBOREncode_AddDoubleToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, double dNum); /** - @brief Add a UTF-8 text string to the encoded output. - - @param[in] pCtx The encoding context to add the text to. - @param[in] szString Null-terminated text to add. - - This works the same as QCBOREncode_AddText(). + * @brief Add a single-precision floating-point number to the encoded output. + * + * @param[in] pCtx The encoding context to add the single to. + * @param[in] fNum The single-precision number to add. + * + * This is identical to QCBOREncode_AddDouble() except the input is + * single-precision. The preferred serialization output will be either + * single-precision or half-precision. + * + * See also QCBOREncode_AddDouble(), QCBOREncode_AddDoubleNoPreferred(), + * and QCBOREncode_AddFloatNoPreferred() and @ref Floating-Point. */ -static void QCBOREncode_AddSZString(QCBOREncodeContext *pCtx, const char *szString); +static void +QCBOREncode_AddFloat(QCBOREncodeContext *pCtx, float fNum); -static void QCBOREncode_AddSZStringToMap(QCBOREncodeContext *pCtx, const char *szLabel, const char *szString); +static void +QCBOREncode_AddFloatToMapSZ(QCBOREncodeContext *pCtx, const char *szLabel, float fNum); -static void QCBOREncode_AddSZStringToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, const char *szString); +static void +QCBOREncode_AddFloatToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, float dNum); -#ifndef USEFULBUF_DISABLE_ALL_FLOAT /** - @brief Add a double-precision floating-point number to the encoded output. - - @param[in] pCtx The encoding context to add the double to. - @param[in] dNum The double-precision number to add. + * @brief Add a double-precision floating-point number without preferred encoding. + * + * @param[in] pCtx The encoding context to add the double to. + * @param[in] dNum The double-precision number to add. + * + * This always outputs the number as a 64-bit double-precision. + * Preferred serialization is not used. + * + * Error handling is the same as QCBOREncode_AddInt64(). + * + * See also QCBOREncode_AddDouble(), QCBOREncode_AddFloat(), and + * QCBOREncode_AddFloatNoPreferred() and @ref Floating-Point. + */ +static void +QCBOREncode_AddDoubleNoPreferred(QCBOREncodeContext *pCtx, double dNum); - This encodes and outputs a floating-point number. CBOR major type 7 - is used. +static void +QCBOREncode_AddDoubleNoPreferredToMapSZ(QCBOREncodeContext *pCtx, const char *szLabel, double dNum); - This implements preferred serialization, selectively encoding the - double-precision floating-point number as either double-precision, - single-precision or half-precision. Infinity, NaN and 0 are always - encoded as half-precision. If no precision will be lost in the - conversion to half-precision, then it will be converted and - encoded. If not and no precision will be lost in conversion to - single-precision, then it will be converted and encoded. If not, then - no conversion is performed, and it encoded as a double-precision. +static void +QCBOREncode_AddDoubleNoPreferredToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, double dNum); - Half-precision floating-point numbers take up 2 bytes, half that of - single-precision, one quarter of double-precision - This automatically reduces the size of encoded CBOR, maybe even by - four if most of values are 0, infinity or NaN. +/** + * @brief Add a single-precision floating-point number without preferred encoding. + * + * @param[in] pCtx The encoding context to add the double to. + * @param[in] fNum The single-precision number to add. + * + * This always outputs the number as a 32-bit single-precision. + * Preferred serialization is not used. + * + * Error handling is the same as QCBOREncode_AddInt64(). + * + * See also QCBOREncode_AddDouble(), QCBOREncode_AddFloat(), and + * QCBOREncode_AddDoubleNoPreferred() and @ref Floating-Point. + */ +static void +QCBOREncode_AddFloatNoPreferred(QCBOREncodeContext *pCtx, float fNum); - When decoded, QCBOR will usually return these values as - double-precision. +static void +QCBOREncode_AddFloatNoPreferredToMapSZ(QCBOREncodeContext *pCtx, const char *szLabel, float fNum); - It is possible to disable this preferred serialization when compiling - QCBOR. In that case, this functions the same as - QCBOREncode_AddDoubleNoPreferred(). +static void +QCBOREncode_AddFloatNoPreferredToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, float fNum); +#endif /* ! USEFULBUF_DISABLE_ALL_FLOAT */ - Error handling is the same as QCBOREncode_AddInt64(). - See also QCBOREncode_AddDoubleNoPreferred(), QCBOREncode_AddFloat() - and QCBOREncode_AddFloatNoPreferred() and @ref Floating-Point. +/** + * @brief Add a tag number. + * + * @param[in] pCtx The encoding context to add the tag to. + * @param[in] uTag The tag to add + * + * This outputs a CBOR major type 6 item that tags the next data item + * that is output usually to indicate it is some new data type. + * + * For many of the common standard tags, a function to encode data + * using it is provided and this is not needed. For example, + * QCBOREncode_AddTDateEpoch() already exists to output integers + * representing dates with the right tag. + * + * The tag is applied to the next data item added to the encoded + * output. That data item that is to be tagged can be of any major + * CBOR type. Any number of tags can be added to a data item by + * calling this multiple times before the data item is added. + * + * See @ref Tags-Overview for discussion of creating new non-standard + * tags. See QCBORDecode_GetNext() for discussion of decoding custom + * tags. */ -void QCBOREncode_AddDouble(QCBOREncodeContext *pCtx, double dNum); - -static void QCBOREncode_AddDoubleToMap(QCBOREncodeContext *pCtx, const char *szLabel, double dNum); - -static void QCBOREncode_AddDoubleToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, double dNum); +static void +QCBOREncode_AddTag(QCBOREncodeContext *pCtx, uint64_t uTag); /** - @brief Add a single-precision floating-point number to the encoded output. + * @brief Add an epoch-based date. + * + * @param[in] pCtx The encoding context to add the date to. + * @param[in] uTagRequirement Either @ref QCBOR_ENCODE_AS_TAG or + * @ref QCBOR_ENCODE_AS_BORROWED. + * @param[in] nDate Number of seconds since 1970-01-01T00:00Z + * in UTC time. + * + * As per RFC 8949 this is similar to UNIX/Linux/POSIX dates. This is + * the most compact way to specify a date and time in CBOR. Note that + * this is always UTC and does not include the time zone. Use + * QCBOREncode_AddDateString() if you want to include the time zone. + * + * The preferred integer serialization rules apply here so the date will be + * encoded in a minimal number of bytes. Until about the year 2106 + * these dates will encode in 6 bytes -- one byte for the tag, one + * byte for the type and 4 bytes for the integer. After that it will + * encode to 10 bytes. + * + * Negative values are supported for dates before 1970. + * + * If you care about leap-seconds and that level of accuracy, make sure + * the system you are running this code on does it correctly. This code + * just takes the value passed in. + * + * This implementation cannot encode fractional seconds using float or + * double even though that is allowed by CBOR, but you can encode them + * if you want to by calling QCBOREncode_AddTag() and QCBOREncode_AddDouble(). + * + * Error handling is the same as QCBOREncode_AddInt64(). + * + * See also QCBOREncode_AddTDaysEpoch(). + */ +static void +QCBOREncode_AddTDateEpoch(QCBOREncodeContext *pCtx, + uint8_t uTagRequirement, + int64_t nDate); - @param[in] pCtx The encoding context to add the double to. - @param[in] fNum The single-precision number to add. +static void +QCBOREncode_AddTDateEpochToMapSZ(QCBOREncodeContext *pCtx, + const char *szLabel, + uint8_t uTagRequirement, + int64_t nDate); - This is identical to QCBOREncode_AddDouble() except the input is - single-precision. +static void +QCBOREncode_AddTDateEpochToMapN(QCBOREncodeContext *pCtx, + int64_t nLabel, + uint8_t uTagRequirement, + int64_t nDate); - See also QCBOREncode_AddDouble(), QCBOREncode_AddDoubleNoPreferred(), - and QCBOREncode_AddFloatNoPreferred() and @ref Floating-Point. -*/ -void QCBOREncode_AddFloat(QCBOREncodeContext *pCtx, float fNum); -static void QCBOREncode_AddFloatToMap(QCBOREncodeContext *pCtx, const char *szLabel, float fNum); -static void QCBOREncode_AddFloatToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, float dNum); /** - @brief Add a double-precision floating-point number without preferred encoding. - - @param[in] pCtx The encoding context to add the double to. - @param[in] dNum The double-precision number to add. - - This always outputs the number as a 64-bit double-precision. - Preferred serialization is not used. + * @brief Add an epoch-based day-count date. + * + * @param[in] pCtx The encoding context to add the date to. + * @param[in] uTagRequirement Either @ref QCBOR_ENCODE_AS_TAG or + * @ref QCBOR_ENCODE_AS_BORROWED. + * @param[in] nDays Number of days before or after 1970-01-0. + * + * This date format is described in + * [RFC 8943] (https://www.rfc-editor.org/rfc/rfc8943.html). + * + * The preferred integer serialization rules apply here so the date + * will be encoded in a minimal number of bytes. Until about the year + * 2149 these dates will encode in 4 bytes -- one byte for the tag, + * one byte for the type and 2 bytes for the integer. + * + * See also QCBOREncode_AddTDateEpoch(). + */ +static void +QCBOREncode_AddTDaysEpoch(QCBOREncodeContext *pCtx, + uint8_t uTagRequirement, + int64_t nDays); - Error handling is the same as QCBOREncode_AddInt64(). +static void +QCBOREncode_AddTDaysEpochToMapSZ(QCBOREncodeContext *pCtx, + const char *szLabel, + uint8_t uTagRequirement, + int64_t nDays); - See also QCBOREncode_AddDouble(), QCBOREncode_AddFloat(), and - QCBOREncode_AddFloatNoPreferred() and @ref Floating-Point. -*/ -void QCBOREncode_AddDoubleNoPreferred(QCBOREncodeContext *pCtx, double dNum); +static void +QCBOREncode_AddTDaysEpochToMapN(QCBOREncodeContext *pCtx, + int64_t nLabel, + uint8_t uTagRequirement, + int64_t nDays); -static void QCBOREncode_AddDoubleNoPreferredToMap(QCBOREncodeContext *pCtx, const char *szLabel, double dNum); -static void QCBOREncode_AddDoubleNoPreferredToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, double dNum); /** - @brief Add a single-precision floating-point number without preferred encoding. - - @param[in] pCtx The encoding context to add the double to. - @param[in] fNum The single-precision number to add. - - This always outputs the number as a 32-bit single-precision. - Preferred serialization is not used. - - Error handling is the same as QCBOREncode_AddInt64(). - - See also QCBOREncode_AddDouble(), QCBOREncode_AddFloat(), and - QCBOREncode_AddDoubleNoPreferred() and @ref Floating-Point. -*/ -void QCBOREncode_AddFloatNoPreferred(QCBOREncodeContext *pCtx, float fNum); + * @brief Add a byte string to the encoded output. + * + * @param[in] pCtx The encoding context to add the bytes to. + * @param[in] Bytes Pointer and length of the input data. + * + * Simply adds the bytes to the encoded output as CBOR major type 2. + * + * If called with @c Bytes.len equal to 0, an empty string will be + * added. When @c Bytes.len is 0, @c Bytes.ptr may be @c NULL. + * + * Error handling is the same as QCBOREncode_AddInt64(). + */ +static void +QCBOREncode_AddBytes(QCBOREncodeContext *pCtx, UsefulBufC Bytes); -static void QCBOREncode_AddFloatNoPreferredToMap(QCBOREncodeContext *pCtx, const char *szLabel, float fNum); +static void +QCBOREncode_AddBytesToMapSZ(QCBOREncodeContext *pCtx, const char *szLabel, UsefulBufC Bytes); -static void QCBOREncode_AddFloatNoPreferredToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, float fNum); -#endif /* USEFULBUF_DISABLE_ALL_FLOAT */ +static void +QCBOREncode_AddBytesToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, UsefulBufC Bytes); /** - @brief Add an optional tag. - - @param[in] pCtx The encoding context to add the tag to. - @param[in] uTag The tag to add + * @brief Set up to write a byte string value directly to encoded output. + * + * @param[in] pCtx The encoding context to add the bytes to. + * @param[out] pPlace Pointer and length of place to write byte string value. + * + * QCBOREncode_AddBytes() is the normal way to encode a byte string. + * This is for special cases and by passes some of the pointer safety. + * + * The purpose of this is to output the bytes that make up a byte + * string value directly to the QCBOR output buffer so you don't need + * to have a copy of it in memory. This is particularly useful if the + * byte string is large, for example, the encrypted payload of a + * COSE_Encrypt message. The payload encryption algorithm can output + * directly to the encoded CBOR buffer, perhaps by making it the + * output buffer for some function (e.g. symmetric encryption) or by + * multiple writes. + * + * The pointer in @c pPlace is where to start writing. Writing is just + * copying bytes to the location by the pointer in @c pPlace. Writing + * past the length in @c pPlace will be writing off the end of the + * output buffer. + * + * If there is no room in the output buffer @ref NULLUsefulBuf will be + * returned and there is no need to call QCBOREncode_CloseBytes(). + * + * The byte string must be closed by calling QCBOREncode_CloseBytes(). + * + * Warning: this bypasses some of the usual checks provided by QCBOR + * against writing off the end of the encoded output buffer. + */ +void +QCBOREncode_OpenBytes(QCBOREncodeContext *pCtx, UsefulBuf *pPlace); - This outputs a CBOR major type 6 item that tags the next data item - that is output usually to indicate it is some new data type. +static void +QCBOREncode_OpenBytesInMapSZ(QCBOREncodeContext *pCtx, + const char *szLabel, + UsefulBuf *pPlace); - For many of the common standard tags, a function to encode data using - it is provided and this is not needed. For example, - QCBOREncode_AddDateEpoch() already exists to output integers - representing dates with the right tag. +static void +QCBOREncode_OpenBytesInMapN(QCBOREncodeContext *pCtx, + int64_t nLabel, + UsefulBuf *pPlace); - The tag is applied to the next data item added to the encoded - output. That data item that is to be tagged can be of any major CBOR - type. Any number of tags can be added to a data item by calling this - multiple times before the data item is added. - See @ref Tags-Overview for discussion of creating new non-standard - tags. See QCBORDecode_GetNext() for discussion of decoding custom - tags. -*/ -void QCBOREncode_AddTag(QCBOREncodeContext *pCtx, uint64_t uTag); +/** + * @brief Close out a byte string written directly to encoded output. + * + * @param[in] pCtx The encoding context to add the bytes to. + * @param[out] uAmount The number of bytes written, the length of the + * byte string. + * + * This closes out a call to QCBOREncode_OpenBytes(). This inserts a + * CBOR header at the front of the byte string value to make it a + * well-formed byte string. + * + * If there was no call to QCBOREncode_OpenBytes() then @ref + * QCBOR_ERR_TOO_MANY_CLOSES is set. + */ +void +QCBOREncode_CloseBytes(QCBOREncodeContext *pCtx, size_t uAmount); /** - @brief Add an epoch-based date. + * @brief Add a binary UUID to the encoded output. + * + * @param[in] pCtx The encoding context to add the UUID to. + * @param[in] uTagRequirement Either @ref QCBOR_ENCODE_AS_TAG or + * @ref QCBOR_ENCODE_AS_BORROWED. + * @param[in] Bytes Pointer and length of the binary UUID. + * + * A binary UUID as defined in [RFC 4122] + * (https://www.rfc-editor.org/rfc/rfc4122.html) is added to the + * output. + * + * It is output as CBOR major type 2, a binary string, with tag @ref + * CBOR_TAG_BIN_UUID indicating the binary string is a UUID. + */ +static void +QCBOREncode_AddTBinaryUUID(QCBOREncodeContext *pCtx, + uint8_t uTagRequirement, + UsefulBufC Bytes); - @param[in] pCtx The encoding context to add the date to. - @param[in] uTagRequirement Either @ref QCBOR_ENCODE_AS_TAG or @ref QCBOR_ENCODE_AS_BORROWED. - @param[in] nDate Number of seconds since 1970-01-01T00:00Z in UTC time. +static void +QCBOREncode_AddTBinaryUUIDToMapSZ(QCBOREncodeContext *pCtx, + const char *szLabel, + uint8_t uTagRequirement, + UsefulBufC Bytes); - As per RFC 8949 this is similar to UNIX/Linux/POSIX dates. This is - the most compact way to specify a date and time in CBOR. Note that - this is always UTC and does not include the time zone. Use - QCBOREncode_AddDateString() if you want to include the time zone. +static void +QCBOREncode_AddTBinaryUUIDToMapN(QCBOREncodeContext *pCtx, + int64_t nLabel, + uint8_t uTagRequirement, + UsefulBufC Bytes); - The preferred integer encoding rules apply here so the date will be encoded in - a minimal number of bytes. Until about the year 2106 these dates will - encode in 6 bytes -- one byte for the tag, one byte for the type and - 4 bytes for the integer. After that it will encode to 10 bytes. - Negative values are supported for dates before 1970. +/** + * @brief Add a positive big number to the encoded output. + * + * @param[in] pCtx The encoding context. + * @param[in] uTagRequirement Either @ref QCBOR_ENCODE_AS_TAG or + * @ref QCBOR_ENCODE_AS_BORROWED. + * @param[in] BigNumber Pointer and length of the big number. + * + * @c BigNumber makes up an aribtrary precision integer in + * network/big-endian byte order. The first byte is the most + * significant. + * + * It is encoded as CBOR major type 2, a binary string, possibly with + * tag @ref CBOR_TAG_POS_BIGNUM. See [RFC 8949 section 3.4.3] + * (https://www.rfc-editor.org/rfc/rfc8949.html#section-3.4.3). No + * processing, such as removal of leading zeros, is perfomed. + * + * RFC 8949 preferred serialization requires big numbers that + * will fit in integers be encoded as integers. That is NOT + * performed. + */ +static void +QCBOREncode_AddTPositiveBignum(QCBOREncodeContext *pCtx, + uint8_t uTagRequirement, + UsefulBufC BigNumber); - If you care about leap-seconds and that level of accuracy, make sure - the system you are running this code on does it correctly. This code - just takes the value passed in. +static void +QCBOREncode_AddTPositiveBignumToMapSZ(QCBOREncodeContext *pCtx, + const char *szLabel, + uint8_t uTagRequirement, + UsefulBufC BigNumber); - This implementation cannot encode fractional seconds using float or - double even though that is allowed by CBOR, but you can encode them - if you want to by calling QCBOREncode_AddTag() and QCBOREncode_AddDouble(). +static void +QCBOREncode_AddTPositiveBignumToMapN(QCBOREncodeContext *pCtx, + int64_t nLabel, + uint8_t uTagRequirement, + UsefulBufC BigNumber); - Error handling is the same as QCBOREncode_AddInt64(). - See also QCBOREncode_AddTDaysEpoch(). - */ -static void QCBOREncode_AddTDateEpoch(QCBOREncodeContext *pCtx, - uint8_t uTagRequirement, - int64_t nDate); - -static void QCBOREncode_AddTDateEpochToMapSZ(QCBOREncodeContext *pCtx, - const char *szLabel, - uint8_t uTagRequirement, - int64_t nDate); - -static void QCBOREncode_AddTDateEpochToMapN(QCBOREncodeContext *pCtx, - int64_t nLabel, - uint8_t uTagRequirement, - int64_t nDate); - - -static void QCBOREncode_AddDateEpoch(QCBOREncodeContext *pCtx, - int64_t nDate); - -static void QCBOREncode_AddDateEpochToMap(QCBOREncodeContext *pCtx, - const char *szLabel, - int64_t nDate); +/** + * @brief Add a negative big number to the encoded output. + * + * @param[in] pCtx The encoding context. + * @param[in] uTagRequirement Either @ref QCBOR_ENCODE_AS_TAG or + * @ref QCBOR_ENCODE_AS_BORROWED. + * @param[in] BigNumber Pointer and length of the big number. + * + * @c BigNumber makes up an aribtrary precision integer in + * network/big-endian byte order. The first byte is the most + * significant. + * + * It is encoded as CBOR major type 2, a binary string, possibly with + * tag @ref CBOR_TAG_NEG_BIGNUM. See [RFC 8949 section 3.4.3] + * (https://www.rfc-editor.org/rfc/rfc8949.html#section-3.4.3). No + * processing, such as removal of leading zeros or the required offset + * of 1 for negative values, is perfomed. + * + * RFC 8949 preferred serialization requires big numbers that + * will fit in integers be encoded as integers. That is NOT + * performed. + */ +static void +QCBOREncode_AddTNegativeBignum(QCBOREncodeContext *pCtx, + uint8_t uTagRequirement, + UsefulBufC BigNumber); -static void QCBOREncode_AddDateEpochToMapN(QCBOREncodeContext *pCtx, - int64_t nLabel, - int64_t nDate); +static void +QCBOREncode_AddTNegativeBignumToMapSZ(QCBOREncodeContext *pCtx, + const char *szLabel, + uint8_t uTagRequirement, + UsefulBufC BigNumber); +static void +QCBOREncode_AddTNegativeBignumToMapN(QCBOREncodeContext *pCtx, + int64_t nLabel, + uint8_t uTagRequirement, + UsefulBufC BigNumber); +#ifndef QCBOR_DISABLE_EXP_AND_MANTISSA /** - @brief Add an epoch-based day-count date. - - @param[in] pCtx The encoding context to add the date to. - @param[in] uTagRequirement Either @ref QCBOR_ENCODE_AS_TAG or - @ref QCBOR_ENCODE_AS_BORROWED. - @param[in] nDays Number of days before or after 1970-01-0. + * @brief Add a decimal fraction to the encoded output. + * + * @param[in] pCtx Encoding context to add the decimal fraction to. + * @param[in] uTagRequirement Either @ref QCBOR_ENCODE_AS_TAG or + * @ref QCBOR_ENCODE_AS_BORROWED. + * @param[in] nMantissa The mantissa. + * @param[in] nBase10Exponent The exponent. + * + * The value is @c nMantissa * 10 ^ @c nBase10Exponent. + * + * A decimal fraction is good for exact representation of some values + * that can't be represented exactly with standard C (IEEE 754) + * floating-point numbers. Much larger and much smaller numbers can + * also be represented than floating-point because of the larger + * number of bits in the exponent. + * + * The decimal fraction is conveyed as two integers, a mantissa and a + * base-10 scaling factor. + * + * For example, 273.15 is represented by the two integers 27315 and -2. + * + * The exponent and mantissa have the range from @c INT64_MIN to + * @c INT64_MAX for both encoding and decoding (CBOR allows + * @c -UINT64_MAX to @c UINT64_MAX, but this implementation doesn't + * support this range to reduce code size and interface complexity a + * little). + * + * Preferred serialization is used when the mantissa or exponent are + * integers, thus they will be encoded in the smallest number of bytes. + * + * See also QCBOREncode_AddTDecimalFractionBigNum() for a decimal + * fraction with arbitrarily large precision and + * QCBOREncode_AddTBigFloat(). + * + * There is no representation of positive or negative infinity or NaN + * (Not a Number). Use QCBOREncode_AddDouble() to encode them. + * + * See @ref expAndMantissa for decoded representation. + */ +static void +QCBOREncode_AddTDecimalFraction(QCBOREncodeContext *pCtx, + uint8_t uTagRequirement, + int64_t nMantissa, + int64_t nBase10Exponent); - This date format is described in - [RFC 8943] (https://tools.ietf.org/html/rfc8943). +static void +QCBOREncode_AddTDecimalFractionToMapSZ(QCBOREncodeContext *pCtx, + const char *szLabel, + uint8_t uTagRequirement, + int64_t nMantissa, + int64_t nBase10Exponent); - The integer encoding rules apply here so the date will be encoded in - a minimal number of bytes. Until about the year 2149 these dates will - encode in 4 bytes -- one byte for the tag, one byte for the type and - 2 bytes for the integer. +static void +QCBOREncode_AddTDecimalFractionToMapN(QCBOREncodeContext *pCtx, + int64_t nLabel, + uint8_t uTagRequirement, + int64_t nMantissa, + int64_t nBase10Exponent); - See also QCBOREncode_AddTDateEpoch(). -*/ -static void QCBOREncode_AddTDaysEpoch(QCBOREncodeContext *pCtx, +/** + * @brief Add a decimal fraction with a big number mantissa to the encoded output. + * + * @param[in] pCtx Encoding context to add the decimal fraction to. + * @param[in] uTagRequirement Either @ref QCBOR_ENCODE_AS_TAG or + * @ref QCBOR_ENCODE_AS_BORROWED. + * @param[in] Mantissa The mantissa. + * @param[in] bIsNegative false if mantissa is positive, true if negative. + * @param[in] nBase10Exponent The exponent. + * + * This is the same as QCBOREncode_AddTDecimalFraction() except the + * mantissa is a big number (See QCBOREncode_AddTPositiveBignum()) + * allowing for arbitrarily large precision. + * + * RFC 8949 preferred serialization requires reduction of big numbers + * that can fit into integers be encoded as integers, not big numbers. + * This implementation does NOT do that. + * + * See @ref expAndMantissa for decoded representation. + */ +static void +QCBOREncode_AddTDecimalFractionBigNum(QCBOREncodeContext *pCtx, uint8_t uTagRequirement, - int64_t nDays); + UsefulBufC Mantissa, + bool bIsNegative, + int64_t nBase10Exponent); -static void QCBOREncode_AddTDaysEpochToMapSZ(QCBOREncodeContext *pCtx, +static void +QCBOREncode_AddTDecimalFractionBigNumToMapSZ(QCBOREncodeContext *pCtx, const char *szLabel, uint8_t uTagRequirement, - int64_t nDays); + UsefulBufC Mantissa, + bool bIsNegative, + int64_t nBase10Exponent); -static void QCBOREncode_AddTDaysEpochToMapN(QCBOREncodeContext *pCtx, +static void +QCBOREncode_AddTDecimalFractionBigNumToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, uint8_t uTagRequirement, - int64_t nDays); - - - + UsefulBufC Mantissa, + bool bIsNegative, + int64_t nBase10Exponent); /** - @brief Add a byte string to the encoded output. - - @param[in] pCtx The encoding context to add the bytes to. - @param[in] Bytes Pointer and length of the input data. - - Simply adds the bytes to the encoded output as CBOR major type 2. - - If called with @c Bytes.len equal to 0, an empty string will be - added. When @c Bytes.len is 0, @c Bytes.ptr may be @c NULL. - - Error handling is the same as QCBOREncode_AddInt64(). + * @brief Add a big floating-point number to the encoded output. + * + * @param[in] pCtx The encoding context to add the bigfloat to. + * @param[in] uTagRequirement Either @ref QCBOR_ENCODE_AS_TAG or + * @ref QCBOR_ENCODE_AS_BORROWED. + * @param[in] nMantissa The mantissa. + * @param[in] nBase2Exponent The exponent. + * + * The value is @c nMantissa * 2 ^ @c nBase2Exponent. + * + * "Bigfloats", as CBOR terms them, are similar to IEEE floating-point + * numbers in having a mantissa and base-2 exponent, but they are not + * supported by hardware or encoded the same. They explicitly use two + * CBOR-encoded integers to convey the mantissa and exponent, each of + * which can be 8, 16, 32 or 64 bits. With both the mantissa and + * exponent 64 bits they can express more precision and a larger range + * than an IEEE double floating-point number. See + * QCBOREncode_AddTBigFloatBigNum() for even more precision. + * + * For example, 1.5 would be represented by a mantissa of 3 and an + * exponent of -1. + * + * The exponent and mantissa have the range from @c INT64_MIN to + * @c INT64_MAX for both encoding and decoding (CBOR allows @c + * -UINT64_MAX to @c UINT64_MAX, but this implementation doesn't + * support this range to reduce code size and interface complexity a + * little). + * + * Preferred serialization is used when the mantissa or exponent are + * integers, thus they will be encoded in the smallest number of bytes. + * + * This can also be used to represent floating-point numbers in + * environments that don't support IEEE 754. + * + * See @ref expAndMantissa for decoded representation. */ -static void QCBOREncode_AddBytes(QCBOREncodeContext *pCtx, UsefulBufC Bytes); +static void +QCBOREncode_AddTBigFloat(QCBOREncodeContext *pCtx, + uint8_t uTagRequirement, + int64_t nMantissa, + int64_t nBase2Exponent); -static void QCBOREncode_AddBytesToMap(QCBOREncodeContext *pCtx, const char *szLabel, UsefulBufC Bytes); +static void +QCBOREncode_AddTBigFloatToMapSZ(QCBOREncodeContext *pCtx, + const char *szLabel, + uint8_t uTagRequirement, + int64_t nMantissa, + int64_t nBase2Exponent); -static void QCBOREncode_AddBytesToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, UsefulBufC Bytes); +static void +QCBOREncode_AddTBigFloatToMapN(QCBOREncodeContext *pCtx, + int64_t nLabel, + uint8_t uTagRequirement, + int64_t nMantissa, + int64_t nBase2Exponent); /** - @brief Set up to write a byte string value directly to encoded output. - - @param[in] pCtx The encoding context to add the bytes to. - @param[out] pPlace Pointer and length of place to write byte string value. - - QCBOREncode_AddBytes() is the normal way to encode a byte string. - This is for special cases and by passes some of the pointer safety. + * @brief Add a big floating-point number with a big number mantissa to + * the encoded output. + * + * @param[in] pCtx The encoding context to add the bigfloat to. + * @param[in] uTagRequirement Either @ref QCBOR_ENCODE_AS_TAG or + * @ref QCBOR_ENCODE_AS_BORROWED. + * @param[in] Mantissa The mantissa. + * @param[in] bIsNegative false if mantissa is positive, true if negative. + * @param[in] nBase2Exponent The exponent. + * + * This is the same as QCBOREncode_AddTBigFloat() except the mantissa + * is a big number (See QCBOREncode_AddTPositiveBignum()) allowing for + * arbitrary precision. + * + * RFC 8949 preferred serialization requires reduction of big numbers + * that can fit into integers be encoded as integers, not big numbers. + * This implementation does NOT do that. + * + * See @ref expAndMantissa for decoded representation. + */ +static void +QCBOREncode_AddTBigFloatBigNum(QCBOREncodeContext *pCtx, + uint8_t uTagRequirement, + UsefulBufC Mantissa, + bool bIsNegative, + int64_t nBase2Exponent); - The purpose of this is to output the bytes that make up a byte string - value directly to the QCBOR output buffer so you don't need to have a - copy of it in memory. This is particularly useful if the byte string - is large, for example, the encrypted payload of a COSE_Encrypt - message. The payload encryption algorithm can output directly to the - encoded CBOR buffer, perhaps by making it the output buffer - for some function (e.g. symmetric encryption) or by multiple writes. +static void +QCBOREncode_AddTBigFloatBigNumToMapSZ(QCBOREncodeContext *pCtx, + const char *szLabel, + uint8_t uTagRequirement, + UsefulBufC Mantissa, + bool bIsNegative, + int64_t nBase2Exponent); - The pointer in \c pPlace is where to start writing. Writing is just - copying bytes to the location by the pointer in \c pPlace. Writing - past the length in \c pPlace will be writing off the end of the - output buffer. +static void +QCBOREncode_AddTBigFloatBigNumToMapN(QCBOREncodeContext *pCtx, + int64_t nLabel, + uint8_t uTagRequirement, + UsefulBufC Mantissa, + bool bIsNegative, + int64_t nBase2Exponent); - If there is no room in the output buffer @ref NULLUsefulBuf will be - returned and there is no need to call QCBOREncode_CloseBytes(). +#endif /* ! QCBOR_DISABLE_EXP_AND_MANTISSA */ - The byte string must be closed by calling QCBOREncode_CloseBytes(). - Warning: this bypasses some of the usual checks provided by QCBOR - against writing off the end of the encoded output buffer. +/** + * @brief Add a text URI to the encoded output. + * + * @param[in] pCtx The encoding context to add the URI to. + * @param[in] uTagRequirement Either @ref QCBOR_ENCODE_AS_TAG or + * @ref QCBOR_ENCODE_AS_BORROWED. + * @param[in] URI Pointer and length of the URI. + * + * The format of URI must be per [RFC 3986] + * (https://www.rfc-editor.org/rfc/rfc3986.html). + * + * It is output as CBOR major type 3, a text string, with tag @ref + * CBOR_TAG_URI indicating the text string is a URI. + * + * A URI in a NULL-terminated string, @c szURI, can be easily added with + * this code: + * + * QCBOREncode_AddTURI(pCtx, QCBOR_ENCODE_AS_TAG, UsefulBuf_FromSZ(szURI)); */ -void -QCBOREncode_OpenBytes(QCBOREncodeContext *pCtx, UsefulBuf *pPlace); +static void +QCBOREncode_AddTURI(QCBOREncodeContext *pCtx, + uint8_t uTagRequirement, + UsefulBufC URI); static void -QCBOREncode_OpenBytesInMapSZ(QCBOREncodeContext *pCtx, const char *szLabel, UsefulBuf *pPlace); +QCBOREncode_AddTURIToMapSZ(QCBOREncodeContext *pCtx, + const char *szLabel, + uint8_t uTagRequirement, + UsefulBufC URI); static void -QCBOREncode_OpenBytesInMapN(QCBOREncodeContext *pCtx, int64_t nLabel, UsefulBuf *pPlace); +QCBOREncode_AddTURIToMapN(QCBOREncodeContext *pCtx, + int64_t nLabel, + uint8_t uTagRequirement, + UsefulBufC URI); /** - @brief Close out a byte string written directly to encoded output. - - @param[in] pCtx The encoding context to add the bytes to. - @param[out] uAmount The number of bytes written, the length of the byte string. - - This closes out a call to QCBOREncode_OpenBytes(). This inserts a - CBOR header at the front of the byte string value to make it a - well-formed byte string. - - If there was no call to QCBOREncode_OpenBytes() then - @ref QCBOR_ERR_TOO_MANY_CLOSES is set. + * @brief Add Base64-encoded text to encoded output. + * + * @param[in] pCtx The encoding context to add the base-64 text to. + * @param[in] uTagRequirement Either @ref QCBOR_ENCODE_AS_TAG or + * @ref QCBOR_ENCODE_AS_BORROWED. + * @param[in] B64Text Pointer and length of the base-64 encoded text. + * + * The text content is Base64 encoded data per [RFC 4648] + * (https://www.rfc-editor.org/rfc/rfc4648.html). + * + * It is output as CBOR major type 3, a text string, with tag @ref + * CBOR_TAG_B64 indicating the text string is Base64 encoded. */ -void QCBOREncode_CloseBytes(QCBOREncodeContext *pCtx, size_t uAmount); - +static void +QCBOREncode_AddTB64Text(QCBOREncodeContext *pCtx, + uint8_t uTagRequirement, + UsefulBufC B64Text); -/** - @brief Add a binary UUID to the encoded output. +static void +QCBOREncode_AddTB64TextToMapSZ(QCBOREncodeContext *pCtx, + const char *szLabel, + uint8_t uTagRequirement, + UsefulBufC B64Text); - @param[in] pCtx The encoding context to add the UUID to. - @param[in] uTagRequirement Either @ref QCBOR_ENCODE_AS_TAG or @ref QCBOR_ENCODE_AS_BORROWED. - @param[in] Bytes Pointer and length of the binary UUID. +static void +QCBOREncode_AddTB64TextToMapN(QCBOREncodeContext *pCtx, + int64_t nLabel, + uint8_t uTagRequirement, + UsefulBufC B64Text); - A binary UUID as defined in [RFC 4122] - (https://tools.ietf.org/html/rfc4122) is added to the output. - It is output as CBOR major type 2, a binary string, with tag @ref - CBOR_TAG_BIN_UUID indicating the binary string is a UUID. +/** + * @brief Add base64url encoded data to encoded output. + * + * @param[in] pCtx The encoding context to add the base64url to. + * @param[in] uTagRequirement Either @ref QCBOR_ENCODE_AS_TAG or + * @ref QCBOR_ENCODE_AS_BORROWED. + * @param[in] B64Text Pointer and length of the base64url encoded text. + * + * The text content is base64URL encoded text as per + * [RFC 4648] (https://www.rfc-editor.org/rfc/rfc4648.html). + * + * It is output as CBOR major type 3, a text string, with tag + * @ref CBOR_TAG_B64URL indicating the text string is a Base64url + * encoded. */ -static void QCBOREncode_AddTBinaryUUID(QCBOREncodeContext *pCtx, - uint8_t uTagRequirement, - UsefulBufC Bytes); - -static void QCBOREncode_AddTBinaryUUIDToMapSZ(QCBOREncodeContext *pCtx, - const char *szLabel, - uint8_t uTagRequirement, - UsefulBufC Bytes); - -static void QCBOREncode_AddTBinaryUUIDToMapN(QCBOREncodeContext *pCtx, - int64_t nLabel, - uint8_t uTagRequirement, - UsefulBufC Bytes); - - -static void QCBOREncode_AddBinaryUUID(QCBOREncodeContext *pCtx, UsefulBufC Bytes); +static void +QCBOREncode_AddTB64URLText(QCBOREncodeContext *pCtx, + uint8_t uTagRequirement, + UsefulBufC B64Text); -static void QCBOREncode_AddBinaryUUIDToMap(QCBOREncodeContext *pCtx, const char *szLabel, UsefulBufC Bytes); +static void +QCBOREncode_AddTB64URLTextToMapSZ(QCBOREncodeContext *pCtx, + const char *szLabel, + uint8_t uTagRequirement, + UsefulBufC B64Text); -static void QCBOREncode_AddBinaryUUIDToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, UsefulBufC Bytes); +static void +QCBOREncode_AddTB64URLTextToMapN(QCBOREncodeContext *pCtx, + int64_t nLabel, + uint8_t uTagRequirement, + UsefulBufC B64Text); /** - @brief Add a positive big number to the encoded output. - - @param[in] pCtx The encoding context to add the big number to. - @param[in] uTagRequirement Either @ref QCBOR_ENCODE_AS_TAG or @ref QCBOR_ENCODE_AS_BORROWED. - @param[in] Bytes Pointer and length of the big number. - - Big numbers are integers larger than 64-bits. Their format is - described in [RFC 8949] (https://tools.ietf.org/html/rfc8949). - - It is output as CBOR major type 2, a binary string, with tag @ref - CBOR_TAG_POS_BIGNUM indicating the binary string is a positive big - number. - - Often big numbers are used to represent cryptographic keys, however, - COSE which defines representations for keys chose not to use this - particular type. + * @brief Add Perl Compatible Regular Expression. + * + * @param[in] pCtx Encoding context to add the regular expression to. + * @param[in] uTagRequirement Either @ref QCBOR_ENCODE_AS_TAG or + * @ref QCBOR_ENCODE_AS_BORROWED. + * @param[in] Regex Pointer and length of the regular expression. + * + * The text content is Perl Compatible Regular + * Expressions (PCRE) / JavaScript syntax [ECMA262]. + * + * It is output as CBOR major type 3, a text string, with tag @ref + * CBOR_TAG_REGEX indicating the text string is a regular expression. */ -static void QCBOREncode_AddTPositiveBignum(QCBOREncodeContext *pCtx, - uint8_t uTagRequirement, - UsefulBufC Bytes); - -static void QCBOREncode_AddTPositiveBignumToMapSZ(QCBOREncodeContext *pCtx, - const char *szLabel, - uint8_t uTagRequirement, - UsefulBufC Bytes); - -static void QCBOREncode_AddTPositiveBignumToMapN(QCBOREncodeContext *pCtx, - int64_t nLabel, - uint8_t uTagRequirement, - UsefulBufC Bytes); - - -static void QCBOREncode_AddPositiveBignum(QCBOREncodeContext *pCtx, - UsefulBufC Bytes); +static void +QCBOREncode_AddTRegex(QCBOREncodeContext *pCtx, + uint8_t uTagRequirement, + UsefulBufC Regex); -static void QCBOREncode_AddPositiveBignumToMap(QCBOREncodeContext *pCtx, - const char *szLabel, - UsefulBufC Bytes); +static void +QCBOREncode_AddTRegexToMapSZ(QCBOREncodeContext *pCtx, + const char *szLabel, + uint8_t uTagRequirement, + UsefulBufC Regex); -static void QCBOREncode_AddPositiveBignumToMapN(QCBOREncodeContext *pCtx, - int64_t nLabel, - UsefulBufC Bytes); +static void +QCBOREncode_AddTRegexToMapN(QCBOREncodeContext *pCtx, + int64_t nLabel, + uint8_t uTagRequirement, + UsefulBufC Regex); /** - @brief Add a negative big number to the encoded output. - - @param[in] pCtx The encoding context to add the big number to. - @param[in] uTagRequirement Either @ref QCBOR_ENCODE_AS_TAG or @ref QCBOR_ENCODE_AS_BORROWED. - @param[in] Bytes Pointer and length of the big number. - - Big numbers are integers larger than 64-bits. Their format is - described in [RFC 8949] (https://tools.ietf.org/html/rfc8949). - - It is output as CBOR major type 2, a binary string, with tag @ref - CBOR_TAG_NEG_BIGNUM indicating the binary string is a negative big - number. - - Often big numbers are used to represent cryptographic keys, however, - COSE which defines representations for keys chose not to use this - particular type. + * @brief MIME encoded data to the encoded output. + * + * @param[in] pCtx The encoding context to add the MIME data to. + * @param[in] uTagRequirement Either @ref QCBOR_ENCODE_AS_TAG or + * @ref QCBOR_ENCODE_AS_BORROWED. + * @param[in] MIMEData Pointer and length of the MIME data. + * + * The text content is in MIME format per [RFC 2045] + * (https://www.rfc-editor.org/rfc/rfc2045.html) including the headers. + * + * It is output as CBOR major type 2, a binary string, with tag + * @ref CBOR_TAG_BINARY_MIME indicating the string is MIME data. This + * outputs tag 257, not tag 36, as it can carry any type of MIME + * binary, 7-bit, 8-bit, quoted-printable and base64 where tag 36 + * cannot. + * + * Previous versions of QCBOR, those before spiffy decode, output tag + * 36. Decoding supports both tag 36 and 257. (if the old behavior + * with tag 36 is needed, copy the inline functions below and change + * the tag number). + * + * See also QCBORDecode_GetMIMEMessage() and + * @ref QCBOR_TYPE_BINARY_MIME. + * + * This does no translation of line endings. See QCBOREncode_AddText() + * for a discussion of line endings in CBOR. */ -static void QCBOREncode_AddTNegativeBignum(QCBOREncodeContext *pCtx, - uint8_t uTagRequirement, - UsefulBufC Bytes); - -static void QCBOREncode_AddTNegativeBignumToMapSZ(QCBOREncodeContext *pCtx, - const char *szLabel, - uint8_t uTagRequirement, - UsefulBufC Bytes); - -static void QCBOREncode_AddTNegativeBignumToMapN(QCBOREncodeContext *pCtx, - int64_t nLabel, - uint8_t uTagRequirement, - UsefulBufC Bytes); - - -static void QCBOREncode_AddNegativeBignum(QCBOREncodeContext *pCtx, - UsefulBufC Bytes); +static void +QCBOREncode_AddTMIMEData(QCBOREncodeContext *pCtx, + uint8_t uTagRequirement, + UsefulBufC MIMEData); -static void QCBOREncode_AddNegativeBignumToMap(QCBOREncodeContext *pCtx, - const char *szLabel, - UsefulBufC Bytes); +static void +QCBOREncode_AddTMIMEDataToMapSZ(QCBOREncodeContext *pCtx, + const char *szLabel, + uint8_t uTagRequirement, + UsefulBufC MIMEData); -static void QCBOREncode_AddNegativeBignumToMapN(QCBOREncodeContext *pCtx, - int64_t nLabel, - UsefulBufC Bytes); +static void +QCBOREncode_AddTMIMEDataToMapN(QCBOREncodeContext *pCtx, + int64_t nLabel, + uint8_t uTagRequirement, + UsefulBufC MIMEData); -#ifndef QCBOR_DISABLE_EXP_AND_MANTISSA /** - @brief Add a decimal fraction to the encoded output. - - @param[in] pCtx The encoding context to add the decimal fraction to. - @param[in] uTagRequirement Either @ref QCBOR_ENCODE_AS_TAG or @ref QCBOR_ENCODE_AS_BORROWED. - @param[in] nMantissa The mantissa. - @param[in] nBase10Exponent The exponent. - - The value is nMantissa * 10 ^ nBase10Exponent. - - A decimal fraction is good for exact representation of some values - that can't be represented exactly with standard C (IEEE 754) - floating-point numbers. Much larger and much smaller numbers can - also be represented than floating-point because of the larger number - of bits in the exponent. - - The decimal fraction is conveyed as two integers, a mantissa and a - base-10 scaling factor. - - For example, 273.15 is represented by the two integers 27315 and -2. - - The exponent and mantissa have the range from @c INT64_MIN to - @c INT64_MAX for both encoding and decoding (CBOR allows @c -UINT64_MAX - to @c UINT64_MAX, but this implementation doesn't support this range to - reduce code size and interface complexity a little). - - CBOR Preferred encoding of the integers is used, thus they will be encoded - in the smallest number of bytes possible. - - See also QCBOREncode_AddDecimalFractionBigNum() for a decimal - fraction with arbitrarily large precision and QCBOREncode_AddBigFloat(). - - There is no representation of positive or negative infinity or NaN - (Not a Number). Use QCBOREncode_AddDouble() to encode them. - - See @ref expAndMantissa for decoded representation. + * @brief Add an RFC 3339 date string + * + * @param[in] pCtx The encoding context to add the date to. + * @param[in] uTagRequirement Either @ref QCBOR_ENCODE_AS_TAG or + * @ref QCBOR_ENCODE_AS_BORROWED. + * @param[in] szDate Null-terminated string with date to add. + * + * The string szDate should be in the form of + * [RFC 3339] (https://www.rfc-editor.org/rfc/rfc3339.html) as defined + * by section 3.3 in [RFC 4287] (https://www.rfc-editor.org/rfc/rfc4287.html). + * This is as described in section 3.4.1 in [RFC 8949] + * (https://www.rfc-editor.org/rfc/rfc8949.html#section3.1.4). + * + * Note that this function doesn't validate the format of the date + * string at all. If you add an incorrect format date string, the + * generated CBOR will be incorrect and the receiver may not be able + * to handle it. + * + * Error handling is the same as QCBOREncode_AddInt64(). + * + * See also QCBOREncode_AddTDayString(). */ -static void QCBOREncode_AddTDecimalFraction(QCBOREncodeContext *pCtx, - uint8_t uTagRequirement, - int64_t nMantissa, - int64_t nBase10Exponent); - -static void QCBOREncode_AddTDecimalFractionToMapSZ(QCBOREncodeContext *pCtx, - const char *szLabel, - uint8_t uTagRequirement, - int64_t nMantissa, - int64_t nBase10Exponent); - -static void QCBOREncode_AddTDecimalFractionToMapN(QCBOREncodeContext *pCtx, - int64_t nLabel, - uint8_t uTagRequirement, - int64_t nMantissa, - int64_t nBase10Exponent); +static void +QCBOREncode_AddTDateString(QCBOREncodeContext *pCtx, + uint8_t uTagRequirement, + const char *szDate); +static void +QCBOREncode_AddTDateStringToMapSZ(QCBOREncodeContext *pCtx, + const char *szLabel, + uint8_t uTagRequirement, + const char *szDate); -static void QCBOREncode_AddDecimalFraction(QCBOREncodeContext *pCtx, - int64_t nMantissa, - int64_t nBase10Exponent); +static void +QCBOREncode_AddTDateStringToMapN(QCBOREncodeContext *pCtx, + int64_t nLabel, + uint8_t uTagRequirement, + const char *szDate); -static void QCBOREncode_AddDecimalFractionToMap(QCBOREncodeContext *pCtx, - const char *szLabel, - int64_t nMantissa, - int64_t nBase10Exponent); -static void QCBOREncode_AddDecimalFractionToMapN(QCBOREncodeContext *pCtx, - int64_t nLabel, - int64_t nMantissa, - int64_t nBase10Exponent); /** - @brief Add a decimal fraction with a big number mantissa to the encoded output. - - @param[in] pCtx The encoding context to add the decimal fraction to. - @param[in] uTagRequirement Either @ref QCBOR_ENCODE_AS_TAG or @ref QCBOR_ENCODE_AS_BORROWED. - @param[in] Mantissa The mantissa. - @param[in] bIsNegative false if mantissa is positive, true if negative. - @param[in] nBase10Exponent The exponent. - - This is the same as QCBOREncode_AddDecimalFraction() except the - mantissa is a big number (See QCBOREncode_AddPositiveBignum()) - allowing for arbitrarily large precision. - - See @ref expAndMantissa for decoded representation. + * @brief Add a date-only string. + * + * @param[in] pCtx The encoding context to add the date to. + * @param[in] uTagRequirement Either @ref QCBOR_ENCODE_AS_TAG or + * @ref QCBOR_ENCODE_AS_BORROWED. + * @param[in] szDate Null-terminated string with date to add. + * + * This date format is described in + * [RFC 8943] (https://www.rfc-editor.org/rfc/rfc8943.html), but that mainly + * references RFC 3339. The string szDate must be in the forrm + * specified the ABNF for a full-date in + * [RFC 3339] (https://www.rfc-editor.org/rfc/rfc3339.html). Examples of this + * are "1985-04-12" and "1937-01-01". The time and the time zone are + * never included. + * + * Note that this function doesn't validate the format of the date + * string at all. If you add an incorrect format date string, the + * generated CBOR will be incorrect and the receiver may not be able + * to handle it. + * + * Error handling is the same as QCBOREncode_AddInt64(). + * + * See also QCBOREncode_AddTDateString(). */ -static void QCBOREncode_AddTDecimalFractionBigNum(QCBOREncodeContext *pCtx, - uint8_t uTagRequirement, - UsefulBufC Mantissa, - bool bIsNegative, - int64_t nBase10Exponent); - -static void QCBOREncode_AddTDecimalFractionBigNumToMapSZ(QCBOREncodeContext *pCtx, - const char *szLabel, - uint8_t uTagRequirement, - UsefulBufC Mantissa, - bool bIsNegative, - int64_t nBase10Exponent); - -static void QCBOREncode_AddTDecimalFractionBigNumToMapN(QCBOREncodeContext *pCtx, - int64_t nLabel, - uint8_t uTagRequirement, - UsefulBufC Mantissa, - bool bIsNegative, - int64_t nBase10Exponent); - - -static void QCBOREncode_AddDecimalFractionBigNum(QCBOREncodeContext *pCtx, - UsefulBufC Mantissa, - bool bIsNegative, - int64_t nBase10Exponent); - -static void QCBOREncode_AddDecimalFractionBigNumToMapSZ(QCBOREncodeContext *pCtx, - const char *szLabel, - UsefulBufC Mantissa, - bool bIsNegative, - int64_t nBase10Exponent); - -static void QCBOREncode_AddDecimalFractionBigNumToMapN(QCBOREncodeContext *pCtx, - int64_t nLabel, - UsefulBufC Mantissa, - bool bIsNegative, - int64_t nBase10Exponent); - -/** - @brief Add a big floating-point number to the encoded output. - - @param[in] pCtx The encoding context to add the bigfloat to. - @param[in] uTagRequirement Either @ref QCBOR_ENCODE_AS_TAG or @ref QCBOR_ENCODE_AS_BORROWED. - @param[in] nMantissa The mantissa. - @param[in] nBase2Exponent The exponent. - - The value is nMantissa * 2 ^ nBase2Exponent. - - "Bigfloats", as CBOR terms them, are similar to IEEE floating-point - numbers in having a mantissa and base-2 exponent, but they are not - supported by hardware or encoded the same. They explicitly use two - CBOR-encoded integers to convey the mantissa and exponent, each of which - can be 8, 16, 32 or 64 bits. With both the mantissa and exponent - 64 bits they can express more precision and a larger range than an - IEEE double floating-point number. See - QCBOREncode_AddBigFloatBigNum() for even more precision. - - For example, 1.5 would be represented by a mantissa of 3 and an - exponent of -1. +static void +QCBOREncode_AddTDaysString(QCBOREncodeContext *pCtx, + uint8_t uTagRequirement, + const char *szDate); - The exponent and mantissa have the range from @c INT64_MIN to - @c INT64_MAX for both encoding and decoding (CBOR allows @c -UINT64_MAX - to @c UINT64_MAX, but this implementation doesn't support this range to - reduce code size and interface complexity a little). +static void +QCBOREncode_AddTDaysStringToMapSZ(QCBOREncodeContext *pCtx, + const char *szLabel, + uint8_t uTagRequirement, + const char *szDate); - CBOR Preferred encoding of the integers is used, thus they will be encoded - in the smallest number of bytes possible. +static void +QCBOREncode_AddTDaysStringToMapN(QCBOREncodeContext *pCtx, + int64_t nLabel, + uint8_t uTagRequirement, + const char *szDate); - This can also be used to represent floating-point numbers in - environments that don't support IEEE 754. - See @ref expAndMantissa for decoded representation. +/** + * @brief Add a standard Boolean. + * + * @param[in] pCtx The encoding context to add the Boolean to. + * @param[in] b true or false from @c . + * + * Adds a Boolean value as CBOR major type 7. + * + * Error handling is the same as QCBOREncode_AddInt64(). */ -static void QCBOREncode_AddTBigFloat(QCBOREncodeContext *pCtx, - uint8_t uTagRequirement, - int64_t nMantissa, - int64_t nBase2Exponent); - -static void QCBOREncode_AddTBigFloatToMapSZ(QCBOREncodeContext *pCtx, - const char *szLabel, - uint8_t uTagRequirement, - int64_t nMantissa, - int64_t nBase2Exponent); - -static void QCBOREncode_AddTBigFloatToMapN(QCBOREncodeContext *pCtx, - int64_t nLabel, - uint8_t uTagRequirement, - int64_t nMantissa, - int64_t nBase2Exponent); - +static void +QCBOREncode_AddBool(QCBOREncodeContext *pCtx, bool b); -static void QCBOREncode_AddBigFloat(QCBOREncodeContext *pCtx, - int64_t nMantissa, - int64_t nBase2Exponent); +static void +QCBOREncode_AddBoolToMapSZ(QCBOREncodeContext *pCtx, const char *szLabel, bool b); -static void QCBOREncode_AddBigFloatToMap(QCBOREncodeContext *pCtx, - const char *szLabel, - int64_t nMantissa, - int64_t nBase2Exponent); +static void +QCBOREncode_AddBoolToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, bool b); -static void QCBOREncode_AddBigFloatToMapN(QCBOREncodeContext *pCtx, - int64_t nLabel, - int64_t nMantissa, - int64_t nBase2Exponent); /** - @brief Add a big floating-point number with a big number mantissa to - the encoded output. - - @param[in] pCtx The encoding context to add the bigfloat to. - @param[in] uTagRequirement Either @ref QCBOR_ENCODE_AS_TAG or @ref QCBOR_ENCODE_AS_BORROWED. - @param[in] Mantissa The mantissa. - @param[in] bIsNegative false if mantissa is positive, true if negative. - @param[in] nBase2Exponent The exponent. - - This is the same as QCBOREncode_AddBigFloat() except the mantissa is - a big number (See QCBOREncode_AddPositiveBignum()) allowing for - arbitrary precision. - - See @ref expAndMantissa for decoded representation. + * @brief Add a NULL to the encoded output. + * + * @param[in] pCtx The encoding context to add the NULL to. + * + * Adds the NULL value as CBOR major type 7. + * + * This NULL doesn't have any special meaning in CBOR such as a + * terminating value for a string or an empty value. + * + * Error handling is the same as QCBOREncode_AddInt64(). */ -static void QCBOREncode_AddTBigFloatBigNum(QCBOREncodeContext *pCtx, - uint8_t uTagRequirement, - UsefulBufC Mantissa, - bool bIsNegative, - int64_t nBase2Exponent); - -static void QCBOREncode_AddTBigFloatBigNumToMapSZ(QCBOREncodeContext *pCtx, - const char *szLabel, - uint8_t uTagRequirement, - UsefulBufC Mantissa, - bool bIsNegative, - int64_t nBase2Exponent); - -static void QCBOREncode_AddTBigFloatBigNumToMapN(QCBOREncodeContext *pCtx, - int64_t nLabel, - uint8_t uTagRequirement, - UsefulBufC Mantissa, - bool bIsNegative, - int64_t nBase2Exponent); - - -static void QCBOREncode_AddBigFloatBigNum(QCBOREncodeContext *pCtx, - UsefulBufC Mantissa, - bool bIsNegative, - int64_t nBase2Exponent); - -static void QCBOREncode_AddBigFloatBigNumToMap(QCBOREncodeContext *pCtx, - const char *szLabel, - UsefulBufC Mantissa, - bool bIsNegative, - int64_t nBase2Exponent); - -static void QCBOREncode_AddBigFloatBigNumToMapN(QCBOREncodeContext *pCtx, - int64_t nLabel, - UsefulBufC Mantissa, - bool bIsNegative, - int64_t nBase2Exponent); -#endif /* QCBOR_DISABLE_EXP_AND_MANTISSA */ - - -/** - @brief Add a text URI to the encoded output. - - @param[in] pCtx The encoding context to add the URI to. - @param[in] uTagRequirement Either @ref QCBOR_ENCODE_AS_TAG or @ref QCBOR_ENCODE_AS_BORROWED. - @param[in] URI Pointer and length of the URI. +static void +QCBOREncode_AddNULL(QCBOREncodeContext *pCtx); - The format of URI must be per [RFC 3986] - (https://tools.ietf.org/html/rfc3986). +static void +QCBOREncode_AddNULLToMapSZ(QCBOREncodeContext *pCtx, const char *szLabel); - It is output as CBOR major type 3, a text string, with tag @ref - CBOR_TAG_URI indicating the text string is a URI. +static void +QCBOREncode_AddNULLToMapN(QCBOREncodeContext *pCtx, int64_t nLabel); - A URI in a NULL-terminated string, @c szURI, can be easily added with - this code: - QCBOREncode_AddURI(pCtx, UsefulBuf_FromSZ(szURI)); +/** + * @brief Add an "undef" to the encoded output. + * + * @param[in] pCtx The encoding context to add the "undef" to. + * + * Adds the undef value as CBOR major type 7. + * + * Note that this value will not translate to JSON. + * + * "undef" doesn't have any special meaning in CBOR such as a + * terminating value for a string or an empty value. + * + * Error handling is the same as QCBOREncode_AddInt64(). */ -static void QCBOREncode_AddTURI(QCBOREncodeContext *pCtx, - uint8_t uTagRequirement, - UsefulBufC URI); - -static void QCBOREncode_AddTURIToMapSZ(QCBOREncodeContext *pCtx, - const char *szLabel, - uint8_t uTagRequirement, - UsefulBufC URI); - -static void QCBOREncode_AddTURIToMapN(QCBOREncodeContext *pCtx, - int64_t nLabel, - uint8_t uTagRequirement, - UsefulBufC URI); - - -static void QCBOREncode_AddURI(QCBOREncodeContext *pCtx, - UsefulBufC URI); +static void +QCBOREncode_AddUndef(QCBOREncodeContext *pCtx); -static void QCBOREncode_AddURIToMap(QCBOREncodeContext *pCtx, - const char *szLabel, - UsefulBufC URI); +static void +QCBOREncode_AddUndefToMapSZ(QCBOREncodeContext *pCtx, const char *szLabel); -static void QCBOREncode_AddURIToMapN(QCBOREncodeContext *pCtx, - int64_t nLabel, - UsefulBufC URI); +static void +QCBOREncode_AddUndefToMapN(QCBOREncodeContext *pCtx, int64_t nLabel); /** - @brief Add Base64-encoded text to encoded output. - - @param[in] pCtx The encoding context to add the base-64 text to. - @param[in] uTagRequirement Either @ref QCBOR_ENCODE_AS_TAG or @ref QCBOR_ENCODE_AS_BORROWED. - @param[in] B64Text Pointer and length of the base-64 encoded text. - - The text content is Base64 encoded data per [RFC 4648] - (https://tools.ietf.org/html/rfc4648). - - It is output as CBOR major type 3, a text string, with tag @ref - CBOR_TAG_B64 indicating the text string is Base64 encoded. + * @brief Add a simple value. + * + * @param[in] pCtx The encode context. + * @param[in] uNum The simple value. + * + * QCBOREncode_AddBool(), QCBOREncode_AddUndef() and + * QCBOREncode_AddNull() are preferred to this for the simple values + * defined in RFC 8949, but this can be used for them too. + * + * The main purpose of this is to add simple values beyond those in + * defined RFC 8949. Note that simple values must be registered with + * IANA. Those in the range of 0 to 19 must be standardized. Those in + * the range of 32 to 255 do not require a standard, but must be + * publically specified. There is no range of values for proprietary + * use. See + * https://www.iana.org/assignments/cbor-simple-values/cbor-simple-values.xhtml */ -static void QCBOREncode_AddTB64Text(QCBOREncodeContext *pCtx, - uint8_t uTagRequirement, - UsefulBufC B64Text); - -static void QCBOREncode_AddTB64TextToMapSZ(QCBOREncodeContext *pCtx, - const char *szLabel, - uint8_t uTagRequirement, - UsefulBufC B64Text); - -static void QCBOREncode_AddTB64TextToMapN(QCBOREncodeContext *pCtx, - int64_t nLabel, - uint8_t uTagRequirement, - UsefulBufC B64Text); - - -static void QCBOREncode_AddB64Text(QCBOREncodeContext *pCtx, - UsefulBufC B64Text); - -static void QCBOREncode_AddB64TextToMap(QCBOREncodeContext *pCtx, - const char *szLabel, - UsefulBufC B64Text); +static void +QCBOREncode_AddSimple(QCBOREncodeContext *pCtx, const uint8_t uNum); -static void QCBOREncode_AddB64TextToMapN(QCBOREncodeContext *pCtx, - int64_t nLabel, - UsefulBufC B64Text); +static void +QCBOREncode_AddSimpleToMapSZ(QCBOREncodeContext *pCtx, + const char *szLabel, + const uint8_t uSimple); +static void +QCBOREncode_AddSimpleToMapN(QCBOREncodeContext *pCtx, + const int64_t nLabel, + const uint8_t uSimple); /** - @brief Add base64url encoded data to encoded output. - - @param[in] pCtx The encoding context to add the base64url to. - @param[in] uTagRequirement Either @ref QCBOR_ENCODE_AS_TAG or @ref QCBOR_ENCODE_AS_BORROWED. - @param[in] B64Text Pointer and length of the base64url encoded text. - - The text content is base64URL encoded text as per [RFC 4648] - (https://tools.ietf.org/html/rfc4648). - - It is output as CBOR major type 3, a text string, with tag @ref - CBOR_TAG_B64URL indicating the text string is a Base64url encoded. + * @brief Indicates that the next items added are in an array. + * + * @param[in] pCtx The encoding context to open the array in. + * + * Arrays are the basic CBOR aggregate or structure type. Call this + * function to start or open an array. Then call the various + * @c QCBOREncode_AddXxx() functions to add the items that go into the + * array. Then call QCBOREncode_CloseArray() when all items have been + * added. The data items in the array can be of any type and can be of + * mixed types. + * + * Nesting of arrays and maps is allowed and supported just by calling + * QCBOREncode_OpenArray() again before calling + * QCBOREncode_CloseArray(). While CBOR has no limit on nesting, this + * implementation does in order to keep it smaller and simpler. The + * limit is @ref QCBOR_MAX_ARRAY_NESTING. This is the max number of + * times this can be called without calling + * QCBOREncode_CloseArray(). QCBOREncode_Finish() will return + * @ref QCBOR_ERR_ARRAY_NESTING_TOO_DEEP when it is called as this + * function just sets an error state and returns no value when this + * occurs. + * + * If you try to add more than @ref QCBOR_MAX_ITEMS_IN_ARRAY items to + * a single array or map, @ref QCBOR_ERR_ARRAY_TOO_LONG will be + * returned when QCBOREncode_Finish() is called. + * + * An array itself must have a label if it is being added to a map. + * Note that array elements do not have labels (but map elements do). + * + * An array itself may be tagged by calling QCBOREncode_AddTag() + * before this call. */ -static void QCBOREncode_AddTB64URLText(QCBOREncodeContext *pCtx, - uint8_t uTagRequirement, - UsefulBufC B64Text); - -static void QCBOREncode_AddTB64URLTextToMapSZ(QCBOREncodeContext *pCtx, - const char *szLabel, - uint8_t uTagRequirement, - UsefulBufC B64Text); - -static void QCBOREncode_AddTB64URLTextToMapN(QCBOREncodeContext *pCtx, - int64_t nLabel, - uint8_t uTagRequirement, - UsefulBufC B64Text); - - -static void QCBOREncode_AddB64URLText(QCBOREncodeContext *pCtx, - UsefulBufC B64Text); +static void +QCBOREncode_OpenArray(QCBOREncodeContext *pCtx); -static void QCBOREncode_AddB64URLTextToMap(QCBOREncodeContext *pCtx, - const char *szLabel, - UsefulBufC B64Text); +static void +QCBOREncode_OpenArrayInMapSZ(QCBOREncodeContext *pCtx, const char *szLabel); -static void QCBOREncode_AddB64URLTextToMapN(QCBOREncodeContext *pCtx, - int64_t nLabel, - UsefulBufC B64Text); +static void +QCBOREncode_OpenArrayInMapN(QCBOREncodeContext *pCtx, int64_t nLabel); /** - @brief Add Perl Compatible Regular Expression. - - @param[in] pCtx The encoding context to add the regular expression to. - @param[in] uTagRequirement Either @ref QCBOR_ENCODE_AS_TAG or @ref QCBOR_ENCODE_AS_BORROWED. - @param[in] Regex Pointer and length of the regular expression. - - The text content is Perl Compatible Regular - Expressions (PCRE) / JavaScript syntax [ECMA262]. - - It is output as CBOR major type 3, a text string, with tag @ref - CBOR_TAG_REGEX indicating the text string is a regular expression. + * @brief Close an open array. + * + * @param[in] pCtx The encoding context to close the array in. + * + * The closes an array opened by QCBOREncode_OpenArray(). It reduces + * nesting level by one. All arrays (and maps) must be closed before + * calling QCBOREncode_Finish(). + * + * When an error occurs as a result of this call, the encoder records + * the error and enters the error state. The error will be returned + * when QCBOREncode_Finish() is called. + * + * If this has been called more times than QCBOREncode_OpenArray(), then + * @ref QCBOR_ERR_TOO_MANY_CLOSES will be returned when QCBOREncode_Finish() + * is called. + * + * If this is called and it is not an array that is currently open, + * @ref QCBOR_ERR_CLOSE_MISMATCH will be returned when + * QCBOREncode_Finish() is called. */ -static void QCBOREncode_AddTRegex(QCBOREncodeContext *pCtx, - uint8_t uTagRequirement, - UsefulBufC Regex); - -static void QCBOREncode_AddTRegexToMapSZ(QCBOREncodeContext *pCtx, - const char *szLabel, - uint8_t uTagRequirement, - UsefulBufC Regex); - -static void QCBOREncode_AddTRegexToMapN(QCBOREncodeContext *pCtx, - int64_t nLabel, - uint8_t uTagRequirement, - UsefulBufC Regex); - - -static void QCBOREncode_AddRegex(QCBOREncodeContext *pCtx, - UsefulBufC Regex); +static void +QCBOREncode_CloseArray(QCBOREncodeContext *pCtx); -static void QCBOREncode_AddRegexToMap(QCBOREncodeContext *pCtx, - const char *szLabel, - UsefulBufC Regex); -static void QCBOREncode_AddRegexToMapN(QCBOREncodeContext *pCtx, - int64_t nLabel, - UsefulBufC Regex); /** - @brief MIME encoded data to the encoded output. - - @param[in] pCtx The encoding context to add the MIME data to. - @param[in] uTagRequirement Either @ref QCBOR_ENCODE_AS_TAG or - @ref QCBOR_ENCODE_AS_BORROWED. - @param[in] MIMEData Pointer and length of the MIME data. - - The text content is in MIME format per [RFC 2045] - (https://tools.ietf.org/html/rfc2045) including the headers. - - It is output as CBOR major type 2, a binary string, with tag @ref - CBOR_TAG_BINARY_MIME indicating the string is MIME data. This - outputs tag 257, not tag 36, as it can carry any type of MIME binary, - 7-bit, 8-bit, quoted-printable and base64 where tag 36 cannot. - - Previous versions of QCBOR, those before spiffy decode, output tag - 36. Decoding supports both tag 36 and 257. (if the old behavior with - tag 36 is needed, copy the inline functions below and change the tag - number). - - See also QCBORDecode_GetMIMEMessage() and - @ref QCBOR_TYPE_BINARY_MIME. - - This does no translation of line endings. See QCBOREncode_AddText() - for a discussion of line endings in CBOR. + * @brief Indicates that the next items added are in a map. + * + * @param[in] pCtx The encoding context to open the map in. + * + * See QCBOREncode_OpenArray() for more information, particularly + * error handling. + * + * CBOR maps are an aggregate type where each item in the map consists + * of a label and a value. They are similar to JSON objects. + * + * The value can be any CBOR type including another map. + * + * The label can also be any CBOR type, but in practice they are + * typically, integers as this gives the most compact output. They + * might also be text strings which gives readability and translation + * to JSON. + * + * Every @c QCBOREncode_AddXxx() call has one version that ends with + * @c InMap for adding items to maps with string labels and one that + * ends with @c InMapN that is for adding with integer labels. + * + * RFC 8949 uses the term "key" instead of "label". + * + * If you wish to use map labels that are neither integer labels nor + * text strings, then just call the QCBOREncode_AddXxx() function + * explicitly to add the label. Then call it again to add the value. + * + * See the [RFC 8949] (https://www.rfc-editor.org/rfc/rfc8949.html) + * for a lot more information on creating maps. */ -static void QCBOREncode_AddTMIMEData(QCBOREncodeContext *pCtx, - uint8_t uTagRequirement, - UsefulBufC MIMEData); - -static void QCBOREncode_AddTMIMEDataToMapSZ(QCBOREncodeContext *pCtx, - const char *szLabel, - uint8_t uTagRequirement, - UsefulBufC MIMEData); - -static void QCBOREncode_AddTMIMEDataToMapN(QCBOREncodeContext *pCtx, - int64_t nLabel, - uint8_t uTagRequirement, - UsefulBufC MIMEData); - - -static void QCBOREncode_AddMIMEData(QCBOREncodeContext *pCtx, - UsefulBufC MIMEData); +static void +QCBOREncode_OpenMap(QCBOREncodeContext *pCtx); -static void QCBOREncode_AddMIMEDataToMap(QCBOREncodeContext *pCtx, - const char *szLabel, - UsefulBufC MIMEData); +static void +QCBOREncode_OpenMapInMapSZ(QCBOREncodeContext *pCtx, const char *szLabel); -static void QCBOREncode_AddMIMEDataToMapN(QCBOREncodeContext *pCtx, - int64_t nLabel, - UsefulBufC MIMEData); +static void +QCBOREncode_OpenMapInMapN(QCBOREncodeContext *pCtx, int64_t nLabel); /** - @brief Add an RFC 3339 date string - - @param[in] pCtx The encoding context to add the date to. - @param[in] uTagRequirement Either @ref QCBOR_ENCODE_AS_TAG or @ref QCBOR_ENCODE_AS_BORROWED. - @param[in] szDate Null-terminated string with date to add. - - The string szDate should be in the form of [RFC 3339] - (https://tools.ietf.org/html/rfc3339) as defined by section 3.3 in - [RFC 4287] (https://tools.ietf.org/html/rfc4287). This is as - described in section 3.4.1 in [RFC 8949] - (https://tools.ietf.org/html/rfc8949). - - Note that this function doesn't validate the format of the date string - at all. If you add an incorrect format date string, the generated - CBOR will be incorrect and the receiver may not be able to handle it. - - Error handling is the same as QCBOREncode_AddInt64(). - - See also QCBOREncode_AddTDayString(). + * @brief Close an open map. + * + * @param[in] pCtx The encoding context to close the map in. + * + * This closes a map opened by QCBOREncode_OpenMap(). It reduces + * nesting level by one. + * + * When an error occurs as a result of this call, the encoder records + * the error and enters the error state. The error will be returned + * when QCBOREncode_Finish() is called. + * + * If this has been called more times than QCBOREncode_OpenMap(), then + * @ref QCBOR_ERR_TOO_MANY_CLOSES will be returned when + * QCBOREncode_Finish() is called. + * + * If this is called and it is not a map that is currently open, + * @ref QCBOR_ERR_CLOSE_MISMATCH will be returned when + * QCBOREncode_Finish() is called. */ -static void QCBOREncode_AddTDateString(QCBOREncodeContext *pCtx, - uint8_t uTagRequirement, - const char *szDate); - -static void QCBOREncode_AddTDateStringToMapSZ(QCBOREncodeContext *pCtx, - const char *szLabel, - uint8_t uTagRequirement, - const char *szDate); - -static void QCBOREncode_AddTDateStringToMapN(QCBOREncodeContext *pCtx, - int64_t nLabel, - uint8_t uTagRequirement, - const char *szDate); - - -static void QCBOREncode_AddDateString(QCBOREncodeContext *pCtx, - const char *szDate); - -static void QCBOREncode_AddDateStringToMap(QCBOREncodeContext *pCtx, - const char *szLabel, - const char *szDate); - -static void QCBOREncode_AddDateStringToMapN(QCBOREncodeContext *pCtx, - int64_t nLabel, - const char *szDate); +static void +QCBOREncode_CloseMap(QCBOREncodeContext *pCtx); /** - @brief Add a date-only string. - - @param[in] pCtx The encoding context to add the date to. - @param[in] uTagRequirement Either @ref QCBOR_ENCODE_AS_TAG or - @ref QCBOR_ENCODE_AS_BORROWED. - @param[in] szDate Null-terminated string with date to add. - - This date format is described in - [RFC 8943] (https://tools.ietf.org/html/rfc8943), but that mainly - references RFC 3339. The string szDate must be in the forrm - specified the ABNF for a full-date in - [RFC 3339] (https://tools.ietf.org/html/rfc3339). Examples of this - are "1985-04-12" and "1937-01-01". The time and the time zone are - never included. - - Note that this function doesn't validate the format of the date - string at all. If you add an incorrect format date string, the - generated CBOR will be incorrect and the receiver may not be able to - handle it. - - Error handling is the same as QCBOREncode_AddInt64(). - - See also QCBOREncode_AddTDateString(). + * @brief Indicates that the next items added are in an indefinite length array. + * + * @param[in] pCtx The encoding context to open the array in. + * + * This is the same as QCBOREncode_OpenArray() except the array is + * indefinite length. + * + * This must be closed with QCBOREncode_CloseArrayIndefiniteLength(). */ static void -QCBOREncode_AddTDaysString(QCBOREncodeContext *pCtx, - uint8_t uTagRequirement, - const char *szDate); +QCBOREncode_OpenArrayIndefiniteLength(QCBOREncodeContext *pCtx); static void -QCBOREncode_AddTDaysStringToMapSZ(QCBOREncodeContext *pCtx, - const char *szLabel, - uint8_t uTagRequirement, - const char *szDate); +QCBOREncode_OpenArrayIndefiniteLengthInMapSZ(QCBOREncodeContext *pCtx, + const char *szLabel); static void -QCBOREncode_AddTDaysStringToMapN(QCBOREncodeContext *pCtx, - int64_t nLabel, - uint8_t uTagRequirement, - const char *szDate); +QCBOREncode_OpenArrayIndefiniteLengthInMapN(QCBOREncodeContext *pCtx, + int64_t nLabel); /** - @brief Add a standard Boolean. - - @param[in] pCtx The encoding context to add the Boolean to. - @param[in] b true or false from @c . + * @brief Close an open indefinite length array. + * + * @param[in] pCtx The encoding context to close the array in. + * + * This is the same as QCBOREncode_CloseArray(), but the open array + * that is being close must be of indefinite length. + */ +static void +QCBOREncode_CloseArrayIndefiniteLength(QCBOREncodeContext *pCtx); - Adds a Boolean value as CBOR major type 7. - Error handling is the same as QCBOREncode_AddInt64(). +/** + * @brief Indicates that the next items added are in an indefinite length map. + * + * @param[in] pCtx The encoding context to open the map in. + * + * This is the same as QCBOREncode_OpenMap() except the array is + * indefinite length. + * + * This must be closed with QCBOREncode_CloseMapIndefiniteLength(). */ -static void QCBOREncode_AddBool(QCBOREncodeContext *pCtx, bool b); +static void +QCBOREncode_OpenMapIndefiniteLength(QCBOREncodeContext *pCtx); + +static void +QCBOREncode_OpenMapIndefiniteLengthInMapSZ(QCBOREncodeContext *pCtx, + const char *szLabel); -static void QCBOREncode_AddBoolToMap(QCBOREncodeContext *pCtx, const char *szLabel, bool b); +static void +QCBOREncode_OpenMapIndefiniteLengthInMapN(QCBOREncodeContext *pCtx, + int64_t nLabel); -static void QCBOREncode_AddBoolToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, bool b); /** - @brief Add a NULL to the encoded output. + * @brief Close an open indefinite length map. + * + * @param[in] pCtx The encoding context to close the map in. + * + * This is the same as QCBOREncode_CloseMap(), but the open map that + * is being close must be of indefinite length. + */ +static void +QCBOREncode_CloseMapIndefiniteLength(QCBOREncodeContext *pCtx); - @param[in] pCtx The encoding context to add the NULL to. - Adds the NULL value as CBOR major type 7. - This NULL doesn't have any special meaning in CBOR such as a - terminating value for a string or an empty value. - Error handling is the same as QCBOREncode_AddInt64(). +/** + * @brief Indicate start of encoded CBOR to be wrapped in a bstr. + * + * @param[in] pCtx The encoding context to open the bstr-wrapped CBOR in. + * + * All added encoded items between this call and a call to + * QCBOREncode_CloseBstrWrap2() will be wrapped in a bstr. They will + * appear in the final output as a byte string. That byte string will + * contain encoded CBOR. This increases nesting level by one. + * + * The typical use case is for encoded CBOR that is to be + * cryptographically hashed, as part of a [RFC 9052, COSE] + * (https://www.rfc-editor.org/rfc/rfc9052.html) implementation. The + * wrapping byte string is taken as input by the hash function (which + * is why it is returned by QCBOREncode_CloseBstrWrap2()). It is also + * easy to recover on decoding with standard CBOR decoders. + * + * Using QCBOREncode_BstrWrap() and QCBOREncode_CloseBstrWrap2() + * avoids having to encode the items first in one buffer (e.g., the + * COSE payload) and then add that buffer as a bstr to another + * encoding (e.g. the COSE to-be-signed bytes, the @c Sig_structure) + * potentially halving the memory needed. + * + * CBOR by nature must be decoded item by item in order from the + * start. By wrapping some CBOR in a byte string, the decoding of + * that wrapped CBOR can be skipped. This is another use of wrapping, + * perhaps because the CBOR is large and deeply nested. Perhaps APIs + * for handling one defined CBOR message that is being embedded in + * another only take input as a byte string. Perhaps the desire is to + * be able to decode the out layer even in the wrapped has errors. */ -static void QCBOREncode_AddNULL(QCBOREncodeContext *pCtx); +static void +QCBOREncode_BstrWrap(QCBOREncodeContext *pCtx); -static void QCBOREncode_AddNULLToMap(QCBOREncodeContext *pCtx, const char *szLabel); +static void +QCBOREncode_BstrWrapInMapSZ(QCBOREncodeContext *pCtx, const char *szLabel); -static void QCBOREncode_AddNULLToMapN(QCBOREncodeContext *pCtx, int64_t nLabel); +static void +QCBOREncode_BstrWrapInMapN(QCBOREncodeContext *pCtx, int64_t nLabel); /** - @brief Add an "undef" to the encoded output. - - @param[in] pCtx The encoding context to add the "undef" to. - - Adds the undef value as CBOR major type 7. + * @brief Close a wrapping bstr. + * + * @param[in] pCtx The encoding context to close of bstr wrapping in. + * @param[in] bIncludeCBORHead Include the encoded CBOR head of the bstr + * as well as the bytes in @c pWrappedCBOR. + * @param[out] pWrappedCBOR A @ref UsefulBufC containing wrapped bytes. + * + * The closes a wrapping bstr opened by QCBOREncode_BstrWrap(). It reduces + * nesting level by one. + * + * A pointer and length of the enclosed encoded CBOR is returned in @c + * *pWrappedCBOR if it is not @c NULL. The main purpose of this is so + * this data can be hashed (e.g., with SHA-256) as part of a + * [RFC 9052, COSE] (https://www.rfc-editor.org/rfc/rfc9052.html) + * implementation. **WARNING**, this pointer and length should be used + * right away before any other calls to @c QCBOREncode_CloseXxx() as + * they will move data around and the pointer and length will no + * longer be to the correct encoded CBOR. + * + * When an error occurs as a result of this call, the encoder records + * the error and enters the error state. The error will be returned + * when QCBOREncode_Finish() is called. + * + * If this has been called more times than QCBOREncode_BstrWrap(), + * then @ref QCBOR_ERR_TOO_MANY_CLOSES will be returned when + * QCBOREncode_Finish() is called. + * + * If this is called and it is not a wrapping bstr that is currently + * open, @ref QCBOR_ERR_CLOSE_MISMATCH will be returned when + * QCBOREncode_Finish() is called. + * + * QCBOREncode_CloseBstrWrap() is a deprecated version of this function + * that is equivalent to the call with @c bIncludeCBORHead @c true. + */ +void +QCBOREncode_CloseBstrWrap2(QCBOREncodeContext *pCtx, bool bIncludeCBORHead, UsefulBufC *pWrappedCBOR); - Note that this value will not translate to JSON. +static void +QCBOREncode_CloseBstrWrap(QCBOREncodeContext *pCtx, UsefulBufC *pWrappedCBOR); - This Undef doesn't have any special meaning in CBOR such as a - terminating value for a string or an empty value. - Error handling is the same as QCBOREncode_AddInt64(). +/** + * @brief Cancel byte string wrapping. + * + * @param[in] pCtx The encoding context. + * + * This cancels QCBOREncode_BstrWrap() making the encoding as if it + * were never called. + * + * WARNING: This does not work on QCBOREncode_BstrWrapInMapSZ() + * or QCBOREncode_BstrWrapInMapN() and there is no error detection + * of an attempt at their use. + * + * This only works if nothing has been added into the wrapped byte + * string. If something has been added, this sets the error + * @ref QCBOR_ERR_CANNOT_CANCEL. */ -static void QCBOREncode_AddUndef(QCBOREncodeContext *pCtx); - -static void QCBOREncode_AddUndefToMap(QCBOREncodeContext *pCtx, const char *szLabel); - -static void QCBOREncode_AddUndefToMapN(QCBOREncodeContext *pCtx, int64_t nLabel); +void +QCBOREncode_CancelBstrWrap(QCBOREncodeContext *pCtx); /** - @brief Indicates that the next items added are in an array. - - @param[in] pCtx The encoding context to open the array in. - - Arrays are the basic CBOR aggregate or structure type. Call this - function to start or open an array. Then call the various @c - QCBOREncode_AddXxx() functions to add the items that go into the - array. Then call QCBOREncode_CloseArray() when all items have been - added. The data items in the array can be of any type and can be of - mixed types. - - Nesting of arrays and maps is allowed and supported just by calling - QCBOREncode_OpenArray() again before calling - QCBOREncode_CloseArray(). While CBOR has no limit on nesting, this - implementation does in order to keep it smaller and simpler. The - limit is @ref QCBOR_MAX_ARRAY_NESTING. This is the max number of - times this can be called without calling - QCBOREncode_CloseArray(). QCBOREncode_Finish() will return @ref - QCBOR_ERR_ARRAY_NESTING_TOO_DEEP when it is called as this function - just sets an error state and returns no value when this occurs. - - If you try to add more than @ref QCBOR_MAX_ITEMS_IN_ARRAY items to a - single array or map, @ref QCBOR_ERR_ARRAY_TOO_LONG will be returned - when QCBOREncode_Finish() is called. - - An array itself must have a label if it is being added to a map. - Note that array elements do not have labels (but map elements do). - - An array itself may be tagged by calling QCBOREncode_AddTag() before this call. + * @brief Add some already-encoded CBOR bytes. + * + * @param[in] pCtx The encoding context to add the already-encode CBOR to. + * @param[in] Encoded The already-encoded CBOR to add to the context. + * + * The encoded CBOR being added must be fully conforming CBOR. It must + * be complete with no arrays or maps that are incomplete. it is OK for the + * raw CBOR added here to have indefinite lengths. + * + * The raw CBOR added here is not checked in anyway. If it is not + * conforming or has open arrays or such, the final encoded CBOR + * will probably be wrong or not what was intended. + * + * If the encoded CBOR being added here contains multiple items, they + * must be enclosed in a map or array. At the top level the raw + * CBOR must be a single data item. */ -static void QCBOREncode_OpenArray(QCBOREncodeContext *pCtx); +void +QCBOREncode_AddEncoded(QCBOREncodeContext *pCtx, UsefulBufC Encoded); -static void QCBOREncode_OpenArrayInMap(QCBOREncodeContext *pCtx, const char *szLabel); +static void +QCBOREncode_AddEncodedToMapSZ(QCBOREncodeContext *pCtx, const char *szLabel, UsefulBufC Encoded); -static void QCBOREncode_OpenArrayInMapN(QCBOREncodeContext *pCtx, int64_t nLabel); +static void +QCBOREncode_AddEncodedToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, UsefulBufC Encoded); /** - @brief Close an open array. - - @param[in] pCtx The encoding context to close the array in. + * @brief Get the encoded result. + * + * @param[in] pCtx The context to finish encoding with. + * @param[out] pEncodedCBOR Structure in which the pointer and length of + * the encoded CBOR is returned. + * + * @retval QCBOR_SUCCESS Encoded CBOR is returned. + * + * @retval QCBOR_ERR_TOO_MANY_CLOSES Nesting error + * + * @retval QCBOR_ERR_CLOSE_MISMATCH Nesting error + * + * @retval QCBOR_ERR_ARRAY_OR_MAP_STILL_OPEN Nesting error + * + * @retval QCBOR_ERR_BUFFER_TOO_LARGE Encoded output buffer size + * + * @retval QCBOR_ERR_BUFFER_TOO_SMALL Encoded output buffer size + * + * @retval QCBOR_ERR_ARRAY_NESTING_TOO_DEEP Implementation limit + * + * @retval QCBOR_ERR_ARRAY_TOO_LONG Implementation limit + * + * On success, the pointer and length of the encoded CBOR are returned + * in @c *pEncodedCBOR. The pointer is the same pointer that was passed + * in to QCBOREncode_Init(). Note that it is not const when passed to + * QCBOREncode_Init(), but it is const when returned here. The length + * will be smaller than or equal to the length passed in when + * QCBOREncode_Init() as this is the length of the actual result, not + * the size of the buffer it was written to. + * + * If a @c NULL was passed for @c Storage.ptr when QCBOREncode_Init() + * was called, @c NULL will be returned here, but the length will be + * that of the CBOR that would have been encoded. + * + * Encoding errors primarily manifest here as most other encoding function + * do no return an error. They just set the error state in the encode + * context after which no encoding function does anything. + * + * Three types of errors manifest here. The first type are nesting + * errors where the number of @c QCBOREncode_OpenXxx() calls do not + * match the number @c QCBOREncode_CloseXxx() calls. The solution is to + * fix the calling code. + * + * The second type of error is because the buffer given is either too + * small or too large. The remedy is to give a correctly sized buffer. + * + * The third type are due to limits in this implementation. + * @ref QCBOR_ERR_ARRAY_NESTING_TOO_DEEP can be worked around by + * encoding the CBOR in two (or more) phases and adding the CBOR from + * the first phase to the second with @c QCBOREncode_AddEncoded(). + * + * If an error is returned, the buffer may have partially encoded + * incorrect CBOR in it and it should not be used. Likewise, the length + * may be incorrect and should not be used. + * + * Note that the error could have occurred in one of the many + * @c QCBOREncode_AddXxx() calls long before QCBOREncode_Finish() was + * called. This error handling reduces the CBOR implementation size + * but makes debugging harder. + * + * This may be called multiple times. It will always return the + * same. It can also be interleaved with calls to + * QCBOREncode_FinishGetSize(). See QCBOREncode_SubString() for a + * means to get the thus-far-encoded CBOR. + * + * QCBOREncode_GetErrorState() can be called to get the current + * error state in order to abort encoding early as an optimization, but + * calling it is is never required. + */ +QCBORError +QCBOREncode_Finish(QCBOREncodeContext *pCtx, UsefulBufC *pEncodedCBOR); - The closes an array opened by QCBOREncode_OpenArray(). It reduces - nesting level by one. All arrays (and maps) must be closed before - calling QCBOREncode_Finish(). - When an error occurs as a result of this call, the encoder records - the error and enters the error state. The error will be returned when - QCBOREncode_Finish() is called. +/** + * @brief Get the encoded CBOR and error status. + * + * @param[in] pCtx The context to finish encoding with. + * @param[out] uEncodedLen The length of the encoded or potentially + * encoded CBOR in bytes. + * + * @return The same errors as QCBOREncode_Finish(). + * + * This functions the same as QCBOREncode_Finish(), but only returns the + * size of the encoded output. + */ +QCBORError +QCBOREncode_FinishGetSize(QCBOREncodeContext *pCtx, size_t *uEncodedLen); - If this has been called more times than QCBOREncode_OpenArray(), then - @ref QCBOR_ERR_TOO_MANY_CLOSES will be returned when QCBOREncode_Finish() - is called. - If this is called and it is not an array that is currently open, @ref - QCBOR_ERR_CLOSE_MISMATCH will be returned when QCBOREncode_Finish() - is called. +/** + * @brief Indicate whether the output storage buffer is NULL. + * + * @param[in] pCtx The encoding context. + * + * @return 1 if the output buffer is @c NULL. + * + * As described in QCBOREncode_Init(), @c Storage.ptr may be give as @c NULL + * for output size calculation. This returns 1 when that is the true, and 0 if not. */ -static void QCBOREncode_CloseArray(QCBOREncodeContext *pCtx); +static int +QCBOREncode_IsBufferNULL(QCBOREncodeContext *pCtx); /** - @brief Indicates that the next items added are in a map. - - @param[in] pCtx The encoding context to open the map in. + * @brief Retrieve the storage buffer passed in to QCBOREncode_Init(). + * + * @param[in] pCtx The encoding context. + * + * @return The output storage buffer passed to QCBOREncode_Init(). + * + * This doesn't give any information about how much has been encoded + * or the error state. It just returns the exact @ref UsefulOutBuf given + * to QCBOREncode_Init(). + */ +static UsefulBuf +QCBOREncode_RetrieveOutputStorage(QCBOREncodeContext *pCtx); - See QCBOREncode_OpenArray() for more information, particularly error - handling. - CBOR maps are an aggregate type where each item in the map consists - of a label and a value. They are similar to JSON objects. +/** + * @brief Get the encoding error state. + * + * @param[in] pCtx The encoding context. + * + * @return One of @ref QCBORError. See return values from + * QCBOREncode_Finish() + * + * Normally encoding errors need only be handled at the end of + * encoding when QCBOREncode_Finish() is called. This can be called to + * get the error result before finish should there be a need to halt + * encoding before QCBOREncode_Finish() is called. + */ +static QCBORError +QCBOREncode_GetErrorState(QCBOREncodeContext *pCtx); - The value can be any CBOR type including another map. - The label can also be any CBOR type, but in practice they are - typically, integers as this gives the most compact output. They might - also be text strings which gives readability and translation to JSON. +/** + * @brief Returns current end of encoded data. + * + * @param[in] pCtx The encoding context. + * + * @return Byte offset of end of encoded data. + * + * The purpose of this is to enable cryptographic hashing over a + * subpart of thus far CBOR-encoded data. Then perhaps a signature + * over the hashed CBOR is added to the encoded output. There is + * nothing specific to hashing or signing in this, so this can be used + * for other too. + * + * Call this to get the offset of the start of the encoded + * to-be-hashed CBOR items, then call QCBOREncode_SubString(). + * QCBOREncode_Tell() can also be called twice, first to get the + * offset of the start and second for the offset of the end. Those + * offsets can be applied to the output storage buffer. + * + * This will return successfully even if the encoder is in the error + * state. + * + * WARNING: All definite-length arrays and maps opened before the + * first call to QCBOREncode_Tell() must not be closed until the + * substring is obtained and processed. Similarly, every + * definite-length array or map opened after the first call to + * QCBOREncode_Tell() must be closed before the substring is obtained + * and processed. The same applies for opened byte strings. There is + * no detection of these errors. This occurs because QCBOR goes back + * and inserts the lengths of definite-length arrays and maps when + * they are closed. This insertion will make the offsets incorrect. + */ +static size_t +QCBOREncode_Tell(QCBOREncodeContext *pCtx); - Every @c QCBOREncode_AddXxx() call has one version that ends with @c - InMap for adding items to maps with string labels and one that ends - with @c InMapN that is for adding with integer labels. - RFC 8949 uses the term "key" instead of "label". +/** + * @brief Get a substring of encoded CBOR for cryptographic hash + * + * @param[in] pCtx The encoding context. + * @param[in] uStart The start offset of substring. + * + * @return Pointer and length of of substring. + * + * @c uStart is obtained by calling QCBOREncode_Tell() before encoding + * the first item in the substring. Then encode some data items. Then + * call this. The substring returned contains the encoded data items. + * + * The substring may have deeply nested arrays and maps as long as any + * opened after the call to QCBOREncode_Tell() are closed before this + * is called. + * + * This will return @c NULLUsefulBufC if the encoder is in the error + * state or if @c uStart is beyond the end of the thus-far encoded + * data items. + * + * If @c uStart is 0, all the thus-far-encoded CBOR will be returned. + * Unlike QCBOREncode_Finish(), this will succeed even if some arrays + * and maps are not closed. + * + * See important usage WARNING in QCBOREncode_Tell() + */ +UsefulBufC +QCBOREncode_SubString(QCBOREncodeContext *pCtx, const size_t uStart); - If you wish to use map labels that are neither integer labels nor - text strings, then just call the QCBOREncode_AddXxx() function - explicitly to add the label. Then call it again to add the value. - See the [RFC 8949] (https://tools.ietf.org/html/rfc8949) for a lot - more information on creating maps. +/** + * @brief Encode the head of a CBOR data item. + * + * @param Buffer Buffer to output the encoded head to; must be + * @ref QCBOR_HEAD_BUFFER_SIZE bytes in size. + * @param uMajorType One of CBOR_MAJOR_TYPE_XX. + * @param uMinLen The minimum number of bytes to encode uNumber. Almost + * always this is 0 to use preferred + * serialization. If this is 4, then even the + * values 0xffff and smaller will be encoded in 4 + * bytes. This is used primarily when encoding a + * float or double put into uNumber as the leading + * zero bytes for them must be encoded. + * @param uNumber The numeric argument part of the CBOR head. + * @return Pointer and length of the encoded head or + * @ref NULLUsefulBufC if the output buffer is too small. + * + * Callers do not to need to call this for normal CBOR encoding. Note + * that it doesn't even take a @ref QCBOREncodeContext argument. + * + * This encodes the major type and argument part of a data item. The + * argument is an integer that is usually either the value or the length + * of the data item. + * + * This is exposed in the public interface to allow hashing of some CBOR + * data types, bstr in particular, a chunk at a time so the full CBOR + * doesn't have to be encoded in a contiguous buffer. + * + * For example, if you have a 100,000 byte binary blob in a buffer that + * needs to be bstr encoded and then hashed. You could allocate a + * 100,010 byte buffer and encode it normally. Alternatively, you can + * encode the head in a 10 byte buffer with this function, hash that and + * then hash the 100,000 bytes using the same hash context. */ -static void QCBOREncode_OpenMap(QCBOREncodeContext *pCtx); +UsefulBufC +QCBOREncode_EncodeHead(UsefulBuf Buffer, + uint8_t uMajorType, + uint8_t uMinLen, + uint64_t uNumber); -static void QCBOREncode_OpenMapInMap(QCBOREncodeContext *pCtx, const char *szLabel); -static void QCBOREncode_OpenMapInMapN(QCBOREncodeContext *pCtx, int64_t nLabel); -/** - @brief Close an open map. +/* ========================================================================= * + * BEGINNING OF DEPRECATED FUNCTIONS * + * * + * There is no plan to remove these in future versions. * + * They just have been replaced by something better. * + * ========================================================================= */ - @param[in] pCtx The encoding context to close the map in . +/* Use QCBOREncode_AddInt64ToMapSZ() instead */ +static void +QCBOREncode_AddInt64ToMap(QCBOREncodeContext *pCtx, const char *szLabel, int64_t nNum); - This closes a map opened by QCBOREncode_OpenMap(). It reduces nesting - level by one. +/* Use QCBOREncode_AddUInt64ToMapSZ() instead */ +static void +QCBOREncode_AddUInt64ToMap(QCBOREncodeContext *pCtx, const char *szLabel, uint64_t uNum); - When an error occurs as a result of this call, the encoder records - the error and enters the error state. The error will be returned when - QCBOREncode_Finish() is called. +/* Use QCBOREncode_AddTextToMapSZ() instead */ +static void +QCBOREncode_AddTextToMap(QCBOREncodeContext *pCtx, const char *szLabel, UsefulBufC Text); - If this has been called more times than QCBOREncode_OpenMap(), - then @ref QCBOR_ERR_TOO_MANY_CLOSES will be returned when - QCBOREncode_Finish() is called. +/* Use QCBOREncode_AddSZStringToMapSZ() instead */ +static void +QCBOREncode_AddSZStringToMap(QCBOREncodeContext *pCtx, const char *szLabel, const char *szString); - If this is called and it is not a map that is currently open, @ref - QCBOR_ERR_CLOSE_MISMATCH will be returned when QCBOREncode_Finish() - is called. - */ -static void QCBOREncode_CloseMap(QCBOREncodeContext *pCtx); +#ifndef USEFULBUF_DISABLE_ALL_FLOAT +/* Use QCBOREncode_AddDoubleToMapSZ() instead */ +static void +QCBOREncode_AddDoubleToMap(QCBOREncodeContext *pCtx, const char *szLabel, double dNum); +/* Use QCBOREncode_AddFloatToMapSZ() instead */ +static void +QCBOREncode_AddFloatToMap(QCBOREncodeContext *pCtx, const char *szLabel, float fNum); -/** - @brief Indicate start of encoded CBOR to be wrapped in a bstr. - - @param[in] pCtx The encoding context to open the bstr-wrapped CBOR in. - - All added encoded items between this call and a call to - QCBOREncode_CloseBstrWrap2() will be wrapped in a bstr. They will - appear in the final output as a byte string. That byte string will - contain encoded CBOR. This increases nesting level by one. - - The typical use case is for encoded CBOR that is to be - cryptographically hashed, as part of a [RFC 8152, COSE] - (https://tools.ietf.org/html/rfc8152) implementation. The - wrapping byte string is taken as input by the hash function - (which is why it is returned by QCBOREncode_CloseBstrWrap2()). - It is also easy to recover on decoding with standard CBOR - decoders. - - Using QCBOREncode_BstrWrap() and QCBOREncode_CloseBstrWrap2() avoids - having to encode the items first in one buffer (e.g., the COSE - payload) and then add that buffer as a bstr to another encoding - (e.g. the COSE to-be-signed bytes, the @c Sig_structure) potentially - halving the memory needed. - - CBOR by nature must be decoded item by item in order from the start. - By wrapping some CBOR in a byte string, the decoding of that wrapped - CBOR can be skipped. This is another use of wrapping, perhaps - because the CBOR is large and deeply nested. Perhaps APIs for - handling one defined CBOR message that is being embedded in another - only take input as a byte string. Perhaps the desire is to be able - to decode the out layer even in the wrapped has errors. - */ -static void QCBOREncode_BstrWrap(QCBOREncodeContext *pCtx); +/* Use QCBOREncode_AddDoubleNoPreferredToMapSZ() instead */ +static void +QCBOREncode_AddDoubleNoPreferredToMap(QCBOREncodeContext *pCtx, const char *szLabel, double dNum); + +/* Use QCBOREncode_AddFloatNoPreferredToMapSZ() instead */ +static void +QCBOREncode_AddFloatNoPreferredToMap(QCBOREncodeContext *pCtx, const char *szLabel, float fNum); +#endif /* ! USEFULBUF_DISABLE_ALL_FLOAT */ -static void QCBOREncode_BstrWrapInMap(QCBOREncodeContext *pCtx, const char *szLabel); +/* Use QCBOREncode_AddTDateEpoch() instead */ +static void +QCBOREncode_AddDateEpoch(QCBOREncodeContext *pCtx, int64_t nDate); -static void QCBOREncode_BstrWrapInMapN(QCBOREncodeContext *pCtx, int64_t nLabel); +/* Use QCBOREncode_AddTDateEpochToMapSZ() instead */ +static void +QCBOREncode_AddDateEpochToMap(QCBOREncodeContext *pCtx, const char *szLabel, int64_t nDate); +/* Use QCBOREncode_AddTDateEpochToMapN() instead */ +static void +QCBOREncode_AddDateEpochToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, int64_t nDate); -/** - @brief Close a wrapping bstr. - - @param[in] pCtx The encoding context to close of bstr wrapping in. - @param[in] bIncludeCBORHead Include the encoded CBOR head of the bstr - as well as the bytes in @c pWrappedCBOR. - @param[out] pWrappedCBOR A @ref UsefulBufC containing wrapped bytes. - - The closes a wrapping bstr opened by QCBOREncode_BstrWrap(). It reduces - nesting level by one. - - A pointer and length of the enclosed encoded CBOR is returned in @c - *pWrappedCBOR if it is not @c NULL. The main purpose of this is so - this data can be hashed (e.g., with SHA-256) as part of a [RFC 8152, - COSE] (https://tools.ietf.org/html/rfc8152) - implementation. **WARNING**, this pointer and length should be used - right away before any other calls to @c QCBOREncode_CloseXxx() as - they will move data around and the pointer and length will no longer - be to the correct encoded CBOR. - - When an error occurs as a result of this call, the encoder records - the error and enters the error state. The error will be returned when - QCBOREncode_Finish() is called. - - If this has been called more times than QCBOREncode_BstrWrap(), then - @ref QCBOR_ERR_TOO_MANY_CLOSES will be returned when - QCBOREncode_Finish() is called. - - If this is called and it is not a wrapping bstr that is currently - open, @ref QCBOR_ERR_CLOSE_MISMATCH will be returned when - QCBOREncode_Finish() is called. - - QCBOREncode_CloseBstrWrap() is a deprecated version of this function - that is equivalent to the call with @c bIncludeCBORHead @c true. - */ -void QCBOREncode_CloseBstrWrap2(QCBOREncodeContext *pCtx, bool bIncludeCBORHead, UsefulBufC *pWrappedCBOR); +/* Use QCBOREncode_AddBytesToMapSZ() instead */ +static void +QCBOREncode_AddBytesToMap(QCBOREncodeContext *pCtx, const char *szLabel, UsefulBufC Bytes); -static void QCBOREncode_CloseBstrWrap(QCBOREncodeContext *pCtx, UsefulBufC *pWrappedCBOR); +/* Use QCBOREncode_AddTBinaryUUID() instead */ +static void +QCBOREncode_AddBinaryUUID(QCBOREncodeContext *pCtx, UsefulBufC Bytes); +/* Use QCBOREncode_AddTBinaryUUIDToMapSZ() instead */ +static void +QCBOREncode_AddBinaryUUIDToMap(QCBOREncodeContext *pCtx, const char *szLabel, UsefulBufC Bytes); -/** - * @brief Cancel byte string wrapping. - * - * @param[in] pCtx The encoding context. - * - * This cancels QCBOREncode_BstrWrap() making tghe encoding as if it - * were never called. - * - * WARNING: This does not work on QCBOREncode_BstrWrapInMap() - * or QCBOREncode_BstrWrapInMapN() and there is no error detection - * of an attempt at their use. - * - * This only works if nothing has been added into the wrapped byte - * string. If something has been added, this sets the error - * @ref QCBOR_ERR_CANNOT_CANCEL. - */ -void QCBOREncode_CancelBstrWrap(QCBOREncodeContext *pCtx); +/* Use QCBOREncode_AddTBinaryUUIDToMapN() instead */ +static void +QCBOREncode_AddBinaryUUIDToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, UsefulBufC Bytes); +/* Use QCBOREncode_AddTPositiveBignum() instead */ +static void +QCBOREncode_AddPositiveBignum(QCBOREncodeContext *pCtx, UsefulBufC BigNumber); -/** - @brief Add some already-encoded CBOR bytes. +/* QCBOREncode_AddTPositiveBignumToMapSZ() instead */ +static void +QCBOREncode_AddPositiveBignumToMap(QCBOREncodeContext *pCtx, + const char *szLabel, + UsefulBufC BigNumber); - @param[in] pCtx The encoding context to add the already-encode CBOR to. - @param[in] Encoded The already-encoded CBOR to add to the context. +/* Use QCBOREncode_AddTPositiveBignumToMapN() instead */ +static void +QCBOREncode_AddPositiveBignumToMapN(QCBOREncodeContext *pCtx, + int64_t nLabel, + UsefulBufC BigNumber); - The encoded CBOR being added must be fully conforming CBOR. It must - be complete with no arrays or maps that are incomplete. While this - encoder doesn't ever produce indefinite lengths, it is OK for the - raw CBOR added here to have indefinite lengths. +/* Use QCBOREncode_AddTNegativeBignum() instead */ +static void +QCBOREncode_AddNegativeBignum(QCBOREncodeContext *pCtx, UsefulBufC BigNumber); - The raw CBOR added here is not checked in anyway. If it is not - conforming or has open arrays or such, the final encoded CBOR - will probably be wrong or not what was intended. +/* Use QCBOREncode_AddTNegativeBignumToMapSZ() instead */ +static void +QCBOREncode_AddNegativeBignumToMap(QCBOREncodeContext *pCtx, const char *szLabel, UsefulBufC BigNumber); - If the encoded CBOR being added here contains multiple items, they - must be enclosed in a map or array. At the top level the raw - CBOR must be a single data item. - */ -static void QCBOREncode_AddEncoded(QCBOREncodeContext *pCtx, UsefulBufC Encoded); +/* Use QCBOREncode_AddTNegativeBignumToMapN() instead */ +static void +QCBOREncode_AddNegativeBignumToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, UsefulBufC BigNumber); -static void QCBOREncode_AddEncodedToMap(QCBOREncodeContext *pCtx, const char *szLabel, UsefulBufC Encoded); -static void QCBOREncode_AddEncodedToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, UsefulBufC Encoded); +#ifndef QCBOR_CONFIG_DISABLE_EXP_AND_MANTISSA +/* Use QCBOREncode_AddTDecimalFraction() instead */ +static void +QCBOREncode_AddDecimalFraction(QCBOREncodeContext *pCtx, + int64_t nMantissa, + int64_t nBase10Exponent); -/** - @brief Get the encoded result. +/* Use QCBOREncode_AddTDecimalFractionToMapSZ() instead */ +static void +QCBOREncode_AddDecimalFractionToMap(QCBOREncodeContext *pCtx, + const char *szLabel, + int64_t nMantissa, + int64_t nBase10Exponent); - @param[in] pCtx The context to finish encoding with. - @param[out] pEncodedCBOR Structure in which the pointer and length of the encoded - CBOR is returned. +/* Use QCBOREncode_AddTDecimalFractionToMapN() instead */ +static void +QCBOREncode_AddDecimalFractionToMapN(QCBOREncodeContext *pCtx, + int64_t nLabel, + int64_t nMantissa, + int64_t nBase10Exponent); - @retval QCBOR_SUCCESS Encoded CBOR is returned. +/* Use QCBOREncode_AddTDecimalFractionBigNum() instead */ +static void +QCBOREncode_AddDecimalFractionBigNum(QCBOREncodeContext *pCtx, + UsefulBufC Mantissa, + bool bIsNegative, + int64_t nBase10Exponent); - @retval QCBOR_ERR_TOO_MANY_CLOSES Nesting error +/* Use QCBOREncode_AddTDecimalFractionBigNumToMapSZ() instead */ +static void +QCBOREncode_AddDecimalFractionBigNumToMapSZ(QCBOREncodeContext *pCtx, + const char *szLabel, + UsefulBufC Mantissa, + bool bIsNegative, + int64_t nBase10Exponent); - @retval QCBOR_ERR_CLOSE_MISMATCH Nesting error +/* Use QCBOREncode_AddTDecimalFractionBigNumToMapN() instead */ +static void +QCBOREncode_AddDecimalFractionBigNumToMapN(QCBOREncodeContext *pCtx, + int64_t nLabel, + UsefulBufC Mantissa, + bool bIsNegative, + int64_t nBase10Exponent); - @retval QCBOR_ERR_ARRAY_OR_MAP_STILL_OPEN Nesting error +/* Use QCBOREncode_AddTBigFloat() instead */ +static void +QCBOREncode_AddBigFloat(QCBOREncodeContext *pCtx, + int64_t nMantissa, + int64_t nBase2Exponent); - @retval QCBOR_ERR_BUFFER_TOO_LARGE Encoded output buffer size +/* Use QCBOREncode_AddTBigFloatToMapSZ() instead */ +static void +QCBOREncode_AddBigFloatToMap(QCBOREncodeContext *pCtx, + const char *szLabel, + int64_t nMantissa, + int64_t nBase2Exponent); - @retval QCBOR_ERR_BUFFER_TOO_SMALL Encoded output buffer size +/* Use QCBOREncode_AddTBigFloatToMapN() instead */ +static void +QCBOREncode_AddBigFloatToMapN(QCBOREncodeContext *pCtx, + int64_t nLabel, + int64_t nMantissa, + int64_t nBase2Exponent); - @retval QCBOR_ERR_ARRAY_NESTING_TOO_DEEP Implementation limit +/* Use QCBOREncode_AddTBigFloatBigNum() instead */ +static void +QCBOREncode_AddBigFloatBigNum(QCBOREncodeContext *pCtx, + UsefulBufC Mantissa, + bool bIsNegative, + int64_t nBase2Exponent); - @retval QCBOR_ERR_ARRAY_TOO_LONG Implementation limit +/* Use QCBOREncode_AddTBigFloatBigNumToMapSZ() instead */ +static void +QCBOREncode_AddBigFloatBigNumToMap(QCBOREncodeContext *pCtx, + const char *szLabel, + UsefulBufC Mantissa, + bool bIsNegative, + int64_t nBase2Exponent); - On success, the pointer and length of the encoded CBOR are returned - in @c *pEncodedCBOR. The pointer is the same pointer that was passed - in to QCBOREncode_Init(). Note that it is not const when passed to - QCBOREncode_Init(), but it is const when returned here. The length - will be smaller than or equal to the length passed in when - QCBOREncode_Init() as this is the length of the actual result, not - the size of the buffer it was written to. +/* Use QCBOREncode_AddTBigFloatBigNumToMapN() instead */ +static void +QCBOREncode_AddBigFloatBigNumToMapN(QCBOREncodeContext *pCtx, + int64_t nLabel, + UsefulBufC Mantissa, + bool bIsNegative, + int64_t nBase2Exponent); +#endif /* ! QCBOR_CONFIG_DISABLE_EXP_AND_MANTISSA */ - If a @c NULL was passed for @c Storage.ptr when QCBOREncode_Init() - was called, @c NULL will be returned here, but the length will be - that of the CBOR that would have been encoded. +/* Use QCBOREncode_AddTURI() instead */ +static void +QCBOREncode_AddURI(QCBOREncodeContext *pCtx, UsefulBufC URI); - Encoding errors primarily manifest here as most other encoding function - do no return an error. They just set the error state in the encode - context after which no encoding function does anything. +/* Use QCBOREncode_AddTURIToMapSZ() instead */ +static void +QCBOREncode_AddURIToMap(QCBOREncodeContext *pCtx, const char *szLabel, UsefulBufC URI); - Three types of errors manifest here. The first type are nesting - errors where the number of @c QCBOREncode_OpenXxx() calls do not - match the number @c QCBOREncode_CloseXxx() calls. The solution is to - fix the calling code. +/* Use QCBOREncode_AddTURIToMapN() instead */ +static void +QCBOREncode_AddURIToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, UsefulBufC URI); - The second type of error is because the buffer given is either too - small or too large. The remedy is to give a correctly sized buffer. +/* Use QCBOREncode_AddTB64Text() instead */ +static void +QCBOREncode_AddB64Text(QCBOREncodeContext *pCtx, UsefulBufC B64Text); - The third type are due to limits in this implementation. @ref - QCBOR_ERR_ARRAY_NESTING_TOO_DEEP can be worked around by encoding the - CBOR in two (or more) phases and adding the CBOR from the first phase - to the second with @c QCBOREncode_AddEncoded(). +/* Use QCBOREncode_AddTB64TextToMapSZ() instead */ +static void +QCBOREncode_AddB64TextToMap(QCBOREncodeContext *pCtx, const char *szLabel, UsefulBufC B64Text); - If an error is returned, the buffer may have partially encoded - incorrect CBOR in it and it should not be used. Likewise, the length - may be incorrect and should not be used. +/* Use QCBOREncode_AddTB64TextToMapN() instead */ +static void +QCBOREncode_AddB64TextToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, UsefulBufC B64Text); - Note that the error could have occurred in one of the many @c - QCBOREncode_AddXxx() calls long before QCBOREncode_Finish() was - called. This error handling reduces the CBOR implementation size but - makes debugging harder. +/* Use QCBOREncode_AddTB64URLText() instead */ +static void +QCBOREncode_AddB64URLText(QCBOREncodeContext *pCtx, UsefulBufC B64Text); - This may be called multiple times. It will always return the same. It - can also be interleaved with calls to QCBOREncode_FinishGetSize(). +/* Use QCBOREncode_AddTB64URLTextToMapSZ() instead */ +static void +QCBOREncode_AddB64URLTextToMap(QCBOREncodeContext *pCtx, + const char *szLabel, + UsefulBufC B64Text); - QCBOREncode_GetErrorState() can be called to get the current - error state in order to abort encoding early as an optimization, but - calling it is is never required. - */ -QCBORError QCBOREncode_Finish(QCBOREncodeContext *pCtx, UsefulBufC *pEncodedCBOR); +/* Use QCBOREncode_AddTB64URLTextToMapN() instead */ +static void +QCBOREncode_AddB64URLTextToMapN(QCBOREncodeContext *pCtx, + int64_t nLabel, + UsefulBufC B64Text); +/* Use QCBOREncode_AddTRegex() instead */ +static void +QCBOREncode_AddRegex(QCBOREncodeContext *pCtx, UsefulBufC Regex); -/** - @brief Get the encoded CBOR and error status. +/* Use QCBOREncode_AddTRegexToMapSZ() instead */ +static void +QCBOREncode_AddRegexToMap(QCBOREncodeContext *pCtx, + const char *szLabel, + UsefulBufC Regex); - @param[in] pCtx The context to finish encoding with. - @param[out] uEncodedLen The length of the encoded or potentially - encoded CBOR in bytes. +/* Use QCBOREncode_AddTRegexToMapN() instead */ +static void +QCBOREncode_AddRegexToMapN(QCBOREncodeContext *pCtx, + int64_t nLabel, + UsefulBufC Regex); - @return The same errors as QCBOREncode_Finish(). +/* Use QCBOREncode_AddTMIMEData() instead */ +static void +QCBOREncode_AddMIMEData(QCBOREncodeContext *pCtx, UsefulBufC MIMEData); - This functions the same as QCBOREncode_Finish(), but only returns the - size of the encoded output. - */ -QCBORError QCBOREncode_FinishGetSize(QCBOREncodeContext *pCtx, size_t *uEncodedLen); +/* Use QCBOREncode_AddTMIMEDataToMapSZ() instead */ +static void +QCBOREncode_AddMIMEDataToMap(QCBOREncodeContext *pCtx, + const char *szLabel, + UsefulBufC MIMEData); +/* Use QCBOREncode_AddTMIMEDataToMapN() instead */ +static void +QCBOREncode_AddMIMEDataToMapN(QCBOREncodeContext *pCtx, + int64_t nLabel, + UsefulBufC MIMEData); -/** - @brief Indicate whether output buffer is NULL or not. +/* Use QCBOREncode_AddTDateString() instead */ +static void +QCBOREncode_AddDateString(QCBOREncodeContext *pCtx, const char *szDate); - @param[in] pCtx The encoding context. +/* Use QCBOREncode_AddTDateStringToMapSZ() instead */ +static void +QCBOREncode_AddDateStringToMap(QCBOREncodeContext *pCtx, + const char *szLabel, + const char *szDate); - @return 1 if the output buffer is @c NULL. +/* Use QCBOREncode_AddTDateStringToMapN instead */ +static void +QCBOREncode_AddDateStringToMapN(QCBOREncodeContext *pCtx, + int64_t nLabel, + const char *szDate); - Sometimes a @c NULL input buffer is given to QCBOREncode_Init() so - that the size of the generated CBOR can be calculated without - allocating a buffer for it. This returns 1 when the output buffer is - NULL and 0 when it is not. -*/ -static int QCBOREncode_IsBufferNULL(QCBOREncodeContext *pCtx); +/* Use QCBOREncode_AddBoolToMapSZ() instead */ +static void +QCBOREncode_AddBoolToMap(QCBOREncodeContext *pCtx, const char *szLabel, bool b); +/* Use QCBOREncode_AddNULLToMapSZ() instead */ +static void +QCBOREncode_AddNULLToMap(QCBOREncodeContext *pCtx, const char *szLabel); -/** - @brief Get the encoding error state. +/* Use QCBOREncode_AddUndefToMapSZ() instead */ +static void +QCBOREncode_AddUndefToMap(QCBOREncodeContext *pCtx, const char *szLabel); - @param[in] pCtx The encoding context. +/* Use QCBOREncode_AddSimpleToMapSZ instead */ +static void +QCBOREncode_AddSimpleToMap(QCBOREncodeContext *pCtx, + const char *szLabel, + const uint8_t uSimple); - @return One of @ref QCBORError. See return values from - QCBOREncode_Finish() +/* Use QCBOREncode_OpenArrayInMapSZ() instead */ +static void +QCBOREncode_OpenArrayInMap(QCBOREncodeContext *pCtx, const char *szLabel); - Normally encoding errors need only be handled at the end of encoding - when QCBOREncode_Finish() is called. This can be called to get the - error result before finish should there be a need to halt encoding - before QCBOREncode_Finish() is called. -*/ -static QCBORError QCBOREncode_GetErrorState(QCBOREncodeContext *pCtx); +/* Use QCBOREncode_OpenMapInMapSZ() instead */ +static void +QCBOREncode_OpenMapInMap(QCBOREncodeContext *pCtx, const char *szLabel); +/* Use QCBOREncode_OpenArrayIndefiniteLengthInMapSZ() instead */ +static void +QCBOREncode_OpenArrayIndefiniteLengthInMap(QCBOREncodeContext *pCtx, + const char *szLabel); -/** - Encode the "head" of a CBOR data item. - - @param buffer Buffer to output the encoded head to; must be - @ref QCBOR_HEAD_BUFFER_SIZE bytes in size. - @param uMajorType One of CBOR_MAJOR_TYPE_XX. - @param uMinLen The minimum number of bytes to encode uNumber. Almost always - this is 0 to use preferred minimal encoding. If this is 4, - then even the values 0xffff and smaller will be encoded - in 4 bytes. This is used primarily when encoding a - float or double put into uNumber as the leading zero bytes - for them must be encoded. - @param uNumber The numeric argument part of the CBOR head. - @return Pointer and length of the encoded head or - @ref NULLUsefulBufC if the output buffer is too small. - - Callers do not to need to call this for normal CBOR encoding. Note that it doesn't even - take a @ref QCBOREncodeContext argument. - - This encodes the major type and argument part of a data item. The - argument is an integer that is usually either the value or the length - of the data item. - - This is exposed in the public interface to allow hashing of some CBOR - data types, bstr in particular, a chunk at a time so the full CBOR - doesn't have to be encoded in a contiguous buffer. - - For example, if you have a 100,000 byte binary blob in a buffer that - needs to be a bstr encoded and then hashed. You could allocate a - 100,010 byte buffer and encode it normally. Alternatively, you can - encode the head in a 10 byte buffer with this function, hash that and - then hash the 100,000 bytes using the same hash context. - - See also QCBOREncode_AddBytesLenOnly(); - */ -UsefulBufC QCBOREncode_EncodeHead(UsefulBuf buffer, - uint8_t uMajorType, - uint8_t uMinLen, - uint64_t uNumber); +/* Use QCBOREncode_OpenMapIndefiniteLengthInMapSZ() instead */ +static void +QCBOREncode_OpenMapIndefiniteLengthInMap(QCBOREncodeContext *pCtx, + const char *szLabel); +/* Use QCBOREncode_BstrWrapInMapSZ() instead */ +static void +QCBOREncode_BstrWrapInMap(QCBOREncodeContext *pCtx, const char *szLabel); +/* Use QCBOREncode_AddEncodedToMapSZ() instead */ +static void +QCBOREncode_AddEncodedToMap(QCBOREncodeContext *pCtx, const char *szLabel, UsefulBufC Encoded); -/* ========================================================================= - BEGINNING OF PRIVATE INLINE IMPLEMENTATION - ========================================================================= */ +/* ========================================================================= * + * END OF DEPRECATED FUNCTIONS * + * ========================================================================= */ -/** - @brief Semi-private method to add a buffer full of bytes to encoded output - - @param[in] pCtx The encoding context to add the integer to. - @param[in] uMajorType The CBOR major type of the bytes. - @param[in] Bytes The bytes to add. - - Use QCBOREncode_AddText() or QCBOREncode_AddBytes() or - QCBOREncode_AddEncoded() instead. They are inline functions that call - this and supply the correct major type. This function is public to - make the inline functions work to keep the overall code size down and - because the C language has no way to make it private. - - If this is called the major type should be @c - CBOR_MAJOR_TYPE_TEXT_STRING, @c CBOR_MAJOR_TYPE_BYTE_STRING or @c - CBOR_MAJOR_NONE_TYPE_RAW. The last one is special for adding - already-encoded CBOR. - */ -void QCBOREncode_AddBuffer(QCBOREncodeContext *pCtx, uint8_t uMajorType, UsefulBufC Bytes); -/** - @brief Semi-private method to open a map, array or bstr-wrapped CBOR - @param[in] pCtx The context to add to. - @param[in] uMajorType The major CBOR type to close - Call QCBOREncode_OpenArray(), QCBOREncode_OpenMap() or - QCBOREncode_BstrWrap() instead of this. - */ -void QCBOREncode_OpenMapOrArray(QCBOREncodeContext *pCtx, uint8_t uMajorType); +/* ========================================================================= * + * BEGINNING OF PRIVATE INLINE IMPLEMENTATION * + * ========================================================================= */ +/* Semi-private funcion used by public inline functions. See qcbor_encode.c */ +void QCBOREncode_Private_AppendCBORHead(QCBOREncodeContext *pMe, + const uint8_t uMajorType, + const uint64_t uArgument, + const uint8_t uMinLen); -/** - @brief Semi-private method to open a map, array with indefinite length - @param[in] pCtx The context to add to. - @param[in] uMajorType The major CBOR type to close +/* Semi-private funcion used by public inline functions. See qcbor_encode.c */ +void +QCBOREncode_Private_AddBuffer(QCBOREncodeContext *pCtx, + uint8_t uMajorType, + UsefulBufC Bytes); - Call QCBOREncode_OpenArrayIndefiniteLength() or - QCBOREncode_OpenMapIndefiniteLength() instead of this. - */ -void QCBOREncode_OpenMapOrArrayIndefiniteLength(QCBOREncodeContext *pCtx, uint8_t uMajorType); +/* Semi-private function for adding a double with preferred encoding. See qcbor_encode.c */ +void +QCBOREncode_Private_AddPreferredDouble(QCBOREncodeContext *pMe, const double dNum); -/** - @brief Semi-private method to close a map, array or bstr wrapped CBOR - @param[in] pCtx The context to add to. - @param[in] uMajorType The major CBOR type to close. +/* Semi-private function for adding a float with preferred encoding. See qcbor_encode.c */ +void +QCBOREncode_Private_AddPreferredFloat(QCBOREncodeContext *pMe, const float fNum); - Call QCBOREncode_CloseArray() or QCBOREncode_CloseMap() instead of this. - */ -void QCBOREncode_CloseMapOrArray(QCBOREncodeContext *pCtx, uint8_t uMajorType); +/* Semi-private funcion used by public inline functions. See qcbor_encode.c */ +void +QCBOREncode_Private_OpenMapOrArray(QCBOREncodeContext *pCtx, + uint8_t uMajorType); -/** - @brief Semi-private method to close a map, array with indefinite length - @param[in] pCtx The context to add to. - @param[in] uMajorType The major CBOR type to close. +/* Semi-private funcion used by public inline functions. See qcbor_encode.c */ +void +QCBOREncode_Private_OpenMapOrArrayIndefiniteLength(QCBOREncodeContext *pCtx, + uint8_t uMajorType); - Call QCBOREncode_CloseArrayIndefiniteLength() or - QCBOREncode_CloseMapIndefiniteLength() instead of this. - */ -void QCBOREncode_CloseMapOrArrayIndefiniteLength(QCBOREncodeContext *pCtx, - uint8_t uMajorType); +/* Semi-private funcion used by public inline functions. See qcbor_encode.c */ +void +QCBOREncode_Private_CloseMapOrArray(QCBOREncodeContext *pCtx, + uint8_t uMajorType); -/** - @brief Semi-private method to add simple types. - @param[in] pCtx The encoding context to add the simple value to. - @param[in] uMinLen Minimum encoding size for uNum. Usually 0. - @param[in] uNum One of CBOR_SIMPLEV_FALSE through _UNDEF or other. +/* Semi-private funcion used by public inline functions. See qcbor_encode.c */ +void +QCBOREncode_Private_CloseMapOrArrayIndefiniteLength(QCBOREncodeContext *pCtx, + uint8_t uMajorType); - This is used to add simple types like true and false. - Call QCBOREncode_AddBool(), QCBOREncode_AddNULL(), - QCBOREncode_AddUndef() instead of this. +/* Semi-private funcion used by public inline functions. See qcbor_encode.c */ +void +QCBOREncode_Private_AddExpMantissa(QCBOREncodeContext *pCtx, + uint64_t uTag, + UsefulBufC BigNumMantissa, + bool bBigNumIsNegative, + int64_t nMantissa, + int64_t nExponent); - This function can add simple values that are not defined by CBOR - yet. This expansion point in CBOR should not be used unless they are - standardized. - Error handling is the same as QCBOREncode_AddInt64(). +/** + * @brief Semi-private method to add simple items and floating-point. + * + * @param[in] pMe The encoding context. + * @param[in] uMinLen Minimum encoding size for uNum. Usually 0. + * @param[in] uArgument The value to add. + * + * This is used to add simple types like true and false and float-point + * values, both of which are type 7. + * + * Call QCBOREncode_AddBool(), QCBOREncode_AddNULL(), + * QCBOREncode_AddUndef() QCBOREncode_AddDouble() instead of this. + * + * Error handling is the same as QCBOREncode_AddInt64(). */ -void QCBOREncode_AddType7(QCBOREncodeContext *pCtx, uint8_t uMinLen, uint64_t uNum); +static inline void +QCBOREncode_Private_AddType7(QCBOREncodeContext *pMe, + const uint8_t uMinLen, + const uint64_t uArgument) +{ + QCBOREncode_Private_AppendCBORHead(pMe, CBOR_MAJOR_TYPE_SIMPLE, uArgument, uMinLen); +} /** - @brief Semi-private method to add bigfloats and decimal fractions. - - @param[in] pCtx The encoding context to add the value to. - @param[in] uTag The type 6 tag indicating what this is to be. - @param[in] BigNumMantissa Is @ref NULLUsefulBufC if mantissa is an - @c int64_t or the actual big number mantissa - if not. - @param[in] bBigNumIsNegative This is @c true if the big number is negative. - @param[in] nMantissa The @c int64_t mantissa if it is not a big number. - @param[in] nExponent The exponent. - - This outputs either the @ref CBOR_TAG_DECIMAL_FRACTION or @ref - CBOR_TAG_BIGFLOAT tag. if @c uTag is @ref CBOR_TAG_INVALID64, then - this outputs the "borrowed" content format. - - The tag content output by this is an array with two members, the - exponent and then the mantissa. The mantissa can be either a big - number or an @c int64_t. - - This implementation cannot output an exponent further from 0 than - @c INT64_MAX. - - To output a mantissa that is between INT64_MAX and UINT64_MAX from 0, - it must be as a big number. - - Typically, QCBOREncode_AddDecimalFraction(), QCBOREncode_AddBigFloat(), - QCBOREncode_AddDecimalFractionBigNum() or QCBOREncode_AddBigFloatBigNum() - is called instead of this. + * @brief Semi-private method to add only the type and length of a byte string. + * + * @param[in] pCtx The context to initialize. + * @param[in] Bytes Pointer and length of the input data. + * + * This will be removed in QCBOR 2.0. It was never a public function. + * + * This is the same as QCBOREncode_AddBytes() except it only adds the + * CBOR encoding for the type and the length. It doesn't actually add + * the bytes. You can't actually produce correct CBOR with this and + * the rest of this API. It is only used for a special case where the + * valid CBOR is created manually by putting this type and length in + * and then adding the actual bytes. In particular, when only a hash + * of the encoded CBOR is needed, where the type and header are hashed + * separately and then the bytes is hashed. This makes it possible to + * implement COSE Sign1 with only one copy of the payload in the + * output buffer, rather than two, roughly cutting memory use in half. + * + * This is only used for this odd case, but this is a supported + * tested function for QCBOR 1.0. + * + * See also QCBOREncode_EncodeHead(). */ -void QCBOREncode_AddExponentAndMantissa(QCBOREncodeContext *pCtx, - uint64_t uTag, - UsefulBufC BigNumMantissa, - bool bBigNumIsNegative, - int64_t nMantissa, - int64_t nExponent); +static void +QCBOREncode_AddBytesLenOnly(QCBOREncodeContext *pCtx, + UsefulBufC Bytes); -/** - @brief Semi-private method to add only the type and length of a byte string. +static void +QCBOREncode_AddBytesLenOnlyToMap(QCBOREncodeContext *pCtx, + const char *szLabel, + UsefulBufC Bytes); - @param[in] pCtx The context to initialize. - @param[in] Bytes Pointer and length of the input data. +static void +QCBOREncode_AddBytesLenOnlyToMapN(QCBOREncodeContext *pCtx, + int64_t nLabel, + UsefulBufC Bytes); - This is the same as QCBOREncode_AddBytes() except it only adds the - CBOR encoding for the type and the length. It doesn't actually add - the bytes. You can't actually produce correct CBOR with this and the - rest of this API. It is only used for a special case where - the valid CBOR is created manually by putting this type and length in - and then adding the actual bytes. In particular, when only a hash of - the encoded CBOR is needed, where the type and header are hashed - separately and then the bytes is hashed. This makes it possible to - implement COSE Sign1 with only one copy of the payload in the output - buffer, rather than two, roughly cutting memory use in half. - This is only used for this odd case, but this is a supported - tested function. +/* Forward declaration */ +static void +QCBOREncode_AddSZString(QCBOREncodeContext *pMe, const char *szString); - See also QCBOREncode_EncodeHead(). -*/ -static inline void QCBOREncode_AddBytesLenOnly(QCBOREncodeContext *pCtx, UsefulBufC Bytes); -static inline void QCBOREncode_AddBytesLenOnlyToMap(QCBOREncodeContext *pCtx, const char *szLabel, UsefulBufC Bytes); -static inline void QCBOREncode_AddBytesLenOnlyToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, UsefulBufC Bytes); +static inline void +QCBOREncode_AddInt64ToMapSZ(QCBOREncodeContext *pMe, + const char *szLabel, + const int64_t nNum) +{ + QCBOREncode_AddSZString(pMe, szLabel); + QCBOREncode_AddInt64(pMe, nNum); +} +static inline void +QCBOREncode_AddInt64ToMap(QCBOREncodeContext *pMe, const char *szLabel, int64_t nNum) +{ + QCBOREncode_AddInt64ToMapSZ(pMe, szLabel, nNum); +} +static inline void +QCBOREncode_AddInt64ToMapN(QCBOREncodeContext *pMe, + const int64_t nLabel, + const int64_t nNum) +{ + QCBOREncode_AddInt64(pMe, nLabel); + QCBOREncode_AddInt64(pMe, nNum); +} static inline void -QCBOREncode_AddInt64ToMap(QCBOREncodeContext *pMe, const char *szLabel, int64_t uNum) +QCBOREncode_AddUInt64(QCBOREncodeContext *pMe, const uint64_t uValue) { - // Use _AddBuffer() because _AddSZString() is defined below, not above - QCBOREncode_AddBuffer(pMe, CBOR_MAJOR_TYPE_TEXT_STRING, UsefulBuf_FromSZ(szLabel)); - QCBOREncode_AddInt64(pMe, uNum); + QCBOREncode_Private_AppendCBORHead(pMe, CBOR_MAJOR_TYPE_POSITIVE_INT, uValue, 0); } + static inline void -QCBOREncode_AddInt64ToMapN(QCBOREncodeContext *pMe, int64_t nLabel, int64_t uNum) +QCBOREncode_AddUInt64ToMapSZ(QCBOREncodeContext *pMe, + const char *szLabel, + const uint64_t uNum) { - QCBOREncode_AddInt64(pMe, nLabel); - QCBOREncode_AddInt64(pMe, uNum); + QCBOREncode_AddSZString(pMe, szLabel); + QCBOREncode_AddUInt64(pMe, uNum); } - static inline void QCBOREncode_AddUInt64ToMap(QCBOREncodeContext *pMe, const char *szLabel, uint64_t uNum) { - // Use _AddBuffer() because _AddSZString() is defined below, not above - QCBOREncode_AddBuffer(pMe, CBOR_MAJOR_TYPE_TEXT_STRING, UsefulBuf_FromSZ(szLabel)); - QCBOREncode_AddUInt64(pMe, uNum); + QCBOREncode_AddUInt64ToMapSZ(pMe, szLabel, uNum); } static inline void -QCBOREncode_AddUInt64ToMapN(QCBOREncodeContext *pMe, int64_t nLabel, uint64_t uNum) +QCBOREncode_AddUInt64ToMapN(QCBOREncodeContext *pMe, + const int64_t nLabel, + const uint64_t uNum) { QCBOREncode_AddInt64(pMe, nLabel); QCBOREncode_AddUInt64(pMe, uNum); @@ -2237,20 +2724,30 @@ QCBOREncode_AddUInt64ToMapN(QCBOREncodeContext *pMe, int64_t nLabel, uint64_t uN static inline void -QCBOREncode_AddText(QCBOREncodeContext *pMe, UsefulBufC Text) +QCBOREncode_AddText(QCBOREncodeContext *pMe, const UsefulBufC Text) { - QCBOREncode_AddBuffer(pMe, CBOR_MAJOR_TYPE_TEXT_STRING, Text); + QCBOREncode_Private_AddBuffer(pMe, CBOR_MAJOR_TYPE_TEXT_STRING, Text); } static inline void -QCBOREncode_AddTextToMap(QCBOREncodeContext *pMe, const char *szLabel, UsefulBufC Text) +QCBOREncode_AddTextToMapSZ(QCBOREncodeContext *pMe, + const char *szLabel, + const UsefulBufC Text) { QCBOREncode_AddText(pMe, UsefulBuf_FromSZ(szLabel)); QCBOREncode_AddText(pMe, Text); } static inline void -QCBOREncode_AddTextToMapN(QCBOREncodeContext *pMe, int64_t nLabel, UsefulBufC Text) +QCBOREncode_AddTextToMap(QCBOREncodeContext *pMe, const char *szLabel, UsefulBufC Text) +{ + QCBOREncode_AddTextToMapSZ(pMe, szLabel, Text); +} + +static inline void +QCBOREncode_AddTextToMapN(QCBOREncodeContext *pMe, + const int64_t nLabel, + const UsefulBufC Text) { QCBOREncode_AddInt64(pMe, nLabel); QCBOREncode_AddText(pMe, Text); @@ -2264,82 +2761,184 @@ QCBOREncode_AddSZString(QCBOREncodeContext *pMe, const char *szString) } static inline void -QCBOREncode_AddSZStringToMap(QCBOREncodeContext *pMe, const char *szLabel, const char *szString) +QCBOREncode_AddSZStringToMapSZ(QCBOREncodeContext *pMe, + const char *szLabel, + const char *szString) { QCBOREncode_AddSZString(pMe, szLabel); QCBOREncode_AddSZString(pMe, szString); } static inline void -QCBOREncode_AddSZStringToMapN(QCBOREncodeContext *pMe, int64_t nLabel, const char *szString) +QCBOREncode_AddSZStringToMap(QCBOREncodeContext *pMe, const char *szLabel, const char *szString) +{ + QCBOREncode_AddSZStringToMapSZ(pMe, szLabel, szString); +} + +static inline void +QCBOREncode_AddSZStringToMapN(QCBOREncodeContext *pMe, + const int64_t nLabel, + const char *szString) { QCBOREncode_AddInt64(pMe, nLabel); QCBOREncode_AddSZString(pMe, szString); } +static inline void +QCBOREncode_AddTag(QCBOREncodeContext *pMe, const uint64_t uTag) +{ + QCBOREncode_Private_AppendCBORHead(pMe, CBOR_MAJOR_TYPE_TAG, uTag, 0); +} + + + + #ifndef USEFULBUF_DISABLE_ALL_FLOAT + static inline void -QCBOREncode_AddDoubleToMap(QCBOREncodeContext *pMe, const char *szLabel, double dNum) +QCBOREncode_AddDoubleNoPreferred(QCBOREncodeContext *pMe, const double dNum) +{ + QCBOREncode_Private_AddType7(pMe, + sizeof(uint64_t), + UsefulBufUtil_CopyDoubleToUint64(dNum)); +} + +static inline void +QCBOREncode_AddFloatNoPreferred(QCBOREncodeContext *pMe, const float fNum) +{ + QCBOREncode_Private_AddType7(pMe, + sizeof(uint32_t), + UsefulBufUtil_CopyFloatToUint32(fNum)); +} + + +static inline void +QCBOREncode_AddDouble(QCBOREncodeContext *pMe, const double dNum) +{ +#ifndef QCBOR_DISABLE_PREFERRED_FLOAT + QCBOREncode_Private_AddPreferredDouble(pMe, dNum); +#else /* QCBOR_DISABLE_PREFERRED_FLOAT */ + QCBOREncode_AddDoubleNoPreferred(pMe, dNum); +#endif /* ! QCBOR_DISABLE_PREFERRED_FLOAT */ +} + +static inline void +QCBOREncode_AddDoubleToMapSZ(QCBOREncodeContext *pMe, + const char *szLabel, + const double dNum) { QCBOREncode_AddSZString(pMe, szLabel); QCBOREncode_AddDouble(pMe, dNum); } static inline void -QCBOREncode_AddDoubleToMapN(QCBOREncodeContext *pMe, int64_t nLabel, double dNum) +QCBOREncode_AddDoubleToMap(QCBOREncodeContext *pMe, const char *szLabel, double dNum) +{ + QCBOREncode_AddDoubleToMapSZ(pMe, szLabel, dNum); +} + +static inline void +QCBOREncode_AddDoubleToMapN(QCBOREncodeContext *pMe, + const int64_t nLabel, + const double dNum) { QCBOREncode_AddInt64(pMe, nLabel); QCBOREncode_AddDouble(pMe, dNum); } + +static inline void +QCBOREncode_AddFloat(QCBOREncodeContext *pMe, const float fNum) +{ +#ifndef QCBOR_DISABLE_PREFERRED_FLOAT + QCBOREncode_Private_AddPreferredFloat(pMe, fNum); +#else /* QCBOR_DISABLE_PREFERRED_FLOAT */ + QCBOREncode_AddFloatNoPreferred(pMe, fNum); +#endif /* ! QCBOR_DISABLE_PREFERRED_FLOAT */ +} + static inline void -QCBOREncode_AddFloatToMap(QCBOREncodeContext *pMe, const char *szLabel, float dNum) +QCBOREncode_AddFloatToMapSZ(QCBOREncodeContext *pMe, + const char *szLabel, + const float dNum) { QCBOREncode_AddSZString(pMe, szLabel); QCBOREncode_AddFloat(pMe, dNum); } static inline void -QCBOREncode_AddFloatToMapN(QCBOREncodeContext *pMe, int64_t nLabel, float fNum) +QCBOREncode_AddFloatToMap(QCBOREncodeContext *pMe, const char *szLabel, float fNum) +{ + QCBOREncode_AddFloatToMapSZ(pMe, szLabel, fNum); +} + +static inline void +QCBOREncode_AddFloatToMapN(QCBOREncodeContext *pMe, + const int64_t nLabel, + const float fNum) { QCBOREncode_AddInt64(pMe, nLabel); QCBOREncode_AddFloat(pMe, fNum); } static inline void -QCBOREncode_AddDoubleNoPreferredToMap(QCBOREncodeContext *pMe, const char *szLabel, double dNum) +QCBOREncode_AddDoubleNoPreferredToMapSZ(QCBOREncodeContext *pMe, + const char *szLabel, + const double dNum) { QCBOREncode_AddSZString(pMe, szLabel); QCBOREncode_AddDoubleNoPreferred(pMe, dNum); } static inline void -QCBOREncode_AddDoubleNoPreferredToMapN(QCBOREncodeContext *pMe, int64_t nLabel, double dNum) +QCBOREncode_AddDoubleNoPreferredToMap(QCBOREncodeContext *pMe, const char *szLabel, double dNum) +{ + QCBOREncode_AddDoubleNoPreferredToMapSZ(pMe, szLabel, dNum); +} + +static inline void +QCBOREncode_AddDoubleNoPreferredToMapN(QCBOREncodeContext *pMe, + const int64_t nLabel, + const double dNum) { QCBOREncode_AddInt64(pMe, nLabel); QCBOREncode_AddDoubleNoPreferred(pMe, dNum); } static inline void -QCBOREncode_AddFloatNoPreferredToMap(QCBOREncodeContext *pMe, const char *szLabel, float dNum) +QCBOREncode_AddFloatNoPreferredToMapSZ(QCBOREncodeContext *pMe, + const char *szLabel, + const float dNum) { QCBOREncode_AddSZString(pMe, szLabel); QCBOREncode_AddFloatNoPreferred(pMe, dNum); } static inline void -QCBOREncode_AddFloatNoPreferredToMapN(QCBOREncodeContext *pMe, int64_t nLabel, float dNum) +QCBOREncode_AddFloatNoPreferredToMap(QCBOREncodeContext *pMe, const char *szLabel, float fNum) +{ + QCBOREncode_AddFloatNoPreferredToMapSZ(pMe, szLabel, fNum); +} + +static inline void +QCBOREncode_AddFloatNoPreferredToMapN(QCBOREncodeContext *pMe, + const int64_t nLabel, + const float dNum) { QCBOREncode_AddInt64(pMe, nLabel); QCBOREncode_AddFloatNoPreferred(pMe, dNum); } -#endif /* USEFULBUF_DISABLE_ALL_FLOAT */ +#endif /* ! USEFULBUF_DISABLE_ALL_FLOAT */ + + static inline void -QCBOREncode_AddTDateEpoch(QCBOREncodeContext *pMe, uint8_t uTag, int64_t nDate) +QCBOREncode_AddTDateEpoch(QCBOREncodeContext *pMe, + const uint8_t uTag, + const int64_t nDate) { if(uTag == QCBOR_ENCODE_AS_TAG) { QCBOREncode_AddTag(pMe, CBOR_TAG_DATE_EPOCH); @@ -2348,34 +2947,45 @@ QCBOREncode_AddTDateEpoch(QCBOREncodeContext *pMe, uint8_t uTag, int64_t nDate) } static inline void -QCBOREncode_AddTDateEpochToMapSZ(QCBOREncodeContext *pMe, const char *szLabel, uint8_t uTag, int64_t nDate) +QCBOREncode_AddTDateEpochToMapSZ(QCBOREncodeContext *pMe, + const char *szLabel, + const uint8_t uTag, + const int64_t nDate) { QCBOREncode_AddSZString(pMe, szLabel); QCBOREncode_AddTDateEpoch(pMe, uTag, nDate); } static inline void -QCBOREncode_AddTDateEpochToMapN(QCBOREncodeContext *pMe, int64_t nLabel, uint8_t uTag, int64_t nDate) +QCBOREncode_AddTDateEpochToMapN(QCBOREncodeContext *pMe, + const int64_t nLabel, + const uint8_t uTag, + const int64_t nDate) { QCBOREncode_AddInt64(pMe, nLabel); QCBOREncode_AddTDateEpoch(pMe, uTag, nDate); } static inline void -QCBOREncode_AddDateEpoch(QCBOREncodeContext *pMe, int64_t nDate) +QCBOREncode_AddDateEpoch(QCBOREncodeContext *pMe, + const int64_t nDate) { QCBOREncode_AddTDateEpoch(pMe, QCBOR_ENCODE_AS_TAG, nDate); } static inline void -QCBOREncode_AddDateEpochToMap(QCBOREncodeContext *pMe, const char *szLabel, int64_t nDate) +QCBOREncode_AddDateEpochToMap(QCBOREncodeContext *pMe, + const char *szLabel, + const int64_t nDate) { QCBOREncode_AddSZString(pMe, szLabel); QCBOREncode_AddDateEpoch(pMe, nDate); } static inline void -QCBOREncode_AddDateEpochToMapN(QCBOREncodeContext *pMe, int64_t nLabel, int64_t nDate) +QCBOREncode_AddDateEpochToMapN(QCBOREncodeContext *pMe, + const int64_t nLabel, + const int64_t nDate) { QCBOREncode_AddInt64(pMe, nLabel); QCBOREncode_AddDateEpoch(pMe, nDate); @@ -2383,7 +2993,9 @@ QCBOREncode_AddDateEpochToMapN(QCBOREncodeContext *pMe, int64_t nLabel, int64_t static inline void -QCBOREncode_AddTDaysEpoch(QCBOREncodeContext *pMe, uint8_t uTag, int64_t nDays) +QCBOREncode_AddTDaysEpoch(QCBOREncodeContext *pMe, + const uint8_t uTag, + const int64_t nDays) { if(uTag == QCBOR_ENCODE_AS_TAG) { QCBOREncode_AddTag(pMe, CBOR_TAG_DAYS_EPOCH); @@ -2392,14 +3004,20 @@ QCBOREncode_AddTDaysEpoch(QCBOREncodeContext *pMe, uint8_t uTag, int64_t nDays) } static inline void -QCBOREncode_AddTDaysEpochToMapSZ(QCBOREncodeContext *pMe, const char *szLabel, uint8_t uTag, int64_t nDays) +QCBOREncode_AddTDaysEpochToMapSZ(QCBOREncodeContext *pMe, + const char *szLabel, + const uint8_t uTag, + const int64_t nDays) { QCBOREncode_AddSZString(pMe, szLabel); QCBOREncode_AddTDaysEpoch(pMe, uTag, nDays); } static inline void -QCBOREncode_AddTDaysEpochToMapN(QCBOREncodeContext *pMe, int64_t nLabel, uint8_t uTag, int64_t nDays) +QCBOREncode_AddTDaysEpochToMapN(QCBOREncodeContext *pMe, + const int64_t nLabel, + const uint8_t uTag, + const int64_t nDays) { QCBOREncode_AddInt64(pMe, nLabel); QCBOREncode_AddTDaysEpoch(pMe, uTag, nDays); @@ -2407,54 +3025,75 @@ QCBOREncode_AddTDaysEpochToMapN(QCBOREncodeContext *pMe, int64_t nLabel, uint8_t static inline void -QCBOREncode_AddBytes(QCBOREncodeContext *pMe, UsefulBufC Bytes) +QCBOREncode_AddBytes(QCBOREncodeContext *pMe, + const UsefulBufC Bytes) { - QCBOREncode_AddBuffer(pMe, CBOR_MAJOR_TYPE_BYTE_STRING, Bytes); + QCBOREncode_Private_AddBuffer(pMe, CBOR_MAJOR_TYPE_BYTE_STRING, Bytes); } static inline void -QCBOREncode_AddBytesToMap(QCBOREncodeContext *pMe, const char *szLabel, UsefulBufC Bytes) +QCBOREncode_AddBytesToMapSZ(QCBOREncodeContext *pMe, + const char *szLabel, + const UsefulBufC Bytes) { QCBOREncode_AddSZString(pMe, szLabel); QCBOREncode_AddBytes(pMe, Bytes); } static inline void -QCBOREncode_AddBytesToMapN(QCBOREncodeContext *pMe, int64_t nLabel, UsefulBufC Bytes) +QCBOREncode_AddBytesToMap(QCBOREncodeContext *pMe, const char *szLabel, UsefulBufC Bytes) +{ + QCBOREncode_AddBytesToMapSZ(pMe, szLabel, Bytes); +} + +static inline void +QCBOREncode_AddBytesToMapN(QCBOREncodeContext *pMe, + const int64_t nLabel, + const UsefulBufC Bytes) { QCBOREncode_AddInt64(pMe, nLabel); QCBOREncode_AddBytes(pMe, Bytes); } static inline void -QCBOREncode_OpenBytesInMapSZ(QCBOREncodeContext *pMe, const char *szLabel, UsefulBuf *pPlace) +QCBOREncode_OpenBytesInMapSZ(QCBOREncodeContext *pMe, + const char *szLabel, + UsefulBuf *pPlace) { QCBOREncode_AddSZString(pMe, szLabel); QCBOREncode_OpenBytes(pMe, pPlace); } static inline void -QCBOREncode_OpenBytesInMapN(QCBOREncodeContext *pMe, int64_t nLabel, UsefulBuf *pPlace) +QCBOREncode_OpenBytesInMapN(QCBOREncodeContext *pMe, + const int64_t nLabel, + UsefulBuf *pPlace) { QCBOREncode_AddInt64(pMe, nLabel); QCBOREncode_OpenBytes(pMe, pPlace); } + static inline void -QCBOREncode_AddBytesLenOnly(QCBOREncodeContext *pMe, UsefulBufC Bytes) +QCBOREncode_AddBytesLenOnly(QCBOREncodeContext *pMe, const UsefulBufC Bytes) { - QCBOREncode_AddBuffer(pMe, CBOR_MAJOR_NONE_TYPE_BSTR_LEN_ONLY, Bytes); + QCBOREncode_Private_AppendCBORHead(pMe, CBOR_MAJOR_TYPE_BYTE_STRING, Bytes.len, 0); } + static inline void -QCBOREncode_AddBytesLenOnlyToMap(QCBOREncodeContext *pMe, const char *szLabel, UsefulBufC Bytes) +QCBOREncode_AddBytesLenOnlyToMap(QCBOREncodeContext *pMe, + const char *szLabel, + const UsefulBufC Bytes) { QCBOREncode_AddSZString(pMe, szLabel); QCBOREncode_AddBytesLenOnly(pMe, Bytes); } static inline void -QCBOREncode_AddBytesLenOnlyToMapN(QCBOREncodeContext *pMe, int64_t nLabel, UsefulBufC Bytes) +QCBOREncode_AddBytesLenOnlyToMapN(QCBOREncodeContext *pMe, + const int64_t nLabel, + const UsefulBufC Bytes) { QCBOREncode_AddInt64(pMe, nLabel); QCBOREncode_AddBytesLenOnly(pMe, Bytes); @@ -2462,7 +3101,9 @@ QCBOREncode_AddBytesLenOnlyToMapN(QCBOREncodeContext *pMe, int64_t nLabel, Usefu static inline void -QCBOREncode_AddTBinaryUUID(QCBOREncodeContext *pMe, uint8_t uTagRequirement, UsefulBufC Bytes) +QCBOREncode_AddTBinaryUUID(QCBOREncodeContext *pMe, + const uint8_t uTagRequirement, + const UsefulBufC Bytes) { if(uTagRequirement == QCBOR_ENCODE_AS_TAG) { QCBOREncode_AddTag(pMe, CBOR_TAG_BIN_UUID); @@ -2473,41 +3114,53 @@ QCBOREncode_AddTBinaryUUID(QCBOREncodeContext *pMe, uint8_t uTagRequirement, Use static inline void QCBOREncode_AddTBinaryUUIDToMapSZ(QCBOREncodeContext *pMe, const char *szLabel, - uint8_t uTagRequirement, - UsefulBufC Bytes) + const uint8_t uTagRequirement, + const UsefulBufC Bytes) { QCBOREncode_AddSZString(pMe, szLabel); QCBOREncode_AddTBinaryUUID(pMe, uTagRequirement, Bytes); } static inline void -QCBOREncode_AddTBinaryUUIDToMapN(QCBOREncodeContext *pMe, int64_t nLabel, uint8_t uTagRequirement, UsefulBufC Bytes) +QCBOREncode_AddTBinaryUUIDToMapN(QCBOREncodeContext *pMe, + const int64_t nLabel, + const uint8_t uTagRequirement, + const UsefulBufC Bytes) { QCBOREncode_AddInt64(pMe, nLabel); QCBOREncode_AddTBinaryUUID(pMe, uTagRequirement, Bytes); } static inline void -QCBOREncode_AddBinaryUUID(QCBOREncodeContext *pMe, UsefulBufC Bytes) +QCBOREncode_AddBinaryUUID(QCBOREncodeContext *pMe, const UsefulBufC Bytes) { QCBOREncode_AddTBinaryUUID(pMe, QCBOR_ENCODE_AS_TAG, Bytes); } static inline void -QCBOREncode_AddBinaryUUIDToMap(QCBOREncodeContext *pMe, const char *szLabel, UsefulBufC Bytes) +QCBOREncode_AddBinaryUUIDToMap(QCBOREncodeContext *pMe, + const char *szLabel, + const UsefulBufC Bytes) { QCBOREncode_AddTBinaryUUIDToMapSZ(pMe, szLabel, QCBOR_ENCODE_AS_TAG, Bytes); } static inline void -QCBOREncode_AddBinaryUUIDToMapN(QCBOREncodeContext *pMe, int64_t nLabel, UsefulBufC Bytes) +QCBOREncode_AddBinaryUUIDToMapN(QCBOREncodeContext *pMe, + const int64_t nLabel, + const UsefulBufC Bytes) { - QCBOREncode_AddTBinaryUUIDToMapN(pMe, nLabel, QCBOR_ENCODE_AS_TAG, Bytes); + QCBOREncode_AddTBinaryUUIDToMapN(pMe, + nLabel, + QCBOR_ENCODE_AS_TAG, + Bytes); } static inline void -QCBOREncode_AddTPositiveBignum(QCBOREncodeContext *pMe, uint8_t uTagRequirement, UsefulBufC Bytes) +QCBOREncode_AddTPositiveBignum(QCBOREncodeContext *pMe, + const uint8_t uTagRequirement, + const UsefulBufC Bytes) { if(uTagRequirement == QCBOR_ENCODE_AS_TAG) { QCBOREncode_AddTag(pMe, CBOR_TAG_POS_BIGNUM); @@ -2518,41 +3171,56 @@ QCBOREncode_AddTPositiveBignum(QCBOREncodeContext *pMe, uint8_t uTagRequirement, static inline void QCBOREncode_AddTPositiveBignumToMapSZ(QCBOREncodeContext *pMe, const char *szLabel, - uint8_t uTagRequirement, - UsefulBufC Bytes) + const uint8_t uTagRequirement, + const UsefulBufC Bytes) { QCBOREncode_AddSZString(pMe, szLabel); QCBOREncode_AddTPositiveBignum(pMe, uTagRequirement, Bytes); } static inline void -QCBOREncode_AddTPositiveBignumToMapN(QCBOREncodeContext *pMe, int64_t nLabel, uint8_t uTagRequirement, UsefulBufC Bytes) +QCBOREncode_AddTPositiveBignumToMapN(QCBOREncodeContext *pMe, + const int64_t nLabel, + const uint8_t uTagRequirement, + const UsefulBufC Bytes) { QCBOREncode_AddInt64(pMe, nLabel); QCBOREncode_AddTPositiveBignum(pMe, uTagRequirement, Bytes); } static inline void -QCBOREncode_AddPositiveBignum(QCBOREncodeContext *pMe, UsefulBufC Bytes) +QCBOREncode_AddPositiveBignum(QCBOREncodeContext *pMe, const UsefulBufC Bytes) { QCBOREncode_AddTPositiveBignum(pMe, QCBOR_ENCODE_AS_TAG, Bytes); } static inline void -QCBOREncode_AddPositiveBignumToMap(QCBOREncodeContext *pMe, const char *szLabel, UsefulBufC Bytes) +QCBOREncode_AddPositiveBignumToMap(QCBOREncodeContext *pMe, + const char *szLabel, + const UsefulBufC Bytes) { - QCBOREncode_AddTPositiveBignumToMapSZ(pMe, szLabel, QCBOR_ENCODE_AS_TAG, Bytes); + QCBOREncode_AddTPositiveBignumToMapSZ(pMe, + szLabel, + QCBOR_ENCODE_AS_TAG, + Bytes); } static inline void -QCBOREncode_AddPositiveBignumToMapN(QCBOREncodeContext *pMe, int64_t nLabel, UsefulBufC Bytes) +QCBOREncode_AddPositiveBignumToMapN(QCBOREncodeContext *pMe, + const int64_t nLabel, + const UsefulBufC Bytes) { - QCBOREncode_AddTPositiveBignumToMapN(pMe, nLabel, QCBOR_ENCODE_AS_TAG, Bytes); + QCBOREncode_AddTPositiveBignumToMapN(pMe, + nLabel, + QCBOR_ENCODE_AS_TAG, + Bytes); } static inline void -QCBOREncode_AddTNegativeBignum(QCBOREncodeContext *pMe, uint8_t uTagRequirement, UsefulBufC Bytes) +QCBOREncode_AddTNegativeBignum(QCBOREncodeContext *pMe, + const uint8_t uTagRequirement, + const UsefulBufC Bytes) { if(uTagRequirement == QCBOR_ENCODE_AS_TAG) { QCBOREncode_AddTag(pMe, CBOR_TAG_NEG_BIGNUM); @@ -2563,36 +3231,49 @@ QCBOREncode_AddTNegativeBignum(QCBOREncodeContext *pMe, uint8_t uTagRequirement, static inline void QCBOREncode_AddTNegativeBignumToMapSZ(QCBOREncodeContext *pMe, const char *szLabel, - uint8_t uTagRequirement, - UsefulBufC Bytes) + const uint8_t uTagRequirement, + const UsefulBufC Bytes) { QCBOREncode_AddSZString(pMe, szLabel); QCBOREncode_AddTNegativeBignum(pMe, uTagRequirement, Bytes); } static inline void -QCBOREncode_AddTNegativeBignumToMapN(QCBOREncodeContext *pMe, int64_t nLabel, uint8_t uTagRequirement, UsefulBufC Bytes) +QCBOREncode_AddTNegativeBignumToMapN(QCBOREncodeContext *pMe, + const int64_t nLabel, + const uint8_t uTagRequirement, + const UsefulBufC Bytes) { QCBOREncode_AddInt64(pMe, nLabel); QCBOREncode_AddTNegativeBignum(pMe, uTagRequirement, Bytes); } static inline void -QCBOREncode_AddNegativeBignum(QCBOREncodeContext *pMe, UsefulBufC Bytes) +QCBOREncode_AddNegativeBignum(QCBOREncodeContext *pMe, const UsefulBufC Bytes) { QCBOREncode_AddTNegativeBignum(pMe, QCBOR_ENCODE_AS_TAG, Bytes); } static inline void -QCBOREncode_AddNegativeBignumToMap(QCBOREncodeContext *pMe, const char *szLabel, UsefulBufC Bytes) +QCBOREncode_AddNegativeBignumToMap(QCBOREncodeContext *pMe, + const char *szLabel, + const UsefulBufC Bytes) { - QCBOREncode_AddTNegativeBignumToMapSZ(pMe, szLabel, QCBOR_ENCODE_AS_TAG, Bytes); + QCBOREncode_AddTNegativeBignumToMapSZ(pMe, + szLabel, + QCBOR_ENCODE_AS_TAG, + Bytes); } static inline void -QCBOREncode_AddNegativeBignumToMapN(QCBOREncodeContext *pMe, int64_t nLabel, UsefulBufC Bytes) +QCBOREncode_AddNegativeBignumToMapN(QCBOREncodeContext *pMe, + const int64_t nLabel, + const UsefulBufC Bytes) { - QCBOREncode_AddTNegativeBignumToMapN(pMe, nLabel, QCBOR_ENCODE_AS_TAG, Bytes); + QCBOREncode_AddTNegativeBignumToMapN(pMe, + nLabel, + QCBOR_ENCODE_AS_TAG, + Bytes); } @@ -2601,9 +3282,9 @@ QCBOREncode_AddNegativeBignumToMapN(QCBOREncodeContext *pMe, int64_t nLabel, Use static inline void QCBOREncode_AddTDecimalFraction(QCBOREncodeContext *pMe, - uint8_t uTagRequirement, - int64_t nMantissa, - int64_t nBase10Exponent) + const uint8_t uTagRequirement, + const int64_t nMantissa, + const int64_t nBase10Exponent) { uint64_t uTag; if(uTagRequirement == QCBOR_ENCODE_AS_TAG) { @@ -2611,7 +3292,7 @@ QCBOREncode_AddTDecimalFraction(QCBOREncodeContext *pMe, } else { uTag = CBOR_TAG_INVALID64; } - QCBOREncode_AddExponentAndMantissa(pMe, + QCBOREncode_Private_AddExpMantissa(pMe, uTag, NULLUsefulBufC, false, @@ -2622,59 +3303,76 @@ QCBOREncode_AddTDecimalFraction(QCBOREncodeContext *pMe, static inline void QCBOREncode_AddTDecimalFractionToMapSZ(QCBOREncodeContext *pMe, const char *szLabel, - uint8_t uTagRequirement, - int64_t nMantissa, - int64_t nBase10Exponent) + const uint8_t uTagRequirement, + const int64_t nMantissa, + const int64_t nBase10Exponent) { QCBOREncode_AddSZString(pMe, szLabel); - QCBOREncode_AddTDecimalFraction(pMe, uTagRequirement, nMantissa, nBase10Exponent); + QCBOREncode_AddTDecimalFraction(pMe, + uTagRequirement, + nMantissa, + nBase10Exponent); } static inline void QCBOREncode_AddTDecimalFractionToMapN(QCBOREncodeContext *pMe, - int64_t nLabel, - uint8_t uTagRequirement, - int64_t nMantissa, - int64_t nBase10Exponent) + const int64_t nLabel, + const uint8_t uTagRequirement, + const int64_t nMantissa, + const int64_t nBase10Exponent) { QCBOREncode_AddInt64(pMe, nLabel); - QCBOREncode_AddTDecimalFraction(pMe, uTagRequirement, nMantissa, nBase10Exponent); + QCBOREncode_AddTDecimalFraction(pMe, + uTagRequirement, + nMantissa, + nBase10Exponent); } static inline void QCBOREncode_AddDecimalFraction(QCBOREncodeContext *pMe, - int64_t nMantissa, - int64_t nBase10Exponent) + const int64_t nMantissa, + const int64_t nBase10Exponent) { - QCBOREncode_AddTDecimalFraction(pMe, QCBOR_ENCODE_AS_TAG, nMantissa, nBase10Exponent); + QCBOREncode_AddTDecimalFraction(pMe, + QCBOR_ENCODE_AS_TAG, + nMantissa, + nBase10Exponent); } static inline void QCBOREncode_AddDecimalFractionToMap(QCBOREncodeContext *pMe, const char *szLabel, - int64_t nMantissa, - int64_t nBase10Exponent) + const int64_t nMantissa, + const int64_t nBase10Exponent) { - QCBOREncode_AddTDecimalFractionToMapSZ(pMe, szLabel, QCBOR_ENCODE_AS_TAG, nMantissa, nBase10Exponent); + QCBOREncode_AddTDecimalFractionToMapSZ(pMe, + szLabel, + QCBOR_ENCODE_AS_TAG, + nMantissa, + nBase10Exponent); } static inline void QCBOREncode_AddDecimalFractionToMapN(QCBOREncodeContext *pMe, - int64_t nLabel, - int64_t nMantissa, - int64_t nBase10Exponent) + const int64_t nLabel, + const int64_t nMantissa, + const int64_t nBase10Exponent) { - QCBOREncode_AddTDecimalFractionToMapN(pMe, nLabel, QCBOR_ENCODE_AS_TAG, nMantissa, nBase10Exponent); + QCBOREncode_AddTDecimalFractionToMapN(pMe, + nLabel, + QCBOR_ENCODE_AS_TAG, + nMantissa, + nBase10Exponent); } static inline void QCBOREncode_AddTDecimalFractionBigNum(QCBOREncodeContext *pMe, - uint8_t uTagRequirement, - UsefulBufC Mantissa, - bool bIsNegative, - int64_t nBase10Exponent) + const uint8_t uTagRequirement, + const UsefulBufC Mantissa, + const bool bIsNegative, + const int64_t nBase10Exponent) { uint64_t uTag; if(uTagRequirement == QCBOR_ENCODE_AS_TAG) { @@ -2682,9 +3380,10 @@ QCBOREncode_AddTDecimalFractionBigNum(QCBOREncodeContext *pMe, } else { uTag = CBOR_TAG_INVALID64; } - QCBOREncode_AddExponentAndMantissa(pMe, + QCBOREncode_Private_AddExpMantissa(pMe, uTag, - Mantissa, bIsNegative, + Mantissa, + bIsNegative, 0, nBase10Exponent); } @@ -2692,42 +3391,54 @@ QCBOREncode_AddTDecimalFractionBigNum(QCBOREncodeContext *pMe, static inline void QCBOREncode_AddTDecimalFractionBigNumToMapSZ(QCBOREncodeContext *pMe, const char *szLabel, - uint8_t uTagRequirement, - UsefulBufC Mantissa, - bool bIsNegative, - int64_t nBase10Exponent) + const uint8_t uTagRequirement, + const UsefulBufC Mantissa, + const bool bIsNegative, + const int64_t nBase10Exponent) { QCBOREncode_AddSZString(pMe, szLabel); - QCBOREncode_AddTDecimalFractionBigNum(pMe, uTagRequirement, Mantissa, bIsNegative, nBase10Exponent); + QCBOREncode_AddTDecimalFractionBigNum(pMe, + uTagRequirement, + Mantissa, + bIsNegative, + nBase10Exponent); } static inline void QCBOREncode_AddTDecimalFractionBigNumToMapN(QCBOREncodeContext *pMe, - int64_t nLabel, - uint8_t uTagRequirement, - UsefulBufC Mantissa, - bool bIsNegative, - int64_t nBase10Exponent) + const int64_t nLabel, + const uint8_t uTagRequirement, + const UsefulBufC Mantissa, + const bool bIsNegative, + const int64_t nBase10Exponent) { QCBOREncode_AddInt64(pMe, nLabel); - QCBOREncode_AddTDecimalFractionBigNum(pMe, uTagRequirement, Mantissa, bIsNegative, nBase10Exponent); + QCBOREncode_AddTDecimalFractionBigNum(pMe, + uTagRequirement, + Mantissa, + bIsNegative, + nBase10Exponent); } static inline void QCBOREncode_AddDecimalFractionBigNum(QCBOREncodeContext *pMe, - UsefulBufC Mantissa, - bool bIsNegative, - int64_t nBase10Exponent) + const UsefulBufC Mantissa, + const bool bIsNegative, + const int64_t nBase10Exponent) { - QCBOREncode_AddTDecimalFractionBigNum(pMe, QCBOR_ENCODE_AS_TAG, Mantissa, bIsNegative, nBase10Exponent); + QCBOREncode_AddTDecimalFractionBigNum(pMe, + QCBOR_ENCODE_AS_TAG, + Mantissa, + bIsNegative, + nBase10Exponent); } static inline void QCBOREncode_AddDecimalFractionBigNumToMapSZ(QCBOREncodeContext *pMe, const char *szLabel, - UsefulBufC Mantissa, - bool bIsNegative, - int64_t nBase10Exponent) + const UsefulBufC Mantissa, + const bool bIsNegative, + const int64_t nBase10Exponent) { QCBOREncode_AddTDecimalFractionBigNumToMapSZ(pMe, szLabel, @@ -2739,10 +3450,10 @@ QCBOREncode_AddDecimalFractionBigNumToMapSZ(QCBOREncodeContext *pMe, static inline void QCBOREncode_AddDecimalFractionBigNumToMapN(QCBOREncodeContext *pMe, - int64_t nLabel, - UsefulBufC Mantissa, - bool bIsNegative, - int64_t nBase2Exponent) + const int64_t nLabel, + const UsefulBufC Mantissa, + const bool bIsNegative, + const int64_t nBase2Exponent) { QCBOREncode_AddTDecimalFractionBigNumToMapN(pMe, nLabel, @@ -2758,9 +3469,9 @@ QCBOREncode_AddDecimalFractionBigNumToMapN(QCBOREncodeContext *pMe, static inline void QCBOREncode_AddTBigFloat(QCBOREncodeContext *pMe, - uint8_t uTagRequirement, - int64_t nMantissa, - int64_t nBase2Exponent) + const uint8_t uTagRequirement, + const int64_t nMantissa, + const int64_t nBase2Exponent) { uint64_t uTag; if(uTagRequirement == QCBOR_ENCODE_AS_TAG) { @@ -2768,15 +3479,20 @@ QCBOREncode_AddTBigFloat(QCBOREncodeContext *pMe, } else { uTag = CBOR_TAG_INVALID64; } - QCBOREncode_AddExponentAndMantissa(pMe, uTag, NULLUsefulBufC, false, nMantissa, nBase2Exponent); + QCBOREncode_Private_AddExpMantissa(pMe, + uTag, + NULLUsefulBufC, + false, + nMantissa, + nBase2Exponent); } static inline void QCBOREncode_AddTBigFloatToMapSZ(QCBOREncodeContext *pMe, const char *szLabel, - uint8_t uTagRequirement, - int64_t nMantissa, - int64_t nBase2Exponent) + const uint8_t uTagRequirement, + const int64_t nMantissa, + const int64_t nBase2Exponent) { QCBOREncode_AddSZString(pMe, szLabel); QCBOREncode_AddTBigFloat(pMe, uTagRequirement, nMantissa, nBase2Exponent); @@ -2784,10 +3500,10 @@ QCBOREncode_AddTBigFloatToMapSZ(QCBOREncodeContext *pMe, static inline void QCBOREncode_AddTBigFloatToMapN(QCBOREncodeContext *pMe, - int64_t nLabel, - uint8_t uTagRequirement, - int64_t nMantissa, - int64_t nBase2Exponent) + const int64_t nLabel, + const uint8_t uTagRequirement, + const int64_t nMantissa, + const int64_t nBase2Exponent) { QCBOREncode_AddInt64(pMe, nLabel); QCBOREncode_AddTBigFloat(pMe, uTagRequirement, nMantissa, nBase2Exponent); @@ -2795,38 +3511,49 @@ QCBOREncode_AddTBigFloatToMapN(QCBOREncodeContext *pMe, static inline void QCBOREncode_AddBigFloat(QCBOREncodeContext *pMe, - int64_t nMantissa, - int64_t nBase2Exponent) + const int64_t nMantissa, + const int64_t nBase2Exponent) { - QCBOREncode_AddTBigFloat(pMe, QCBOR_ENCODE_AS_TAG, nMantissa, nBase2Exponent); + QCBOREncode_AddTBigFloat(pMe, + QCBOR_ENCODE_AS_TAG, + nMantissa, + nBase2Exponent); } static inline void QCBOREncode_AddBigFloatToMap(QCBOREncodeContext *pMe, const char *szLabel, - int64_t nMantissa, - int64_t nBase2Exponent) + const int64_t nMantissa, + const int64_t nBase2Exponent) { - QCBOREncode_AddTBigFloatToMapSZ(pMe, szLabel, QCBOR_ENCODE_AS_TAG, nMantissa, nBase2Exponent); + QCBOREncode_AddTBigFloatToMapSZ(pMe, + szLabel, + QCBOR_ENCODE_AS_TAG, + nMantissa, + nBase2Exponent); } static inline void QCBOREncode_AddBigFloatToMapN(QCBOREncodeContext *pMe, - int64_t nLabel, - int64_t nMantissa, - int64_t nBase2Exponent) + const int64_t nLabel, + const int64_t nMantissa, + const int64_t nBase2Exponent) { - QCBOREncode_AddTBigFloatToMapN(pMe, nLabel, QCBOR_ENCODE_AS_TAG, nMantissa, nBase2Exponent); + QCBOREncode_AddTBigFloatToMapN(pMe, + nLabel, + QCBOR_ENCODE_AS_TAG, + nMantissa, + nBase2Exponent); } static inline void QCBOREncode_AddTBigFloatBigNum(QCBOREncodeContext *pMe, - uint8_t uTagRequirement, - UsefulBufC Mantissa, - bool bIsNegative, - int64_t nBase2Exponent) + const uint8_t uTagRequirement, + const UsefulBufC Mantissa, + const bool bIsNegative, + const int64_t nBase2Exponent) { uint64_t uTag; if(uTagRequirement == QCBOR_ENCODE_AS_TAG) { @@ -2834,67 +3561,95 @@ QCBOREncode_AddTBigFloatBigNum(QCBOREncodeContext *pMe, } else { uTag = CBOR_TAG_INVALID64; } - QCBOREncode_AddExponentAndMantissa(pMe, uTag, Mantissa, bIsNegative, 0, nBase2Exponent); + QCBOREncode_Private_AddExpMantissa(pMe, + uTag, + Mantissa, + bIsNegative, + 0, + nBase2Exponent); } static inline void QCBOREncode_AddTBigFloatBigNumToMapSZ(QCBOREncodeContext *pMe, const char *szLabel, - uint8_t uTagRequirement, - UsefulBufC Mantissa, - bool bIsNegative, - int64_t nBase2Exponent) + const uint8_t uTagRequirement, + const UsefulBufC Mantissa, + const bool bIsNegative, + const int64_t nBase2Exponent) { QCBOREncode_AddSZString(pMe, szLabel); - QCBOREncode_AddTBigFloatBigNum(pMe, uTagRequirement, Mantissa, bIsNegative, nBase2Exponent); + QCBOREncode_AddTBigFloatBigNum(pMe, + uTagRequirement, + Mantissa, + bIsNegative, + nBase2Exponent); } static inline void QCBOREncode_AddTBigFloatBigNumToMapN(QCBOREncodeContext *pMe, - int64_t nLabel, - uint8_t uTagRequirement, - UsefulBufC Mantissa, - bool bIsNegative, - int64_t nBase2Exponent) + const int64_t nLabel, + const uint8_t uTagRequirement, + const UsefulBufC Mantissa, + const bool bIsNegative, + const int64_t nBase2Exponent) { QCBOREncode_AddInt64(pMe, nLabel); - QCBOREncode_AddTBigFloatBigNum(pMe, uTagRequirement, Mantissa, bIsNegative, nBase2Exponent); + QCBOREncode_AddTBigFloatBigNum(pMe, + uTagRequirement, + Mantissa, + bIsNegative, + nBase2Exponent); } static inline void QCBOREncode_AddBigFloatBigNum(QCBOREncodeContext *pMe, - UsefulBufC Mantissa, - bool bIsNegative, - int64_t nBase2Exponent) + const UsefulBufC Mantissa, + const bool bIsNegative, + const int64_t nBase2Exponent) { - QCBOREncode_AddTBigFloatBigNum(pMe, QCBOR_ENCODE_AS_TAG, Mantissa, bIsNegative, nBase2Exponent); + QCBOREncode_AddTBigFloatBigNum(pMe, + QCBOR_ENCODE_AS_TAG, + Mantissa, bIsNegative, + nBase2Exponent); } static inline void QCBOREncode_AddBigFloatBigNumToMap(QCBOREncodeContext *pMe, const char *szLabel, - UsefulBufC Mantissa, - bool bIsNegative, - int64_t nBase2Exponent) + const UsefulBufC Mantissa, + const bool bIsNegative, + const int64_t nBase2Exponent) { - QCBOREncode_AddTBigFloatBigNumToMapSZ(pMe, szLabel, QCBOR_ENCODE_AS_TAG, Mantissa, bIsNegative, nBase2Exponent); + QCBOREncode_AddTBigFloatBigNumToMapSZ(pMe, + szLabel, + QCBOR_ENCODE_AS_TAG, + Mantissa, + bIsNegative, + nBase2Exponent); } static inline void QCBOREncode_AddBigFloatBigNumToMapN(QCBOREncodeContext *pMe, - int64_t nLabel, - UsefulBufC Mantissa, - bool bIsNegative, - int64_t nBase2Exponent) + const int64_t nLabel, + const UsefulBufC Mantissa, + const bool bIsNegative, + const int64_t nBase2Exponent) { - QCBOREncode_AddTBigFloatBigNumToMapN(pMe, nLabel, QCBOR_ENCODE_AS_TAG, Mantissa, bIsNegative, nBase2Exponent); + QCBOREncode_AddTBigFloatBigNumToMapN(pMe, + nLabel, + QCBOR_ENCODE_AS_TAG, + Mantissa, + bIsNegative, + nBase2Exponent); } -#endif /* QCBOR_DISABLE_EXP_AND_MANTISSA */ +#endif /* ! QCBOR_DISABLE_EXP_AND_MANTISSA */ static inline void -QCBOREncode_AddTURI(QCBOREncodeContext *pMe, uint8_t uTagRequirement, UsefulBufC URI) +QCBOREncode_AddTURI(QCBOREncodeContext *pMe, + const uint8_t uTagRequirement, + const UsefulBufC URI) { if(uTagRequirement == QCBOR_ENCODE_AS_TAG) { QCBOREncode_AddTag(pMe, CBOR_TAG_URI); @@ -2903,33 +3658,43 @@ QCBOREncode_AddTURI(QCBOREncodeContext *pMe, uint8_t uTagRequirement, UsefulBufC } static inline void -QCBOREncode_AddTURIToMapSZ(QCBOREncodeContext *pMe, const char *szLabel, uint8_t uTagRequirement, UsefulBufC URI) +QCBOREncode_AddTURIToMapSZ(QCBOREncodeContext *pMe, + const char *szLabel, + const uint8_t uTagRequirement, + const UsefulBufC URI) { QCBOREncode_AddSZString(pMe, szLabel); QCBOREncode_AddTURI(pMe, uTagRequirement, URI); } static inline void -QCBOREncode_AddTURIToMapN(QCBOREncodeContext *pMe, int64_t nLabel, uint8_t uTagRequirement, UsefulBufC URI) +QCBOREncode_AddTURIToMapN(QCBOREncodeContext *pMe, + const int64_t nLabel, + const uint8_t uTagRequirement, + const UsefulBufC URI) { QCBOREncode_AddInt64(pMe, nLabel); QCBOREncode_AddTURI(pMe, uTagRequirement, URI); } static inline void -QCBOREncode_AddURI(QCBOREncodeContext *pMe, UsefulBufC URI) +QCBOREncode_AddURI(QCBOREncodeContext *pMe, const UsefulBufC URI) { QCBOREncode_AddTURI(pMe, QCBOR_ENCODE_AS_TAG, URI); } static inline void -QCBOREncode_AddURIToMap(QCBOREncodeContext *pMe, const char *szLabel, UsefulBufC URI) +QCBOREncode_AddURIToMap(QCBOREncodeContext *pMe, + const char *szLabel, + const UsefulBufC URI) { QCBOREncode_AddTURIToMapSZ(pMe, szLabel, QCBOR_ENCODE_AS_TAG, URI); } static inline void -QCBOREncode_AddURIToMapN(QCBOREncodeContext *pMe, int64_t nLabel, UsefulBufC URI) +QCBOREncode_AddURIToMapN(QCBOREncodeContext *pMe, + const int64_t nLabel, + const UsefulBufC URI) { QCBOREncode_AddTURIToMapN(pMe, nLabel, QCBOR_ENCODE_AS_TAG, URI); } @@ -2937,7 +3702,9 @@ QCBOREncode_AddURIToMapN(QCBOREncodeContext *pMe, int64_t nLabel, UsefulBufC URI static inline void -QCBOREncode_AddTB64Text(QCBOREncodeContext *pMe, uint8_t uTagRequirement, UsefulBufC B64Text) +QCBOREncode_AddTB64Text(QCBOREncodeContext *pMe, + const uint8_t uTagRequirement, + const UsefulBufC B64Text) { if(uTagRequirement == QCBOR_ENCODE_AS_TAG) { QCBOREncode_AddTag(pMe, CBOR_TAG_B64); @@ -2948,34 +3715,41 @@ QCBOREncode_AddTB64Text(QCBOREncodeContext *pMe, uint8_t uTagRequirement, Useful static inline void QCBOREncode_AddTB64TextToMapSZ(QCBOREncodeContext *pMe, const char *szLabel, - uint8_t uTagRequirement, - UsefulBufC B64Text) + const uint8_t uTagRequirement, + const UsefulBufC B64Text) { QCBOREncode_AddSZString(pMe, szLabel); QCBOREncode_AddTB64Text(pMe, uTagRequirement, B64Text); } static inline void -QCBOREncode_AddTB64TextToMapN(QCBOREncodeContext *pMe, int64_t nLabel, uint8_t uTagRequirement, UsefulBufC B64Text) +QCBOREncode_AddTB64TextToMapN(QCBOREncodeContext *pMe, + const int64_t nLabel, + const uint8_t uTagRequirement, + const UsefulBufC B64Text) { QCBOREncode_AddInt64(pMe, nLabel); QCBOREncode_AddTB64Text(pMe, uTagRequirement, B64Text); } static inline void -QCBOREncode_AddB64Text(QCBOREncodeContext *pMe, UsefulBufC B64Text) +QCBOREncode_AddB64Text(QCBOREncodeContext *pMe, const UsefulBufC B64Text) { QCBOREncode_AddTB64Text(pMe, QCBOR_ENCODE_AS_TAG, B64Text); } static inline void -QCBOREncode_AddB64TextToMap(QCBOREncodeContext *pMe, const char *szLabel, UsefulBufC B64Text) +QCBOREncode_AddB64TextToMap(QCBOREncodeContext *pMe, + const char *szLabel, + const UsefulBufC B64Text) { QCBOREncode_AddTB64TextToMapSZ(pMe, szLabel, QCBOR_ENCODE_AS_TAG, B64Text); } static inline void -QCBOREncode_AddB64TextToMapN(QCBOREncodeContext *pMe, int64_t nLabel, UsefulBufC B64Text) +QCBOREncode_AddB64TextToMapN(QCBOREncodeContext *pMe, + const int64_t nLabel, + const UsefulBufC B64Text) { QCBOREncode_AddTB64TextToMapN(pMe, nLabel, QCBOR_ENCODE_AS_TAG, B64Text); } @@ -2983,7 +3757,9 @@ QCBOREncode_AddB64TextToMapN(QCBOREncodeContext *pMe, int64_t nLabel, UsefulBufC static inline void -QCBOREncode_AddTB64URLText(QCBOREncodeContext *pMe, uint8_t uTagRequirement, UsefulBufC B64Text) +QCBOREncode_AddTB64URLText(QCBOREncodeContext *pMe, + const uint8_t uTagRequirement, + const UsefulBufC B64Text) { if(uTagRequirement == QCBOR_ENCODE_AS_TAG) { QCBOREncode_AddTag(pMe, CBOR_TAG_B64URL); @@ -2994,34 +3770,44 @@ QCBOREncode_AddTB64URLText(QCBOREncodeContext *pMe, uint8_t uTagRequirement, Use static inline void QCBOREncode_AddTB64URLTextToMapSZ(QCBOREncodeContext *pMe, const char *szLabel, - uint8_t uTagRequirement, - UsefulBufC B64Text) + const uint8_t uTagRequirement, + const UsefulBufC B64Text) { QCBOREncode_AddSZString(pMe, szLabel); QCBOREncode_AddTB64URLText(pMe, uTagRequirement, B64Text); } static inline void -QCBOREncode_AddTB64URLTextToMapN(QCBOREncodeContext *pMe, int64_t nLabel, uint8_t uTagRequirement, UsefulBufC B64Text) +QCBOREncode_AddTB64URLTextToMapN(QCBOREncodeContext *pMe, + const int64_t nLabel, + const uint8_t uTagRequirement, + const UsefulBufC B64Text) { QCBOREncode_AddInt64(pMe, nLabel); QCBOREncode_AddTB64URLText(pMe, uTagRequirement, B64Text); } static inline void -QCBOREncode_AddB64URLText(QCBOREncodeContext *pMe, UsefulBufC B64Text) +QCBOREncode_AddB64URLText(QCBOREncodeContext *pMe, const UsefulBufC B64Text) { QCBOREncode_AddTB64URLText(pMe, QCBOR_ENCODE_AS_TAG, B64Text); } static inline void -QCBOREncode_AddB64URLTextToMap(QCBOREncodeContext *pMe, const char *szLabel, UsefulBufC B64Text) +QCBOREncode_AddB64URLTextToMap(QCBOREncodeContext *pMe, + const char *szLabel, + const UsefulBufC B64Text) { - QCBOREncode_AddTB64URLTextToMapSZ(pMe, szLabel, QCBOR_ENCODE_AS_TAG, B64Text); + QCBOREncode_AddTB64URLTextToMapSZ(pMe, + szLabel, + QCBOR_ENCODE_AS_TAG, + B64Text); } static inline void -QCBOREncode_AddB64URLTextToMapN(QCBOREncodeContext *pMe, int64_t nLabel, UsefulBufC B64Text) +QCBOREncode_AddB64URLTextToMapN(QCBOREncodeContext *pMe, + const int64_t nLabel, + const UsefulBufC B64Text) { QCBOREncode_AddTB64URLTextToMapN(pMe, nLabel, QCBOR_ENCODE_AS_TAG, B64Text); } @@ -3029,7 +3815,9 @@ QCBOREncode_AddB64URLTextToMapN(QCBOREncodeContext *pMe, int64_t nLabel, UsefulB static inline void -QCBOREncode_AddTRegex(QCBOREncodeContext *pMe, uint8_t uTagRequirement, UsefulBufC Bytes) +QCBOREncode_AddTRegex(QCBOREncodeContext *pMe, + const uint8_t uTagRequirement, + const UsefulBufC Bytes) { if(uTagRequirement == QCBOR_ENCODE_AS_TAG) { QCBOREncode_AddTag(pMe, CBOR_TAG_REGEX); @@ -3038,33 +3826,43 @@ QCBOREncode_AddTRegex(QCBOREncodeContext *pMe, uint8_t uTagRequirement, UsefulBu } static inline void -QCBOREncode_AddTRegexToMapSZ(QCBOREncodeContext *pMe, const char *szLabel, uint8_t uTagRequirement, UsefulBufC Bytes) +QCBOREncode_AddTRegexToMapSZ(QCBOREncodeContext *pMe, + const char *szLabel, + const uint8_t uTagRequirement, + const UsefulBufC Bytes) { QCBOREncode_AddSZString(pMe, szLabel); QCBOREncode_AddTRegex(pMe, uTagRequirement, Bytes); } static inline void -QCBOREncode_AddTRegexToMapN(QCBOREncodeContext *pMe, int64_t nLabel, uint8_t uTagRequirement, UsefulBufC Bytes) +QCBOREncode_AddTRegexToMapN(QCBOREncodeContext *pMe, + const int64_t nLabel, + const uint8_t uTagRequirement, + const UsefulBufC Bytes) { QCBOREncode_AddInt64(pMe, nLabel); QCBOREncode_AddTRegex(pMe, uTagRequirement, Bytes); } static inline void -QCBOREncode_AddRegex(QCBOREncodeContext *pMe, UsefulBufC Bytes) +QCBOREncode_AddRegex(QCBOREncodeContext *pMe, const UsefulBufC Bytes) { QCBOREncode_AddTRegex(pMe, QCBOR_ENCODE_AS_TAG, Bytes); } static inline void -QCBOREncode_AddRegexToMap(QCBOREncodeContext *pMe, const char *szLabel, UsefulBufC Bytes) +QCBOREncode_AddRegexToMap(QCBOREncodeContext *pMe, + const char *szLabel, + const UsefulBufC Bytes) { QCBOREncode_AddTRegexToMapSZ(pMe, szLabel, QCBOR_ENCODE_AS_TAG, Bytes); } static inline void -QCBOREncode_AddRegexToMapN(QCBOREncodeContext *pMe, int64_t nLabel, UsefulBufC Bytes) +QCBOREncode_AddRegexToMapN(QCBOREncodeContext *pMe, + const int64_t nLabel, + const UsefulBufC Bytes) { QCBOREncode_AddTRegexToMapN(pMe, nLabel, QCBOR_ENCODE_AS_TAG, Bytes); @@ -3072,7 +3870,9 @@ QCBOREncode_AddRegexToMapN(QCBOREncodeContext *pMe, int64_t nLabel, UsefulBufC B static inline void -QCBOREncode_AddTMIMEData(QCBOREncodeContext *pMe, uint8_t uTagRequirement, UsefulBufC MIMEData) +QCBOREncode_AddTMIMEData(QCBOREncodeContext *pMe, + const uint8_t uTagRequirement, + const UsefulBufC MIMEData) { if(uTagRequirement == QCBOR_ENCODE_AS_TAG) { QCBOREncode_AddTag(pMe, CBOR_TAG_BINARY_MIME); @@ -3083,15 +3883,18 @@ QCBOREncode_AddTMIMEData(QCBOREncodeContext *pMe, uint8_t uTagRequirement, Usefu static inline void QCBOREncode_AddTMIMEDataToMapSZ(QCBOREncodeContext *pMe, const char *szLabel, - uint8_t uTagRequirement, - UsefulBufC MIMEData) + const uint8_t uTagRequirement, + const UsefulBufC MIMEData) { QCBOREncode_AddSZString(pMe, szLabel); QCBOREncode_AddTMIMEData(pMe, uTagRequirement, MIMEData); } static inline void -QCBOREncode_AddTMIMEDataToMapN(QCBOREncodeContext *pMe, int64_t nLabel, uint8_t uTagRequirement, UsefulBufC MIMEData) +QCBOREncode_AddTMIMEDataToMapN(QCBOREncodeContext *pMe, + const int64_t nLabel, + const uint8_t uTagRequirement, + const UsefulBufC MIMEData) { QCBOREncode_AddInt64(pMe, nLabel); QCBOREncode_AddTMIMEData(pMe, uTagRequirement, MIMEData); @@ -3104,20 +3907,26 @@ QCBOREncode_AddMIMEData(QCBOREncodeContext *pMe, UsefulBufC MIMEData) } static inline void -QCBOREncode_AddMIMEDataToMap(QCBOREncodeContext *pMe, const char *szLabel, UsefulBufC MIMEData) +QCBOREncode_AddMIMEDataToMap(QCBOREncodeContext *pMe, + const char *szLabel, + const UsefulBufC MIMEData) { QCBOREncode_AddTMIMEDataToMapSZ(pMe, szLabel, QCBOR_ENCODE_AS_TAG, MIMEData); } static inline void -QCBOREncode_AddMIMEDataToMapN(QCBOREncodeContext *pMe, int64_t nLabel, UsefulBufC MIMEData) +QCBOREncode_AddMIMEDataToMapN(QCBOREncodeContext *pMe, + const int64_t nLabel, + const UsefulBufC MIMEData) { QCBOREncode_AddTMIMEDataToMapN(pMe, nLabel, QCBOR_ENCODE_AS_TAG, MIMEData); } static inline void -QCBOREncode_AddTDateString(QCBOREncodeContext *pMe, uint8_t uTagRequirement, const char *szDate) +QCBOREncode_AddTDateString(QCBOREncodeContext *pMe, + const uint8_t uTagRequirement, + const char *szDate) { if(uTagRequirement == QCBOR_ENCODE_AS_TAG) { QCBOREncode_AddTag(pMe, CBOR_TAG_DATE_STRING); @@ -3128,7 +3937,7 @@ QCBOREncode_AddTDateString(QCBOREncodeContext *pMe, uint8_t uTagRequirement, con static inline void QCBOREncode_AddTDateStringToMapSZ(QCBOREncodeContext *pMe, const char *szLabel, - uint8_t uTagRequirement, + const uint8_t uTagRequirement, const char *szDate) { QCBOREncode_AddSZString(pMe, szLabel); @@ -3136,7 +3945,10 @@ QCBOREncode_AddTDateStringToMapSZ(QCBOREncodeContext *pMe, } static inline void -QCBOREncode_AddTDateStringToMapN(QCBOREncodeContext *pMe, int64_t nLabel, uint8_t uTagRequirement, const char *szDate) +QCBOREncode_AddTDateStringToMapN(QCBOREncodeContext *pMe, + const int64_t nLabel, + const uint8_t uTagRequirement, + const char *szDate) { QCBOREncode_AddInt64(pMe, nLabel); QCBOREncode_AddTDateString(pMe, uTagRequirement, szDate); @@ -3149,20 +3961,26 @@ QCBOREncode_AddDateString(QCBOREncodeContext *pMe, const char *szDate) } static inline void -QCBOREncode_AddDateStringToMap(QCBOREncodeContext *pMe, const char *szLabel, const char *szDate) +QCBOREncode_AddDateStringToMap(QCBOREncodeContext *pMe, + const char *szLabel, + const char *szDate) { QCBOREncode_AddTDateStringToMapSZ(pMe, szLabel, QCBOR_ENCODE_AS_TAG, szDate); } static inline void -QCBOREncode_AddDateStringToMapN(QCBOREncodeContext *pMe, int64_t nLabel, const char *szDate) +QCBOREncode_AddDateStringToMapN(QCBOREncodeContext *pMe, + const int64_t nLabel, + const char *szDate) { QCBOREncode_AddTDateStringToMapN(pMe, nLabel, QCBOR_ENCODE_AS_TAG, szDate); } static inline void -QCBOREncode_AddTDaysString(QCBOREncodeContext *pMe, uint8_t uTagRequirement, const char *szDate) +QCBOREncode_AddTDaysString(QCBOREncodeContext *pMe, + const uint8_t uTagRequirement, + const char *szDate) { if(uTagRequirement == QCBOR_ENCODE_AS_TAG) { QCBOREncode_AddTag(pMe, CBOR_TAG_DAYS_STRING); @@ -3173,7 +3991,7 @@ QCBOREncode_AddTDaysString(QCBOREncodeContext *pMe, uint8_t uTagRequirement, con static inline void QCBOREncode_AddTDaysStringToMapSZ(QCBOREncodeContext *pMe, const char *szLabel, - uint8_t uTagRequirement, + const uint8_t uTagRequirement, const char *szDate) { QCBOREncode_AddSZString(pMe, szLabel); @@ -3181,29 +3999,51 @@ QCBOREncode_AddTDaysStringToMapSZ(QCBOREncodeContext *pMe, } static inline void -QCBOREncode_AddTDaysStringToMapN(QCBOREncodeContext *pMe, int64_t nLabel, uint8_t uTagRequirement, const char *szDate) +QCBOREncode_AddTDaysStringToMapN(QCBOREncodeContext *pMe, + const int64_t nLabel, + const uint8_t uTagRequirement, + const char *szDate) { QCBOREncode_AddInt64(pMe, nLabel); QCBOREncode_AddTDaysString(pMe, uTagRequirement, szDate); } - static inline void -QCBOREncode_AddSimple(QCBOREncodeContext *pMe, uint64_t uNum) +QCBOREncode_AddSimple(QCBOREncodeContext *pMe, const uint8_t uNum) { - QCBOREncode_AddType7(pMe, 0, uNum); + /* This check often is optimized out because uNum is known at compile time. */ +#ifndef QCBOR_DISABLE_ENCODE_USAGE_GUARDS + if(uNum >= CBOR_SIMPLEV_RESERVED_START && uNum <= CBOR_SIMPLEV_RESERVED_END) { + pMe->uError = QCBOR_ERR_ENCODE_UNSUPPORTED; + return; + } +#endif /* ! QCBOR_DISABLE_ENCODE_USAGE_GUARDS */ + + QCBOREncode_Private_AddType7(pMe, 0, uNum); } static inline void -QCBOREncode_AddSimpleToMap(QCBOREncodeContext *pMe, const char *szLabel, uint8_t uSimple) +QCBOREncode_AddSimpleToMapSZ(QCBOREncodeContext *pMe, + const char *szLabel, + const uint8_t uSimple) { QCBOREncode_AddSZString(pMe, szLabel); QCBOREncode_AddSimple(pMe, uSimple); } static inline void -QCBOREncode_AddSimpleToMapN(QCBOREncodeContext *pMe, int nLabel, uint8_t uSimple) +QCBOREncode_AddSimpleToMap(QCBOREncodeContext *pMe, + const char *szLabel, + const uint8_t uSimple) +{ + QCBOREncode_AddSimpleToMapSZ(pMe, szLabel, uSimple); +} + +static inline void +QCBOREncode_AddSimpleToMapN(QCBOREncodeContext *pMe, + const int64_t nLabel, + const uint8_t uSimple) { QCBOREncode_AddInt64(pMe, nLabel); QCBOREncode_AddSimple(pMe, uSimple); @@ -3211,7 +4051,7 @@ QCBOREncode_AddSimpleToMapN(QCBOREncodeContext *pMe, int nLabel, uint8_t uSimple static inline void -QCBOREncode_AddBool(QCBOREncodeContext *pMe, bool b) +QCBOREncode_AddBool(QCBOREncodeContext *pMe, const bool b) { uint8_t uSimple = CBOR_SIMPLEV_FALSE; if(b) { @@ -3221,14 +4061,20 @@ QCBOREncode_AddBool(QCBOREncodeContext *pMe, bool b) } static inline void -QCBOREncode_AddBoolToMap(QCBOREncodeContext *pMe, const char *szLabel, bool b) +QCBOREncode_AddBoolToMapSZ(QCBOREncodeContext *pMe, const char *szLabel, const bool b) { QCBOREncode_AddSZString(pMe, szLabel); QCBOREncode_AddBool(pMe, b); } static inline void -QCBOREncode_AddBoolToMapN(QCBOREncodeContext *pMe, int64_t nLabel, bool b) +QCBOREncode_AddBoolToMap(QCBOREncodeContext *pMe, const char *szLabel, bool b) +{ + QCBOREncode_AddBoolToMapSZ(pMe, szLabel, b); +} + +static inline void +QCBOREncode_AddBoolToMapN(QCBOREncodeContext *pMe, const int64_t nLabel, const bool b) { QCBOREncode_AddInt64(pMe, nLabel); QCBOREncode_AddBool(pMe, b); @@ -3242,14 +4088,20 @@ QCBOREncode_AddNULL(QCBOREncodeContext *pMe) } static inline void -QCBOREncode_AddNULLToMap(QCBOREncodeContext *pMe, const char *szLabel) +QCBOREncode_AddNULLToMapSZ(QCBOREncodeContext *pMe, const char *szLabel) { QCBOREncode_AddSZString(pMe, szLabel); QCBOREncode_AddNULL(pMe); } static inline void -QCBOREncode_AddNULLToMapN(QCBOREncodeContext *pMe, int64_t nLabel) +QCBOREncode_AddNULLToMap(QCBOREncodeContext *pMe, const char *szLabel) +{ + QCBOREncode_AddNULLToMapSZ(pMe, szLabel); +} + +static inline void +QCBOREncode_AddNULLToMapN(QCBOREncodeContext *pMe, const int64_t nLabel) { QCBOREncode_AddInt64(pMe, nLabel); QCBOREncode_AddNULL(pMe); @@ -3263,14 +4115,20 @@ QCBOREncode_AddUndef(QCBOREncodeContext *pMe) } static inline void -QCBOREncode_AddUndefToMap(QCBOREncodeContext *pMe, const char *szLabel) +QCBOREncode_AddUndefToMapSZ(QCBOREncodeContext *pMe, const char *szLabel) { QCBOREncode_AddSZString(pMe, szLabel); QCBOREncode_AddUndef(pMe); } static inline void -QCBOREncode_AddUndefToMapN(QCBOREncodeContext *pMe, int64_t nLabel) +QCBOREncode_AddUndefToMap(QCBOREncodeContext *pCtx, const char *szLabel) +{ + QCBOREncode_AddUndefToMapSZ(pCtx, szLabel); +} + +static inline void +QCBOREncode_AddUndefToMapN(QCBOREncodeContext *pMe, const int64_t nLabel) { QCBOREncode_AddInt64(pMe, nLabel); QCBOREncode_AddUndef(pMe); @@ -3280,18 +4138,25 @@ QCBOREncode_AddUndefToMapN(QCBOREncodeContext *pMe, int64_t nLabel) static inline void QCBOREncode_OpenArray(QCBOREncodeContext *pMe) { - QCBOREncode_OpenMapOrArray(pMe, CBOR_MAJOR_TYPE_ARRAY); + QCBOREncode_Private_OpenMapOrArray(pMe, CBOR_MAJOR_TYPE_ARRAY); } static inline void -QCBOREncode_OpenArrayInMap(QCBOREncodeContext *pMe, const char *szLabel) +QCBOREncode_OpenArrayInMapSZ(QCBOREncodeContext *pMe, const char *szLabel) { QCBOREncode_AddSZString(pMe, szLabel); QCBOREncode_OpenArray(pMe); } static inline void -QCBOREncode_OpenArrayInMapN(QCBOREncodeContext *pMe, int64_t nLabel) +QCBOREncode_OpenArrayInMap(QCBOREncodeContext *pMe, const char *szLabel) +{ + QCBOREncode_OpenArrayInMapSZ(pMe, szLabel); +} + + +static inline void +QCBOREncode_OpenArrayInMapN(QCBOREncodeContext *pMe, const int64_t nLabel) { QCBOREncode_AddInt64(pMe, nLabel); QCBOREncode_OpenArray(pMe); @@ -3300,25 +4165,31 @@ QCBOREncode_OpenArrayInMapN(QCBOREncodeContext *pMe, int64_t nLabel) static inline void QCBOREncode_CloseArray(QCBOREncodeContext *pMe) { - QCBOREncode_CloseMapOrArray(pMe, CBOR_MAJOR_TYPE_ARRAY); + QCBOREncode_Private_CloseMapOrArray(pMe, CBOR_MAJOR_TYPE_ARRAY); } static inline void QCBOREncode_OpenMap(QCBOREncodeContext *pMe) { - QCBOREncode_OpenMapOrArray(pMe, CBOR_MAJOR_TYPE_MAP); + QCBOREncode_Private_OpenMapOrArray(pMe, CBOR_MAJOR_TYPE_MAP); } static inline void -QCBOREncode_OpenMapInMap(QCBOREncodeContext *pMe, const char *szLabel) +QCBOREncode_OpenMapInMapSZ(QCBOREncodeContext *pMe, const char *szLabel) { QCBOREncode_AddSZString(pMe, szLabel); QCBOREncode_OpenMap(pMe); } static inline void -QCBOREncode_OpenMapInMapN(QCBOREncodeContext *pMe, int64_t nLabel) +QCBOREncode_OpenMapInMap(QCBOREncodeContext *pMe, const char *szLabel) +{ + QCBOREncode_OpenMapInMapSZ(pMe, szLabel); +} + +static inline void +QCBOREncode_OpenMapInMapN(QCBOREncodeContext *pMe, const int64_t nLabel) { QCBOREncode_AddInt64(pMe, nLabel); QCBOREncode_OpenMap(pMe); @@ -3327,24 +4198,33 @@ QCBOREncode_OpenMapInMapN(QCBOREncodeContext *pMe, int64_t nLabel) static inline void QCBOREncode_CloseMap(QCBOREncodeContext *pMe) { - QCBOREncode_CloseMapOrArray(pMe, CBOR_MAJOR_TYPE_MAP); + QCBOREncode_Private_CloseMapOrArray(pMe, CBOR_MAJOR_TYPE_MAP); } static inline void QCBOREncode_OpenArrayIndefiniteLength(QCBOREncodeContext *pMe) { - QCBOREncode_OpenMapOrArrayIndefiniteLength(pMe, CBOR_MAJOR_NONE_TYPE_ARRAY_INDEFINITE_LEN); + QCBOREncode_Private_OpenMapOrArrayIndefiniteLength(pMe, CBOR_MAJOR_NONE_TYPE_ARRAY_INDEFINITE_LEN); } static inline void -QCBOREncode_OpenArrayIndefiniteLengthInMap(QCBOREncodeContext *pMe, const char *szLabel) +QCBOREncode_OpenArrayIndefiniteLengthInMapSZ(QCBOREncodeContext *pMe, + const char *szLabel) { QCBOREncode_AddSZString(pMe, szLabel); QCBOREncode_OpenArrayIndefiniteLength(pMe); } static inline void -QCBOREncode_OpenArrayIndefiniteLengthInMapN(QCBOREncodeContext *pMe, int64_t nLabel) +QCBOREncode_OpenArrayIndefiniteLengthInMap(QCBOREncodeContext *pMe, + const char *szLabel) +{ + QCBOREncode_OpenArrayIndefiniteLengthInMapSZ(pMe, szLabel); +} + +static inline void +QCBOREncode_OpenArrayIndefiniteLengthInMapN(QCBOREncodeContext *pMe, + const int64_t nLabel) { QCBOREncode_AddInt64(pMe, nLabel); QCBOREncode_OpenArrayIndefiniteLength(pMe); @@ -3353,25 +4233,34 @@ QCBOREncode_OpenArrayIndefiniteLengthInMapN(QCBOREncodeContext *pMe, int64_t nL static inline void QCBOREncode_CloseArrayIndefiniteLength(QCBOREncodeContext *pMe) { - QCBOREncode_CloseMapOrArrayIndefiniteLength(pMe, CBOR_MAJOR_NONE_TYPE_ARRAY_INDEFINITE_LEN); + QCBOREncode_Private_CloseMapOrArrayIndefiniteLength(pMe, CBOR_MAJOR_NONE_TYPE_ARRAY_INDEFINITE_LEN); } static inline void QCBOREncode_OpenMapIndefiniteLength(QCBOREncodeContext *pMe) { - QCBOREncode_OpenMapOrArrayIndefiniteLength(pMe, CBOR_MAJOR_NONE_TYPE_MAP_INDEFINITE_LEN); + QCBOREncode_Private_OpenMapOrArrayIndefiniteLength(pMe, CBOR_MAJOR_NONE_TYPE_MAP_INDEFINITE_LEN); } static inline void -QCBOREncode_OpenMapIndefiniteLengthInMap(QCBOREncodeContext *pMe, const char *szLabel) +QCBOREncode_OpenMapIndefiniteLengthInMapSZ(QCBOREncodeContext *pMe, + const char *szLabel) { QCBOREncode_AddSZString(pMe, szLabel); QCBOREncode_OpenMapIndefiniteLength(pMe); } static inline void -QCBOREncode_OpenMapIndefiniteLengthInMapN(QCBOREncodeContext *pMe, int64_t nLabel) +QCBOREncode_OpenMapIndefiniteLengthInMap(QCBOREncodeContext *pMe, + const char *szLabel) +{ + QCBOREncode_OpenMapIndefiniteLengthInMapSZ(pMe, szLabel); +} + +static inline void +QCBOREncode_OpenMapIndefiniteLengthInMapN(QCBOREncodeContext *pMe, + const int64_t nLabel) { QCBOREncode_AddInt64(pMe, nLabel); QCBOREncode_OpenMapIndefiniteLength(pMe); @@ -3380,25 +4269,31 @@ QCBOREncode_OpenMapIndefiniteLengthInMapN(QCBOREncodeContext *pMe, int64_t nLabe static inline void QCBOREncode_CloseMapIndefiniteLength(QCBOREncodeContext *pMe) { - QCBOREncode_CloseMapOrArrayIndefiniteLength(pMe, CBOR_MAJOR_NONE_TYPE_MAP_INDEFINITE_LEN); + QCBOREncode_Private_CloseMapOrArrayIndefiniteLength(pMe, CBOR_MAJOR_NONE_TYPE_MAP_INDEFINITE_LEN); } static inline void QCBOREncode_BstrWrap(QCBOREncodeContext *pMe) { - QCBOREncode_OpenMapOrArray(pMe, CBOR_MAJOR_TYPE_BYTE_STRING); + QCBOREncode_Private_OpenMapOrArray(pMe, CBOR_MAJOR_TYPE_BYTE_STRING); } static inline void -QCBOREncode_BstrWrapInMap(QCBOREncodeContext *pMe, const char *szLabel) +QCBOREncode_BstrWrapInMapSZ(QCBOREncodeContext *pMe, const char *szLabel) { QCBOREncode_AddSZString(pMe, szLabel); QCBOREncode_BstrWrap(pMe); } static inline void -QCBOREncode_BstrWrapInMapN(QCBOREncodeContext *pMe, int64_t nLabel) +QCBOREncode_BstrWrapInMap(QCBOREncodeContext *pMe, const char *szLabel) +{ + QCBOREncode_BstrWrapInMapSZ(pMe, szLabel); +} + +static inline void +QCBOREncode_BstrWrapInMapN(QCBOREncodeContext *pMe, const int64_t nLabel) { QCBOREncode_AddInt64(pMe, nLabel); QCBOREncode_BstrWrap(pMe); @@ -3411,21 +4306,26 @@ QCBOREncode_CloseBstrWrap(QCBOREncodeContext *pMe, UsefulBufC *pWrappedCBOR) } + static inline void -QCBOREncode_AddEncoded(QCBOREncodeContext *pMe, UsefulBufC Encoded) +QCBOREncode_AddEncodedToMapSZ(QCBOREncodeContext *pMe, + const char *szLabel, + const UsefulBufC Encoded) { - QCBOREncode_AddBuffer(pMe, CBOR_MAJOR_NONE_TYPE_RAW, Encoded); + QCBOREncode_AddSZString(pMe, szLabel); + QCBOREncode_AddEncoded(pMe, Encoded); } static inline void QCBOREncode_AddEncodedToMap(QCBOREncodeContext *pMe, const char *szLabel, UsefulBufC Encoded) { - QCBOREncode_AddSZString(pMe, szLabel); - QCBOREncode_AddEncoded(pMe, Encoded); + QCBOREncode_AddEncodedToMapSZ(pMe, szLabel, Encoded); } static inline void -QCBOREncode_AddEncodedToMapN(QCBOREncodeContext *pMe, int64_t nLabel, UsefulBufC Encoded) +QCBOREncode_AddEncodedToMapN(QCBOREncodeContext *pMe, + const int64_t nLabel, + const UsefulBufC Encoded) { QCBOREncode_AddInt64(pMe, nLabel); QCBOREncode_AddEncoded(pMe, Encoded); @@ -3438,28 +4338,44 @@ QCBOREncode_IsBufferNULL(QCBOREncodeContext *pMe) return UsefulOutBuf_IsBufferNULL(&(pMe->OutBuf)); } + +static inline UsefulBuf +QCBOREncode_RetrieveOutputStorage(QCBOREncodeContext *pMe) +{ + return UsefulOutBuf_RetrieveOutputStorage(&(pMe->OutBuf)); +} + + static inline QCBORError QCBOREncode_GetErrorState(QCBOREncodeContext *pMe) { if(UsefulOutBuf_GetError(&(pMe->OutBuf))) { - // Items didn't fit in the buffer. - // This check catches this condition for all the appends and inserts - // so checks aren't needed when the appends and inserts are performed. - // And of course UsefulBuf will never overrun the input buffer given - // to it. No complex analysis of the error handling in this file is - // needed to know that is true. Just read the UsefulBuf code. + /* Items didn't fit in the buffer. This check catches this + * condition for all the appends and inserts so checks aren't + * needed when the appends and inserts are performed. And of + * course UsefulBuf will never overrun the input buffer given to + * it. No complex analysis of the error handling in this file is + * needed to know that is true. Just read the UsefulBuf code. + */ pMe->uError = QCBOR_ERR_BUFFER_TOO_SMALL; - // QCBOR_ERR_BUFFER_TOO_SMALL masks other errors, but that is - // OK. Once the caller fixes this, they'll be unmasked. + /* QCBOR_ERR_BUFFER_TOO_SMALL masks other errors, but that is + * OK. Once the caller fixes this, they'll be unmasked. + */ } return (QCBORError)pMe->uError; } -/* ======================================================================== - END OF PRIVATE INLINE IMPLEMENTATION - ======================================================================== */ +static inline size_t +QCBOREncode_Tell(QCBOREncodeContext *pMe) +{ + return UsefulOutBuf_GetEndPosition(&(pMe->OutBuf)); +} + +/* ======================================================================== * + * END OF PRIVATE INLINE IMPLEMENTATION * + * ======================================================================== */ #ifdef __cplusplus } diff --git a/3rdparty/exported/QCBOR/qcbor/qcbor_private.h b/3rdparty/exported/QCBOR/qcbor/qcbor_private.h index 9a2a720fe6d6..a061809cc508 100644 --- a/3rdparty/exported/QCBOR/qcbor/qcbor_private.h +++ b/3rdparty/exported/QCBOR/qcbor/qcbor_private.h @@ -1,35 +1,35 @@ -/*============================================================================== - Copyright (c) 2016-2018, The Linux Foundation. - Copyright (c) 2018-2021, Laurence Lundblade. - Copyright (c) 2021, Arm Limited. - All rights reserved. - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are - met: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following - disclaimer in the documentation and/or other materials provided - with the distribution. - * Neither the name of The Linux Foundation nor the names of its - contributors, nor the name "Laurence Lundblade" may be used to - endorse or promote products derived from this software without - specific prior written permission. - - THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED - WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT - ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS - BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR - BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE - OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN - IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - =============================================================================*/ +/* ========================================================================== + * Copyright (c) 2016-2018, The Linux Foundation. + * Copyright (c) 2018-2024, Laurence Lundblade. + * Copyright (c) 2021, Arm Limited. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * * Neither the name of The Linux Foundation nor the names of its + * contributors, nor the name "Laurence Lundblade" may be used to + * endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ========================================================================= */ #ifndef qcbor_private_h @@ -38,6 +38,7 @@ #include #include "UsefulBuf.h" +#include "qcbor/qcbor_common.h" #ifdef __cplusplus @@ -48,56 +49,52 @@ extern "C" { #endif -/* - The maxium nesting of arrays and maps when encoding or decoding. - (Further down in the file there is a definition that refers to this - that is public. This is done this way so there can be a nice - separation of public and private parts in this file. -*/ -#define QCBOR_MAX_ARRAY_NESTING1 15 // Do not increase this over 255 - - -/* The largest offset to the start of an array or map. It is slightly - less than UINT32_MAX so the error condition can be tested on 32-bit machines. - UINT32_MAX comes from uStart in QCBORTrackNesting being a uin32_t. - - This will cause trouble on a machine where size_t is less than 32-bits. +/* This was originally defined as QCBOR_CONFIG_DISABLE_EXP_AND_MANTISSA, + * but this is inconsistent with all the other QCBOR_DISABLE_ + * #defines, so the name was changed and this was added for backwards + * compatibility */ -#define QCBOR_MAX_ARRAY_OFFSET (UINT32_MAX - 100) - +#ifdef QCBOR_CONFIG_DISABLE_EXP_AND_MANTISSA +#define QCBOR_DISABLE_EXP_AND_MANTISSA +#endif -/* The number of tags that are 16-bit or larger that can be handled - in a decode. +/* If USEFULBUF_DISABLE_ALL_FLOATis defined then define + * QCBOR_DISABLE_FLOAT_HW_USE and QCBOR_DISABLE_PREFERRED_FLOAT */ -#define QCBOR_NUM_MAPPED_TAGS 4 +#ifdef USEFULBUF_DISABLE_ALL_FLOAT +#ifndef QCBOR_DISABLE_FLOAT_HW_USE +#define QCBOR_DISABLE_FLOAT_HW_USE +#endif /* QCBOR_DISABLE_FLOAT_HW_USE */ +#ifndef QCBOR_DISABLE_PREFERRED_FLOAT +#define QCBOR_DISABLE_PREFERRED_FLOAT +#endif /* QCBOR_DISABLE_PREFERRED_FLOAT */ +#endif /* USEFULBUF_DISABLE_ALL_FLOAT */ -/* The number of tags (of any size) recorded for an individual item. */ -#define QCBOR_MAX_TAGS_PER_ITEM1 4 /* - Convenience macro for selecting the proper return value in case floating - point feature(s) are disabled. - - The macros: - - FLOAT_ERR_CODE_NO_FLOAT(x) Can be used when disabled floating point should - result error, and all other cases should return - 'x'. - - The below macros always return QCBOR_ERR_ALL_FLOAT_DISABLED when all floating - point is disabled. - - FLOAT_ERR_CODE_NO_HALF_PREC(x) Can be used when disabled preferred float - results in error, and all other cases should - return 'x'. - FLOAT_ERR_CODE_NO_FLOAT_HW(x) Can be used when disabled hardware floating - point results in error, and all other cases - should return 'x'. - FLOAT_ERR_CODE_NO_HALF_PREC_NO_FLOAT_HW(x) Can be used when either disabled - preferred float or disabling - hardware floating point results in - error, and all other cases should - return 'x'. + * Convenience macro for selecting the proper return value in case floating + * point feature(s) are disabled. + * + * The macros: + * + * FLOAT_ERR_CODE_NO_FLOAT(x) Can be used when disabled floating point should + * result error, and all other cases should return + * 'x'. + * + * The below macros always return QCBOR_ERR_ALL_FLOAT_DISABLED when all + * floating point is disabled. + * + * FLOAT_ERR_CODE_NO_HALF_PREC(x) Can be used when disabled preferred float + * results in error, and all other cases should + * return 'x'. + * FLOAT_ERR_CODE_NO_FLOAT_HW(x) Can be used when disabled hardware floating + * point results in error, and all other cases + * should return 'x'. + * FLOAT_ERR_CODE_NO_HALF_PREC_NO_FLOAT_HW(x) Can be used when either disabled + * preferred float or disabling + * hardware floating point results in + * error, and all other cases should + * return 'x'. */ #ifdef USEFULBUF_DISABLE_ALL_FLOAT #define FLOAT_ERR_CODE_NO_FLOAT(x) QCBOR_ERR_ALL_FLOAT_DISABLED @@ -126,103 +123,163 @@ extern "C" { /* - PRIVATE DATA STRUCTURE + * These are special values for the AdditionalInfo bits that are part of + * the first byte. Mostly they encode the length of the data item. + */ +#define LEN_IS_ONE_BYTE 24 +#define LEN_IS_TWO_BYTES 25 +#define LEN_IS_FOUR_BYTES 26 +#define LEN_IS_EIGHT_BYTES 27 +#define ADDINFO_RESERVED1 28 +#define ADDINFO_RESERVED2 29 +#define ADDINFO_RESERVED3 30 +#define LEN_IS_INDEFINITE 31 - Holds the data for tracking array and map nesting during encoding. Pairs up - with the Nesting_xxx functions to make an "object" to handle nesting encoding. - uStart is a uint32_t instead of a size_t to keep the size of this - struct down so it can be on the stack without any concern. It would be about - double if size_t was used instead. +/* + * 24 is a special number for CBOR. Integers and lengths + * less than it are encoded in the same byte as the major type. + */ +#define CBOR_TWENTY_FOUR 24 + + +/* + * Values for the 5 bits for items of major type 7 + */ +#define CBOR_SIMPLEV_FALSE 20 +#define CBOR_SIMPLEV_TRUE 21 +#define CBOR_SIMPLEV_NULL 22 +#define CBOR_SIMPLEV_UNDEF 23 +#define CBOR_SIMPLEV_ONEBYTE 24 +#define HALF_PREC_FLOAT 25 +#define SINGLE_PREC_FLOAT 26 +#define DOUBLE_PREC_FLOAT 27 +#define CBOR_SIMPLE_BREAK 31 +#define CBOR_SIMPLEV_RESERVED_START CBOR_SIMPLEV_ONEBYTE +#define CBOR_SIMPLEV_RESERVED_END CBOR_SIMPLE_BREAK + + +/* The largest offset to the start of an array or map. It is slightly + * less than UINT32_MAX so the error condition can be tested on 32-bit + * machines. UINT32_MAX comes from uStart in QCBORTrackNesting being + * a uin32_t. + * + * This will cause trouble on a machine where size_t is less than 32-bits. + */ +#define QCBOR_MAX_ARRAY_OFFSET (UINT32_MAX - 100) + - Size approximation (varies with CPU/compiler): - 64-bit machine: (15 + 1) * (4 + 2 + 1 + 1 pad) + 8 = 136 bytes - 32-bit machine: (15 + 1) * (4 + 2 + 1 + 1 pad) + 4 = 132 bytes -*/ +/* The number of tags that are 16-bit or larger that can be handled + * in a decode. + */ +#define QCBOR_NUM_MAPPED_TAGS 4 + +/* The number of tags (of any size) recorded for an individual item. */ +#define QCBOR_MAX_TAGS_PER_ITEM1 4 + + + + +/* + * PRIVATE DATA STRUCTURE + * + * Holds the data for tracking array and map nesting during + * encoding. Pairs up with the Nesting_xxx functions to make an + * "object" to handle nesting encoding. + * + * uStart is a uint32_t instead of a size_t to keep the size of this + * struct down so it can be on the stack without any concern. It + * would be about double if size_t was used instead. + * + * Size approximation (varies with CPU/compiler): + * 64-bit machine: (15 + 1) * (4 + 2 + 1 + 1 pad) + 8 = 136 bytes + * 32-bit machine: (15 + 1) * (4 + 2 + 1 + 1 pad) + 4 = 132 bytes + */ typedef struct __QCBORTrackNesting { - // PRIVATE DATA STRUCTURE + /* PRIVATE DATA STRUCTURE */ struct { - // See function QCBOREncode_OpenMapOrArray() for details on how this works - uint32_t uStart; // uStart is the byte position where the array starts - uint16_t uCount; // Number of items in the arrary or map; counts items - // in a map, not pairs of items - uint8_t uMajorType; // Indicates if item is a map or an array - } pArrays[QCBOR_MAX_ARRAY_NESTING1+1], // stored state for the nesting levels - *pCurrentNesting; // the current nesting level + /* See QCBOREncode_OpenMapOrArray() for details on how this works */ + uint32_t uStart; /* uStart is the position where the array starts */ + uint16_t uCount; /* Number of items in the arrary or map; counts items + * in a map, not pairs of items */ + uint8_t uMajorType; /* Indicates if item is a map or an array */ + } pArrays[QCBOR_MAX_ARRAY_NESTING+1], /* stored state for nesting levels */ + *pCurrentNesting; /* the current nesting level */ } QCBORTrackNesting; /* - PRIVATE DATA STRUCTURE - - Context / data object for encoding some CBOR. Used by all encode functions to - form a public "object" that does the job of encdoing. - - Size approximation (varies with CPU/compiler): - 64-bit machine: 27 + 1 (+ 4 padding) + 136 = 32 + 136 = 168 bytes - 32-bit machine: 15 + 1 + 132 = 148 bytes -*/ + * PRIVATE DATA STRUCTURE + * + * Context / data object for encoding some CBOR. Used by all encode + * functions to form a public "object" that does the job of encdoing. + * + * Size approximation (varies with CPU/compiler): + * 64-bit machine: 27 + 1 (+ 4 padding) + 136 = 32 + 136 = 168 bytes + * 32-bit machine: 15 + 1 + 132 = 148 bytes + */ struct _QCBOREncodeContext { - // PRIVATE DATA STRUCTURE - UsefulOutBuf OutBuf; // Pointer to output buffer, its length and - // position in it - uint8_t uError; // Error state, always from QCBORError enum - QCBORTrackNesting nesting; // Keep track of array and map nesting + /* PRIVATE DATA STRUCTURE */ + UsefulOutBuf OutBuf; /* Pointer to output buffer, its length and + * position in it. */ + uint8_t uError; /* Error state, always from QCBORError enum */ + QCBORTrackNesting nesting; /* Keep track of array and map nesting */ }; /* - PRIVATE DATA STRUCTURE - - Holds the data for array and map nesting for decoding work. This - structure and the DecodeNesting_Xxx() functions in qcbor_decode.c - form an "object" that does the work for arrays and maps. All access - to this structure is through DecodeNesting_Xxx() functions. - - 64-bit machine size - 128 = 16 * 8 for the two unions - 64 = 16 * 4 for the uLevelType, 1 byte padded to 4 bytes for alignment - 16 = 16 bytes for two pointers - 208 TOTAL - - 32-bit machine size is 200 bytes + * PRIVATE DATA STRUCTURE + * + * Holds the data for array and map nesting for decoding work. This + * structure and the DecodeNesting_Xxx() functions in qcbor_decode.c + * form an "object" that does the work for arrays and maps. All access + * to this structure is through DecodeNesting_Xxx() functions. + * + * 64-bit machine size + * 128 = 16 * 8 for the two unions + * 64 = 16 * 4 for the uLevelType, 1 byte padded to 4 bytes for alignment + * 16 = 16 bytes for two pointers + * 208 TOTAL + * + * 32-bit machine size is 200 bytes */ typedef struct __QCBORDecodeNesting { - // PRIVATE DATA STRUCTURE + /* PRIVATE DATA STRUCTURE */ struct nesting_decode_level { /* - This keeps tracking info for each nesting level. There are two - main types of levels: - 1) Byte count tracking. This is for the top level input CBOR - which might be a single item or a CBOR sequence and byte - string wrapped encoded CBOR. - 2) Item tracking. This is for maps and arrays. - - uLevelType has value QCBOR_TYPE_BYTE_STRING for 1) and - QCBOR_TYPE_MAP or QCBOR_TYPE_ARRAY or QCBOR_TYPE_MAP_AS_ARRAY - for 2). - - Item tracking is either for definite or indefinite-length - maps/arrays. For definite lengths, the total count and items - unconsumed are tracked. For indefinite-length, uTotalCount is - QCBOR_COUNT_INDICATES_INDEFINITE_LENGTH (UINT16_MAX) and there - is no per-item count of members. For indefinite-length maps and - arrays, uCountCursor is UINT16_MAX if not consumed and zero if - it is consumed in the pre-order traversal. Additionally, if - entered in bounded mode, uCountCursor is - QCBOR_COUNT_INDICATES_ZERO_LENGTH to indicate it is empty. - - This also records whether a level is bounded or not. All - byte-count tracked levels (the top-level sequence and - bstr-wrapped CBOR) are bounded. Maps and arrays may or may not - be bounded. They are bounded if they were Entered() and not if - they were traversed with GetNext(). They are marked as bounded - by uStartOffset not being UINT32_MAX. + * This keeps tracking info for each nesting level. There are two + * main types of levels: + * 1) Byte count tracking. This is for the top level input CBOR + * which might be a single item or a CBOR sequence and byte + * string wrapped encoded CBOR. + * 2) Item count tracking. This is for maps and arrays. + * + * uLevelType has value QCBOR_TYPE_BYTE_STRING for 1) and + * QCBOR_TYPE_MAP or QCBOR_TYPE_ARRAY or QCBOR_TYPE_MAP_AS_ARRAY + * for 2). + * + * Item count tracking is either for definite or indefinite-length + * maps/arrays. For definite lengths, the total count and items + * unconsumed are tracked. For indefinite-length, uTotalCount is + * QCBOR_COUNT_INDICATES_INDEFINITE_LENGTH (UINT16_MAX) and + * there is no per-item count of members. For indefinite-length + * maps and arrays, uCountCursor is UINT16_MAX if not consumed + * and zero if it is consumed in the pre-order + * traversal. Additionally, if entered in bounded mode, + * uCountCursor is QCBOR_COUNT_INDICATES_ZERO_LENGTH to indicate + * it is empty. + * + * This also records whether a level is bounded or not. All + * byte-count tracked levels (the top-level sequence and + * bstr-wrapped CBOR) are bounded implicitly. Maps and arrays + * may or may not be bounded. They are bounded if they were + * Entered() and not if they were traversed with GetNext(). They + * are marked as bounded by uStartOffset not being @c UINT32_MAX. */ /* - If uLevelType can put in a separately indexed array, the union/ - struct will be 8 bytes rather than 9 and a lot of wasted - padding for alignment will be saved. + * If uLevelType can put in a separately indexed array, the + * union/struct will be 8 bytes rather than 9 and a lot of + * wasted padding for alignment will be saved. */ uint8_t uLevelType; union { @@ -232,6 +289,8 @@ typedef struct __QCBORDecodeNesting { uint16_t uCountTotal; uint16_t uCountCursor; #define QCBOR_NON_BOUNDED_OFFSET UINT32_MAX + /* The start of the array or map in bounded mode so + * the input can be rewound for GetInMapXx() by label. */ uint32_t uStartOffset; } ma; /* for maps and arrays */ struct { @@ -242,88 +301,87 @@ typedef struct __QCBORDecodeNesting { uint32_t uBstrStartOffset; } bs; /* for top-level sequence and bstr-wrapped CBOR */ } u; - } pLevels[QCBOR_MAX_ARRAY_NESTING1+1], + } pLevels[QCBOR_MAX_ARRAY_NESTING+1], *pCurrent, *pCurrentBounded; /* - pCurrent is for item-by-item pre-order traversal. - - pCurrentBounded points to the current bounding level or is NULL if - there isn't one. - - pCurrent must always be below pCurrentBounded as the pre-order - traversal is always bounded by the bounding level. - - When a bounded level is entered, the pre-order traversal is set to - the first item in the bounded level. When a bounded level is - exited, the pre-order traversl is set to the next item after the - map, array or bstr. This may be more than one level up, or even - the end of the input CBOR. + * pCurrent is for item-by-item pre-order traversal. + * + * pCurrentBounded points to the current bounding level or is NULL + * if there isn't one. + * + * pCurrent must always be below pCurrentBounded as the pre-order + * traversal is always bounded by the bounding level. + * + * When a bounded level is entered, the pre-order traversal is set + * to the first item in the bounded level. When a bounded level is + * exited, the pre-order traversl is set to the next item after the + * map, array or bstr. This may be more than one level up, or even + * the end of the input CBOR. */ } QCBORDecodeNesting; typedef struct { - // PRIVATE DATA STRUCTURE + /* PRIVATE DATA STRUCTURE */ void *pAllocateCxt; UsefulBuf (* pfAllocator)(void *pAllocateCxt, void *pOldMem, size_t uNewSize); } QCBORInternalAllocator; /* - PRIVATE DATA STRUCTURE - - The decode context. This data structure plus the public QCBORDecode_xxx - functions form an "object" that does CBOR decoding. - - Size approximation (varies with CPU/compiler): - 64-bit machine: 32 + 1 + 1 + 6 bytes padding + 72 + 16 + 8 + 8 = 144 bytes - 32-bit machine: 16 + 1 + 1 + 2 bytes padding + 68 + 8 + 8 + 4 = 108 bytes + * PRIVATE DATA STRUCTURE + * + * The decode context. This data structure plus the public + * QCBORDecode_xxx functions form an "object" that does CBOR decoding. + * + * Size approximation (varies with CPU/compiler): + * 64-bit machine: 32 + 1 + 1 + 6 bytes padding + 72 + 16 + 8 + 8 = 144 bytes + * 32-bit machine: 16 + 1 + 1 + 2 bytes padding + 68 + 8 + 8 + 4 = 108 bytes */ struct _QCBORDecodeContext { - // PRIVATE DATA STRUCTURE + /* PRIVATE DATA STRUCTURE */ UsefulInputBuf InBuf; - QCBORDecodeNesting nesting; - - // If a string allocator is configured for indefinite-length - // strings, it is configured here. + /* If a string allocator is configured for indefinite-length + * strings, it is configured here. + */ QCBORInternalAllocator StringAllocator; - // These are special for the internal MemPool allocator. - // They are not used otherwise. We tried packing these - // in the MemPool itself, but there are issues - // with memory alignment. + /* These are special for the internal MemPool allocator. They are + * not used otherwise. We tried packing these in the MemPool + * itself, but there are issues with memory alignment. + */ uint32_t uMemPoolSize; uint32_t uMemPoolFreeOffset; - // A cached offset to the end of the current map - // 0 if no value is cached. + /* A cached offset to the end of the current map 0 if no value is + * cached. + */ #define QCBOR_MAP_OFFSET_CACHE_INVALID UINT32_MAX uint32_t uMapEndOffsetCache; uint8_t uDecodeMode; uint8_t bStringAllocateAll; - uint8_t uLastError; // QCBORError stuffed into a uint8_t + uint8_t uLastError; /* QCBORError stuffed into a uint8_t */ /* See MapTagNumber() for description of how tags are mapped. */ uint64_t auMappedTags[QCBOR_NUM_MAPPED_TAGS]; uint16_t uLastTags[QCBOR_MAX_TAGS_PER_ITEM1]; - }; -// Used internally in the impementation here -// Must not conflict with any of the official CBOR types -#define CBOR_MAJOR_NONE_TYPE_RAW 9 -#define CBOR_MAJOR_NONE_TAG_LABEL_REORDER 10 -#define CBOR_MAJOR_NONE_TYPE_BSTR_LEN_ONLY 11 -#define CBOR_MAJOR_NONE_TYPE_OPEN_BSTR 12 + +/* Used internally in the impementation here Must not conflict with + * any of the official CBOR types + */ +#define CBOR_MAJOR_NONE_TAG_LABEL_REORDER 10 +#define CBOR_MAJOR_NONE_TYPE_OPEN_BSTR 12 -// Add this to types to indicate they are to be encoded as indefinite lengths +/* Add this to types to indicate they are to be encoded as indefinite lengths */ #define QCBOR_INDEFINITE_LEN_TYPE_MODIFIER 0x80 #define CBOR_MAJOR_NONE_TYPE_ARRAY_INDEFINITE_LEN \ CBOR_MAJOR_TYPE_ARRAY + QCBOR_INDEFINITE_LEN_TYPE_MODIFIER diff --git a/3rdparty/exported/QCBOR/qcbor/qcbor_spiffy_decode.h b/3rdparty/exported/QCBOR/qcbor/qcbor_spiffy_decode.h index 0faddc386307..48e3bbd2e510 100644 --- a/3rdparty/exported/QCBOR/qcbor/qcbor_spiffy_decode.h +++ b/3rdparty/exported/QCBOR/qcbor/qcbor_spiffy_decode.h @@ -1,15 +1,15 @@ -/*============================================================================ - qcbor_spiffy_decode.h -- higher-level easier-to-use CBOR decoding. - - Copyright (c) 2020-2021, Laurence Lundblade. All rights reserved. - Copyright (c) 2021, Arm Limited. All rights reserved. - - SPDX-License-Identifier: BSD-3-Clause - - See BSD-3-Clause license in README.md - - Forked from qcbor_decode.h on 7/23/2020 - ============================================================================*/ +/* ========================================================================== + * qcbor_spiffy_decode.h -- higher-level easier-to-use CBOR decoding. + * + * Copyright (c) 2020-2024, Laurence Lundblade. All rights reserved. + * Copyright (c) 2021, Arm Limited. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + * + * See BSD-3-Clause license in file named "LICENSE" + * + * Forked from qcbor_decode.h on 7/23/2020 + * ========================================================================== */ #ifndef qcbor_spiffy_decode_h #define qcbor_spiffy_decode_h @@ -26,1725 +26,2189 @@ extern "C" { /** - @file qcbor_spiffy_decode.h - - @anchor SpiffyDecode - # Spiffy Decode - - This section discusses spiffy decoding assuming familiarity with - the general description of decoding in the - @ref BasicDecode section. - - Spiffy decode is extra decode features over and above the @ref - BasicDecode features that generally are easier to use, mirror the - encoding functions better and can result in smaller code size for - larger and more complex CBOR protocols. In particular, spiffy decode - facilitates getting the next data item of a specific type, setting an - error if it is not of that type. It facilitates explicitly entering - and exiting arrays and maps. It facilates fetching items by label - from a map including duplicate label detection. - - Encoded CBOR can be viewed to have a tree structure where the leaf - nodes are non-aggregate types like integers and strings and the - intermediate nodes are either arrays or maps. Fundamentally, all - decoding is a pre-order traversal of the tree. Calling - QCBORDecode_GetNext() repeatedly will perform this. - - This pre-order traversal gives natural decoding of arrays where the - array members are taken in order, but does not give natural decoding - of maps where access by label is usually preferred. Using the - QCBORDecode_EnterMap() and QCBORDecode_GetXxxxInMapX() methods like - QCBORDecode_GetInt64InMapN(), map items can be accessed by - label. QCBORDecode_EnterMap() bounds decoding to a particular - map. QCBORDecode_GetXxxxInMapX() methods allows decoding the item of - a particular label in the particular map. This can be used with - nested maps by using QCBORDecode_EnterMapFromMapX(). - - When QCBORDecode_EnterMap() is called, pre-order traversal continues - to work. There is a cursor that is run over the tree with calls to - QCBORDecode_GetNext(). This can be intermixed with calls to - QCBORDecode_GetXxxxInMapX(). The pre-order traversal is limited just - to the map entered. Attempts to QCBORDecode_GetNext() beyond the end - of the map will give the @ref QCBOR_ERR_NO_MORE_ITEMS error. - - There is also QCBORDecode_EnterArray() to decode arrays. It will - narrow the traversal to the extent of the array entered. - - All the QCBORDecode_GetXxxxInMapX() methods support duplicate label - detection and will result in an error if the map has duplicate - labels. - - All the QCBORDecode_GetXxxxInMapX() methods are implemented by - performing the pre-order traversal of the map to find the labeled - item everytime it is called. It doesn't build up a hash table, a - binary search tree or some other efficiently searchable structure - internally. For simple trees this is fine and for high-speed CPUs - this is fine, but for complex trees on slow CPUs, it may have - performance issues (these have not be quantified yet). One way ease - this is to use QCBORDecode_GetItemsInMap() which allows decoding of a - list of items expected in an map in one traveral. - - @anchor Tag-Usage - ## Tag Usage - - Data types beyond the basic CBOR types of numbers, strings, maps and - arrays are called tags. The main registry of these new types is in - the IANA CBOR tags registry. These new types may be simple such a - number that is to be interpreted as a date, or of moderate complexity - such as defining a decimal fraction that is an array containing a - mantissa and exponent, or complex such as format for signing and - encryption. - - When a tag occurs in a protocol it is encoded as an integer tag - number plus the content of the tag. - - The content format of a tag may also be "borrowed". For example, a - protocol definition may say that a particular data item is an epoch - date just like tag 1, but not actually tag 1. In practice the - difference is the presence or absence of the integer tag number in - the encoded CBOR. - - The decoding functions for these new types takes a tag requirement - parameter to say whether the item is a tag, is just borrowing the - content format and is not a tag, or whether either is OK. - - If the parameter indicates the item must be a tag (@ref - QCBOR_TAG_REQUIREMENT_TAG), then @ref QCBOR_ERR_UNEXPECTED_TYPE is - set if it is not one of the expected tag types. To decode correctly - the contents of the tag must also be of the correct type. For - example, to decode an epoch date tag the content must be an integer - or floating-point value. - - If the parameter indicates it should not be a tag - (@ref QCBOR_TAG_REQUIREMENT_NOT_A_TAG), then - @ref QCBOR_ERR_UNEXPECTED_TYPE set if it is a tag or the type of the - encoded CBOR is not what is expected. In the example of an epoch - date, the data type must be an integer or floating-point value. This - is the case where the content format of a tag is borrowed. - - The parameter can also indicate that either a tag or no tag is - allowed ( @ref QCBOR_TAG_REQUIREMENT_OPTIONAL_TAG ). A good protocol - design should however be clear and choose one or the other and not - need this option. This is a way to implement "be liberal in what you - accept", however these days that is less in favor. See - https://tools.ietf.org/id/draft-thomson-postel-was-wrong-03.html. - - Map searching works with indefinite length strings. A string - allocator must be set up the same as for any handling of indefinite - length strings. However, It currently over-allocates memory from the - string pool and thus requires a much larger string pool than it - should. The over-allocation happens every time a map is searched by - label. (This may be corrected in the future). -*/ + * @file qcbor_spiffy_decode.h + * + * @anchor SpiffyDecode + * # Spiffy Decode + * + * This section discusses spiffy decoding assuming familiarity with + * the general description of decoding in the + * @ref BasicDecode section. + * + * Spiffy decode is extra decode features over and above the @ref + * BasicDecode features that generally are easier to use, mirror the + * encoding functions better and can result in smaller code size for + * larger and more complex CBOR protocols. In particular, spiffy + * decode facilitates getting the next data item of a specific type, + * setting an error if it is not of that type. It facilitates + * explicitly entering and exiting arrays and maps. It facilates + * fetching items by label from a map including duplicate label + * detection. + * + * Encoded CBOR can be viewed to have a tree structure where the leaf + * nodes are non-aggregate types like integers and strings and the + * intermediate nodes are either arrays or maps. Fundamentally, all + * decoding is a pre-order traversal of the tree. Calling + * QCBORDecode_GetNext() repeatedly will perform this. + * + * This pre-order traversal gives natural decoding of arrays where the + * array members are taken in order, but does not give natural decoding + * of maps where access by label is usually preferred. Using the + * QCBORDecode_EnterMap() and QCBORDecode_GetXxxxInMapX() methods like + * QCBORDecode_GetInt64InMapN(), map items can be accessed by + * label. QCBORDecode_EnterMap() bounds decoding to a particular + * map. QCBORDecode_GetXxxxInMapX() methods allows decoding the item of + * a particular label in the particular map. This can be used with + * nested maps by using QCBORDecode_EnterMapFromMapX(). + * + * When QCBORDecode_EnterMap() is called, pre-order traversal + * continues to work. There is a cursor that is run over the tree with + * calls to QCBORDecode_GetNext(). Attempts to use + * QCBORDecode_GetNext() beyond the end of the map will give the + * @ref QCBOR_ERR_NO_MORE_ITEMS error. + * + * Use of the traversal cursor can be mixed with the fetching of items + * by label with some caveats. When a non-aggregate item like an + * integer or string is fetched by label, the traversal cursor is + * unaffected so the mixing can be done freely. When an aggregate + * item is entered by label (by QCBORDecode_EnterMapFromMapN() and + * similar), the traversal cursor is set to the item after the + * subordinate aggregate item when it is exited. This will not matter + * to many use cases. Use cases that mix can be sure to separate + * traversal by the cursor from fetching by label. + * QCBORDecode_Rewind() may be useful to reset the traversal cursor + * after fetching aggregate items by label. + * + * (This behavior was incorrectly documented in QCBOR 1.2 and prior + * which described aggregate and non-aggregate as behaving the same. + * Rather than changing to make aggregate and non-aggregate + * consistent, the behavior is retained and documented because 1) it + * is usable as is, 2) a change would bring backward compatibility + * issues, 3) the change would increase the decode context size and + * code size. In QCBOR 1.3 test cases were added to validate the + * behavior. No problems were uncovered.) + * + * QCBORDecode_EnterArray() can be used to narrow the traversal to the + * extent of the array. + * + * All the QCBORDecode_GetXxxxInMapX() methods support duplicate label + * detection and will result in an error if the map has duplicate + * labels. + * + * All the QCBORDecode_GetXxxxInMapX() methods are implemented by + * performing the pre-order traversal of the map to find the labeled + * item everytime it is called. It doesn't build up a hash table, a + * binary search tree or some other efficiently searchable structure + * internally. For small maps this is fine and for high-speed CPUs + * this is fine, but for large, perhaps deeply nested, maps on slow + * CPUs, it may have performance issues (these have not be + * quantified). One way ease this is to use + * QCBORDecode_GetItemsInMap() which allows decoding of a list of + * items expected in an map in one traveral. + * + * @anchor Tag-Usage + * ## Tag Usage + * + * Data types beyond the basic CBOR types of numbers, strings, maps and + * arrays are called tags. The main registry of these new types is in + * the IANA CBOR tags registry. These new types may be simple such a + * number that is to be interpreted as a date, or of moderate complexity + * such as defining a decimal fraction that is an array containing a + * mantissa and exponent, or complex such as format for signing and + * encryption. + * + * When a tag occurs in a protocol it is encoded as an integer tag + * number plus the content of the tag. + * + * The content format of a tag may also be "borrowed". For example, a + * protocol definition may say that a particular data item is an epoch + * date just like tag 1, but not actually tag 1. In practice the + * difference is the presence or absence of the integer tag number in + * the encoded CBOR. + * + * The decoding functions for these new types takes a tag requirement + * parameter to say whether the item is a tag, is just borrowing the + * content format and is not a tag, or whether either is OK. + * + * If the parameter indicates the item must be a tag (@ref + * QCBOR_TAG_REQUIREMENT_TAG), then @ref QCBOR_ERR_UNEXPECTED_TYPE is + * set if it is not one of the expected tag types. To decode correctly + * the contents of the tag must also be of the correct type. For + * example, to decode an epoch date tag the content must be an integer + * or floating-point value. + * + * If the parameter indicates it should not be a tag + * (@ref QCBOR_TAG_REQUIREMENT_NOT_A_TAG), then + * @ref QCBOR_ERR_UNEXPECTED_TYPE set if it is a tag or the type of the + * encoded CBOR is not what is expected. In the example of an epoch + * date, the data type must be an integer or floating-point value. This + * is the case where the content format of a tag is borrowed. + * + * The parameter can also indicate that either a tag or no tag is + * allowed ( @ref QCBOR_TAG_REQUIREMENT_OPTIONAL_TAG ). A good protocol + * design should however be clear and choose one or the other and not + * need this option. This is a way to implement "be liberal in what you + * accept", however these days that is less in favor. See + * https://tools.ietf.org/id/draft-thomson-postel-was-wrong-03.html. + * + * Map searching works with indefinite length strings. A string + * allocator must be set up the same as for any handling of indefinite + * length strings. However, It currently over-allocates memory from the + * string pool and thus requires a much larger string pool than it + * should. The over-allocation happens every time a map is searched by + * label. (This may be corrected in the future). + */ /** The data item must be a tag of the expected type. It is an error - if it is not. For example when calling QCBORDecode_GetEpochDate(), - the data item must be an @ref CBOR_TAG_DATE_EPOCH tag. - See @ref Tag-Usage. */ + * if it is not. For example when calling QCBORDecode_GetEpochDate(), + * the data item must be an @ref CBOR_TAG_DATE_EPOCH tag. See + * @ref Tag-Usage. */ #define QCBOR_TAG_REQUIREMENT_TAG 0 /** The data item must be of the type expected for content data type - being fetched. It is an error if it is not. For example, when - calling QCBORDecode_GetEpochDate() and it must not be an @ref - CBOR_TAG_DATE_EPOCH tag. See @ref Tag-Usage. */ + * being fetched. It is an error if it is not. For example, when + * calling QCBORDecode_GetEpochDate() and it must not be an @ref + * CBOR_TAG_DATE_EPOCH tag. See @ref Tag-Usage. */ #define QCBOR_TAG_REQUIREMENT_NOT_A_TAG 1 /** Either of the above two are allowed. This allows implementation of - being liberal in what you receive, but it is better if CBOR-based - protocols pick one and stick to and not required the reciever to - take either. See @ref Tag-Usage. */ + * being liberal in what you receive, but it is better if CBOR-based + * protocols pick one and stick to and not required the reciever to + * take either. See @ref Tag-Usage. */ #define QCBOR_TAG_REQUIREMENT_OPTIONAL_TAG 2 /** Add this into the above value if other tags not processed by QCBOR - are to be allowed to surround the data item. See @ref Tag-Usage. */ + * are to be allowed to surround the data item. See @ref Tag-Usage. */ #define QCBOR_TAG_REQUIREMENT_ALLOW_ADDITIONAL_TAGS 0x80 /** Conversion will proceed if the CBOR item to be decoded is an - integer or either type 0 (unsigned) or type 1 (negative). */ + * integer or either type 0 (unsigned) or type 1 (negative). */ #define QCBOR_CONVERT_TYPE_XINT64 0x01 /** Conversion will proceed if the CBOR item to be decoded is either - double, single or half-precision floating-point (major type 7). */ + * double, single or half-precision floating-point (major type 7). */ #define QCBOR_CONVERT_TYPE_FLOAT 0x02 /** Conversion will proceed if the CBOR item to be decoded is a big - number, positive or negative (tag 2 or tag 3). */ + * number, positive or negative (tag 2 or tag 3). */ #define QCBOR_CONVERT_TYPE_BIG_NUM 0x04 /** Conversion will proceed if the CBOR item to be decoded is a - decimal fraction (tag 4). */ + * decimal fraction (tag 4). */ #define QCBOR_CONVERT_TYPE_DECIMAL_FRACTION 0x08 /** Conversion will proceed if the CBOR item to be decoded is a big - float (tag 5). */ + * float (tag 5). */ #define QCBOR_CONVERT_TYPE_BIGFLOAT 0x10 /** - @brief Decode next item into a signed 64-bit integer. - - @param[in] pCtx The decode context. - @param[out] pnValue The returned 64-bit signed integer. - - The CBOR data item to decode must be a positive or negative integer - (CBOR major type 0 or 1). If not @ref QCBOR_ERR_UNEXPECTED_TYPE is set. - - If the CBOR integer is either too large or too small to fit in an - int64_t, the error @ref QCBOR_ERR_INT_OVERFLOW or @ref - QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW is set. Note that type 0 - unsigned integers can be larger than will fit in an int64_t and type - 1 negative integers can be smaller than will fit in an int64_t. - - Please see @ref Decode-Errors-Overview "Decode Errors Overview". - - See also QCBORDecode_GetUInt64(), QCBORDecode_GetInt64Convert() and - QCBORDecode_GetInt64ConvertAll(). + * @brief Decode next item into a signed 64-bit integer. + * + * @param[in] pCtx The decode context. + * @param[out] pnValue The returned 64-bit signed integer. + * + * The CBOR data item to decode must be a positive or negative integer + * (CBOR major type 0 or 1). If not @ref QCBOR_ERR_UNEXPECTED_TYPE is set. + * + * If the CBOR integer is either too large or too small to fit in an + * int64_t, the error @ref QCBOR_ERR_INT_OVERFLOW or + * @ref QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW is set. Note that type 0 + * unsigned integers can be larger than will fit in an int64_t and + * type 1 negative integers can be smaller than will fit in an + * int64_t. + * + * Please see @ref Decode-Errors-Overview "Decode Errors Overview". + * + * See also QCBORDecode_GetUInt64(), QCBORDecode_GetInt64Convert(), + * QCBORDecode_GetInt64ConvertAll() and QCBORDecode_GetDoubleConvert() */ -static void QCBORDecode_GetInt64(QCBORDecodeContext *pCtx, - int64_t *pnValue); +static void +QCBORDecode_GetInt64(QCBORDecodeContext *pCtx, + int64_t *pnValue); -static void QCBORDecode_GetInt64InMapN(QCBORDecodeContext *pCtx, - int64_t nLabel, - int64_t *pnValue); +static void +QCBORDecode_GetInt64InMapN(QCBORDecodeContext *pCtx, + int64_t nLabel, + int64_t *pnValue); -static void QCBORDecode_GetInt64InMapSZ(QCBORDecodeContext *pCtx, - const char *szLabel, - int64_t *pnValue); +static void +QCBORDecode_GetInt64InMapSZ(QCBORDecodeContext *pCtx, + const char *szLabel, + int64_t *pnValue); /** - @brief Decode next item into a signed 64-bit integer with basic conversions. + * @brief Decode next item into a signed 64-bit integer with basic conversions. + * + * @param[in] pCtx The decode context. + * @param[in] uConvertTypes The integer conversion options. + * @param[out] pnValue The returned 64-bit signed integer. + * + * @c uConvertTypes controls what conversions this will perform and + * thus what CBOR types will be decoded. @c uConvertType is a bit map + * listing the conversions to be allowed. This function supports + * @ref QCBOR_CONVERT_TYPE_XINT64 and @ref QCBOR_CONVERT_TYPE_FLOAT + * conversions. + * + * Please see @ref Decode-Errors-Overview "Decode Errors Overview". + * + * If the CBOR data type can never be convered by this function or the + * conversion was not selected in @c uConversionTypes + * @ref QCBOR_ERR_UNEXPECTED_TYPE is set. + * + * When converting floating-point values, the integer is rounded to + * the nearest integer using llround(). By default, floating-point + * suport is enabled for QCBOR. + * + * If floating-point HW use is disabled this will set + * @ref QCBOR_ERR_HW_FLOAT_DISABLED if a single-precision number is + * encountered. If half-precision support is disabled, this will set + * @ref QCBOR_ERR_HALF_PRECISION_DISABLED if a half-precision number + * is encountered. + * + * If floating-point usage is disabled this will set + * @ref QCBOR_ERR_ALL_FLOAT_DISABLED if a floating point value is + * encountered. + * + * See also QCBORDecode_GetInt64ConvertAll() which will perform the + * same conversions as this and a lot more at the cost of adding more + * object code to your executable. + */ +static void +QCBORDecode_GetInt64Convert(QCBORDecodeContext *pCtx, + uint32_t uConvertTypes, + int64_t *pnValue); - @param[in] pCtx The decode context. - @param[in] uConvertTypes The integer conversion options. - @param[out] pnValue The returned 64-bit signed integer. +static void +QCBORDecode_GetInt64ConvertInMapN(QCBORDecodeContext *pCtx, + int64_t nLabel, + uint32_t uConvertTypes, + int64_t *pnValue); - @c uConvertTypes controls what conversions this will perform and thus - what CBOR types will be decoded. @c uConvertType is a bit map - listing the conversions to be allowed. This function supports @ref - QCBOR_CONVERT_TYPE_XINT64 and @ref QCBOR_CONVERT_TYPE_FLOAT - conversions. +static void +QCBORDecode_GetInt64ConvertInMapSZ(QCBORDecodeContext *pCtx, + const char *szLabel, + uint32_t uConvertTypes, + int64_t *pnValue); - Please see @ref Decode-Errors-Overview "Decode Errors Overview". - If the CBOR data type can never be convered by this function or the - conversion was not selected in @c uConversionTypes @ref - @ref QCBOR_ERR_UNEXPECTED_TYPE is set. +/** + * @brief Decode next item into a signed 64-bit integer with conversions. + * + * @param[in] pCtx The decode context. + * @param[in] uConvertTypes The integer conversion options. + * @param[out] pnValue The returned 64-bit signed integer. + * + * This is the same as QCBORDecode_GetInt64Convert() but additionally + * supports conversion from positive and negative bignums, decimal + * fractions and big floats, including decimal fractions and big floats + * that use bignums. The conversion types supported are + * @ref QCBOR_CONVERT_TYPE_XINT64, @ref QCBOR_CONVERT_TYPE_FLOAT, + * @ref QCBOR_CONVERT_TYPE_BIG_NUM, + * @ref QCBOR_CONVERT_TYPE_DECIMAL_FRACTION and + * @ref QCBOR_CONVERT_TYPE_BIGFLOAT. + * + * Please see @ref Decode-Errors-Overview "Decode Errors Overview". + * + * Note that most these types can support numbers much larger that can + * be represented by in a 64-bit integer, so + * @ref QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW may often be encountered. + * + * When converting bignums and decimal fractions, + * @ref QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW will be set if the result + * is below 1, unless the mantissa is zero, in which case the + * coversion is successful and the value of 0 is returned. + * + * See also QCBORDecode_GetInt64ConvertAll() which does some of these + * conversions, but links in much less object code. See also + * QCBORDecode_GetUInt64ConvertAll(). + * + * This relies on CBOR tags to identify big numbers, decimal fractions + * and big floats. It will not attempt to decode non-tag CBOR that might + * be one of these. (If QCBOR_DISABLE_TAGS is set, this is effectively + * the same as QCBORDecode_GetInt64Convert() because all the additional + * number types this decodes are tags). + */ +void +QCBORDecode_GetInt64ConvertAll(QCBORDecodeContext *pCtx, + uint32_t uConvertTypes, + int64_t *pnValue); - When converting floating-point values, the integer is rounded to the - nearest integer using llround(). By default, floating-point suport is - enabled for QCBOR. +void +QCBORDecode_GetInt64ConvertAllInMapN(QCBORDecodeContext *pCtx, + int64_t nLabel, + uint32_t uConvertTypes, + int64_t *pnValue); - If floating-point HW use is disabled this will set - @ref QCBOR_ERR_HW_FLOAT_DISABLED if a single-precision - number is encountered. If half-precision support is disabled, - this will set QCBOR_ERR_HALF_PRECISION_DISABLED if - a half-precision number is encountered. +void +QCBORDecode_GetInt64ConvertAllInMapSZ(QCBORDecodeContext *pCtx, + const char *szLabel, + uint32_t uConvertTypes, + int64_t *pnValue); - If floating-point usage is disabled this will set @ref QCBOR_ERR_ALL_FLOAT_DISABLED - if a floating point value is encountered. - See also QCBORDecode_GetInt64ConvertAll() which will perform the same - conversions as this and a lot more at the cost of adding more object - code to your executable. +/** + * @brief Decode next item into an unsigned 64-bit integer. + * + * @param[in] pCtx The decode context. + * @param[out] puValue The returned 64-bit unsigned integer. + * + * This is the same as QCBORDecode_GetInt64(), but returns an unsigned integer + * and thus can only decode CBOR positive integers. + * @ref QCBOR_ERR_NUMBER_SIGN_CONVERSION is set if the input is a negative + * integer. + * + * Please see @ref Decode-Errors-Overview "Decode Errors Overview". + * + * See also QCBORDecode_GetUInt64Convert() and QCBORDecode_GetUInt64ConvertAll(). */ -static void QCBORDecode_GetInt64Convert(QCBORDecodeContext *pCtx, - uint32_t uConvertTypes, - int64_t *pnValue); +static void +QCBORDecode_GetUInt64(QCBORDecodeContext *pCtx, + uint64_t *puValue); -static void QCBORDecode_GetInt64ConvertInMapN(QCBORDecodeContext *pCtx, - int64_t nLabel, - uint32_t uConvertTypes, - int64_t *pnValue); +static void +QCBORDecode_GetUInt64InMapN(QCBORDecodeContext *pCtx, + int64_t nLabel, + uint64_t *puValue); -static void QCBORDecode_GetInt64ConvertInMapSZ(QCBORDecodeContext *pCtx, - const char *szLabel, - uint32_t uConvertTypes, - int64_t *pnValue); +static void +QCBORDecode_GetUInt64InMapSZ(QCBORDecodeContext *pCtx, + const char *szLabel, + uint64_t *puValue); /** - @brief Decode next item into a signed 64-bit integer with conversions. - - @param[in] pCtx The decode context. - @param[in] uConvertTypes The integer conversion options. - @param[out] pnValue The returned 64-bit signed integer. - - This is the same as QCBORDecode_GetInt64Convert() but additionally - supports conversion from positive and negative bignums, decimal - fractions and big floats, including decimal fractions and big floats - that use bignums. The conversion types supported are @ref - QCBOR_CONVERT_TYPE_XINT64, @ref QCBOR_CONVERT_TYPE_FLOAT, @ref - QCBOR_CONVERT_TYPE_BIG_NUM, @ref QCBOR_CONVERT_TYPE_DECIMAL_FRACTION - and @ref QCBOR_CONVERT_TYPE_BIGFLOAT. - - Please see @ref Decode-Errors-Overview "Decode Errors Overview". - - Note that most these types can support numbers much larger that can - be represented by in a 64-bit integer, so @ref - QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW may often be encountered. - - When converting bignums and decimal fractions @ref - QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW will be set if the result is - below 1, unless the mantissa is zero, in which case the coversion is - successful and the value of 0 is returned. - - See also QCBORDecode_GetInt64ConvertAll() which does some of these - conversions, but links in much less object code. See also - QCBORDecode_GetUInt64ConvertAll(). - - This relies on CBOR tags to identify big numbers, decimal fractions - and big floats. It will not attempt to decode non-tag CBOR that might - be one of these. (If QCBOR_DISABLE_TAGS is set, this is effectively - the same as QCBORDecode_GetInt64Convert() because all the additional - number types this decodes are tags). + * @brief Decode next item as an unsigned 64-bit integer with basic conversions. + * + * @param[in] pCtx The decode context. + * @param[in] uConvertTypes The integer conversion options. + * @param[out] puValue The returned 64-bit unsigned integer. + * + * This is the same as QCBORDecode_GetInt64Convert(), but returns an + * unsigned integer and thus sets @ref QCBOR_ERR_NUMBER_SIGN_CONVERSION + * if the value to be decoded is negatve. + * + * If floating-point HW use is disabled this will set + * @ref QCBOR_ERR_HW_FLOAT_DISABLED if a single-precision number is + * encountered. If half-precision support is disabled, this will set + * @ref QCBOR_ERR_HALF_PRECISION_DISABLED if a half-precision number + * is encountered. + * + * If floating-point usage is disabled this will set + * @ref QCBOR_ERR_ALL_FLOAT_DISABLED if a floating point value is + * encountered. + * + * See also QCBORDecode_GetUInt64Convert() and + * QCBORDecode_GetUInt64ConvertAll(). */ -void QCBORDecode_GetInt64ConvertAll(QCBORDecodeContext *pCtx, - uint32_t uConvertTypes, - int64_t *pnValue); +static void +QCBORDecode_GetUInt64Convert(QCBORDecodeContext *pCtx, + uint32_t uConvertTypes, + uint64_t *puValue); -void QCBORDecode_GetInt64ConvertAllInMapN(QCBORDecodeContext *pCtx, - int64_t nLabel, - uint32_t uConvertTypes, - int64_t *pnValue); +static void +QCBORDecode_GetUInt64ConvertInMapN(QCBORDecodeContext *pCtx, + int64_t nLabel, + uint32_t uConvertTypes, + uint64_t *puValue); -void QCBORDecode_GetInt64ConvertAllInMapSZ(QCBORDecodeContext *pCtx, - const char *szLabel, - uint32_t uConvertTypes, - int64_t *pnValue); +static void +QCBORDecode_GetUInt64ConvertInMapSZ(QCBORDecodeContext *pCtx, + const char *szLabel, + uint32_t uConvertTypes, + uint64_t *puValue); /** - @brief Decode next item into an unsigned 64-bit integer. - - @param[in] pCtx The decode context. - @param[out] puValue The returned 64-bit unsigned integer. - - This is the same as QCBORDecode_GetInt64(), but returns an unsigned integer - and thus can only decode CBOR positive integers. - @ref QCBOR_ERR_NUMBER_SIGN_CONVERSION is set if the input is a negative - integer. + * @brief Decode next item into an unsigned 64-bit integer with conversions + * + * @param[in] pCtx The decode context. + * @param[in] uConvertTypes The integer conversion options. + * @param[out] puValue The returned 64-bit unsigned integer. + * + * This is the same as QCBORDecode_GetInt64ConvertAll(), but returns + * an unsigned integer and thus sets @ref QCBOR_ERR_NUMBER_SIGN_CONVERSION + * if the value to be decoded is negatve. + * + * See also QCBORDecode_GetUInt64() and QCBORDecode_GetUInt64Convert(). + */ +void +QCBORDecode_GetUInt64ConvertAll(QCBORDecodeContext *pCtx, + uint32_t uConvertTypes, + uint64_t *puValue); - Please see @ref Decode-Errors-Overview "Decode Errors Overview". +void +QCBORDecode_GetUInt64ConvertAllInMapN(QCBORDecodeContext *pCtx, + int64_t nLabel, + uint32_t uConvertTypes, + uint64_t *puValue); - See also QCBORDecode_GetUInt64Convert() and QCBORDecode_GetUInt64ConvertAll(). -*/ -static void QCBORDecode_GetUInt64(QCBORDecodeContext *pCtx, - uint64_t *puValue); +void +QCBORDecode_GetUInt64ConvertAllInMapSZ(QCBORDecodeContext *pCtx, + const char *szLabel, + uint32_t uConvertTypes, + uint64_t *puValue); -static void QCBORDecode_GetUInt64InMapN(QCBORDecodeContext *pCtx, - int64_t nLabel, - uint64_t *puValue); -static void QCBORDecode_GetUInt64InMapSZ(QCBORDecodeContext *pCtx, - const char *szLabel, - uint64_t *puValue); /** - @brief Decode next item as an unsigned 64-bit integer with basic conversions. - - @param[in] pCtx The decode context. - @param[in] uConvertTypes The integer conversion options. - @param[out] puValue The returned 64-bit unsigned integer. - - This is the same as QCBORDecode_GetInt64Convert(), but returns an - unsigned integer and thus sets @ref QCBOR_ERR_NUMBER_SIGN_CONVERSION - is set if the value to be decoded is negatve. - - If floating-point HW use is disabled this will set - @ref QCBOR_ERR_HW_FLOAT_DISABLED if a single-precision - number is encountered. If half-precision support is disabled, - this will set QCBOR_ERR_HALF_PRECISION_DISABLED if - a half-precision number is encountered. - - If floating-point usage is disabled this will set @ref QCBOR_ERR_ALL_FLOAT_DISABLED - if a floating point value is encountered. - - See also QCBORDecode_GetUInt64Convert() and - QCBORDecode_GetUInt64ConvertAll(). -*/ -static void QCBORDecode_GetUInt64Convert(QCBORDecodeContext *pCtx, - uint32_t uConvertTypes, - uint64_t *puValue); + * @brief Decode the next item as a byte string + * + * @param[in] pCtx The decode context. + * @param[out] pBytes The decoded byte string. + * + * The CBOR item to decode must be a byte string, CBOR type 2. + * + * Please see @ref Decode-Errors-Overview "Decode Errors Overview". + * + * If the CBOR item to decode is not a byte string, the + * @ref QCBOR_ERR_UNEXPECTED_TYPE error is set. + */ +static void +QCBORDecode_GetByteString(QCBORDecodeContext *pCtx, + UsefulBufC *pBytes); -static void QCBORDecode_GetUInt64ConvertInMapN(QCBORDecodeContext *pCtx, - int64_t nLabel, - uint32_t uConvertTypes, - uint64_t *puValue); +static void +QCBORDecode_GetByteStringInMapN(QCBORDecodeContext *pCtx, + int64_t nLabel, + UsefulBufC *pBytes); -static void QCBORDecode_GetUInt64ConvertInMapSZ(QCBORDecodeContext *pCtx, - const char *szLabel, - uint32_t uConvertTypes, - uint64_t *puValue); +static void +QCBORDecode_GetByteStringInMapSZ(QCBORDecodeContext *pCtx, + const char *szLabel, + UsefulBufC *pBytes); /** - @brief Decode next item into an unsigned 64-bit integer with conversions - - @param[in] pCtx The decode context. - @param[in] uConvertTypes The integer conversion options. - @param[out] puValue The returned 64-bit unsigned integer. - - This is the same as QCBORDecode_GetInt64ConvertAll(), but returns an - unsigned integer and thus sets @ref QCBOR_ERR_NUMBER_SIGN_CONVERSION - if the value to be decoded is negatve. - - See also QCBORDecode_GetUInt64() and - QCBORDecode_GetUInt64Convert(). -*/ -void QCBORDecode_GetUInt64ConvertAll(QCBORDecodeContext *pCtx, - uint32_t uConvertTypes, - uint64_t *puValue); + * @brief Decode the next item as a text string. + * + * @param[in] pCtx The decode context. + * @param[out] pText The decoded byte string. + * + * The CBOR item to decode must be a text string, CBOR type 3. + * + * Please see @ref Decode-Errors-Overview "Decode Errors Overview". + * It the CBOR item to decode is not a text string, the + * @ref QCBOR_ERR_UNEXPECTED_TYPE error is set. + * + * This does no translation of line endings. See QCBOREncode_AddText() + * for a discussion of line endings in CBOR. + */ +static void +QCBORDecode_GetTextString(QCBORDecodeContext *pCtx, + UsefulBufC *pText); -void QCBORDecode_GetUInt64ConvertAllInMapN(QCBORDecodeContext *pCtx, - int64_t nLabel, - uint32_t uConvertTypes, - uint64_t *puValue); +static void +QCBORDecode_GetTextStringInMapN(QCBORDecodeContext *pCtx, + int64_t nLabel, + UsefulBufC *pText); -void QCBORDecode_GetUInt64ConvertAllInMapSZ(QCBORDecodeContext *pCtx, - const char *szLabel, - uint32_t uConvertTypes, - uint64_t *puValue); +static void +QCBORDecode_GetTextStringInMapSZ(QCBORDecodeContext *pCtx, + const char *szLabel, + UsefulBufC *pText); +#ifndef USEFULBUF_DISABLE_ALL_FLOAT /** - @brief Decode the next item as a byte string + * @brief Decode next item into a double floating-point value. + * + * @param[in] pCtx The decode context. + * @param[out] pValue The returned floating-point value. + * + * The CBOR data item to decode must be a half-precision, + * single-precision or double-precision floating-point value. If not + * @ref QCBOR_ERR_UNEXPECTED_TYPE is set. + * + * If floating-point HW use is disabled this will set + * @ref QCBOR_ERR_HW_FLOAT_DISABLED if a single-precision number is + * encountered. If half-precision support is disabled, this will set + * @ref QCBOR_ERR_HALF_PRECISION_DISABLED if a half-precision number + * is encountered. + * + * Please see @ref Decode-Errors-Overview "Decode Errors Overview". + * + * See also QCBORDecode_GetDoubleConvert() and + * QCBORDecode_GetDoubleConvertAll(). + */ +static void +QCBORDecode_GetDouble(QCBORDecodeContext *pCtx, + double *pValue); + +static void +QCBORDecode_GetDoubleInMapN(QCBORDecodeContext *pCtx, + int64_t nLabel, + double *pdValue); - @param[in] pCtx The decode context - @param[out] pBytes The decoded byte string +static void +QCBORDecode_GetDoubleInMapSZ(QCBORDecodeContext *pCtx, + const char *szLabel, + double *pdValue); - The CBOR item to decode must be a byte string, CBOR type 2. - Please see @ref Decode-Errors-Overview "Decode Errors Overview". +/** + * @brief Decode next item into a double floating-point with basic conversion. + * + * @param[in] pCtx The decode context. + * @param[in] uConvertTypes The integer conversion options. + * @param[out] pdValue The returned floating-point value. + * + * This will decode CBOR integer and floating-point numbers, returning + * them as a double floating-point number. This function supports - If the CBOR item to decode is not a byte string, the @ref - QCBOR_ERR_UNEXPECTED_TYPE error is set. + * @ref QCBOR_CONVERT_TYPE_XINT64 and @ref QCBOR_CONVERT_TYPE_FLOAT + * conversions. If the encoded CBOR is not one of the requested types + * or a type not supported by this function, @ref QCBOR_ERR_UNEXPECTED_TYPE + * is set. + * + * Please see @ref Decode-Errors-Overview "Decode Errors Overview". + * + * If floating-point HW use is disabled this will set + * @ref QCBOR_ERR_HW_FLOAT_DISABLED if a single-precision number is + * encountered. If half-precision support is disabled, this will set + * @ref QCBOR_ERR_HALF_PRECISION_DISABLED if a half-precision number is + * encountered. + * + * Positive and negative integers can always be converted to + * floating-point, so this will never error on CBOR major type 0 or 1. + * + * Note that a large 64-bit integer can have more precision (64 bits) + * than even a double floating-point (52 bits) value, so there is loss + * of precision in some conversions. + * + * See also QCBORDecode_GetDouble() and QCBORDecode_GetDoubleConvertAll(). */ -static void QCBORDecode_GetByteString(QCBORDecodeContext *pCtx, - UsefulBufC *pBytes); +static void +QCBORDecode_GetDoubleConvert(QCBORDecodeContext *pCtx, + uint32_t uConvertTypes, + double *pdValue); -static void QCBORDecode_GetByteStringInMapN(QCBORDecodeContext *pCtx, - int64_t nLabel, - UsefulBufC *pBytes); +static void +QCBORDecode_GetDoubleConvertInMapN(QCBORDecodeContext *pCtx, + int64_t nLabel, + uint32_t uConvertTypes, + double *pdValue); -static void QCBORDecode_GetByteStringInMapSZ(QCBORDecodeContext *pCtx, - const char *szLabel, - UsefulBufC *pBytes); +static void +QCBORDecode_GetDoubleConvertInMapSZ(QCBORDecodeContext *pCtx, + const char *szLabel, + uint32_t uConvertTypes, + double *pdValue); /** - @brief Decode the next item as a text string. + * @brief Decode next item as a double floating-point value with conversion. + * + * @param[in] pCtx The decode context. + * @param[in] uConvertTypes The integer conversion options. + * @param[out] pdValue The returned floating-point value. + * + * This is the same as QCBORDecode_GetDoubleConvert() but supports + * many more conversions at the cost of linking in more object + * code. The conversion types supported are @ref QCBOR_CONVERT_TYPE_XINT64, + * @ref QCBOR_CONVERT_TYPE_FLOAT, @ref QCBOR_CONVERT_TYPE_BIG_NUM, + * @ref QCBOR_CONVERT_TYPE_DECIMAL_FRACTION and + * @ref QCBOR_CONVERT_TYPE_BIGFLOAT. + * + * Big numbers, decimal fractions and big floats that are too small or + * too large to be reprented as a double floating-point number will be + * returned as plus or minus zero or infinity rather than setting an + * under or overflow error. + * + * There is often loss of precision in the conversion. + * + * See also QCBORDecode_GetDoubleConvert() and QCBORDecode_GetDoubleConvert(). + */ +void +QCBORDecode_GetDoubleConvertAll(QCBORDecodeContext *pCtx, + uint32_t uConvertTypes, + double *pdValue); - @param[in] pCtx The decode context. - @param[out] pText The decoded byte string. +void +QCBORDecode_GetDoubleConvertAllInMapN(QCBORDecodeContext *pCtx, + int64_t nLabel, + uint32_t uConvertTypes, + double *pdValue); - The CBOR item to decode must be a text string, CBOR type 3. +void +QCBORDecode_GetDoubleConvertAllInMapSZ(QCBORDecodeContext *pCtx, + const char *szLabel, + uint32_t uConvertTypes, + double *pdValue); +#endif /* USEFULBUF_DISABLE_ALL_FLOAT */ - Please see @ref Decode-Errors-Overview "Decode Errors Overview". It the CBOR item - to decode is not a text string, the @ref QCBOR_ERR_UNEXPECTED_TYPE - error is set. - This does no translation of line endings. See QCBOREncode_AddText() - for a discussion of line endings in CBOR. -*/ -static void QCBORDecode_GetTextString(QCBORDecodeContext *pCtx, - UsefulBufC *pText); -static void QCBORDecode_GetTextStringInMapN(QCBORDecodeContext *pCtx, - int64_t nLabel, - UsefulBufC *pText); -static void QCBORDecode_GetTextStringInMapSZ(QCBORDecodeContext *pCtx, - const char *szLabel, - UsefulBufC *pText); +/** + * @brief Enter an array for decoding in bounded mode. + * + * @param[in] pCtx The decode context. + * @param[out] pItem The optionally returned QCBORItem that has the + * label and tags for the array. May be @c NULL (and + * usually is). + * + * This enters an array for decoding in bounded mode. The items in + * the array are decoded in order the same as when not in bounded mode, + * but the decoding will not proceed past the end or the array. + * + * The typical way to iterate over items in an array is to call + * QCBORDecode_VGetNext() until QCBORDecode_GetError() returns + * @ref QCBOR_ERR_NO_MORE_ITEMS. Other methods like QCBORDecode_GetInt64(), + * QCBORDecode_GetBignum() and such may also called until + * QCBORDecode_GetError() doesn't return QCBOR_SUCCESS. + * + * Another option is to get the array item count from + * @c pItem->val.uCount, but note that that will not work with + * indefinte-length arrays, where as QCBORDecode_GetError() will. + * + * Nested decoding of arrays may be handled by calling + * QCBORDecode_EnterArray() or by using QCBORDecode_VGetNext() to + * descend into and back out of the nested array. + * + * QCBORDecode_Rewind() can be called to restart decoding from the + * first item in the array. + * + * When all decoding in an array is complete, QCBORDecode_ExitArray() must + * be called. It is a decoding error to not have a corresponding call + * to QCBORDecode_ExitArray() for every call to QCBORDecode_EnterArray(). + * If not, @ref QCBOR_ERR_ARRAY_OR_MAP_STILL_OPEN will be returned when + * QCBORDecode_Finish() is called. + * + * After QCBORDecode_ExitArray() is called the traversal cusor is at + * the item right after the array. This is true whether or not all + * items in the array were consumed. QCBORDecode_ExitArray() can even + * be called right after QCBORDecode_EnterArray() as a way to skip + * over an array and all its contents. + * + * This works the same for definite and indefinite length arrays. + * + * Please see @ref Decode-Errors-Overview "Decode Errors Overview". + * + * If attempting to enter a data item that is not an array + * @ref QCBOR_ERR_UNEXPECTED_TYPE wil be set. + * + * Nested arrays and maps may be entered to a depth of + * @ref QCBOR_MAX_ARRAY_NESTING. + * + * See also QCBORDecode_ExitArray(), QCBORDecode_EnterMap(), + * QCBORDecode_EnterBstrWrapped() and QCBORDecode_GetArray(). + */ +static void +QCBORDecode_EnterArray(QCBORDecodeContext *pCtx, QCBORItem *pItem); +void +QCBORDecode_EnterArrayFromMapN(QCBORDecodeContext *pMe, int64_t uLabel); +void +QCBORDecode_EnterArrayFromMapSZ(QCBORDecodeContext *pMe, const char *szLabel); -#ifndef USEFULBUF_DISABLE_ALL_FLOAT /** - @brief Decode next item into a double floating-point value. - - @param[in] pCtx The decode context - @param[out] pValue The returned floating-point value. - - The CBOR data item to decode must be a half-precision, - single-precision or double-precision floating-point value. If not - @ref QCBOR_ERR_UNEXPECTED_TYPE is set. + * @brief Exit an array that has been enetered. + * + * @param[in] pCtx The decode context. + * + * An array must have been entered for this to succeed. + * + * The items in the array that was entered do not have to have been + * consumed for this to succeed. + * + * This sets the traversal cursor to the item after the + * array that was exited. + * + * This will result in an error if any item in the array is not well + * formed (since all items in the array must be decoded to find its + * end), or there are not enough items in the array. + */ +static void +QCBORDecode_ExitArray(QCBORDecodeContext *pCtx); - If floating-point HW use is disabled this will set - @ref QCBOR_ERR_HW_FLOAT_DISABLED if a single-precision - number is encountered. If half-precision support is disabled, - this will set QCBOR_ERR_HALF_PRECISION_DISABLED if - a half-precision number is encountered. - Please see @ref Decode-Errors-Overview "Decode Errors Overview". - See also QCBORDecode_GetDoubleConvert() and - QCBORDecode_GetDoubleConvertAll(). -*/ -static void QCBORDecode_GetDouble(QCBORDecodeContext *pCtx, - double *pValue); +/** + * @brief Get the encoded bytes that make up an array. + * + * @param[in] pCtx The decode context. + * @param[out] pItem Place to return the item. + * @param[out] pEncodedCBOR Place to return pointer and length of the array. + * + * The next item to decode must be an array. + * + * The encoded bytes of the array will be returned. They can be + * decoded by another decoder instance. + * + * @c pItem will have the label and tags for the array. It is filled + * in the same as if QCBORDecode_GetNext() were called on the array item. In + * particular, the array count will be filled in for definite-length + * arrays and set to @c UINT16_MAX for indefinite-length arrays. + * + * This works on both definite and indefinite length arrays (unless + * indefinite length array decoding has been disabled). + * + * The pointer returned is to the data item that opens the array. The + * length in bytes includes it and all the member data items. If the array + * occurs in another map and thus has a label, the label is not included + * in what is returned. + * + * If the array is preceeded by tags, those encoded tags are included + * in the encoded CBOR that is returned. + * + * QCBORDecode_GetArray() consumes the entire array and leaves the + * traversal cursor at the item after the array. + * QCBORDecode_GetArrayFromMapN() and QCBORDecode_GetArrayFromMapSZ() + * don't affect the traversal cursor. + * + * This traverses the whole array and every subordinate array or map in + * it. This is necessary to determine the length of the array. + * + * This will fail if any item in the array is not well-formed. + * + * This uses a few hundred bytes of stack, more than most methods. + * + * See also QCBORDecode_EnterArray(). + */ +static void +QCBORDecode_GetArray(QCBORDecodeContext *pCtx, + QCBORItem *pItem, + UsefulBufC *pEncodedCBOR); -static void QCBORDecode_GetDoubleInMapN(QCBORDecodeContext *pCtx, - int64_t nLabel, - double *pdValue); +static void +QCBORDecode_GetArrayFromMapN(QCBORDecodeContext *pCtx, + int64_t nLabel, + QCBORItem *pItem, + UsefulBufC *pEncodedCBOR); -static void QCBORDecode_GetDoubleInMapSZ(QCBORDecodeContext *pCtx, - const char *szLabel, - double *pdValue); +static void +QCBORDecode_GetArrayFromMapSZ(QCBORDecodeContext *pCtx, + const char *szLabel, + QCBORItem *pItem, + UsefulBufC *pEncodedCBOR); /** - @brief Decode next item into a double floating-point value with basic conversion. - - @param[in] pCtx The decode context. - @param[in] uConvertTypes The integer conversion options. - @param[out] pdValue The returned floating-point value. + * @brief Enter a map for decoding and searching. + * + * @param[in] pCtx The decode context. + * @param[out] pItem The optionally returned QCBORItem that has the + * label and tags for the map. May be @c NULL (and + * usually is). + * + * The next item in the CBOR input must be map or this sets an error. + * + * This puts the decoder in bounded mode which narrows decoding to the + * map entered and enables getting items by label. + * + * All items in the map must be well-formed to be able to search it by + * label because a full traversal is done for each search. If not, the + * search will retun an error for the item that is not well-formed. + * This will be the first non-well-formed item which may not be the + * item with the label that is the target of the search. + * + * Nested maps can be decoded like this by entering each map in turn. + * + * Call QCBORDecode_ExitMap() to exit the current map decoding + * level. When all map decoding layers are exited then bounded mode is + * fully exited. + * + * While in bounded mode, QCBORDecode_GetNext() works as usual on the + * map and the traversal cursor is maintained. It starts out + * at the first item in the map just entered. Attempts to get items + * off the end of the map will give error @ref QCBOR_ERR_NO_MORE_ITEMS + * rather going to the next item after the map as it would when not in + * bounded mode. + * + * It is possible to mix use of the traversal cursor with the fetching + * of items in a map by label with the caveat that fetching + * non-aggregate items by label behaves differently from entering subordinate + * aggregate items by label. See dicussion in @ref SpiffyDecode. + * + * Exiting leaves the traversal cursor at the data item following the + * last entry in the map or at the end of the input CBOR if there + * nothing after the map. + * + * Entering and Exiting a map is a way to skip over an entire map and + * its contents. After QCBORDecode_ExitMap(), the traversal + * cursor will be at the first item after the map. + * + * Please see @ref Decode-Errors-Overview "Decode Errors Overview". + * + * See also QCBORDecode_EnterArray() and + * QCBORDecode_EnterBstrWrapped(). Entering and exiting any nested + * combination of maps, arrays and bstr-wrapped CBOR is supported up + * to the maximum of @ref QCBOR_MAX_ARRAY_NESTING. + * + * See also QCBORDecode_GetMap(). + */ +static void +QCBORDecode_EnterMap(QCBORDecodeContext *pCtx, QCBORItem *pItem); - This will decode CBOR integer and floating-point numbers, returning - them as a double floating-point number. This function supports @ref - QCBOR_CONVERT_TYPE_XINT64 and @ref QCBOR_CONVERT_TYPE_FLOAT - conversions. If the encoded CBOR is not one of the requested types or a type - not supported by this function, @ref QCBOR_ERR_UNEXPECTED_TYPE is - set. +void +QCBORDecode_EnterMapFromMapN(QCBORDecodeContext *pCtx, int64_t nLabel); - Please see @ref Decode-Errors-Overview "Decode Errors Overview". +void +QCBORDecode_EnterMapFromMapSZ(QCBORDecodeContext *pCtx, const char *szLabel); - If floating-point HW use is disabled this will set - @ref QCBOR_ERR_HW_FLOAT_DISABLED if a single-precision - number is encountered. If half-precision support is disabled, - this will set QCBOR_ERR_HALF_PRECISION_DISABLED if - a half-precision number is encountered. - Positive and negative integers can always be converted to - floating-point, so this will never error on CBOR major type 0 or 1. +/** + * @brief Exit a map that has been enetered. + * + * @param[in] pCtx The decode context. + * + * A map must have been entered for this to succeed. + * + * The items in the map that was entered do not have to have been + * consumed for this to succeed. + * + * This sets the traversal cursor to the item after the map + * that was exited. + * + * This will result in an error if any item in the map is not well + * formed (since all items in the map must be decoded to find its + * end), or there are not enough items in the map. + */ +static void +QCBORDecode_ExitMap(QCBORDecodeContext *pCtx); - Note that a large 64-bit integer can have more precision (64 bits) - than even a double floating-point (52 bits) value, so there is loss - of precision in some conversions. - See also QCBORDecode_GetDouble() and QCBORDecode_GetDoubleConvertAll(). -*/ -static void QCBORDecode_GetDoubleConvert(QCBORDecodeContext *pCtx, - uint32_t uConvertTypes, - double *pdValue); +/** + * @brief Get the bytes that make up a map. + * + * @param[in] pCtx The decode context. + * @param[out] pItem Place to return the item. + * @param[out] pEncodedCBOR Place to return pointer and length of the map. + * + * The next item to decode must be a map. + * + * The encoded bytes of the map will be returned. They can be + * decoded by another decoder instance. + * + * @c pItem will have the label and tags for the array. It is filled + * in the same as if QCBORDecode_GetNext() were called on the map item. In + * particular, the map count will be filled in for definite-length + * maps and set to @c UINT16_MAX for indefinite-length maps. + * + * This works on both definite and indefinite length maps (unless + * indefinite length map decoding has been disabled). + * + * The pointer returned is to the data item that opens the map. The + * length in bytes includes it and all the member data items. If the map + * occurs in another map and thus has a label, the label is not included + * in what is returned. + * + * If the map is preceeded by tags, those encoded tags are included in + * the encoded CBOR that is returned. + * + * QCBORDecode_GetMap() consumes the entire array and leaves the + * traversal cursor at the item after the map. + * QCBORDecode_GetMapFromMapN() and QCBORDecode_GetMapFromMapSZ() + * don't affect the traversal cursor. + * + * This traverses the whole map and every subordinate array or map in + * it. This is necessary to determine the length of the map. The + * traversal cursor is left at the first item after the map. + * + * This will fail if any item in the map is not well-formed. + * + * This uses a few hundred bytes of stack, more than most methods. + * + * See also QCBORDecode_EnterMap(). + */ +static void +QCBORDecode_GetMap(QCBORDecodeContext *pCtx, + QCBORItem *pItem, + UsefulBufC *pEncodedCBOR); -static void QCBORDecode_GetDoubleConvertInMapN(QCBORDecodeContext *pCtx, - int64_t nLabel, - uint32_t uConvertTypes, - double *pdValue); +static void +QCBORDecode_GetMapFromMapN(QCBORDecodeContext *pCtx, + int64_t nLabel, + QCBORItem *pItem, + UsefulBufC *pEncodedCBOR); -static void QCBORDecode_GetDoubleConvertInMapSZ(QCBORDecodeContext *pCtx, - const char *szLabel, - uint32_t uConvertTypes, - double *pdValue); +static void +QCBORDecode_GetMapFromMapSZ(QCBORDecodeContext *pCtx, + const char *szLabel, + QCBORItem *pItem, + UsefulBufC *pEncodedCBOR); /** - @brief Decode next item as a double floating-point value with conversion. - - @param[in] pCtx The decode context. - @param[in] uConvertTypes The integer conversion options. - @param[out] pdValue The returned floating-point value. - - This is the same as QCBORDecode_GetDoubleConvert() but supports many - more conversions at the cost of linking in more object code. The - conversion types supported are @ref QCBOR_CONVERT_TYPE_XINT64, @ref - QCBOR_CONVERT_TYPE_FLOAT, @ref QCBOR_CONVERT_TYPE_BIG_NUM, @ref - QCBOR_CONVERT_TYPE_DECIMAL_FRACTION and @ref - QCBOR_CONVERT_TYPE_BIGFLOAT. - - Big numbers, decimal fractions and big floats that are too small or - too large to be reprented as a double floating-point number will be - returned as plus or minus zero or infinity rather than setting an - under or overflow error. - - There is often loss of precision in the conversion. + * @brief Reset traversal cursor to start of map, array, byte-string + * wrapped CBOR or start of input. + * + * @param[in] pCtx The decode context. + * + * If an array, map or wrapping byte string has been entered this sets + * the traversal cursor to its beginning. If several arrays, maps or + * byte strings have been entered, this sets the traversal cursor to + * the beginning of the one most recently entered. + * + * If no map or array has been entered, this resets the traversal + * cursor to the beginning of the input CBOR. + * + * This also resets the error state. + */ +void +QCBORDecode_Rewind(QCBORDecodeContext *pCtx); - See also QCBORDecode_GetDoubleConvert() and QCBORDecode_GetDoubleConvert(). -*/ -void QCBORDecode_GetDoubleConvertAll(QCBORDecodeContext *pCtx, - uint32_t uConvertTypes, - double *pdValue); -void QCBORDecode_GetDoubleConvertAllInMapN(QCBORDecodeContext *pCtx, - int64_t nLabel, - uint32_t uConvertTypes, - double *pdValue); +/** + * @brief Get an item in map by label and type. + * + * @param[in] pCtx The decode context. + * @param[in] nLabel The integer label. + * @param[in] uQcborType The QCBOR type. One of @c QCBOR_TYPE_XXX. + * @param[out] pItem The returned item. + * + * A map must have been entered to use this. If not + * @ref QCBOR_ERR_MAP_NOT_ENTERED is set. + * + * The map is searched for an item of the requested label and type. + * @ref QCBOR_TYPE_ANY can be given to search for the label without + * matching the type. + * + * This will always search the entire map. This will always perform + * duplicate label detection, setting @ref QCBOR_ERR_DUPLICATE_LABEL + * if there is more than one occurance of the label being searched + * for. + * + * Duplicate label detection is performed for the item being sought + * and only for the item being sought. + * + * This performs a full decode of every item in the map being + * searched which involves a full traversal of every item. For maps + * with little nesting, this is of little consequence, but may be of + * consequence for large deeply nested CBOR structures on slow CPUs. + * + * The position of the traversal cursor is not changed. + * + * Please see @ref Decode-Errors-Overview "Decode Errors Overview". + * + * See also QCBORDecode_GetItemsInMap() for error discussion. + */ +void +QCBORDecode_GetItemInMapN(QCBORDecodeContext *pCtx, + int64_t nLabel, + uint8_t uQcborType, + QCBORItem *pItem); -void QCBORDecode_GetDoubleConvertAllInMapSZ(QCBORDecodeContext *pCtx, - const char *szLabel, - uint32_t uConvertTypes, - double *pdValue); -#endif /* USEFULBUF_DISABLE_ALL_FLOAT */ +void +QCBORDecode_GetItemInMapSZ(QCBORDecodeContext *pCtx, + const char *szLabel, + uint8_t uQcborType, + QCBORItem *pItem); +/** + * @brief Get a group of labeled items all at once from a map + * + * @param[in] pCtx The decode context. + * @param[in,out] pItemList On input, the items to search for. On output, + * the returne *d items. + * + * This gets several labeled items out of a map. + * + * @c pItemList is an array of items terminated by an item with @c + * uLabelType @ref QCBOR_TYPE_NONE. + * + * On input the labels to search for are in the @c uLabelType and + * label fields in the items in @c pItemList. + * + * Also on input are the requested QCBOR types in the field + * @c uDataType. To match any type, searching just by label, + * @c uDataType can be @ref QCBOR_TYPE_ANY. + * + * This is a CPU-efficient way to decode a bunch of items in a map. It + * is more efficient than scanning each individually because the map + * only needs to be traversed once. + * + * This will return maps and arrays that are in the map, but provides + * no way to descend into and decode them. Use + * QCBORDecode_EnterMapinMapN(), QCBORDecode_EnterArrayInMapN() and + * such to descend into and process maps and arrays. + * + * The position of the traversal cursor is not changed. + * + * Please see @ref Decode-Errors-Overview "Decode Errors Overview". + * + * The following errors are set: + * + * @ref QCBOR_ERR_MAP_NOT_ENTERED when calling this without previousl + * calling QCBORDecode_EnterMap() or other methods to enter a map. + * + * @ref QCBOR_ERR_DUPLICATE_LABEL when one of the labels being searched + * for is duplicate. + * + * @ref QCBOR_ERR_HIT_END or other errors classifed as not-well-formed + * by QCBORDecode_IsNotWellFormed() as it is not possible to traverse + * maps that have any non-well formed items. + * + * @ref QCBOR_ERR_UNEXPECTED_TYPE when the type of an item found by + * matching a label is not the type requested. + * + * @ref QCBOR_ERR_ARRAY_NESTING_TOO_DEEP and other implementation + * limit errors as it is not possible to travere a map beyond the + * limits of the implementation. + * + * The error may occur on items that are not being searched for. For + * example, it is impossible to traverse over a map that has an array in + * it that is not closed or over array and map nesting deeper than this + * implementation can track. + * + * See also QCBORDecode_GetItemInMapN(). + */ +void +QCBORDecode_GetItemsInMap(QCBORDecodeContext *pCtx, QCBORItem *pItemList); /** - @brief Enter an array for decoding in bounded mode. - - @param[in] pCtx The decode context. - @param[out] pItem The optionally returned QCBORItem that has the - label and tags for the array. May be @c NULL (and - usually is). + * @brief Per-item callback for map searching. + * + * @param[in] pCallbackCtx Pointer to the caller-defined context for the callback. + * @param[in] pItem The item from the map. + * + * The error set is intended for QCBOR errors, not general protocol + * decoding errors. If this sets other than @ref QCBOR_SUCCESS, the + * search will stop and the value it returns will be set in + * QCBORDecode_GetItemsInMapWithCallback(). The special error, + * @ref QCBOR_ERR_CALLBACK_FAIL, can be returned to indicate some + * protocol processing error that is not a CBOR error. The specific + * details of the protocol processing error can be returned the call + * back context. + */ +typedef QCBORError (*QCBORItemCallback)(void *pCallbackCtx, + const QCBORItem *pItem); - This enters an array for decoding in bounded mode. The items in array - are decoded in order the same as when not in bounded mode, but the - decoding will not proceed past the end or the array. The error @ref - QCBOR_ERR_NO_MORE_ITEMS will be set when the end of the array is - encountered. To decode past the end of the array, - QCBORDecode_ExitArray() must be called. Also, QCBORDecode_Finish() - will return an error if all arrays that were enetered are not exited. - This works the same for definite and indefinite length arrays. +/** + * @brief Get a group of labeled items all at once from a map with a callback. + * + * @param[in] pCtx The decode context. + * @param[in,out] pItemList On input, the items to search for. On output, + * the returne *d items. + * @param[in,out] pCallbackCtx Pointer to a context structure for + * @ref QCBORItemCallback + * @param[in] pfCB Pointer to function of type + * @ref QCBORItemCallback that is called on + * unmatched items. + * + * This searchs a map like QCBORDecode_GetItemsInMap(), but calls a + * callback on items not matched rather than ignoring them. If @c + * pItemList is empty, the call back will be called on every item in the + * map. + * + * Like QCBORDecode_GetItemsInMap(), this only matches and calls back on + * the items at the top level of the map entered. Items in nested + * maps and arrays are skipped over and not candidate for matching or the + * callback. + * + * See QCBORItemCallback() for error handling. + */ +void +QCBORDecode_GetItemsInMapWithCallback(QCBORDecodeContext *pCtx, + QCBORItem *pItemList, + void *pCallbackCtx, + QCBORItemCallback pfCB); - Please see @ref Decode-Errors-Overview "Decode Errors Overview". - If attempting to enter a data item that is not an array @ref - QCBOR_ERR_UNEXPECTED_TYPE wil be set. - Nested arrays and maps may be entered to a depth of @ref - QCBOR_MAX_ARRAY_NESTING. - See also QCBORDecode_ExitArray(), QCBORDecode_EnterMap() and - QCBORDecode_EnterBstrWrapped(). +/** + * @brief Decode the next item as a Boolean. + * + * @param[in] pCtx The decode context. + * @param[out] pbBool The decoded byte string. + * + * The CBOR item to decode must be either the CBOR simple value (CBOR + * type 7) @c true or @c false. + * + * Please see @ref Decode-Errors-Overview "Decode Errors Overview". If + * the CBOR item to decode is not true or false the @ref + * QCBOR_ERR_UNEXPECTED_TYPE error is set. */ -static void QCBORDecode_EnterArray(QCBORDecodeContext *pCtx, QCBORItem *pItem); +void +QCBORDecode_GetBool(QCBORDecodeContext *pCtx, bool *pbBool); -void QCBORDecode_EnterArrayFromMapN(QCBORDecodeContext *pMe, int64_t uLabel); +void +QCBORDecode_GetBoolInMapN(QCBORDecodeContext *pCtx, + int64_t nLabel, + bool *pbBool); -void QCBORDecode_EnterArrayFromMapSZ(QCBORDecodeContext *pMe, const char *szLabel); +void +QCBORDecode_GetBoolInMapSZ(QCBORDecodeContext *pCtx, + const char *szLabel, + bool *pbBool); /** - @brief Exit an array that has been enetered. - - @param[in] pCtx The decode context. + * @brief Decode the next item as a null. + * + * @param[in] pCtx The decode context. + * + * The CBOR item to decode must be the CBOR simple value (CBOR type 7) + * @c null. The reason to call this is to see if an error is returned + * or not indicating whether the item is a CBOR null. If it is not + * then the @ref QCBOR_ERR_UNEXPECTED_TYPE error is set. + */ +static void +QCBORDecode_GetNull(QCBORDecodeContext *pCtx); - An array must have been entered for this to succeed. +static void +QCBORDecode_GetNullInMapN(QCBORDecodeContext *pCtx, + int64_t nLabel); - The items in the array that was entered do not have to have been - consumed for this to succeed. +static void +QCBORDecode_GetNullInMapSZ(QCBORDecodeContext *pCtx, + const char *szLabel); - This sets the pre-order traversal cursor to the item after the array - that was exited. - This will result in an error if any item in the array is not well - formed (since all items in the array must be decoded to find its - end), or there are not enough items in the array. -*/ -static void QCBORDecode_ExitArray(QCBORDecodeContext *pCtx); +/** + * @brief Decode the next item as a CBOR "undefined" item. + * + * @param[in] pCtx The decode context. + * + * The CBOR item to decode must be the CBOR simple value (CBOR type 7) + * @c undefined. The reason to call this is to see if an error is + * returned or not indicating whether the item is a CBOR undefed + * item. If it is not then the @ref QCBOR_ERR_UNEXPECTED_TYPE error is + * set. + */ +static void +QCBORDecode_GetUndefined(QCBORDecodeContext *pCtx); +static void +QCBORDecode_GetUndefinedInMapN(QCBORDecodeContext *pCtx, + int64_t nLabel); +static void +QCBORDecode_GetUndefinedInMapSZ(QCBORDecodeContext *pCtx, + const char *szLabel); /** - @brief Enter a map for decoding and searching. - - @param[in] pCtx The decode context. - @param[out] pItem The optionally returned QCBORItem that has the - label and tags for the map. May be @c NULL (and - usually is). + * @brief Decode the next item as a CBOR simple value. + * + * @param[in] pCtx The decode context. + * @param[out] puSimpleValue The simplle value returned. + * + * The purpose of this is to get a CBOR simple value other than a + * Boolean, NULL or "undefined", but this works on all simple + * values. See QCBOREncode_AddSimple() for more details on simple + * values in general. + * + * See QCBORDecode_GetBool(), QCBORDecode_GetNull(), + * QCBORDecode_GetUndefined() for the preferred way of getting those + * simple values. + */ +void +QCBORDecode_GetSimple(QCBORDecodeContext *pCtx, uint8_t *puSimpleValue); - The next item in the CBOR input must be map or this sets an error. +void +QCBORDecode_GetSimpleInMapN(QCBORDecodeContext *pCtx, + int64_t nLabel, + uint8_t *puSimpleValue); - This puts the decoder in bounded mode which narrows decoding to the - map entered and enables getting items by label. +void +QCBORDecode_GetSimpleInMapSZ(QCBORDecodeContext *pCtx, + const char *szLabel, + uint8_t *puSimpleValue); - All items in the map must be well-formed to be able to search it by - label because a full traversal is done for each search. If not, the - search will retun an error for the item that is not well-formed. - This will be the first non-well-formed item which may not be the item - with the label that is the target of the search. - Nested maps can be decoded like this by entering each map in turn. - Call QCBORDecode_ExitMap() to exit the current map decoding - level. When all map decoding layers are exited then bounded mode is - fully exited. - While in bounded mode, QCBORDecode_GetNext() works as usual on the - map and the in-order traversal cursor is maintained. It starts out at - the first item in the map just entered. Attempts to get items off the - end of the map will give error @ref QCBOR_ERR_NO_MORE_ITEMS rather - going to the next item after the map as it would when not in bounded - mode. +/** + * @brief Decode the next item as a date string. + * + * @param[in] pCtx The decode context. + * @param[in] uTagRequirement One of @c QCBOR_TAG_REQUIREMENT_XXX. + * @param[out] pDateString The decoded date. + * + * This decodes the standard CBOR date/time string tag, integer tag + * number of 0, or encoded CBOR that is not a tag, but borrows the + * date string content format. + * + * Please see @ref Decode-Errors-Overview "Decode Errors Overview". + * + * See @ref Tag-Usage for discussion on tag requirements. + * + * See also @ref CBOR_TAG_DATE_STRING, QCBOREncode_AddDateString() and + * @ref QCBOR_TYPE_DATE_STRING. + */ +static void +QCBORDecode_GetDateString(QCBORDecodeContext *pCtx, + uint8_t uTagRequirement, + UsefulBufC *pDateString); - Exiting leaves the pre-order cursor at the data item following the - last entry in the map or at the end of the input CBOR if there - nothing after the map. +static void +QCBORDecode_GetDateStringInMapN(QCBORDecodeContext *pCtx, + int64_t nLabel, + uint8_t uTagRequirement, + UsefulBufC *pDateString); - Entering and Exiting a map is a way to skip over an entire map and - its contents. After QCBORDecode_ExitMap(), the pre-order traversal - cursor will be at the first item after the map. +static void +QCBORDecode_GetDateStringInMapSZ(QCBORDecodeContext *pCtx, + const char *szLabel, + uint8_t uTagRequirement, + UsefulBufC *pDateString); - Please see @ref Decode-Errors-Overview "Decode Errors Overview". - See also QCBORDecode_EnterArray() and QCBORDecode_EnterBstrWrapped(). - Entering and exiting any nested combination of maps, arrays and - bstr-wrapped CBOR is supported up to the maximum of @ref - QCBOR_MAX_ARRAY_NESTING. +/** + * @brief Decode the next item as a date-only string. + * + * @param[in] pCtx The decode context. + * @param[in] uTagRequirement One of @c QCBOR_TAG_REQUIREMENT_XXX. + * @param[out] pDateString The decoded date. + * + * This decodes the CBOR date-only string tag, integer tag number of + * 1004, or encoded CBOR that is not a tag, but borrows the date-only + * string content format. An example of the format is "1985-04-12". + * + * Please see @ref Decode-Errors-Overview "Decode Errors Overview". + * + * See @ref Tag-Usage for discussion on tag requirements. + * + * See also @ref CBOR_TAG_DAYS_STRING, QCBOREncode_AddDaysString() and + * @ref QCBOR_TYPE_DAYS_STRING. */ -static void QCBORDecode_EnterMap(QCBORDecodeContext *pCtx, QCBORItem *pItem); +static void +QCBORDecode_GetDaysString(QCBORDecodeContext *pCtx, + uint8_t uTagRequirement, + UsefulBufC *pDateString); -void QCBORDecode_EnterMapFromMapN(QCBORDecodeContext *pCtx, int64_t nLabel); +static void +QCBORDecode_GetDaysStringInMapN(QCBORDecodeContext *pCtx, + int64_t nLabel, + uint8_t uTagRequirement, + UsefulBufC *pDateString); -void QCBORDecode_EnterMapFromMapSZ(QCBORDecodeContext *pCtx, const char *szLabel); +static void +QCBORDecode_GetDaysStringInMapSZ(QCBORDecodeContext *pCtx, + const char *szLabel, + uint8_t uTagRequirement, + UsefulBufC *pDateString); /** - @brief Exit a map that has been enetered. - - @param[in] pCtx The decode context. - - A map must have been entered for this to succeed. - - The items in the map that was entered do not have to have been - consumed for this to succeed. + * @brief Decode the next item as an epoch date. + * + * @param[in] pCtx The decode context. + * @param[in] uTagRequirement One of @c QCBOR_TAG_REQUIREMENT_XXX. + * @param[out] pnTime The decoded epoch date. + * + * This decodes the standard CBOR epoch date/time tag, integer tag + * number of 1. This will also decode any integer or floating-point + * number as an epoch date (a tag 1 epoch date is just an integer or + * floating-point number). + * + * This will set @ref QCBOR_ERR_DATE_OVERFLOW if the input integer + * will not fit in an @c int64_t. Note that an @c int64_t can + * represent a range of over 500 billion years with one second + * resolution. + * + * Floating-point dates are always returned as an @c int64_t. The + * fractional part is discarded. + * + * If the input is a floating-point date and the QCBOR library is + * compiled with some or all floating-point features disabled, the + * following errors will be set. If the input is half-precision and + * half-precision is disabled @ref QCBOR_ERR_HALF_PRECISION_DISABLED + * is set. This function needs hardware floating-point to convert the + * floating-point value to an integer so if HW floating point is + * disabled @ref QCBOR_ERR_HW_FLOAT_DISABLED is set. If all + * floating-point is disabled then @ref QCBOR_ERR_ALL_FLOAT_DISABLED + * is set. A previous version of this function would return + * @ref QCBOR_ERR_FLOAT_DATE_DISABLED in some, but not all, cases when + * floating-point decoding was disabled. + * + * Floating-point dates that are plus infinity, minus infinity or NaN + * (not-a-number) will result in the @ref QCBOR_ERR_DATE_OVERFLOW + * error. + * + * Please see @ref Decode-Errors-Overview "Decode Errors Overview". + * + * See @ref Tag-Usage for discussion on tag requirements. + * + * See also @ref CBOR_TAG_DATE_EPOCH, QCBOREncode_AddTDateEpoch() and + * @ref QCBOR_TYPE_DATE_EPOCH. +*/ +void +QCBORDecode_GetEpochDate(QCBORDecodeContext *pCtx, + uint8_t uTagRequirement, + int64_t *pnTime); - This sets the pre-order traversal cursor to the item after the map - that was exited. +void +QCBORDecode_GetEpochDateInMapN(QCBORDecodeContext *pCtx, + int64_t nLabel, + uint8_t uTagRequirement, + int64_t *pnTime); - This will result in an error if any item in the map is not well - formed (since all items in the map must be decoded to find its end), - or there are not enough items in the map. -*/ -static void QCBORDecode_ExitMap(QCBORDecodeContext *pCtx); +void +QCBORDecode_GetEpochDateInMapSZ(QCBORDecodeContext *pCtx, + const char *szLabel, + uint8_t uTagRequirement, + int64_t *pnTime); /** - @brief Reset traversal cursor to start of map, array, byte-string - wrapped CBOR or start of input. + * @brief Decode the next item as an days-count epoch date. + * + * @param[in] pCtx The decode context. + * @param[in] uTagRequirement One of @c QCBOR_TAG_REQUIREMENT_XXX. + * @param[out] pnDays The decoded epoch date. + * + * This decodes the CBOR epoch date tag, integer tag number of 100, or + * encoded CBOR that is not a tag, but borrows the content format. The + * date is the number of days (not number of seconds) before or after + * Jan 1, 1970. + * + * Please see @ref Decode-Errors-Overview "Decode Errors Overview". + * + * See @ref Tag-Usage for discussion on tag requirements. + * + * See also @ref CBOR_TAG_DAYS_EPOCH, QCBOREncode_AddTDaysEpoch() and + * @ref QCBOR_TYPE_DAYS_EPOCH. +*/ +void +QCBORDecode_GetEpochDays(QCBORDecodeContext *pCtx, + uint8_t uTagRequirement, + int64_t *pnDays); - @param[in] pCtx The decode context. +void +QCBORDecode_GetEpochDaysInMapN(QCBORDecodeContext *pCtx, + int64_t nLabel, + uint8_t uTagRequirement, + int64_t *pnDays); - If an array, map or wrapping byte string has been entered this sets - the traversal cursor to its beginning. If several arrays, maps or - byte strings have been entered, this sets the traversal cursor to the - beginning of the one most recently entered. +void +QCBORDecode_GetEpochDaysInMapSZ(QCBORDecodeContext *pCtx, + const char *szLabel, + uint8_t uTagRequirement, + int64_t *pnDays); - If no map or array has been entered, this resets the traversal cursor - to the beginning of the input CBOR. - This also resets the error state. - */ -void QCBORDecode_Rewind(QCBORDecodeContext *pCtx); /** - @brief Get an item in map by label and type. - - @param[in] pCtx The decode context. - @param[in] nLabel The integer label. - @param[in] uQcborType The QCBOR type. One of @c QCBOR_TYPE_XXX. - @param[out] pItem The returned item. - - A map must have been entered to use this. If not @ref - QCBOR_ERR_MAP_NOT_ENTERED is set. + * @brief Decode the next item as a big number. + * + * @param[in] pCtx The decode context. + * @param[in] uTagRequirement One of @c QCBOR_TAG_REQUIREMENT_XXX. + * @param[out] pValue The returned big number. + * @param[out] pbIsNegative Is @c true if the big number is negative. This + * is only valid when @c uTagRequirement is + * @ref QCBOR_TAG_REQUIREMENT_TAG. + * + * This decodes a standard CBOR big number, integer tag number of 2 or + * 3, or encoded CBOR that is not a tag, but borrows the content + * format. + * + * Please see @ref Decode-Errors-Overview "Decode Errors Overview". + * + * The big number is in network byte order. The first byte in @c + * pValue is the most significant byte. There may be leading zeros. + * + * The negative value is computed as -1 - n, where n is the postive + * big number in @c pValue. There is no standard representation for + * big numbers, positive or negative in C, so this implementation + * leaves it up to the caller to apply this computation for negative + * big numbers. + * + * RFC 8949 preferred serialization requires that big numbers + * that fit into integers be encoded as integers. This function + * will error if the input CBOR is a type 0 or 1 integers. A + * future version of QCBOR fixes this, but in the mean time + * the application must handle this manually. + * + * See @ref Tag-Usage for discussion on tag requirements. + * + * Determination of the sign of the big number depends on the tag + * requirement of the protocol using the big number. If the protocol + * requires tagging, @ref QCBOR_TAG_REQUIREMENT_TAG, then the sign + * indication is in the protocol and @c pbIsNegative indicates the + * sign. If the protocol doesn't use a tag, @ref QCBOR_TAG_REQUIREMENT_NOT_A_TAG, + * then the protocol design must have some way of indicating the sign. + * + * See also QCBORDecode_GetInt64ConvertAll(), + * QCBORDecode_GetUInt64ConvertAll() and + * QCBORDecode_GetDoubleConvertAll() which can convert big numbers. + * + * See also @ref CBOR_TAG_POS_BIGNUM, @ref CBOR_TAG_NEG_BIGNUM, + * QCBOREncode_AddTPositiveBignum(), QCBOREncode_AddTNegativeBignum(), + * @ref QCBOR_TYPE_POSBIGNUM and @ref QCBOR_TYPE_NEGBIGNUM. + */ +void +QCBORDecode_GetBignum(QCBORDecodeContext *pCtx, + uint8_t uTagRequirement, + UsefulBufC *pValue, + bool *pbIsNegative); - The map is searched for an item of the requested label and type. - @ref QCBOR_TYPE_ANY can be given to search for the label without - matching the type. +void +QCBORDecode_GetBignumInMapN(QCBORDecodeContext *pCtx, + int64_t nLabel, + uint8_t uTagRequirement, + UsefulBufC *pValue, + bool *pbIsNegative); - This will always search the entire map. This will always perform - duplicate label detection, setting @ref QCBOR_ERR_DUPLICATE_LABEL if - there is more than one occurance of the label being searched for. +void +QCBORDecode_GetBignumInMapSZ(QCBORDecodeContext *pCtx, + const char *szLabel, + uint8_t uTagRequirement, + UsefulBufC *pValue, + bool *pbIsNegative); - Duplicate label detection is performed for the item being sought, but - only for the item being sought. - This performs a full decode of every item in the map being searched, - which involves a full traversal of every item. For maps with little - nesting, this is of little consequence, but may be of consequence for - large deeply nested CBOR structures on slow CPUs. - The position of the pre-order traversal cursor is not changed. - Please see @ref Decode-Errors-Overview "Decode Errors Overview". +#ifndef QCBOR_DISABLE_EXP_AND_MANTISSA +/** + * @brief Decode the next item as a decimal fraction. + * + * @param[in] pCtx The decode context. + * @param[in] uTagRequirement One of @c QCBOR_TAG_REQUIREMENT_XXX. + * @param[out] pnMantissa The mantissa. + * @param[out] pnExponent The base 10 exponent. + * + * This decodes a standard CBOR decimal fraction, integer tag number + * of 4, or encoded CBOR that is not a tag, but borrows the content + * format. + * + * Please see @ref Decode-Errors-Overview "Decode Errors Overview". + * + * The value of this is computed by: + * + * mantissa * ( 10 ** exponent ) + * + * In the encoded CBOR, the mantissa and exponent may be of CBOR type + * 0 (positive integer), type 1 (negative integer), type 2 tag 2 + * (positive big number) or type 2 tag 3 (negative big number). This + * implementation will attempt to convert all of these to an @c + * int64_t. If the value won't fit, @ref QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW + * or @ref QCBOR_ERR_BAD_EXP_AND_MANTISSA will be set. + * + * This implementation limits the exponent to between @c INT64_MIN and + * @c INT64_MAX while CBOR allows the range of @c -UINT64_MAX to + * @c UINT64_MAX. + * + * Various format and type issues will result in + * @ref QCBOR_ERR_BAD_EXP_AND_MANTISSA being set. + * + * See @ref Tag-Usage for discussion on tag requirements. + * + * See also QCBORDecode_GetInt64ConvertAll(), + * QCBORDecode_GetUInt64ConvertAll() and + * QCBORDecode_GetDoubleConvertAll() which can convert big numbers. + * + * See also @ref CBOR_TAG_DECIMAL_FRACTION, + * QCBOREncode_AddTDecimalFraction(), @ref QCBOR_TYPE_DECIMAL_FRACTION + * and QCBORDecode_GetDecimalFractionBig(). + * + * If QCBOR_DISABLE_TAGS is set, the only input this will decode is an + * array of two integers. It will set an error if the the array is + * preceded by by a tag number or if the mantissa is a big number. + */ +void +QCBORDecode_GetDecimalFraction(QCBORDecodeContext *pCtx, + uint8_t uTagRequirement, + int64_t *pnMantissa, + int64_t *pnExponent); - See also QCBORDecode_GetItemsInMap() for error discussion. -*/ -void QCBORDecode_GetItemInMapN(QCBORDecodeContext *pCtx, - int64_t nLabel, - uint8_t uQcborType, - QCBORItem *pItem); +void +QCBORDecode_GetDecimalFractionInMapN(QCBORDecodeContext *pCtx, + int64_t nLabel, + uint8_t uTagRequirement, + int64_t *pnMantissa, + int64_t *pnExponent); -void QCBORDecode_GetItemInMapSZ(QCBORDecodeContext *pCtx, - const char *szLabel, - uint8_t uQcborType, - QCBORItem *pItem); +void +QCBORDecode_GetDecimalFractionInMapSZ(QCBORDecodeContext *pMe, + const char *szLabel, + uint8_t uTagRequirement, + int64_t *pnMantissa, + int64_t *pnExponent); /** - @brief Get a group of labeled items all at once from a map - - @param[in] pCtx The decode context. - @param[in,out] pItemList On input the items to search for. On output the returned items. + * @brief Decode the next item as a decimal fraction with a big number mantissa. + * + * @param[in] pCtx The decode context. + * @param[in] uTagRequirement One of @c QCBOR_TAG_REQUIREMENT_XXX. + * @param[in] MantissaBuffer The buffer in which to put the mantissa. + * @param[out] pMantissa The big num mantissa. + * @param[out] pbMantissaIsNegative Is @c true if @c pMantissa is negative. + * @param[out] pnExponent The base 10 exponent. + * + * This is the same as QCBORDecode_GetDecimalFraction() except the + * mantissa is returned as a big number. + * + * In the encoded CBOR, the mantissa may be a type 0 (positive + * integer), type 1 (negative integer), type 2 tag 2 (positive big + * number) or type 2 tag 3 (negative big number). This implementation + * will convert all these to a big number. The limit to this + * conversion is the size of @c MantissaBuffer. + * + * The mantissa returned does NOT have the offset + * of one applied when it is negative. To get the true value + * one must be added to @c *pMantissa (which requires + * some big number arithmetic and may increase the length + * of it by one). + * + * For QCBOR before v1.5, this function had a bug where + * by the negative mantissa sometimes had the offset of + * one applied, making this function somewhat usless for + * negative mantissas. Specifically if the to-be-decoded CBOR + * was a type 1 integer the offset was applied and when it + * was a tag 3, the offset was not applied. It is possible + * that a tag 3 could contain a value in the range of a type 1 + * integer. @ref QCBORExpAndMantissa is + * correct and can be used instead of this. + * + * See also QCBORDecode_GetInt64ConvertAll(), + * QCBORDecode_GetUInt64ConvertAll() and + * QCBORDecode_GetDoubleConvertAll() which can convert decimal + * fractions. + * + * See also @ref CBOR_TAG_DECIMAL_FRACTION, + * QCBOREncode_AddTDecimalFraction(), @ref QCBOR_TYPE_DECIMAL_FRACTION + * and QCBORDecode_GetDecimalFraction(). + */ +void +QCBORDecode_GetDecimalFractionBig(QCBORDecodeContext *pCtx, + uint8_t uTagRequirement, + UsefulBuf MantissaBuffer, + UsefulBufC *pMantissa, + bool *pbMantissaIsNegative, + int64_t *pnExponent); - This gets several labeled items out of a map. +void +QCBORDecode_GetDecimalFractionBigInMapN(QCBORDecodeContext *pCtx, + int64_t nLabel, + uint8_t uTagRequirement, + UsefulBuf MantissaBuffer, + UsefulBufC *pbMantissaIsNegative, + bool *pbIsNegative, + int64_t *pnExponent); - @c pItemList is an array of items terminated by an item with @c - uLabelType @ref QCBOR_TYPE_NONE. +void +QCBORDecode_GetDecimalFractionBigInMapSZ(QCBORDecodeContext *pCtx, + const char *szLabel, + uint8_t uTagRequirement, + UsefulBuf MantissaBuffer, + UsefulBufC *pMantissa, + bool *pbMantissaIsNegative, + int64_t *pnExponent); - On input the labels to search for are in the @c uLabelType and label - fields in the items in @c pItemList. - Also on input are the requested QCBOR types in the field @c - uDataType. To match any type, searching just by label, @c uDataType - can be @ref QCBOR_TYPE_ANY. +/** + * @brief Decode the next item as a big float. + * + * @param[in] pCtx The decode context. + * @param[in] uTagRequirement One of @c QCBOR_TAG_REQUIREMENT_XXX. + * @param[out] pnMantissa The mantissa. + * @param[out] pnExponent The base 2 exponent. + * + * This decodes a standard CBOR big float, integer tag number of 5, or + * encoded CBOR that is not a tag, but borrows the content format. + * + * This is the same as QCBORDecode_GetDecimalFraction() with the + * important distinction that the value is computed by: + * + * mantissa * ( 2 ** exponent ) + * + * If the mantissa is a tag that is a positive or negative big number, + * this will attempt to fit it into the int64_t that @c pnMantissa is + * and set an overflow error if it doesn't fit. + * + * See also QCBORDecode_GetInt64ConvertAll(), + * QCBORDecode_GetUInt64ConvertAll() and + * QCBORDecode_GetDoubleConvertAll() which can convert big floats. + * + * See also @ref CBOR_TAG_BIGFLOAT, QCBOREncode_AddTBigFloat(), @ref + * QCBOR_TYPE_BIGFLOAT and QCBORDecode_GetBigFloatBig(). + */ +void +QCBORDecode_GetBigFloat(QCBORDecodeContext *pCtx, + uint8_t uTagRequirement, + int64_t *pnMantissa, + int64_t *pnExponent); - This is a CPU-efficient way to decode a bunch of items in a map. It - is more efficient than scanning each individually because the map - only needs to be traversed once. +void +QCBORDecode_GetBigFloatInMapN(QCBORDecodeContext *pCtx, + int64_t nLabel, + uint8_t uTagRequirement, + int64_t *pnMantissa, + int64_t *pnExponent); - This will return maps and arrays that are in the map, but provides no - way to descend into and decode them. Use - QCBORDecode_EnterMapinMapN(), QCBORDecode_EnterArrayInMapN() and such - to descend into and process maps and arrays. +void +QCBORDecode_GetBigFloatInMapSZ(QCBORDecodeContext *pCtx, + const char *szLabel, + uint8_t uTagRequirement, + int64_t *pnMantissa, + int64_t *pnExponent); - The position of the pre-order traversal cursor is not changed. - Please see @ref Decode-Errors-Overview "Decode Errors Overview". +/** + * @brief Decode the next item as a big float with a big number mantissa. + * + * @param[in] pCtx The decode context. + * @param[in] uTagRequirement One of @c QCBOR_TAG_REQUIREMENT_XXX. + * @param[in] MantissaBuffer The buffer in which to put the mantissa. + * @param[out] pMantissa The big num mantissa. + * @param[out] pbMantissaIsNegative Is @c true if @c pMantissa is negative. + * @param[out] pnExponent The base 2 exponent. + * + * This is the same as QCBORDecode_GetDecimalFractionBig() with the + * important distinction that the value is computed by: + * + * mantissa * ( 2 ** exponent ) + * + * This has the same issue with negative mantissas as + * QCBORDecode_GetDecimalFractionBig(). + * + * See also QCBORDecode_GetInt64ConvertAll(), + * QCBORDecode_GetUInt64ConvertAll() and + * QCBORDecode_GetDoubleConvertAll() which can convert big floats. + * + * See also @ref CBOR_TAG_BIGFLOAT, QCBOREncode_AddTBigFloat(), + * @ref QCBOR_TYPE_BIGFLOAT and QCBORDecode_GetBigFloat(). + */ +void +QCBORDecode_GetBigFloatBig(QCBORDecodeContext *pCtx, + uint8_t uTagRequirement, + UsefulBuf MantissaBuffer, + UsefulBufC *pMantissa, + bool *pbMantissaIsNegative, + int64_t *pnExponent); - The following errors are set: +void +QCBORDecode_GetBigFloatBigInMapN(QCBORDecodeContext *pCtx, + int64_t nLabel, + uint8_t uTagRequirement, + UsefulBuf MantissaBuffer, + UsefulBufC *pMantissa, + bool *pbMantissaIsNegative, + int64_t *pnExponent); - @ref QCBOR_ERR_MAP_NOT_ENTERED when calling this without previousl - calling QCBORDecode_EnterMap() or other methods to enter a map. +void +QCBORDecode_GetBigFloatBigInMapSZ(QCBORDecodeContext *pCtx, + const char *szLabel, + uint8_t uTagRequirement, + UsefulBuf MantissaBuffer, + UsefulBufC *pMantissa, + bool *pbMantissaIsNegative, + int64_t *pnExponent); +#endif /* #ifndef QCBOR_DISABLE_EXP_AND_MANTISSA */ - @ref QCBOR_ERR_DUPLICATE_LABEL when one of the labels being searched - for is duplicate. - @ref QCBOR_ERR_HIT_END or other errors classifed as not-well-formed - by QCBORDecode_IsNotWellFormed() as it is not possible to traverse - maps that have any non-well formed items. - @ref QCBOR_ERR_UNEXPECTED_TYPE when the type of an item found by - matching a label is not the type requested. - @ref QCBOR_ERR_ARRAY_NESTING_TOO_DEEP and other implementation limit - errors as it is not possible to travere a map beyond the limits of - the implementation. +/** + * @brief Decode the next item as a URI. + * + * @param[in] pCtx The decode context. + * @param[in] uTagRequirement One of @c QCBOR_TAG_REQUIREMENT_XXX. + * @param[out] pURI The decoded URI. + * + * This decodes a standard CBOR URI tag, integer tag number of 32, or + * encoded CBOR that is not a tag, that is a URI encoded in a text + * string. + * + * Please see @ref Decode-Errors-Overview "Decode Errors Overview". + * + * See @ref Tag-Usage for discussion on tag requirements. + * + * See also @ref CBOR_TAG_URI, QCBOREncode_AddTURI() and + * @ref QCBOR_TYPE_URI. + */ +static void +QCBORDecode_GetURI(QCBORDecodeContext *pCtx, + uint8_t uTagRequirement, + UsefulBufC *pURI); - The error may occur on items that are not being searched for. For - example, it is impossible to traverse over a map that has an array in - it that is not closed or over array and map nesting deeper than this - implementation can track. +static void +QCBORDecode_GetURIInMapN(QCBORDecodeContext *pCtx, + int64_t nLabel, + uint8_t uTagRequirement, + UsefulBufC *pURI); - See also QCBORDecode_GetItemInMapN(). - */ -void QCBORDecode_GetItemsInMap(QCBORDecodeContext *pCtx, QCBORItem *pItemList); +static void +QCBORDecode_GetURIInMapSZ(QCBORDecodeContext *pCtx, + const char * szLabel, + uint8_t uTagRequirement, + UsefulBufC *pURI); /** - @brief Per-item callback for map searching. - - @param[in] pCallbackCtx Pointer to the caller-defined context for the callback - @param[in] pItem The item from the map. - - The error set is intended for QCBOR errors, not general protocol - decoding errors. If this sets other than @ref QCBOR_SUCCESS, the - search will stop and the value it returns will be set in - QCBORDecode_GetItemsInMapWithCallback(). The special error, @ref - QCBOR_ERR_CALLBACK_FAIL, can be returned to indicate some protocol - processing error that is not a CBOR error. The specific details of - the protocol processing error can be returned the call back context. - */ -typedef QCBORError (*QCBORItemCallback)(void *pCallbackCtx, - const QCBORItem *pItem); - - -/** - @brief Get a group of labeled items all at once from a map with a callback - - @param[in] pCtx The decode context. - @param[in,out] pItemList On input the items to search for. On output the returned items. - @param[in,out] pCallbackCtx Pointer to a context structure for @ref QCBORItemCallback - @param[in] pfCB pointer to function of type @ref QCBORItemCallback that is called on unmatched items. - - This searchs a map like QCBORDecode_GetItemsInMap(), but calls a - callback on items not matched rather than ignoring them. If @c - pItemList is empty, the call back will be called on every item in the - map. - - Like QCBORDecode_GetItemsInMap(), this only matches and calls back on - the items at the top level of the map entered. Items in nested - maps and arrays are skipped over and not candidate for matching or the - callback. - - See QCBORItemCallback() for error handling. + * @brief Decode the next item as base64 encoded text. + * + * @param[in] pCtx The decode context. + * @param[in] uTagRequirement One of @c QCBOR_TAG_REQUIREMENT_XXX. + * @param[out] pB64Text The decoded base64 text. + * + * This decodes a standard CBOR base64 tag, integer tag number of 34, + * or encoded CBOR that is not a tag, that is base64 encoded bytes + * encoded in a text string. + * + * Please see @ref Decode-Errors-Overview "Decode Errors Overview". + * + * See @ref Tag-Usage for discussion on tag requirements. + * + * Note that this does not actually remove the base64 encoding. + * + * See also @ref CBOR_TAG_B64, QCBOREncode_AddB64Text() and + * @ref QCBOR_TYPE_BASE64. */ -void QCBORDecode_GetItemsInMapWithCallback(QCBORDecodeContext *pCtx, - QCBORItem *pItemList, - void *pCallbackCtx, - QCBORItemCallback pfCB); - - - - -/** - @brief Decode the next item as a Boolean. - - @param[in] pCtx The decode context. - @param[out] pbBool The decoded byte string. - - The CBOR item to decode must be either the CBOR simple value (CBOR - type 7) @c true or @c false. - - Please see @ref Decode-Errors-Overview "Decode Errors Overview". If - the CBOR item to decode is not true or false the @ref - QCBOR_ERR_UNEXPECTED_TYPE error is set. -*/ -void QCBORDecode_GetBool(QCBORDecodeContext *pCtx, bool *pbBool); - -void QCBORDecode_GetBoolInMapN(QCBORDecodeContext *pCtx, - int64_t nLabel, - bool *pbBool); - -void QCBORDecode_GetBoolInMapSZ(QCBORDecodeContext *pCtx, - const char *szLabel, - bool *pbBool); - - -/** - @brief Decode the next item as a null. - - @param[in] pCtx The decode context. - - The CBOR item to decode must be the CBOR simple value (CBOR type 7) - @c null. The reason to call this is to see if an error is returned or - not indicating whether the item is a CBOR null. If it is not then the - @ref QCBOR_ERR_UNEXPECTED_TYPE error is set. -*/ -static void QCBORDecode_GetNull(QCBORDecodeContext *pCtx); - -static void QCBORDecode_GetNullInMapN(QCBORDecodeContext *pCtx, - int64_t nLabel); - -static void QCBORDecode_GetNullInMapSZ(QCBORDecodeContext *pCtx, - const char *szLabel); - +static void +QCBORDecode_GetB64(QCBORDecodeContext *pCtx, + uint8_t uTagRequirement, + UsefulBufC *pB64Text); -/** - @brief Decode the next item as a CBOR "undefined" item. - - @param[in] pCtx The decode context. - - The CBOR item to decode must be the CBOR simple value (CBOR type 7) - @c undefined. The reason to call this is to see if an error is - returned or not indicating whether the item is a CBOR undefed - item. If it is not then the @ref QCBOR_ERR_UNEXPECTED_TYPE error is - set. -*/ -static void QCBORDecode_GetUndefined(QCBORDecodeContext *pCtx); - -static void QCBORDecode_GetUndefinedInMapN(QCBORDecodeContext *pCtx, - int64_t nLabel); - -static void QCBORDecode_GetUndefinedInMapSZ(QCBORDecodeContext *pCtx, - const char *szLabel); - - -/** - @brief Decode the next item as a date string. - - @param[in] pCtx The decode context. - @param[in] uTagRequirement One of @c QCBOR_TAG_REQUIREMENT_XXX. - @param[out] pDateString The decoded date. - - This decodes the standard CBOR date/time string tag, integer tag - number of 0, or encoded CBOR that is not a tag, but borrows the - date string content format. - - Please see @ref Decode-Errors-Overview "Decode Errors Overview". - - See @ref Tag-Usage for discussion on tag requirements. - - See also @ref CBOR_TAG_DATE_STRING, QCBOREncode_AddDateString() and - @ref QCBOR_TYPE_DATE_STRING. -*/ -static void QCBORDecode_GetDateString(QCBORDecodeContext *pCtx, - uint8_t uTagRequirement, - UsefulBufC *pDateString); - -static void QCBORDecode_GetDateStringInMapN(QCBORDecodeContext *pCtx, - int64_t nLabel, - uint8_t uTagRequirement, - UsefulBufC *pDateString); - -static void QCBORDecode_GetDateStringInMapSZ(QCBORDecodeContext *pCtx, - const char *szLabel, - uint8_t uTagRequirement, - UsefulBufC *pDateString); - - -/** - @brief Decode the next item as a date-only string. - - @param[in] pCtx The decode context. - @param[in] uTagRequirement One of @c QCBOR_TAG_REQUIREMENT_XXX. - @param[out] pDateString The decoded date. - - This decodes the CBOR date-only string tag, integer tag - number of 1004, or encoded CBOR that is not a tag, but borrows the - date-only string content format. An example of the format - is "1985-04-12". - - Please see @ref Decode-Errors-Overview "Decode Errors Overview". - - See @ref Tag-Usage for discussion on tag requirements. - - See also @ref CBOR_TAG_DAYS_STRING, QCBOREncode_AddDaysString() and - @ref QCBOR_TYPE_DAYS_STRING. -*/ -static void QCBORDecode_GetDaysString(QCBORDecodeContext *pCtx, - uint8_t uTagRequirement, - UsefulBufC *pDateString); - -static void QCBORDecode_GetDaysStringInMapN(QCBORDecodeContext *pCtx, - int64_t nLabel, - uint8_t uTagRequirement, - UsefulBufC *pDateString); - -static void QCBORDecode_GetDaysStringInMapSZ(QCBORDecodeContext *pCtx, - const char *szLabel, - uint8_t uTagRequirement, - UsefulBufC *pDateString); +static void +QCBORDecode_GetB64InMapN(QCBORDecodeContext *pCtx, + int64_t nLabel, + uint8_t uTagRequirement, + UsefulBufC *pB64Text); +static void +QCBORDecode_GetB64InMapSZ(QCBORDecodeContext *pCtx, + const char *szLabel, + uint8_t uTagRequirement, + UsefulBufC *pB64Text); /** - @brief Decode the next item as an epoch date. - - @param[in] pCtx The decode context. - @param[in] uTagRequirement One of @c QCBOR_TAG_REQUIREMENT_XXX. - @param[out] pnTime The decoded epoch date. - - This decodes the standard CBOR epoch date/time tag, integer tag - number of 1. This will also decode any integer or floating-point - number as an epoch date (a tag 1 epoch date is just an integer or - floating-point number). - - This will set @ref QCBOR_ERR_DATE_OVERFLOW if the input integer will - not fit in an @c int64_t. Note that an @c int64_t can represent a - range of over 500 billion years with one second resolution. - - Floating-point dates are always returned as an @c int64_t. The - fractional part is discarded. - - If the input is a floating-point date and the QCBOR library is - compiled with some or all floating-point features disabled, the - following errors will be set. If the input is half-precision and - half-precision is disabled @ref QCBOR_ERR_HALF_PRECISION_DISABLED is - set. This function needs hardware floating-point to convert the - floating-point value to an integer so if HW floating point is - disabled QCBOR_ERR_HW_FLOAT_DISABLED is set. If all floating-point is - disabled then @ref QCBOR_ERR_ALL_FLOAT_DISABLED is set. A previous - version of this function would return @ref QCBOR_ERR_FLOAT_DATE_DISABLED - in some, but not all, cases when floating-point decoding was disabled. - - Floating-point dates that are plus infinity, minus infinity or NaN - (not-a-number) will result in the @ref QCBOR_ERR_DATE_OVERFLOW error. - - Please see @ref Decode-Errors-Overview "Decode Errors Overview". - - See @ref Tag-Usage for discussion on tag requirements. - - See also @ref CBOR_TAG_DATE_EPOCH, QCBOREncode_AddDateEpoch() and - @ref QCBOR_TYPE_DATE_EPOCH. -*/ -void QCBORDecode_GetEpochDate(QCBORDecodeContext *pCtx, - uint8_t uTagRequirement, - int64_t *pnTime); - -void QCBORDecode_GetEpochDateInMapN(QCBORDecodeContext *pCtx, - int64_t nLabel, - uint8_t uTagRequirement, - int64_t *pnTime); + * @brief Decode the next item as base64URL encoded text. + * + * @param[in] pCtx The decode context. + * @param[in] uTagRequirement One of @c QCBOR_TAG_REQUIREMENT_XXX. + * @param[out] pB64Text The decoded base64 text. + * + * This decodes a standard CBOR base64url tag, integer tag number of + * 33, or encoded CBOR that is not a tag, that is base64url encoded + * bytes encoded in a text string. + * + * Please see @ref Decode-Errors-Overview "Decode Errors Overview". + * + * See @ref Tag-Usage for discussion on tag requirements. + * + * Note that this does not actually remove the base64url encoding. + * + * See also @ref CBOR_TAG_B64URL, QCBOREncode_AddTB64URLText() and + * @ref QCBOR_TYPE_BASE64URL. + */ +static void +QCBORDecode_GetB64URL(QCBORDecodeContext *pCtx, + uint8_t uTagRequirement, + UsefulBufC *pB64Text); -void QCBORDecode_GetEpochDateInMapSZ(QCBORDecodeContext *pCtx, - const char *szLabel, - uint8_t uTagRequirement, - int64_t *pnTime); +static void +QCBORDecode_GetB64URLInMapN(QCBORDecodeContext *pCtx, + int64_t nLabel, + uint8_t uTagRequirement, + UsefulBufC *pB64Text); +static void +QCBORDecode_GetB64URLInMapSZ(QCBORDecodeContext *pCtx, + const char *szLabel, + uint8_t uTagRequirement, + UsefulBufC *pB64Text); /** - @brief Decode the next item as an days-count epoch date. - - @param[in] pCtx The decode context. - @param[in] uTagRequirement One of @c QCBOR_TAG_REQUIREMENT_XXX. - @param[out] pnDays The decoded epoch date. - - This decodes the CBOR epoch date tag, integer tag number of 100, or - encoded CBOR that is not a tag, but borrows the content format. The - date is the number of days (not number of seconds) before or after - Jan 1, 1970. - - Please see @ref Decode-Errors-Overview "Decode Errors Overview". - - See @ref Tag-Usage for discussion on tag requirements. - - See also @ref CBOR_TAG_DAYS_EPOCH, QCBOREncode_AddTDaysEpoch() and - @ref QCBOR_TYPE_DAYS_EPOCH. -*/ -void QCBORDecode_GetEpochDays(QCBORDecodeContext *pCtx, - uint8_t uTagRequirement, - int64_t *pnDays); - -void QCBORDecode_GetEpochDaysInMapN(QCBORDecodeContext *pCtx, - int64_t nLabel, - uint8_t uTagRequirement, - int64_t *pnDays); - -void QCBORDecode_GetEpochDaysInMapSZ(QCBORDecodeContext *pCtx, - const char *szLabel, - uint8_t uTagRequirement, - int64_t *pnDays); + * @brief Decode the next item as a regular expression. + * + * @param[in] pCtx The decode context. + * @param[in] uTagRequirement One of @c QCBOR_TAG_REQUIREMENT_XXX. + * @param[out] pRegex The decoded regular expression. + * + * This decodes a standard CBOR regex tag, integer tag number of 35, + * or encoded CBOR that is not a tag, that is a PERL-compatible + * regular expression encoded in a text string. + * + * Please see @ref Decode-Errors-Overview "Decode Errors Overview". + * + * See @ref Tag-Usage for discussion on tag requirements. + * + * See also @ref CBOR_TAG_REGEX, QCBOREncode_AddTRegex() and + * @ref QCBOR_TYPE_REGEX. + */ +static void +QCBORDecode_GetRegex(QCBORDecodeContext *pCtx, + uint8_t uTagRequirement, + UsefulBufC *pRegex); +static void +QCBORDecode_GetRegexInMapN(QCBORDecodeContext *pCtx, + int64_t nLabel, + uint8_t uTagRequirement, + UsefulBufC *pRegex); +static void +QCBORDecode_GetRegexInMapSZ(QCBORDecodeContext *pCtx, + const char * szLabel, + uint8_t uTagRequirement, + UsefulBufC *pRegex); /** - @brief Decode the next item as a big number. - - @param[in] pCtx The decode context. - @param[in] uTagRequirement One of @c QCBOR_TAG_REQUIREMENT_XXX. - @param[out] pValue The returned big number. - @param[out] pbIsNegative Is @c true if the big number is negative. This - is only valid when @c uTagRequirement is - @ref QCBOR_TAG_REQUIREMENT_TAG. - - This decodes a standard CBOR big number, integer tag number of 2 or - 3, or encoded CBOR that is not a tag, but borrows the content format. - - Please see @ref Decode-Errors-Overview "Decode Errors Overview". - - The big number is in network byte order. The first byte in @c pValue - is the most significant byte. There may be leading zeros. - - The negative value is computed as -1 - n, where n is the postive big - number in @c pValue. There is no standard representation for - big numbers, positive or negative in C, so this implementation leaves - it up to the caller to apply this computation for negative big numbers. - - See @ref Tag-Usage for discussion on tag requirements. - - Determination of the sign of the big number depends on the tag - requirement of the protocol using the big number. If the protocol - requires tagging, @ref QCBOR_TAG_REQUIREMENT_TAG, then the sign - indication is in the protocol and @c pbIsNegative indicates the - sign. If the protocol doesn't use a tag, @ref - QCBOR_TAG_REQUIREMENT_NOT_A_TAG, then the protocol design must have some - way of indicating the sign. - - See also QCBORDecode_GetInt64ConvertAll(), - QCBORDecode_GetUInt64ConvertAll() and - QCBORDecode_GetDoubleConvertAll() which can convert big numbers. - - See also @ref CBOR_TAG_POS_BIGNUM, @ref CBOR_TAG_NEG_BIGNUM, - QCBOREncode_AddPositiveBignum(), QCBOREncode_AddNegativeBignum(), - @ref QCBOR_TYPE_POSBIGNUM and @ref QCBOR_TYPE_NEGBIGNUM. - -*/ -// Improvement: Add function that converts integers and other to big nums -void QCBORDecode_GetBignum(QCBORDecodeContext *pCtx, + * @brief Decode the next item as a MIME message. + * + * @param[in] pCtx The decode context. + * @param[in] uTagRequirement One of @c QCBOR_TAG_REQUIREMENT_XXX. + * @param[out] pMessage The decoded regular expression. + * @param[out] pbIsTag257 @c true if tag was 257. May be @c NULL. + * + * This decodes the standard CBOR MIME and binary MIME tags, integer + * tag numbers of 36 or 257, or encoded CBOR that is not a tag, that + * is a MIME message encoded in a text or binary string. + * + * Please see @ref Decode-Errors-Overview "Decode Errors Overview". + * + * See @ref Tag-Usage for discussion on tag requirements. + * + * The MIME message itself is not parsed. + * + * This decodes both tag 36 and 257. If it is tag 257, pbIsTag257 is + * @c true. The difference between the two is that tag 36 is utf8 and + * tag 257 is a byte string that can carry binary MIME. QCBOR + * processes them exactly the same. Possibly the difference can be + * ignored. NULL can be passed to have no value returned. + * + * See also @ref CBOR_TAG_MIME, @ref CBOR_TAG_BINARY_MIME, + * QCBOREncode_AddTMIMEData(), @ref QCBOR_TYPE_MIME and + * @ref QCBOR_TYPE_BINARY_MIME. + * + * This does no translation of line endings. See QCBOREncode_AddText() + * for a discussion of line endings in CBOR. + */ +static void +QCBORDecode_GetMIMEMessage(QCBORDecodeContext *pCtx, uint8_t uTagRequirement, - UsefulBufC *pValue, - bool *pbIsNegative); + UsefulBufC *pMessage, + bool *pbIsTag257); + +static void +QCBORDecode_GetMIMEMessageInMapN(QCBORDecodeContext *pCtx, + int64_t nLabel, + uint8_t uTagRequirement, + UsefulBufC *pMessage, + bool *pbIsTag257); -void QCBORDecode_GetBignumInMapN(QCBORDecodeContext *pCtx, - int64_t nLabel, - uint8_t uTagRequirement, - UsefulBufC *pValue, - bool *pbIsNegative); -void QCBORDecode_GetBignumInMapSZ(QCBORDecodeContext *pCtx, +static void +QCBORDecode_GetMIMEMessageInMapSZ(QCBORDecodeContext *pCtx, const char *szLabel, uint8_t uTagRequirement, - UsefulBufC *pValue, - bool *pbIsNegative); - - - - -#ifndef QCBOR_DISABLE_EXP_AND_MANTISSA -/** - @brief Decode the next item as a decimal fraction. - - @param[in] pCtx The decode context. - @param[in] uTagRequirement One of @c QCBOR_TAG_REQUIREMENT_XXX. - @param[out] pnMantissa The mantissa. - @param[out] pnExponent The base 10 exponent. - - This decodes a standard CBOR decimal fraction, integer tag number of - 4, or encoded CBOR that is not a tag, but borrows the content format. - - Please see @ref Decode-Errors-Overview "Decode Errors Overview". - - The value of this is computed by: - - mantissa * ( 10 ** exponent ) - - In the encoded CBOR, the mantissa and exponent may be of CBOR type 0 - (positive integer), type 1 (negative integer), type 2 tag 2 (positive - big number) or type 2 tag 3 (negative big number). This - implementation will attempt to convert all of these to an @c - int64_t. If the value won't fit, @ref - QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW or - QCBOR_ERR_BAD_EXP_AND_MANTISSA will be set. - - This implementation limits the exponent to between @c INT64_MIN and - @c INT64_MAX while CBOR allows the range of @c -UINT64_MAX to - @c UINT64_MAX. - - Various format and type issues will result in @ref - QCBOR_ERR_BAD_EXP_AND_MANTISSA being set. - - See @ref Tag-Usage for discussion on tag requirements. - - See also QCBORDecode_GetInt64ConvertAll(), - QCBORDecode_GetUInt64ConvertAll() and - QCBORDecode_GetDoubleConvertAll() which can convert big numbers. - - See also @ref CBOR_TAG_DECIMAL_FRACTION, - QCBOREncode_AddDecimalFraction(), @ref QCBOR_TYPE_DECIMAL_FRACTION - and QCBORDecode_GetDecimalFractionBig(). - - If QCBOR_DISABLE_TAGS is set, the only input this will decode is - an array of two integers. It will set an error if the the array is preceded - by by a tag number or if the mantissa is a big number. -*/ -void QCBORDecode_GetDecimalFraction(QCBORDecodeContext *pCtx, - uint8_t uTagRequirement, - int64_t *pnMantissa, - int64_t *pnExponent); - -void QCBORDecode_GetDecimalFractionInMapN(QCBORDecodeContext *pCtx, - int64_t nLabel, - uint8_t uTagRequirement, - int64_t *pnMantissa, - int64_t *pnExponent); - -void QCBORDecode_GetDecimalFractionInMapSZ(QCBORDecodeContext *pMe, - const char *szLabel, - uint8_t uTagRequirement, - int64_t *pnMantissa, - int64_t *pnExponent); - - -/** - @brief Decode the next item as a decimal fraction with a big number mantissa. - - @param[in] pCtx The decode context. - @param[in] uTagRequirement One of @c QCBOR_TAG_REQUIREMENT_XXX. - @param[in] MantissaBuffer The buffer in which to put the mantissa. - @param[out] pMantissa The big num mantissa. - @param[out] pbMantissaIsNegative Is @c true if @c pMantissa is negative. - @param[out] pnExponent The base 10 exponent. - - This is the same as QCBORDecode_GetDecimalFraction() except the - mantissa is returned as a big number. - - In the encoded CBOR, the mantissa may be a type 0 (positive integer), - type 1 (negative integer), type 2 tag 2 (positive big number) or type - 2 tag 3 (negative big number). This implementation will convert all - these to a big number. The limit to this conversion is the size of @c - MantissaBuffer. - - See also QCBORDecode_GetInt64ConvertAll(), - QCBORDecode_GetUInt64ConvertAll() and - QCBORDecode_GetDoubleConvertAll() which can convert decimal - fractions. - - See also @ref CBOR_TAG_DECIMAL_FRACTION, - QCBOREncode_AddDecimalFraction(), @ref QCBOR_TYPE_DECIMAL_FRACTION - and QCBORDecode_GetDecimalFraction(). -*/ -void QCBORDecode_GetDecimalFractionBig(QCBORDecodeContext *pCtx, - uint8_t uTagRequirement, - UsefulBuf MantissaBuffer, - UsefulBufC *pMantissa, - bool *pbMantissaIsNegative, - int64_t *pnExponent); - -void QCBORDecode_GetDecimalFractionBigInMapN(QCBORDecodeContext *pCtx, - int64_t nLabel, - uint8_t uTagRequirement, - UsefulBuf MantissaBuffer, - UsefulBufC *pbMantissaIsNegative, - bool *pbIsNegative, - int64_t *pnExponent); - -void QCBORDecode_GetDecimalFractionBigInMapSZ(QCBORDecodeContext *pCtx, - const char *szLabel, - uint8_t uTagRequirement, - UsefulBuf MantissaBuffer, - UsefulBufC *pMantissa, - bool *pbMantissaIsNegative, - int64_t *pnExponent); - + UsefulBufC *pMessage, + bool *pbIsTag257); /** - @brief Decode the next item as a big float. - - @param[in] pCtx The decode context. - @param[in] uTagRequirement One of @c QCBOR_TAG_REQUIREMENT_XXX. - @param[out] pnMantissa The mantissa. - @param[out] pnExponent The base 2 exponent. - - This decodes a standard CBOR big float, integer tag number of 5, or - encoded CBOR that is not a tag, but borrows the content format. - - This is the same as QCBORDecode_GetDecimalFraction() with the - important distinction that the value is computed by: - - mantissa * ( 2 ** exponent ) - - If the mantissa is a tag that is a positive or negative big number, - this will attempt to fit it into the int64_t that @c pnMantissa is - and set an overflow error if it doesn't fit. - - See also QCBORDecode_GetInt64ConvertAll(), - QCBORDecode_GetUInt64ConvertAll() and - QCBORDecode_GetDoubleConvertAll() which can convert big floats. - - See also @ref CBOR_TAG_BIGFLOAT, QCBOREncode_AddBigFloat(), @ref - QCBOR_TYPE_BIGFLOAT and QCBORDecode_GetBigFloatBig(). + * @brief Decode the next item as a UUID. + * + * @param[in] pCtx The decode context. + * @param[in] uTagRequirement One of @c QCBOR_TAG_REQUIREMENT_XXX. + * @param[out] pUUID The decoded UUID + * + * This decodes a standard CBOR UUID tag, integer tag number of 37, or + * encoded CBOR that is not a tag, that is a UUID encoded in a byte + * string. + * + * Please see @ref Decode-Errors-Overview "Decode Errors Overview". + * + * See @ref Tag-Usage for discussion on tag requirements. + * + * See also @ref CBOR_TAG_BIN_UUID, QCBOREncode_AddTBinaryUUID() and + * @ref QCBOR_TYPE_UUID. */ -void QCBORDecode_GetBigFloat(QCBORDecodeContext *pCtx, - uint8_t uTagRequirement, - int64_t *pnMantissa, - int64_t *pnExponent); - -void QCBORDecode_GetBigFloatInMapN(QCBORDecodeContext *pCtx, - int64_t nLabel, - uint8_t uTagRequirement, - int64_t *pnMantissa, - int64_t *pnExponent); - -void QCBORDecode_GetBigFloatInMapSZ(QCBORDecodeContext *pCtx, - const char *szLabel, - uint8_t uTagRequirement, - int64_t *pnMantissa, - int64_t *pnExponent); - - -/** - @brief Decode the next item as a big float with a big number mantissa. - - @param[in] pCtx The decode context. - @param[in] uTagRequirement One of @c QCBOR_TAG_REQUIREMENT_XXX. - @param[in] MantissaBuffer The buffer in which to put the mantissa. - @param[out] pMantissa The big num mantissa. - @param[out] pbMantissaIsNegative Is @c true if @c pMantissa is negative. - @param[out] pnExponent The base 2 exponent. - - This is the same as QCBORDecode_GetDecimalFractionBig() with the - important distinction that the value is computed by: - - mantissa * ( 2 ** exponent ) - - See also QCBORDecode_GetInt64ConvertAll(), - QCBORDecode_GetUInt64ConvertAll() and - QCBORDecode_GetDoubleConvertAll() which can convert big floats. +static void +QCBORDecode_GetBinaryUUID(QCBORDecodeContext *pCtx, + uint8_t uTagRequirement, + UsefulBufC *pUUID); - See also @ref CBOR_TAG_BIGFLOAT, QCBOREncode_AddBigFloat(), - @ref QCBOR_TYPE_BIGFLOAT and QCBORDecode_GetBigFloat(). - */ -void QCBORDecode_GetBigFloatBig(QCBORDecodeContext *pCtx, +static void +QCBORDecode_GetBinaryUUIDInMapN(QCBORDecodeContext *pCtx, + int64_t nLabel, uint8_t uTagRequirement, - UsefulBuf MantissaBuffer, - UsefulBufC *pMantissa, - bool *pbMantissaIsNegative, - int64_t *pnExponent); - -void QCBORDecode_GetBigFloatBigInMapN(QCBORDecodeContext *pCtx, - int64_t nLabel, - uint8_t uTagRequirement, - UsefulBuf MantissaBuffer, - UsefulBufC *pMantissa, - bool *pbMantissaIsNegative, - int64_t *pnExponent); - -void QCBORDecode_GetBigFloatBigInMapSZ(QCBORDecodeContext *pCtx, - const char *szLabel, - uint8_t uTagRequirement, - UsefulBuf MantissaBuffer, - UsefulBufC *pMantissa, - bool *pbMantissaIsNegative, - int64_t *pnExponent); -#endif /* #ifndef QCBOR_DISABLE_EXP_AND_MANTISSA */ + UsefulBufC *pUUID); +static void +QCBORDecode_GetBinaryUUIDInMapSZ(QCBORDecodeContext *pCtx, + const char *szLabel, + uint8_t uTagRequirement, + UsefulBufC *pUUID); /** - @brief Decode the next item as a URI. - - @param[in] pCtx The decode context. - @param[in] uTagRequirement One of @c QCBOR_TAG_REQUIREMENT_XXX. - @param[out] pURI The decoded URI. - - This decodes a standard CBOR URI tag, integer tag number of 32, - or encoded CBOR that is not a tag, that is a URI encoded in a text string. - - Please see @ref Decode-Errors-Overview "Decode Errors Overview". - - See @ref Tag-Usage for discussion on tag requirements. - - See also @ref CBOR_TAG_URI, QCBOREncode_AddURI() and - @ref QCBOR_TYPE_URI. + * @brief Decode some byte-string wrapped CBOR. + * + * @param[in] pCtx The decode context. + * @param[in] uTagRequirement One of @c QCBOR_TAG_REQUIREMENT_XXX. + * @param[out] pBstr Pointer and length of byte-string wrapped CBOR (optional). + * + * This is for use on some CBOR that has been wrapped in a byte + * string. There are several ways that this can occur. + * + * First is tag 24 and tag 63. Tag 24 wraps a single CBOR data item + * and 63 a CBOR sequence. This implementation doesn't distinguish + * between the two (it would be more code and doesn't seem important). + * + * The @ref Tag-Usage discussion on the tag requirement applies here + * just the same as any other tag. + * + * In other cases, CBOR is wrapped in a byte string, but it is + * identified as CBOR by other means. The contents of a COSE payload + * are one example of that. They can be identified by the COSE content + * type, or they can be identified as CBOR indirectly by the protocol + * that uses COSE. for example, if a blob of CBOR is identified as a + * CWT, then the COSE payload is CBOR. To enter into CBOR of this + * type use the @ref QCBOR_TAG_REQUIREMENT_NOT_A_TAG as the \c + * uTagRequirement argument. + * + * Note that byte string wrapped CBOR can also be decoded by getting + * the byte string with QCBORDecode_GetItem() or + * QCBORDecode_GetByteString() and feeding it into another instance of + * QCBORDecode. Doing it with this function has the advantage of using + * less memory as another instance of QCBORDecode is not necessary. + * + * When the wrapped CBOR is entered with this function, the pre-order + * traversal and such are bounded to the wrapped + * CBOR. QCBORDecode_ExitBstrWrapped() must be called to resume + * processing CBOR outside the wrapped CBOR. + * + * This does not work on indefinite-length strings. The + * error @ref QCBOR_ERR_CANNOT_ENTER_ALLOCATED_STRING will be set. + * + * If @c pBstr is not @c NULL the pointer and length of the wrapped + * CBOR will be returned. This is usually not needed, but sometimes + * useful, particularly in the case of verifying signed data like the + * COSE payload. This is usually the pointer and length of the data is + * that is hashed or MACed. + * + * Please see @ref Decode-Errors-Overview "Decode Errors Overview". + * + * See also QCBORDecode_ExitBstrWrapped(), QCBORDecode_EnterMap() and + * QCBORDecode_EnterArray(). */ -static void QCBORDecode_GetURI(QCBORDecodeContext *pCtx, - uint8_t uTagRequirement, - UsefulBufC *pURI); - -static void QCBORDecode_GetURIInMapN(QCBORDecodeContext *pCtx, - int64_t nLabel, - uint8_t uTagRequirement, - UsefulBufC *pURI); - -static void QCBORDecode_GetURIInMapSZ(QCBORDecodeContext *pCtx, - const char * szLabel, - uint8_t uTagRequirement, - UsefulBufC *pURI); - - -/** - @brief Decode the next item as base64 encoded text. - - @param[in] pCtx The decode context. - @param[in] uTagRequirement One of @c QCBOR_TAG_REQUIREMENT_XXX. - @param[out] pB64Text The decoded base64 text. - - This decodes a standard CBOR base64 tag, integer tag number of 34, or - encoded CBOR that is not a tag, that is base64 encoded bytes encoded - in a text string. - - Please see @ref Decode-Errors-Overview "Decode Errors Overview". - - See @ref Tag-Usage for discussion on tag requirements. - - Note that this does not actually remove the base64 encoding. - - See also @ref CBOR_TAG_B64, QCBOREncode_AddB64Text() and - @ref QCBOR_TYPE_BASE64. -*/ -static void QCBORDecode_GetB64(QCBORDecodeContext *pCtx, - uint8_t uTagRequirement, - UsefulBufC *pB64Text); +void +QCBORDecode_EnterBstrWrapped(QCBORDecodeContext *pCtx, + uint8_t uTagRequirement, + UsefulBufC *pBstr); -static void QCBORDecode_GetB64InMapN(QCBORDecodeContext *pCtx, +void +QCBORDecode_EnterBstrWrappedFromMapN(QCBORDecodeContext *pCtx, int64_t nLabel, uint8_t uTagRequirement, - UsefulBufC *pB64Text); + UsefulBufC *pBstr); -static void QCBORDecode_GetB64InMapSZ(QCBORDecodeContext *pCtx, +void +QCBORDecode_EnterBstrWrappedFromMapSZ(QCBORDecodeContext *pCtx, const char *szLabel, uint8_t uTagRequirement, - UsefulBufC *pB64Text); - -/** - @brief Decode the next item as base64URL encoded text. - - @param[in] pCtx The decode context. - @param[in] uTagRequirement One of @c QCBOR_TAG_REQUIREMENT_XXX. - @param[out] pB64Text The decoded base64 text. - - This decodes a standard CBOR base64url tag, integer tag number of 33, - or encoded CBOR that is not a tag, that is base64url encoded bytes - encoded in a text string. - - Please see @ref Decode-Errors-Overview "Decode Errors Overview". - - See @ref Tag-Usage for discussion on tag requirements. + UsefulBufC *pBstr); - Note that this does not actually remove the base64url encoding. - - See also @ref CBOR_TAG_B64URL, QCBOREncode_AddB64URLText() and - @ref QCBOR_TYPE_BASE64URL. -*/ -static void QCBORDecode_GetB64URL(QCBORDecodeContext *pCtx, - uint8_t uTagRequirement, - UsefulBufC *pB64Text); - -static void QCBORDecode_GetB64URLInMapN(QCBORDecodeContext *pCtx, - int64_t nLabel, - uint8_t uTagRequirement, - UsefulBufC *pB64Text); - -static void QCBORDecode_GetB64URLInMapSZ(QCBORDecodeContext *pCtx, - const char *szLabel, - uint8_t uTagRequirement, - UsefulBufC *pB64Text); /** - @brief Decode the next item as a regular expression. - - @param[in] pCtx The decode context. - @param[in] uTagRequirement One of @c QCBOR_TAG_REQUIREMENT_XXX. - @param[out] pRegex The decoded regular expression. - - This decodes a standard CBOR regex tag, integer tag number of 35, or - encoded CBOR that is not a tag, that is a PERL-compatible regular - expression encoded in a text string. - - Please see @ref Decode-Errors-Overview "Decode Errors Overview". - - See @ref Tag-Usage for discussion on tag requirements. - - See also @ref CBOR_TAG_REGEX, QCBOREncode_AddRegex() and - @ref QCBOR_TYPE_REGEX. - */ -static void QCBORDecode_GetRegex(QCBORDecodeContext *pCtx, - uint8_t uTagRequirement, - UsefulBufC *pRegex); - -static void QCBORDecode_GetRegexInMapN(QCBORDecodeContext *pCtx, - int64_t nLabel, - uint8_t uTagRequirement, - UsefulBufC *pRegex); - -static void QCBORDecode_GetRegexInMapSZ(QCBORDecodeContext *pCtx, - const char * szLabel, - uint8_t uTagRequirement, - UsefulBufC *pRegex); - - -/** - @brief Decode the next item as a MIME message. - - @param[in] pCtx The decode context. - @param[in] uTagRequirement One of @c QCBOR_TAG_REQUIREMENT_XXX. - @param[out] pMessage The decoded regular expression. - @param[out] pbIsTag257 @c true if tag was 257. May be @c NULL. - - This decodes the standard CBOR MIME and binary MIME tags, integer tag - numbers of 36 or 257, or encoded CBOR that is not a tag, that is a - MIME message encoded in a text or binary string. - - Please see @ref Decode-Errors-Overview "Decode Errors Overview". - - See @ref Tag-Usage for discussion on tag requirements. - - The MIME message itself is not parsed. - - This decodes both tag 36 and 257. If it is tag 257, pbIsTag257 - is @c true. The difference between the two is that - tag 36 is utf8 and tag 257 is a byte string that can - carry binary MIME. QCBOR processes them exactly - the same. Possibly the difference can be ignored. - NULL can be passed to have no value returned. - - See also @ref CBOR_TAG_MIME, @ref CBOR_TAG_BINARY_MIME, - QCBOREncode_AddTMIMEData(), @ref QCBOR_TYPE_MIME and - @ref QCBOR_TYPE_BINARY_MIME. - - This does no translation of line endings. See QCBOREncode_AddText() - for a discussion of line endings in CBOR. -*/ -static void QCBORDecode_GetMIMEMessage(QCBORDecodeContext *pCtx, - uint8_t uTagRequirement, - UsefulBufC *pMessage, - bool *pbIsTag257); - -static void QCBORDecode_GetMIMEMessageInMapN(QCBORDecodeContext *pCtx, - int64_t nLabel, - uint8_t uTagRequirement, - UsefulBufC *pMessage, - bool *pbIsTag257); - - -static void QCBORDecode_GetMIMEMessageInMapSZ(QCBORDecodeContext *pCtx, - const char *szLabel, - uint8_t uTagRequirement, - UsefulBufC *pMessage, - bool *pbIsTag257); - -/** - @brief Decode the next item as a UUID - - @param[in] pCtx The decode context. - @param[in] uTagRequirement One of @c QCBOR_TAG_REQUIREMENT_XXX. - @param[out] pUUID The decoded UUID - - This decodes a standard CBOR UUID tag, integer tag number of 37, or - encoded CBOR that is not a tag, that is a UUID encoded in a byte - string. - - Please see @ref Decode-Errors-Overview "Decode Errors Overview". - - See @ref Tag-Usage for discussion on tag requirements. - - See also @ref CBOR_TAG_BIN_UUID, QCBOREncode_AddBinaryUUID() and - @ref QCBOR_TYPE_UUID. + * @brief Exit some bstr-wrapped CBOR has been enetered. + * + * @param[in] pCtx The decode context. + * + * Bstr-wrapped CBOR must have been entered for this to succeed. + * + * The items in the wrapped CBOR that was entered do not have to have + * been consumed for this to succeed. + * + * The this sets the traversal cursor to the item after the + * byte string that was exited. */ -static inline void QCBORDecode_GetBinaryUUID(QCBORDecodeContext *pCtx, - uint8_t uTagRequirement, - UsefulBufC *pUUID); - -inline static void QCBORDecode_GetBinaryUUIDInMapN(QCBORDecodeContext *pCtx, - int64_t nLabel, - uint8_t uTagRequirement, - UsefulBufC *pUUID); - -inline static void QCBORDecode_GetBinaryUUIDInMapSZ(QCBORDecodeContext *pCtx, - const char *szLabel, - uint8_t uTagRequirement, - UsefulBufC *pUUID); +void +QCBORDecode_ExitBstrWrapped(QCBORDecodeContext *pCtx); -/** - @brief Decode some byte-string wrapped CBOR. - - @param[in] pCtx The decode context. - @param[in] uTagRequirement One of @c QCBOR_TAG_REQUIREMENT_XXX. - @param[out] pBstr Pointer and length of byte-string wrapped CBOR (optional). - - This is for use on some CBOR that has been wrapped in a byte - string. There are several ways that this can occur. - - First is tag 24 and tag 63. Tag 24 wraps a single CBOR data item and - 63 a CBOR sequence. This implementation doesn't distinguish between - the two (it would be more code and doesn't seem important). - - The @ref Tag-Usage discussion on the tag requirement applies here - just the same as any other tag. - - In other cases, CBOR is wrapped in a byte string, but it is - identified as CBOR by other means. The contents of a COSE payload are - one example of that. They can be identified by the COSE content type, - or they can be identified as CBOR indirectly by the protocol that - uses COSE. for example, if a blob of CBOR is identified as a CWT, - then the COSE payload is CBOR. To enter into CBOR of this type use - the @ref QCBOR_TAG_REQUIREMENT_NOT_A_TAG as the \c uTagRequirement - argument. - - Note that byte string wrapped CBOR can also be decoded by getting the - byte string with QCBORDecode_GetItem() or QCBORDecode_GetByteString() - and feeding it into another instance of QCBORDecode. Doing it with - this function has the advantage of using less memory as another - instance of QCBORDecode is not necessary. - - When the wrapped CBOR is entered with this function, the pre-order - traversal and such are bounded to the wrapped - CBOR. QCBORDecode_ExitBstrWrapped() must be called to resume processing - CBOR outside the wrapped CBOR. - - This does not (currently) work on indefinite-length strings. The - (confusing) error @ref QCBOR_ERR_INPUT_TOO_LARGE will be set. - - If @c pBstr is not @c NULL the pointer and length of the wrapped - CBOR will be returned. This is usually not needed, but sometimes - useful, particularly in the case of verifying signed data like the - COSE payload. This is usually the pointer and length of the - data is that is hashed or MACed. - - Please see @ref Decode-Errors-Overview "Decode Errors Overview". - - See also QCBORDecode_ExitBstrWrapped(), QCBORDecode_EnterMap() and - QCBORDecode_EnterArray(). - */ -void QCBORDecode_EnterBstrWrapped(QCBORDecodeContext *pCtx, - uint8_t uTagRequirement, - UsefulBufC *pBstr); -void QCBORDecode_EnterBstrWrappedFromMapN(QCBORDecodeContext *pCtx, - int64_t nLabel, - uint8_t uTagRequirement, - UsefulBufC *pBstr); +/* ========================================================================= * + * BEGINNING OF PRIVATE INLINE IMPLEMENTATION * + * ========================================================================= */ -void QCBORDecode_EnterBstrWrappedFromMapSZ(QCBORDecodeContext *pCtx, - const char *szLabel, - uint8_t uTagRequirement, - UsefulBufC *pBstr); + +/* Semi-private funcion used by public inline functions. See qcbor_decode.c */ +void +QCBORDecode_Private_GetUInt64Convert(QCBORDecodeContext *pCtx, + uint32_t uConvertTypes, + uint64_t *puValue, + QCBORItem *pItem); -/** - @brief Exit some bstr-wrapped CBOR has been enetered. +/* Semi-private funcion used by public inline functions. See qcbor_decode.c */ +void +QCBORDecode_Private_GetUInt64ConvertInMapN(QCBORDecodeContext *pCtx, + int64_t nLabel, + uint32_t uConvertTypes, + uint64_t *puValue, + QCBORItem *pItem); - @param[in] pCtx The decode context. - Bstr-wrapped CBOR must have been entered for this to succeed. +/* Semi-private funcion used by public inline functions. See qcbor_decode.c */ +void +QCBORDecode_Private_GetUInt64ConvertInMapSZ(QCBORDecodeContext *pCtx, + const char *szLabel, + uint32_t uConvertTypes, + uint64_t *puValue, + QCBORItem *pItem); - The items in the wrapped CBOR that was entered do not have to have been - consumed for this to succeed. +/* Semi-private funcion used by public inline functions. See qcbor_decode.c */ +void +QCBORDecode_Private_EnterBoundedMapOrArray(QCBORDecodeContext *pCtx, + uint8_t uType, + QCBORItem *pItem); - The this sets the pre-order traversal cursor to the item after - the byte string that was exited. -*/ -void QCBORDecode_ExitBstrWrapped(QCBORDecodeContext *pCtx); +/* Semi-private funcion used by public inline functions. See qcbor_decode.c */ +void +QCBORDecode_Private_ExitBoundedMapOrArray(QCBORDecodeContext *pCtx, + uint8_t uType); +/* Semi-private funcion used by public inline functions. See qcbor_decode.c */ +void +QCBORDecode_Private_GetInt64Convert(QCBORDecodeContext *pCtx, + uint32_t uConvertTypes, + int64_t *pnValue, + QCBORItem *pItem); +/* Semi-private funcion used by public inline functions. See qcbor_decode.c */ +void +QCBORDecode_Private_GetInt64ConvertInMapN(QCBORDecodeContext *pCtx, + int64_t nLabel, + uint32_t uConvertTypes, + int64_t *pnValue, + QCBORItem *pItem); -/* =========================================================================== - BEGINNING OF PRIVATE INLINE IMPLEMENTATION - ========================================================================== */ +/* Semi-private funcion used by public inline functions. See qcbor_decode.c */ +void +QCBORDecode_Private_GetInt64ConvertInMapSZ(QCBORDecodeContext *pCtx, + const char *szLabel, + uint32_t uConvertTypes, + int64_t *pnValue, + QCBORItem *pItem); -// Semi-private +#ifndef USEFULBUF_DISABLE_ALL_FLOAT +/* Semi-private funcion used by public inline functions. See qcbor_decode.c */ void -QCBORDecode_GetUInt64ConvertInternal(QCBORDecodeContext *pMe, +QCBORDecode_Private_GetDoubleConvert(QCBORDecodeContext *pCtx, uint32_t uConvertTypes, - uint64_t *puValue, + double *pValue, QCBORItem *pItem); -// Semi-private +/* Semi-private funcion used by public inline functions. See qcbor_decode.c */ void -QCBORDecode_GetUInt64ConvertInternalInMapN(QCBORDecodeContext *pMe, +QCBORDecode_Private_GetDoubleConvertInMapN(QCBORDecodeContext *pCtx, int64_t nLabel, uint32_t uConvertTypes, - uint64_t *puValue, + double *pdValue, QCBORItem *pItem); -// Semi-private +/* Semi-private funcion used by public inline functions. See qcbor_decode.c */ void -QCBORDecode_GetUInt64ConvertInternalInMapSZ(QCBORDecodeContext *pMe, +QCBORDecode_Private_GetDoubleConvertInMapSZ(QCBORDecodeContext *pCtx, const char *szLabel, uint32_t uConvertTypes, - uint64_t *puValue, + double *pdValue, QCBORItem *pItem); +#endif /* !USEFULBUF_DISABLE_ALL_FLOAT */ + +#define QCBOR_TAGSPEC_NUM_TYPES 4 +/* Semi-private data structure (which might change). + * + * See QCBOR_Private_CheckTagRequirement() which uses this to check the + * type of an item to be decoded as a tag or tag content. + * + * Improvement: Carefully understand what compilers do with this, + * particularly initialization and see if it can be optimized so there + * is less code and maybe so it can be smaller. + */ +typedef struct { + /* One of QCBOR_TAGSPEC_MATCH_xxx */ + uint8_t uTagRequirement; + /* The tagged type translated into QCBOR_TYPE_XXX. Used to match + * explicit tagging */ + uint8_t uTaggedTypes[QCBOR_TAGSPEC_NUM_TYPES]; + /* The types of the content, which are used to match implicit + * tagging */ + uint8_t uAllowedContentTypes[QCBOR_TAGSPEC_NUM_TYPES]; +} QCBOR_Private_TagSpec; -void QCBORDecode_GetUInt64Convert(QCBORDecodeContext *pMe, - uint32_t uConvertTypes, - uint64_t *puValue) +/* Semi-private funcion used by public inline functions. See qcbor_decode.c */ +void +QCBORDecode_Private_GetTaggedString(QCBORDecodeContext *pCtx, + QCBOR_Private_TagSpec TagSpec, + UsefulBufC *pBstr); + + +/* Semi-private funcion used by public inline functions. See qcbor_decode.c */ +void +QCBORDecode_Private_GetTaggedStringInMapN(QCBORDecodeContext *pCtx, + int64_t nLabel, + QCBOR_Private_TagSpec TagSpec, + UsefulBufC *pString); + +/* Semi-private funcion used by public inline functions. See qcbor_decode.c */ +void +QCBORDecode_Private_GetTaggedStringInMapSZ(QCBORDecodeContext *pCtx, + const char *szLabel, + QCBOR_Private_TagSpec TagSpec, + UsefulBufC *pString); + + +/* Semi-private funcion used by public inline functions. See qcbor_decode.c */ +QCBORError +QCBORDecode_Private_GetMIME(uint8_t uTagRequirement, + const QCBORItem *pItem, + UsefulBufC *pMessage, + bool *pbIsTag257); + + + + + +static inline void +QCBORDecode_GetUInt64Convert(QCBORDecodeContext *pMe, + const uint32_t uConvertTypes, + uint64_t *puValue) { QCBORItem Item; - QCBORDecode_GetUInt64ConvertInternal(pMe, uConvertTypes, puValue, &Item); + QCBORDecode_Private_GetUInt64Convert(pMe, uConvertTypes, puValue, &Item); } -inline static void +static inline void QCBORDecode_GetUInt64ConvertInMapN(QCBORDecodeContext *pMe, - int64_t nLabel, - uint32_t uConvertTypes, + const int64_t nLabel, + const uint32_t uConvertTypes, uint64_t *puValue) { QCBORItem Item; - QCBORDecode_GetUInt64ConvertInternalInMapN(pMe, + QCBORDecode_Private_GetUInt64ConvertInMapN(pMe, nLabel, uConvertTypes, puValue, &Item); } -inline static void +static inline void QCBORDecode_GetUInt64ConvertInMapSZ(QCBORDecodeContext *pMe, const char *szLabel, - uint32_t uConvertTypes, + const uint32_t uConvertTypes, uint64_t *puValue) { QCBORItem Item; - QCBORDecode_GetUInt64ConvertInternalInMapSZ(pMe, + QCBORDecode_Private_GetUInt64ConvertInMapSZ(pMe, szLabel, uConvertTypes, puValue, @@ -1757,9 +2221,9 @@ QCBORDecode_GetUInt64(QCBORDecodeContext *pMe, uint64_t *puValue) QCBORDecode_GetUInt64Convert(pMe, QCBOR_CONVERT_TYPE_XINT64, puValue); } -inline static void +static inline void QCBORDecode_GetUInt64InMapN(QCBORDecodeContext *pMe, - int64_t nLabel, + const int64_t nLabel, uint64_t *puValue) { QCBORDecode_GetUInt64ConvertInMapN(pMe, @@ -1768,7 +2232,7 @@ QCBORDecode_GetUInt64InMapN(QCBORDecodeContext *pMe, puValue); } -inline static void +static inline void QCBORDecode_GetUInt64InMapSZ(QCBORDecodeContext *pMe, const char *szLabel, uint64_t *puValue) @@ -1780,103 +2244,188 @@ QCBORDecode_GetUInt64InMapSZ(QCBORDecodeContext *pMe, } -// Semi-private -void QCBORDecode_EnterBoundedMapOrArray(QCBORDecodeContext *pMe, uint8_t uType, QCBORItem *pItem); - -// Semi-private -inline static void QCBORDecode_EnterMap(QCBORDecodeContext *pMe, QCBORItem *pItem) { - QCBORDecode_EnterBoundedMapOrArray(pMe, QCBOR_TYPE_MAP, pItem); +static inline void +QCBORDecode_EnterMap(QCBORDecodeContext *pMe, QCBORItem *pItem) { + QCBORDecode_Private_EnterBoundedMapOrArray(pMe, QCBOR_TYPE_MAP, pItem); } -// Semi-private -inline static void QCBORDecode_EnterArray(QCBORDecodeContext *pMe, QCBORItem *pItem) { - QCBORDecode_EnterBoundedMapOrArray(pMe, QCBOR_TYPE_ARRAY, pItem); +static inline void +QCBORDecode_EnterArray(QCBORDecodeContext *pMe, QCBORItem *pItem) { + QCBORDecode_Private_EnterBoundedMapOrArray(pMe, QCBOR_TYPE_ARRAY, pItem); } -// Semi-private -void QCBORDecode_ExitBoundedMapOrArray(QCBORDecodeContext *pMe, uint8_t uType); - -static inline void QCBORDecode_ExitArray(QCBORDecodeContext *pMe) +static inline void +QCBORDecode_ExitArray(QCBORDecodeContext *pMe) { - QCBORDecode_ExitBoundedMapOrArray(pMe, QCBOR_TYPE_ARRAY); + QCBORDecode_Private_ExitBoundedMapOrArray(pMe, QCBOR_TYPE_ARRAY); } -static inline void QCBORDecode_ExitMap(QCBORDecodeContext *pMe) +static inline void +QCBORDecode_ExitMap(QCBORDecodeContext *pMe) { - QCBORDecode_ExitBoundedMapOrArray(pMe, QCBOR_TYPE_MAP); + QCBORDecode_Private_ExitBoundedMapOrArray(pMe, QCBOR_TYPE_MAP); } -// Semi-private +/* Semi-private funcion used by public inline functions. See qcbor_decode.c */ void -QCBORDecode_GetInt64ConvertInternal(QCBORDecodeContext *pMe, - uint32_t uConvertTypes, - int64_t *pnValue, - QCBORItem *pItem); +QCBORDecode_Private_GetArrayOrMap(QCBORDecodeContext *pCtx, + uint8_t uType, + QCBORItem *pItem, + UsefulBufC *pEncodedCBOR); -// Semi-private -void -QCBORDecode_GetInt64ConvertInternalInMapN(QCBORDecodeContext *pMe, - int64_t nLabel, - uint32_t uConvertTypes, - int64_t *pnValue, - QCBORItem *pItem); -// Semi-private +/* Semi-private funcion used by public inline functions. See qcbor_decode.c */ void -QCBORDecode_GetInt64ConvertInternalInMapSZ(QCBORDecodeContext *pMe, - const char *szLabel, - uint32_t uConvertTypes, - int64_t *pnValue, - QCBORItem *pItem); +QCBORDecode_Private_SearchAndGetArrayOrMap(QCBORDecodeContext *pCtx, + QCBORItem *pTarget, + QCBORItem *pItem, + UsefulBufC *pEncodedCBOR); + + +static inline void +QCBORDecode_GetArray(QCBORDecodeContext *pMe, + QCBORItem *pItem, + UsefulBufC *pEncodedCBOR) +{ + QCBORDecode_Private_GetArrayOrMap(pMe, QCBOR_TYPE_ARRAY, pItem, pEncodedCBOR); +} + + +static inline void +QCBORDecode_GetArrayFromMapN(QCBORDecodeContext *pMe, + int64_t nLabel, + QCBORItem *pItem, + UsefulBufC *pEncodedCBOR) +{ + QCBORItem OneItemSeach[2]; + OneItemSeach[0].uLabelType = QCBOR_TYPE_INT64; + OneItemSeach[0].label.int64 = nLabel; + OneItemSeach[0].uDataType = QCBOR_TYPE_ARRAY; + OneItemSeach[1].uLabelType = QCBOR_TYPE_NONE; + + QCBORDecode_Private_SearchAndGetArrayOrMap(pMe, OneItemSeach, pItem, pEncodedCBOR); +} + + +static inline void +QCBORDecode_GetArrayFromMapSZ(QCBORDecodeContext *pMe, + const char *szLabel, + QCBORItem *pItem, + UsefulBufC *pEncodedCBOR) +{ +#ifndef QCBOR_DISABLE_NON_INTEGER_LABELS + QCBORItem OneItemSeach[2]; + OneItemSeach[0].uLabelType = QCBOR_TYPE_TEXT_STRING; + OneItemSeach[0].label.string = UsefulBuf_FromSZ(szLabel); + OneItemSeach[0].uDataType = QCBOR_TYPE_ARRAY; + OneItemSeach[1].uLabelType = QCBOR_TYPE_NONE; + + QCBORDecode_Private_SearchAndGetArrayOrMap(pMe, OneItemSeach, pItem, pEncodedCBOR); +#else + (void)szLabel; + (void)pItem; + (void)pEncodedCBOR; + pMe->uLastError = QCBOR_ERR_MAP_LABEL_TYPE; +#endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */ +} + +static inline void +QCBORDecode_GetMap(QCBORDecodeContext *pMe, + QCBORItem *pItem, + UsefulBufC *pEncodedCBOR) +{ + QCBORDecode_Private_GetArrayOrMap(pMe, QCBOR_TYPE_MAP, pItem, pEncodedCBOR); +} + + +static inline void +QCBORDecode_GetMapFromMapN(QCBORDecodeContext *pMe, + int64_t nLabel, + QCBORItem *pItem, + UsefulBufC *pEncodedCBOR) +{ + QCBORItem OneItemSeach[2]; + OneItemSeach[0].uLabelType = QCBOR_TYPE_INT64; + OneItemSeach[0].label.int64 = nLabel; + OneItemSeach[0].uDataType = QCBOR_TYPE_MAP; + OneItemSeach[1].uLabelType = QCBOR_TYPE_NONE; -inline static void + QCBORDecode_Private_SearchAndGetArrayOrMap(pMe, OneItemSeach, pItem, pEncodedCBOR); +} + + +static inline void +QCBORDecode_GetMapFromMapSZ(QCBORDecodeContext *pMe, + const char *szLabel, + QCBORItem *pItem, + UsefulBufC *pEncodedCBOR) +{ +#ifndef QCBOR_DISABLE_NON_INTEGER_LABELS + QCBORItem OneItemSeach[2]; + OneItemSeach[0].uLabelType = QCBOR_TYPE_TEXT_STRING; + OneItemSeach[0].label.string = UsefulBuf_FromSZ(szLabel); + OneItemSeach[0].uDataType = QCBOR_TYPE_MAP; + OneItemSeach[1].uLabelType = QCBOR_TYPE_NONE; + + QCBORDecode_Private_SearchAndGetArrayOrMap(pMe, OneItemSeach, pItem, pEncodedCBOR); +#else + (void)szLabel; + (void)pItem; + (void)pEncodedCBOR; + pMe->uLastError = QCBOR_ERR_MAP_LABEL_TYPE; +#endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */ +} + + + +static inline void QCBORDecode_GetInt64Convert(QCBORDecodeContext *pMe, - uint32_t uConvertTypes, + const uint32_t uConvertTypes, int64_t *pnValue) { QCBORItem Item; - QCBORDecode_GetInt64ConvertInternal(pMe, uConvertTypes, pnValue, &Item); + QCBORDecode_Private_GetInt64Convert(pMe, uConvertTypes, pnValue, &Item); } -inline static void +static inline void QCBORDecode_GetInt64ConvertInMapN(QCBORDecodeContext *pMe, - int64_t nLabel, - uint32_t uConvertTypes, + const int64_t nLabel, + const uint32_t uConvertTypes, int64_t *pnValue) { QCBORItem Item; - QCBORDecode_GetInt64ConvertInternalInMapN(pMe, + QCBORDecode_Private_GetInt64ConvertInMapN(pMe, nLabel, uConvertTypes, pnValue, &Item); } -inline static void +static inline void QCBORDecode_GetInt64ConvertInMapSZ(QCBORDecodeContext *pMe, const char *szLabel, - uint32_t uConvertTypes, + const uint32_t uConvertTypes, int64_t *pnValue) { QCBORItem Item; - QCBORDecode_GetInt64ConvertInternalInMapSZ(pMe, + QCBORDecode_Private_GetInt64ConvertInMapSZ(pMe, szLabel, uConvertTypes, pnValue, &Item); } -inline static void +static inline void QCBORDecode_GetInt64(QCBORDecodeContext *pMe, int64_t *pnValue) { QCBORDecode_GetInt64Convert(pMe, QCBOR_CONVERT_TYPE_XINT64, pnValue); } -inline static void +static inline void QCBORDecode_GetInt64InMapN(QCBORDecodeContext *pMe, - int64_t nLabel, + const int64_t nLabel, int64_t *pnValue) { QCBORDecode_GetInt64ConvertInMapN(pMe, @@ -1885,7 +2434,7 @@ QCBORDecode_GetInt64InMapN(QCBORDecodeContext *pMe, pnValue); } -inline static void +static inline void QCBORDecode_GetInt64InMapSZ(QCBORDecodeContext *pMe, const char *szLabel, int64_t *pnValue) @@ -1901,76 +2450,52 @@ QCBORDecode_GetInt64InMapSZ(QCBORDecodeContext *pMe, #ifndef USEFULBUF_DISABLE_ALL_FLOAT -// Semi-private -void -QCBORDecode_GetDoubleConvertInternal(QCBORDecodeContext *pMe, - uint32_t uConvertTypes, - double *pValue, - QCBORItem *pItem); - -// Semi-private -void -QCBORDecode_GetDoubleConvertInternalInMapN(QCBORDecodeContext *pMe, - int64_t nLabel, - uint32_t uConvertTypes, - double *pdValue, - QCBORItem *pItem); - -// Semi-private -void -QCBORDecode_GetDoubleConvertInternalInMapSZ(QCBORDecodeContext *pMe, - const char *szLabel, - uint32_t uConvertTypes, - double *pdValue, - QCBORItem *pItem); - - -inline static void +static inline void QCBORDecode_GetDoubleConvert(QCBORDecodeContext *pMe, - uint32_t uConvertTypes, + const uint32_t uConvertTypes, double *pdValue) { - QCBORItem Item; - QCBORDecode_GetDoubleConvertInternal(pMe, uConvertTypes, pdValue, &Item); + QCBORItem Item; + QCBORDecode_Private_GetDoubleConvert(pMe, uConvertTypes, pdValue, &Item); } -inline static void +static inline void QCBORDecode_GetDoubleConvertInMapN(QCBORDecodeContext *pMe, - int64_t nLabel, + const int64_t nLabel, uint32_t uConvertTypes, double *pdValue) { QCBORItem Item; - QCBORDecode_GetDoubleConvertInternalInMapN(pMe, + QCBORDecode_Private_GetDoubleConvertInMapN(pMe, nLabel, uConvertTypes, pdValue, &Item); } -inline static void +static inline void QCBORDecode_GetDoubleConvertInMapSZ(QCBORDecodeContext *pMe, const char *szLabel, - uint32_t uConvertTypes, + const uint32_t uConvertTypes, double *pdValue) { QCBORItem Item; - QCBORDecode_GetDoubleConvertInternalInMapSZ(pMe, + QCBORDecode_Private_GetDoubleConvertInMapSZ(pMe, szLabel, uConvertTypes, pdValue, &Item); } -inline static void +static inline void QCBORDecode_GetDouble(QCBORDecodeContext *pMe, double *pValue) { QCBORDecode_GetDoubleConvert(pMe, QCBOR_CONVERT_TYPE_FLOAT, pValue); } -inline static void +static inline void QCBORDecode_GetDoubleInMapN(QCBORDecodeContext *pMe, - int64_t nLabel, + const int64_t nLabel, double *pdValue) { QCBORDecode_GetDoubleConvertInMapN(pMe, @@ -1979,7 +2504,7 @@ QCBORDecode_GetDoubleInMapN(QCBORDecodeContext *pMe, pdValue); } -inline static void +static inline void QCBORDecode_GetDoubleInMapSZ(QCBORDecodeContext *pMe, const char *szLabel, double *pdValue) @@ -1993,96 +2518,49 @@ QCBORDecode_GetDoubleInMapSZ(QCBORDecodeContext *pMe, -#define QCBOR_TAGSPEC_NUM_TYPES 4 -/* Semi-private data structure (which might change). - * - * See CheckTagRequirement() which uses this to check the type of a - * item to be decoded as a tag or tag content. - * - * Improvement: Carefully understand what compilers do with this, - * particularly initialization and see if it can be optimized so there - * is less code and maybe so it can be smaller. - */ -typedef struct { - /* One of QCBOR_TAGSPEC_MATCH_xxx */ - uint8_t uTagRequirement; - /* The tagged type translated into QCBOR_TYPE_XXX. Used to match - * explicit tagging */ - uint8_t uTaggedTypes[QCBOR_TAGSPEC_NUM_TYPES]; - /* The types of the content, which are used to match implicit - * tagging */ - uint8_t uAllowedContentTypes[QCBOR_TAGSPEC_NUM_TYPES]; -} TagSpecification; - - -// Semi private -void QCBORDecode_GetTaggedStringInternal(QCBORDecodeContext *pMe, - TagSpecification TagSpec, - UsefulBufC *pBstr); - - -// Semi private -void QCBORDecode_GetTaggedStringInMapN(QCBORDecodeContext *pMe, - int64_t nLabel, - TagSpecification TagSpec, - UsefulBufC *pString); - -// Semi private -void QCBORDecode_GetTaggedStringInMapSZ(QCBORDecodeContext *pMe, - const char * szLabel, - TagSpecification TagSpec, - UsefulBufC *pString); - - -// Semi private -QCBORError QCBORDecode_GetMIMEInternal(uint8_t uTagRequirement, - const QCBORItem *pItem, - UsefulBufC *pMessage, - bool *pbIsTag257); - static inline void QCBORDecode_GetByteString(QCBORDecodeContext *pMe, UsefulBufC *pValue) { // Complier should make this just a 64-bit integer parameter - const TagSpecification TagSpec = + const QCBOR_Private_TagSpec TagSpec = { - QCBOR_TAG_REQUIREMENT_NOT_A_TAG, + QCBOR_TAG_REQUIREMENT_TAG | QCBOR_TAG_REQUIREMENT_ALLOW_ADDITIONAL_TAGS, {QCBOR_TYPE_BYTE_STRING, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}, {QCBOR_TYPE_BYTE_STRING, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE} }; - QCBORDecode_GetTaggedStringInternal(pMe, TagSpec, pValue); + QCBORDecode_Private_GetTaggedString(pMe, TagSpec, pValue); } -inline static void +static inline void QCBORDecode_GetByteStringInMapN(QCBORDecodeContext *pMe, - int64_t nLabel, + const int64_t nLabel, UsefulBufC *pBstr) { - const TagSpecification TagSpec = + const QCBOR_Private_TagSpec TagSpec = { - QCBOR_TAG_REQUIREMENT_NOT_A_TAG, + QCBOR_TAG_REQUIREMENT_NOT_A_TAG | QCBOR_TAG_REQUIREMENT_ALLOW_ADDITIONAL_TAGS, {QCBOR_TYPE_BYTE_STRING, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}, {QCBOR_TYPE_BYTE_STRING, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE} }; - QCBORDecode_GetTaggedStringInMapN(pMe, nLabel, TagSpec, pBstr); + QCBORDecode_Private_GetTaggedStringInMapN(pMe, nLabel, TagSpec, pBstr); } -inline static void +static inline void QCBORDecode_GetByteStringInMapSZ(QCBORDecodeContext *pMe, const char *szLabel, UsefulBufC *pBstr) { - const TagSpecification TagSpec = + const QCBOR_Private_TagSpec TagSpec = { - QCBOR_TAG_REQUIREMENT_NOT_A_TAG, + QCBOR_TAG_REQUIREMENT_NOT_A_TAG | QCBOR_TAG_REQUIREMENT_ALLOW_ADDITIONAL_TAGS, {QCBOR_TYPE_BYTE_STRING, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}, {QCBOR_TYPE_BYTE_STRING, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE} }; - QCBORDecode_GetTaggedStringInMapSZ(pMe, szLabel, TagSpec, pBstr); + QCBORDecode_Private_GetTaggedStringInMapSZ(pMe, szLabel, TagSpec, pBstr); } @@ -2090,46 +2568,46 @@ static inline void QCBORDecode_GetTextString(QCBORDecodeContext *pMe, UsefulBufC *pValue) { // Complier should make this just 64-bit integer parameter - const TagSpecification TagSpec = + const QCBOR_Private_TagSpec TagSpec = { - QCBOR_TAG_REQUIREMENT_NOT_A_TAG, + QCBOR_TAG_REQUIREMENT_NOT_A_TAG | QCBOR_TAG_REQUIREMENT_ALLOW_ADDITIONAL_TAGS, {QCBOR_TYPE_TEXT_STRING, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}, {QCBOR_TYPE_TEXT_STRING, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE} }; - QCBORDecode_GetTaggedStringInternal(pMe, TagSpec, pValue); + QCBORDecode_Private_GetTaggedString(pMe, TagSpec, pValue); } -inline static void +static inline void QCBORDecode_GetTextStringInMapN(QCBORDecodeContext *pMe, - int64_t nLabel, + const int64_t nLabel, UsefulBufC *pText) { // This TagSpec only matches text strings; it also should optimize down // to passing a 64-bit integer - const TagSpecification TagSpec = + const QCBOR_Private_TagSpec TagSpec = { - QCBOR_TAG_REQUIREMENT_NOT_A_TAG, + QCBOR_TAG_REQUIREMENT_NOT_A_TAG | QCBOR_TAG_REQUIREMENT_ALLOW_ADDITIONAL_TAGS, {QCBOR_TYPE_TEXT_STRING, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}, {QCBOR_TYPE_TEXT_STRING, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE} }; - QCBORDecode_GetTaggedStringInMapN(pMe, nLabel, TagSpec, pText); + QCBORDecode_Private_GetTaggedStringInMapN(pMe, nLabel, TagSpec, pText); } -inline static void +static inline void QCBORDecode_GetTextStringInMapSZ(QCBORDecodeContext *pMe, const char *szLabel, UsefulBufC *pText) { - const TagSpecification TagSpec = + const QCBOR_Private_TagSpec TagSpec = { - QCBOR_TAG_REQUIREMENT_NOT_A_TAG, + QCBOR_TAG_REQUIREMENT_NOT_A_TAG | QCBOR_TAG_REQUIREMENT_ALLOW_ADDITIONAL_TAGS, {QCBOR_TYPE_TEXT_STRING, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}, {QCBOR_TYPE_TEXT_STRING, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE} }; - QCBORDecode_GetTaggedStringInMapSZ(pMe, szLabel, TagSpec, pText); + QCBORDecode_Private_GetTaggedStringInMapSZ(pMe, szLabel, TagSpec, pText); } static inline void @@ -2145,7 +2623,7 @@ QCBORDecode_GetNull(QCBORDecodeContext *pMe) static inline void QCBORDecode_GetNullInMapN(QCBORDecodeContext *pMe, - int64_t nLabel) + const int64_t nLabel) { QCBORItem Item; QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_NULL, &Item); @@ -2153,7 +2631,7 @@ QCBORDecode_GetNullInMapN(QCBORDecodeContext *pMe, static inline void QCBORDecode_GetNullInMapSZ(QCBORDecodeContext *pMe, - const char * szLabel) + const char *szLabel) { QCBORItem Item; QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_NULL, &Item); @@ -2172,7 +2650,7 @@ QCBORDecode_GetUndefined(QCBORDecodeContext *pMe) static inline void QCBORDecode_GetUndefinedInMapN(QCBORDecodeContext *pMe, - int64_t nLabel) + const int64_t nLabel) { QCBORItem Item; QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_UNDEF, &Item); @@ -2180,304 +2658,309 @@ QCBORDecode_GetUndefinedInMapN(QCBORDecodeContext *pMe, static inline void QCBORDecode_GetUndefinedInMapSZ(QCBORDecodeContext *pMe, - const char * szLabel) + const char *szLabel) { QCBORItem Item; QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_UNDEF, &Item); } + static inline void QCBORDecode_GetDateString(QCBORDecodeContext *pMe, - uint8_t uTagRequirement, + const uint8_t uTagRequirement, UsefulBufC *pValue) { - const TagSpecification TagSpec = + const QCBOR_Private_TagSpec TagSpec = { uTagRequirement, {QCBOR_TYPE_DATE_STRING, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}, {QCBOR_TYPE_TEXT_STRING, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE} }; - QCBORDecode_GetTaggedStringInternal(pMe, TagSpec, pValue); + QCBORDecode_Private_GetTaggedString(pMe, TagSpec, pValue); } -inline static void +static inline void QCBORDecode_GetDateStringInMapN(QCBORDecodeContext *pMe, - int64_t nLabel, - uint8_t uTagRequirement, + const int64_t nLabel, + const uint8_t uTagRequirement, UsefulBufC *pText) { - const TagSpecification TagSpec = + const QCBOR_Private_TagSpec TagSpec = { uTagRequirement, {QCBOR_TYPE_DATE_STRING, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}, {QCBOR_TYPE_TEXT_STRING, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE} }; - QCBORDecode_GetTaggedStringInMapN(pMe, nLabel, TagSpec, pText); + QCBORDecode_Private_GetTaggedStringInMapN(pMe, nLabel, TagSpec, pText); } -inline static void +static inline void QCBORDecode_GetDateStringInMapSZ(QCBORDecodeContext *pMe, const char *szLabel, - uint8_t uTagRequirement, + const uint8_t uTagRequirement, UsefulBufC *pText) { - const TagSpecification TagSpec = + const QCBOR_Private_TagSpec TagSpec = { uTagRequirement, {QCBOR_TYPE_DATE_STRING, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}, {QCBOR_TYPE_TEXT_STRING, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE} }; - QCBORDecode_GetTaggedStringInMapSZ(pMe, szLabel, TagSpec, pText); + QCBORDecode_Private_GetTaggedStringInMapSZ(pMe, szLabel, TagSpec, pText); } static inline void QCBORDecode_GetDaysString(QCBORDecodeContext *pMe, - uint8_t uTagRequirement, + const uint8_t uTagRequirement, UsefulBufC *pValue) { - const TagSpecification TagSpec = + const QCBOR_Private_TagSpec TagSpec = { uTagRequirement, {QCBOR_TYPE_DAYS_STRING, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}, {QCBOR_TYPE_TEXT_STRING, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE} }; - QCBORDecode_GetTaggedStringInternal(pMe, TagSpec, pValue); + QCBORDecode_Private_GetTaggedString(pMe, TagSpec, pValue); } -inline static void +static inline void QCBORDecode_GetDaysStringInMapN(QCBORDecodeContext *pMe, - int64_t nLabel, - uint8_t uTagRequirement, + const int64_t nLabel, + const uint8_t uTagRequirement, UsefulBufC *pText) { - const TagSpecification TagSpec = + const QCBOR_Private_TagSpec TagSpec = { uTagRequirement, {QCBOR_TYPE_DAYS_STRING, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}, {QCBOR_TYPE_TEXT_STRING, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE} }; - QCBORDecode_GetTaggedStringInMapN(pMe, nLabel, TagSpec, pText); + QCBORDecode_Private_GetTaggedStringInMapN(pMe, nLabel, TagSpec, pText); } -inline static void +static inline void QCBORDecode_GetDaysStringInMapSZ(QCBORDecodeContext *pMe, const char *szLabel, - uint8_t uTagRequirement, + const uint8_t uTagRequirement, UsefulBufC *pText) { - const TagSpecification TagSpec = + const QCBOR_Private_TagSpec TagSpec = { uTagRequirement, {QCBOR_TYPE_DAYS_STRING, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}, {QCBOR_TYPE_TEXT_STRING, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE} }; - QCBORDecode_GetTaggedStringInMapSZ(pMe, szLabel, TagSpec, pText); + QCBORDecode_Private_GetTaggedStringInMapSZ(pMe, szLabel, TagSpec, pText); } -static inline void QCBORDecode_GetURI(QCBORDecodeContext *pMe, - uint8_t uTagRequirement, - UsefulBufC *pUUID) +static inline void +QCBORDecode_GetURI(QCBORDecodeContext *pMe, + const uint8_t uTagRequirement, + UsefulBufC *pUUID) { - const TagSpecification TagSpec = + const QCBOR_Private_TagSpec TagSpec = { uTagRequirement, {QCBOR_TYPE_URI, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}, {QCBOR_TYPE_TEXT_STRING, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE} }; - QCBORDecode_GetTaggedStringInternal(pMe, TagSpec, pUUID); + QCBORDecode_Private_GetTaggedString(pMe, TagSpec, pUUID); } -inline static void +static inline void QCBORDecode_GetURIInMapN(QCBORDecodeContext *pMe, - int64_t nLabel, - uint8_t uTagRequirement, + const int64_t nLabel, + const uint8_t uTagRequirement, UsefulBufC *pUUID) { - const TagSpecification TagSpec = + const QCBOR_Private_TagSpec TagSpec = { uTagRequirement, {QCBOR_TYPE_URI, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}, {QCBOR_TYPE_TEXT_STRING, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE} }; - QCBORDecode_GetTaggedStringInMapN(pMe, nLabel, TagSpec, pUUID); + QCBORDecode_Private_GetTaggedStringInMapN(pMe, nLabel, TagSpec, pUUID); } -inline static void +static inline void QCBORDecode_GetURIInMapSZ(QCBORDecodeContext *pMe, const char *szLabel, - uint8_t uTagRequirement, + const uint8_t uTagRequirement, UsefulBufC *pUUID) { - const TagSpecification TagSpec = + const QCBOR_Private_TagSpec TagSpec = { uTagRequirement, {QCBOR_TYPE_URI, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}, {QCBOR_TYPE_TEXT_STRING, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE} }; - QCBORDecode_GetTaggedStringInMapSZ(pMe, szLabel, TagSpec, pUUID); + QCBORDecode_Private_GetTaggedStringInMapSZ(pMe, szLabel, TagSpec, pUUID); } -static inline void QCBORDecode_GetB64(QCBORDecodeContext *pMe, - uint8_t uTagRequirement, - UsefulBufC *pB64Text) +static inline void +QCBORDecode_GetB64(QCBORDecodeContext *pMe, + const uint8_t uTagRequirement, + UsefulBufC *pB64Text) { - const TagSpecification TagSpec = + const QCBOR_Private_TagSpec TagSpec = { uTagRequirement, {QCBOR_TYPE_BASE64, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}, {QCBOR_TYPE_TEXT_STRING, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE} }; - QCBORDecode_GetTaggedStringInternal(pMe, TagSpec, pB64Text); + QCBORDecode_Private_GetTaggedString(pMe, TagSpec, pB64Text); } -inline static void QCBORDecode_GetB64InMapN(QCBORDecodeContext *pMe, - int64_t nLabel, - uint8_t uTagRequirement, - UsefulBufC *pB64Text) +static inline void +QCBORDecode_GetB64InMapN(QCBORDecodeContext *pMe, + const int64_t nLabel, + const uint8_t uTagRequirement, + UsefulBufC *pB64Text) { - const TagSpecification TagSpec = + const QCBOR_Private_TagSpec TagSpec = { uTagRequirement, {QCBOR_TYPE_BASE64, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}, {QCBOR_TYPE_TEXT_STRING, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE} }; - QCBORDecode_GetTaggedStringInMapN(pMe, nLabel, TagSpec, pB64Text); + QCBORDecode_Private_GetTaggedStringInMapN(pMe, nLabel, TagSpec, pB64Text); } -inline static void +static inline void QCBORDecode_GetB64InMapSZ(QCBORDecodeContext *pMe, const char *szLabel, - uint8_t uTagRequirement, + const uint8_t uTagRequirement, UsefulBufC *pB64Text) { - const TagSpecification TagSpec = + const QCBOR_Private_TagSpec TagSpec = { uTagRequirement, {QCBOR_TYPE_BASE64, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}, {QCBOR_TYPE_TEXT_STRING, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE} }; - QCBORDecode_GetTaggedStringInMapSZ(pMe, szLabel, TagSpec, pB64Text); + QCBORDecode_Private_GetTaggedStringInMapSZ(pMe, szLabel, TagSpec, pB64Text); } static inline void QCBORDecode_GetB64URL(QCBORDecodeContext *pMe, - uint8_t uTagRequirement, + const uint8_t uTagRequirement, UsefulBufC *pB64Text) { - const TagSpecification TagSpec = + const QCBOR_Private_TagSpec TagSpec = { uTagRequirement, {QCBOR_TYPE_BASE64URL, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}, {QCBOR_TYPE_TEXT_STRING, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE} }; - QCBORDecode_GetTaggedStringInternal(pMe, TagSpec, pB64Text); + QCBORDecode_Private_GetTaggedString(pMe, TagSpec, pB64Text); } -inline static void +static inline void QCBORDecode_GetB64URLInMapN(QCBORDecodeContext *pMe, - int64_t nLabel, - uint8_t uTagRequirement, + const int64_t nLabel, + const uint8_t uTagRequirement, UsefulBufC *pB64Text) { - const TagSpecification TagSpec = + const QCBOR_Private_TagSpec TagSpec = { uTagRequirement, {QCBOR_TYPE_BASE64URL, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}, {QCBOR_TYPE_TEXT_STRING, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE} }; - QCBORDecode_GetTaggedStringInMapN(pMe, nLabel, TagSpec, pB64Text); + QCBORDecode_Private_GetTaggedStringInMapN(pMe, nLabel, TagSpec, pB64Text); } -inline static void +static inline void QCBORDecode_GetB64URLInMapSZ(QCBORDecodeContext *pMe, const char *szLabel, - uint8_t uTagRequirement, + const uint8_t uTagRequirement, UsefulBufC *pB64Text) { - const TagSpecification TagSpec = + const QCBOR_Private_TagSpec TagSpec = { uTagRequirement, {QCBOR_TYPE_BASE64URL, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}, {QCBOR_TYPE_TEXT_STRING, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE} }; - QCBORDecode_GetTaggedStringInMapSZ(pMe, szLabel, TagSpec, pB64Text); + QCBORDecode_Private_GetTaggedStringInMapSZ(pMe, szLabel, TagSpec, pB64Text); } -static inline void QCBORDecode_GetRegex(QCBORDecodeContext *pMe, - uint8_t uTagRequirement, - UsefulBufC *pRegex) +static inline void +QCBORDecode_GetRegex(QCBORDecodeContext *pMe, + const uint8_t uTagRequirement, + UsefulBufC *pRegex) { - const TagSpecification TagSpec = + const QCBOR_Private_TagSpec TagSpec = { uTagRequirement, {QCBOR_TYPE_REGEX, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}, {QCBOR_TYPE_TEXT_STRING, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE} }; - QCBORDecode_GetTaggedStringInternal(pMe, TagSpec, pRegex); + QCBORDecode_Private_GetTaggedString(pMe, TagSpec, pRegex); } static inline void QCBORDecode_GetRegexInMapN(QCBORDecodeContext *pMe, - int64_t nLabel, - uint8_t uTagRequirement, + const int64_t nLabel, + const uint8_t uTagRequirement, UsefulBufC *pRegex) { - const TagSpecification TagSpec = + const QCBOR_Private_TagSpec TagSpec = { uTagRequirement, {QCBOR_TYPE_REGEX, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}, {QCBOR_TYPE_TEXT_STRING, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE} }; - QCBORDecode_GetTaggedStringInMapN(pMe, nLabel, TagSpec, pRegex); + QCBORDecode_Private_GetTaggedStringInMapN(pMe, nLabel, TagSpec, pRegex); } static inline void QCBORDecode_GetRegexInMapSZ(QCBORDecodeContext *pMe, const char * szLabel, - uint8_t uTagRequirement, + const uint8_t uTagRequirement, UsefulBufC *pRegex) { - const TagSpecification TagSpec = + const QCBOR_Private_TagSpec TagSpec = { uTagRequirement, {QCBOR_TYPE_REGEX, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}, {QCBOR_TYPE_TEXT_STRING, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE} }; - QCBORDecode_GetTaggedStringInMapSZ(pMe, szLabel, TagSpec, pRegex); + QCBORDecode_Private_GetTaggedStringInMapSZ(pMe, szLabel, TagSpec, pRegex); } static inline void QCBORDecode_GetMIMEMessage(QCBORDecodeContext *pMe, - uint8_t uTagRequirement, + const uint8_t uTagRequirement, UsefulBufC *pMessage, bool *pbIsTag257) { if(pMe->uLastError != QCBOR_SUCCESS) { - // Already in error state, do nothing + /* Already in error state, do nothing */ return; } @@ -2488,7 +2971,7 @@ QCBORDecode_GetMIMEMessage(QCBORDecodeContext *pMe, return; } - pMe->uLastError = (uint8_t)QCBORDecode_GetMIMEInternal(uTagRequirement, + pMe->uLastError = (uint8_t)QCBORDecode_Private_GetMIME(uTagRequirement, &Item, pMessage, pbIsTag257); @@ -2496,8 +2979,8 @@ QCBORDecode_GetMIMEMessage(QCBORDecodeContext *pMe, static inline void QCBORDecode_GetMIMEMessageInMapN(QCBORDecodeContext *pMe, - int64_t nLabel, - uint8_t uTagRequirement, + const int64_t nLabel, + const uint8_t uTagRequirement, UsefulBufC *pMessage, bool *pbIsTag257) { @@ -2505,7 +2988,7 @@ QCBORDecode_GetMIMEMessageInMapN(QCBORDecodeContext *pMe, QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, &Item); if(pMe->uLastError == QCBOR_SUCCESS) { - pMe->uLastError = (uint8_t)QCBORDecode_GetMIMEInternal(uTagRequirement, + pMe->uLastError = (uint8_t)QCBORDecode_Private_GetMIME(uTagRequirement, &Item, pMessage, pbIsTag257); @@ -2515,7 +2998,7 @@ QCBORDecode_GetMIMEMessageInMapN(QCBORDecodeContext *pMe, static inline void QCBORDecode_GetMIMEMessageInMapSZ(QCBORDecodeContext *pMe, const char *szLabel, - uint8_t uTagRequirement, + const uint8_t uTagRequirement, UsefulBufC *pMessage, bool *pbIsTag257) { @@ -2523,7 +3006,7 @@ QCBORDecode_GetMIMEMessageInMapSZ(QCBORDecodeContext *pMe, QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item); if(pMe->uLastError == QCBOR_SUCCESS) { - pMe->uLastError = (uint8_t)QCBORDecode_GetMIMEInternal(uTagRequirement, + pMe->uLastError = (uint8_t)QCBORDecode_Private_GetMIME(uTagRequirement, &Item, pMessage, pbIsTag257); @@ -2533,51 +3016,54 @@ QCBORDecode_GetMIMEMessageInMapSZ(QCBORDecodeContext *pMe, static inline void QCBORDecode_GetBinaryUUID(QCBORDecodeContext *pMe, - uint8_t uTagRequirement, + const uint8_t uTagRequirement, UsefulBufC *pUUID) { - const TagSpecification TagSpec = + const QCBOR_Private_TagSpec TagSpec = { uTagRequirement, {QCBOR_TYPE_UUID, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}, {QCBOR_TYPE_BYTE_STRING, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE} }; - QCBORDecode_GetTaggedStringInternal(pMe, TagSpec, pUUID); + QCBORDecode_Private_GetTaggedString(pMe, TagSpec, pUUID); } -inline static void +static inline void QCBORDecode_GetBinaryUUIDInMapN(QCBORDecodeContext *pMe, - int64_t nLabel, - uint8_t uTagRequirement, + const int64_t nLabel, + const uint8_t uTagRequirement, UsefulBufC *pUUID) { - const TagSpecification TagSpec = + const QCBOR_Private_TagSpec TagSpec = { uTagRequirement, {QCBOR_TYPE_UUID, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}, {QCBOR_TYPE_BYTE_STRING, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE} }; - QCBORDecode_GetTaggedStringInMapN(pMe, nLabel, TagSpec, pUUID); + QCBORDecode_Private_GetTaggedStringInMapN(pMe, nLabel, TagSpec, pUUID); } -inline static void +static inline void QCBORDecode_GetBinaryUUIDInMapSZ(QCBORDecodeContext *pMe, const char *szLabel, - uint8_t uTagRequirement, + const uint8_t uTagRequirement, UsefulBufC *pUUID) { - const TagSpecification TagSpec = + const QCBOR_Private_TagSpec TagSpec = { uTagRequirement, {QCBOR_TYPE_UUID, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}, {QCBOR_TYPE_BYTE_STRING, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE} }; - QCBORDecode_GetTaggedStringInMapSZ(pMe, szLabel, TagSpec, pUUID); + QCBORDecode_Private_GetTaggedStringInMapSZ(pMe, szLabel, TagSpec, pUUID); } +/* ======================================================================== * + * END OF PRIVATE INLINE IMPLEMENTATION * + * ======================================================================== */ #ifdef __cplusplus } diff --git a/3rdparty/exported/QCBOR/src/UsefulBuf.c b/3rdparty/exported/QCBOR/src/UsefulBuf.c index b36e5d00d36d..4a7970f9e133 100644 --- a/3rdparty/exported/QCBOR/src/UsefulBuf.c +++ b/3rdparty/exported/QCBOR/src/UsefulBuf.c @@ -1,33 +1,36 @@ -/*============================================================================== - Copyright (c) 2016-2018, The Linux Foundation. - Copyright (c) 2018-2022, Laurence Lundblade. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following - disclaimer in the documentation and/or other materials provided - with the distribution. - * Neither the name of The Linux Foundation nor the names of its - contributors, nor the name "Laurence Lundblade" may be used to - endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED -WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT -ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS -BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR -BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, -WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE -OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN -IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - =============================================================================*/ +/* ========================================================================== + * Copyright (c) 2016-2018, The Linux Foundation. + * Copyright (c) 2018-2024, Laurence Lundblade. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * * Neither the name of The Linux Foundation nor the names of its + * contributors, nor the name "Laurence Lundblade" may be used to + * endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ========================================================================= */ + + /*============================================================================= FILE: UsefulBuf.c @@ -41,9 +44,11 @@ IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. when who what, where, why -------- ---- --------------------------------------------------- + 08/08/2024 llundblade Add UsefulOutBuf_SubString(). + 21/05/2024 llundblade Comment formatting and some code tidiness. 19/12/2022 llundblade Don't pass NULL to memmove when adding empty data. 4/11/2022 llundblade Add GetOutPlace and Advance to UsefulOutBuf - 3/6/2021 mcr/llundblade Fix warnings related to --Wcast-qual + 3/6/2021 mcr/llundblade Fix warnings related to --Wcast-qual 01/28/2020 llundblade Refine integer signedness to quiet static analysis. 01/08/2020 llundblade Documentation corrections & improved code formatting. 11/08/2019 llundblade Re check pointer math and update comments @@ -61,18 +66,20 @@ IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "UsefulBuf.h" -// used to catch use of uninitialized or corrupted UsefulOutBuf +/* used to catch use of uninitialized or corrupted UsefulOutBuf */ #define USEFUL_OUT_BUF_MAGIC (0x0B0F) /* - Public function -- see UsefulBuf.h + * Public function -- see UsefulBuf.h */ UsefulBufC UsefulBuf_CopyOffset(UsefulBuf Dest, size_t uOffset, const UsefulBufC Src) { - // Do this with subtraction so it doesn't give erroneous - // result if uOffset + Src.len overflows - if(uOffset > Dest.len || Src.len > Dest.len - uOffset) { // uOffset + Src.len > Dest.len + /* Do this with subtraction so it doesn't give an erroneous + * result if uOffset + Src.len overflows. Right side is equivalent to + * uOffset + Src.len > Dest.len + */ + if(uOffset > Dest.len || Src.len > Dest.len - uOffset) { return NULLUsefulBufC; } @@ -83,24 +90,25 @@ UsefulBufC UsefulBuf_CopyOffset(UsefulBuf Dest, size_t uOffset, const UsefulBufC /* - Public function -- see UsefulBuf.h + * Public function -- see UsefulBuf.h */ int UsefulBuf_Compare(const UsefulBufC UB1, const UsefulBufC UB2) { - // use the comparisons rather than subtracting lengths to - // return an int instead of a size_t + /* Use comparisons rather than subtracting lengths to + * return an int instead of a size_t + */ if(UB1.len < UB2.len) { return -1; } else if (UB1.len > UB2.len) { return 1; - } // else UB1.len == UB2.len + } /* else UB1.len == UB2.len */ return memcmp(UB1.ptr, UB2.ptr, UB1.len); } /* - Public function -- see UsefulBuf.h + * Public function -- see UsefulBuf.h */ size_t UsefulBuf_IsValue(const UsefulBufC UB, uint8_t uValue) { @@ -113,7 +121,7 @@ size_t UsefulBuf_IsValue(const UsefulBufC UB, uint8_t uValue) for(const uint8_t *p = UB.ptr; p < pEnd; p++) { if(*p != uValue) { /* Byte didn't match */ - /* Cast from signed to unsigned . Safe because the loop increments.*/ + /* Cast from signed to unsigned. Safe because the loop increments.*/ return (size_t)(p - (const uint8_t *)UB.ptr); } } @@ -124,7 +132,7 @@ size_t UsefulBuf_IsValue(const UsefulBufC UB, uint8_t uValue) /* - Public function -- see UsefulBuf.h + * Public function -- see UsefulBuf.h */ size_t UsefulBuf_FindBytes(UsefulBufC BytesToSearch, UsefulBufC BytesToFind) { @@ -133,7 +141,11 @@ size_t UsefulBuf_FindBytes(UsefulBufC BytesToSearch, UsefulBufC BytesToFind) } for(size_t uPos = 0; uPos <= BytesToSearch.len - BytesToFind.len; uPos++) { - if(!UsefulBuf_Compare((UsefulBufC){((const uint8_t *)BytesToSearch.ptr) + uPos, BytesToFind.len}, BytesToFind)) { + UsefulBufC SearchNext; + + SearchNext.ptr = ((const uint8_t *)BytesToSearch.ptr) + uPos; + SearchNext.len = BytesToFind.len; + if(!UsefulBuf_Compare(SearchNext, BytesToFind)) { return uPos; } } @@ -143,9 +155,9 @@ size_t UsefulBuf_FindBytes(UsefulBufC BytesToSearch, UsefulBufC BytesToFind) /* - Public function -- see UsefulBuf.h - - Code Reviewers: THIS FUNCTION DOES POINTER MATH + * Public function -- see UsefulBuf.h + * + * Code Reviewers: THIS FUNCTION DOES POINTER MATH */ void UsefulOutBuf_Init(UsefulOutBuf *pMe, UsefulBuf Storage) { @@ -154,17 +166,18 @@ void UsefulOutBuf_Init(UsefulOutBuf *pMe, UsefulBuf Storage) pMe->UB = Storage; #if 0 - // This check is off by default. - - // The following check fails on ThreadX - - // Sanity check on the pointer and size to be sure we are not - // passed a buffer that goes off the end of the address space. - // Given this test, we know that all unsigned lengths less than - // me->size are valid and won't wrap in any pointer additions - // based off of pStorage in the rest of this code. + /* This check is off by default. + * + * The following check fails on ThreadX + * + * Sanity check on the pointer and size to be sure we are not + * passed a buffer that goes off the end of the address space. + * Given this test, we know that all unsigned lengths less than + * me->size are valid and won't wrap in any pointer additions + * based off of pStorage in the rest of this code. + */ const uintptr_t ptrM = UINTPTR_MAX - Storage.len; - if(Storage.ptr && (uintptr_t)Storage.ptr > ptrM) // Check #0 + if(Storage.ptr && (uintptr_t)Storage.ptr > ptrM) /* Check #0 */ me->err = 1; #endif } @@ -172,101 +185,107 @@ void UsefulOutBuf_Init(UsefulOutBuf *pMe, UsefulBuf Storage) /* - Public function -- see UsefulBuf.h - - The core of UsefulOutBuf -- put some bytes in the buffer without writing off - the end of it. - - Code Reviewers: THIS FUNCTION DOES POINTER MATH - - This function inserts the source buffer, NewData, into the destination - buffer, me->UB.ptr. - - Destination is represented as: - me->UB.ptr -- start of the buffer - me->UB.len -- size of the buffer UB.ptr - me->data_len -- length of value data in UB - - Source is data: - NewData.ptr -- start of source buffer - NewData.len -- length of source buffer - - Insertion point: - uInsertionPos. - - Steps: - - 0. Corruption checks on UsefulOutBuf - - 1. Figure out if the new data will fit or not - - 2. Is insertion position in the range of valid data? - - 3. If insertion point is not at the end, slide data to the right of the - insertion point to the right - - 4. Put the new data in at the insertion position. - + * Public function -- see UsefulBuf.h + * + * The core of UsefulOutBuf -- put some bytes in the buffer without writing off + * the end of it. + * + * Code Reviewers: THIS FUNCTION DOES POINTER MATH + * + * This function inserts the source buffer, NewData, into the destination + * buffer, me->UB.ptr. + * + * Destination is represented as: + * me->UB.ptr -- start of the buffer + * me->UB.len -- size of the buffer UB.ptr + * me->data_len -- length of value data in UB + * + * Source is data: + * NewData.ptr -- start of source buffer + * NewData.len -- length of source buffer + * + * Insertion point: + * uInsertionPos. + * + * Steps: + * + * 0. Corruption checks on UsefulOutBuf + * + * 1. Figure out if the new data will fit or not + * + * 2. Is insertion position in the range of valid data? + * + * 3. If insertion point is not at the end, slide data to the right of the + * insertion point to the right + * + * 4. Put the new data in at the insertion position. + * */ void UsefulOutBuf_InsertUsefulBuf(UsefulOutBuf *pMe, UsefulBufC NewData, size_t uInsertionPos) { if(pMe->err) { - // Already in error state. + /* Already in error state. */ return; } - /* 0. Sanity check the UsefulOutBuf structure */ - // A "counter measure". If magic number is not the right number it - // probably means me was not initialized or it was corrupted. Attackers - // can defeat this, but it is a hurdle and does good with very - // little code. + /* 0. Sanity check the UsefulOutBuf structure + * A "counter measure". If magic number is not the right number it + * probably means pMe was not initialized or it was corrupted. Attackers + * can defeat this, but it is a hurdle and does good with very + * little code. + */ if(pMe->magic != USEFUL_OUT_BUF_MAGIC) { pMe->err = 1; - return; // Magic number is wrong due to uninitalization or corrption + return; /* Magic number is wrong due to uninitalization or corrption */ } - // Make sure valid data is less than buffer size. This would only occur - // if there was corruption of me, but it is also part of the checks to - // be sure there is no pointer arithmatic under/overflow. - if(pMe->data_len > pMe->UB.len) { // Check #1 + /* Make sure valid data is less than buffer size. This would only occur + * if there was corruption of me, but it is also part of the checks to + * be sure there is no pointer arithmatic under/overflow. + */ + if(pMe->data_len > pMe->UB.len) { /* Check #1 */ pMe->err = 1; - // Offset of valid data is off the end of the UsefulOutBuf due to - // uninitialization or corruption + /* Offset of valid data is off the end of the UsefulOutBuf due to + * uninitialization or corruption + */ return; } - /* 1. Will it fit? */ - // WillItFit() is the same as: NewData.len <= (me->UB.len - me->data_len) - // Check #1 makes sure subtraction in RoomLeft will not wrap around - if(! UsefulOutBuf_WillItFit(pMe, NewData.len)) { // Check #2 - // The new data will not fit into the the buffer. + /* 1. Will it fit? + * WillItFit() is the same as: NewData.len <= (me->UB.len - me->data_len) + * Check #1 makes sure subtraction in RoomLeft will not wrap around + */ + if(! UsefulOutBuf_WillItFit(pMe, NewData.len)) { /* Check #2 */ + /* The new data will not fit into the the buffer. */ pMe->err = 1; return; } - /* 2. Check the Insertion Position */ - // This, with Check #1, also confirms that uInsertionPos <= me->data_len and - // that uInsertionPos + pMe->UB.ptr will not wrap around the end of the - // address space. - if(uInsertionPos > pMe->data_len) { // Check #3 - // Off the end of the valid data in the buffer. + /* 2. Check the Insertion Position + * This, with Check #1, also confirms that uInsertionPos <= me->data_len and + * that uInsertionPos + pMe->UB.ptr will not wrap around the end of the + * address space. + */ + if(uInsertionPos > pMe->data_len) { /* Check #3 */ + /* Off the end of the valid data in the buffer. */ pMe->err = 1; return; } /* 3. Slide existing data to the right */ if (!UsefulOutBuf_IsBufferNULL(pMe)) { - uint8_t *pSourceOfMove = ((uint8_t *)pMe->UB.ptr) + uInsertionPos; // PtrMath #1 - size_t uNumBytesToMove = pMe->data_len - uInsertionPos; // PtrMath #2 - uint8_t *pDestinationOfMove = pSourceOfMove + NewData.len; // PtrMath #3 + uint8_t *pSourceOfMove = ((uint8_t *)pMe->UB.ptr) + uInsertionPos; /* PtrMath #1 */ + size_t uNumBytesToMove = pMe->data_len - uInsertionPos; /* PtrMath #2 */ + uint8_t *pDestinationOfMove = pSourceOfMove + NewData.len; /* PtrMath #3*/ - // To know memmove won't go off end of destination, see PtrMath #4 - // Use memove because it handles overlapping buffers + /* To know memmove won't go off end of destination, see PtrMath #4. + * Use memove because it handles overlapping buffers + */ memmove(pDestinationOfMove, pSourceOfMove, uNumBytesToMove); /* 4. Put the new data in */ uint8_t *pInsertionPoint = pSourceOfMove; - // To know memmove won't go off end of destination, see PtrMath #5 + /* To know memmove won't go off end of destination, see PtrMath #5 */ if(NewData.ptr != NULL) { memmove(pInsertionPoint, NewData.ptr, NewData.len); } @@ -277,30 +296,30 @@ void UsefulOutBuf_InsertUsefulBuf(UsefulOutBuf *pMe, UsefulBufC NewData, size_t /* - Rationale that describes why the above pointer math is safe - - PtrMath #1 will never wrap around over because - Check #0 in UsefulOutBuf_Init makes sure me->UB.ptr + me->UB.len doesn't wrap - Check #1 makes sure me->data_len is less than me->UB.len - Check #3 makes sure uInsertionPos is less than me->data_len - - PtrMath #2 will never wrap around under because - Check #3 makes sure uInsertionPos is less than me->data_len - - PtrMath #3 will never wrap around over because - PtrMath #1 is checked resulting in pSourceOfMove being between me->UB.ptr and me->UB.ptr + me->data_len - Check #2 that NewData.len will fit in the unused space left in me->UB - - PtrMath #4 will never wrap under because - Calculation for extent or memmove is uRoomInDestination = me->UB.len - (uInsertionPos + NewData.len) - Check #3 makes sure uInsertionPos is less than me->data_len - Check #3 allows Check #2 to be refactored as NewData.Len > (me->size - uInsertionPos) - This algebraically rearranges to me->size > uInsertionPos + NewData.len - - PtrMath #5 will never wrap under because - Calculation for extent of memove is uRoomInDestination = me->UB.len - uInsertionPos; - Check #1 makes sure me->data_len is less than me->size - Check #3 makes sure uInsertionPos is less than me->data_len + * Rationale that describes why the above pointer math is safe + * + * PtrMath #1 will never wrap around over because + * Check #0 in UsefulOutBuf_Init that me->UB.ptr + me->UB.len doesn't wrap + * Check #1 makes sure me->data_len is less than me->UB.len + * Check #3 makes sure uInsertionPos is less than me->data_len + * + * PtrMath #2 will never wrap around under because + * Check #3 makes sure uInsertionPos is less than me->data_len + * + * PtrMath #3 will never wrap around over because + * PtrMath #1 is checked resulting in pSourceOfMove being between me->UB.ptr and me->UB.ptr + me->data_len + * Check #2 that NewData.len will fit in the unused space left in me->UB + * + * PtrMath #4 will never wrap under because + * Calculation for extent or memmove is uRoomInDestination = me->UB.len - (uInsertionPos + NewData.len) + * Check #3 makes sure uInsertionPos is less than me->data_len + * Check #3 allows Check #2 to be refactored as NewData.Len > (me->size - uInsertionPos) + * This algebraically rearranges to me->size > uInsertionPos + NewData.len + * + * PtrMath #5 will never wrap under because + * Calculation for extent of memove is uRoomInDestination = me->UB.len - uInsertionPos; + * Check #1 makes sure me->data_len is less than me->size + * Check #3 makes sure uInsertionPos is less than me->data_len */ @@ -338,7 +357,7 @@ void UsefulOutBuf_Advance(UsefulOutBuf *pMe, size_t uAmount) * checks to be sure there is no pointer arithmatic * under/overflow. */ - if(pMe->data_len > pMe->UB.len) { // Check #1 + if(pMe->data_len > pMe->UB.len) { /* Check #1 */ pMe->err = 1; /* Offset of valid data is off the end of the UsefulOutBuf due * to uninitialization or corruption. @@ -363,7 +382,7 @@ void UsefulOutBuf_Advance(UsefulOutBuf *pMe, size_t uAmount) /* - Public function -- see UsefulBuf.h + * Public function -- see UsefulBuf.h */ UsefulBufC UsefulOutBuf_OutUBuf(UsefulOutBuf *pMe) { @@ -381,9 +400,9 @@ UsefulBufC UsefulOutBuf_OutUBuf(UsefulOutBuf *pMe) /* - Public function -- see UsefulBuf.h - - Copy out the data accumulated in to the output buffer. + * Public function -- see UsefulBuf.h + * + * Copy out the data accumulated in to the output buffer. */ UsefulBufC UsefulOutBuf_CopyOut(UsefulOutBuf *pMe, UsefulBuf pDest) { @@ -395,32 +414,60 @@ UsefulBufC UsefulOutBuf_CopyOut(UsefulOutBuf *pMe, UsefulBuf pDest) } +/* + * Public function -- see UsefulBuf.h + * + * Code Reviewers: THIS FUNCTION DOES POINTER MATH + */ +UsefulBufC UsefulOutBuf_SubString(UsefulOutBuf *pMe, + const size_t uStart, + const size_t uLen) +{ + const UsefulBufC Tmp = UsefulOutBuf_OutUBuf(pMe); + if(UsefulBuf_IsNULLC(Tmp)) { + return NULLUsefulBufC; + } -/* - Public function -- see UsefulBuf.h + if(uStart > Tmp.len) { + return NULLUsefulBufC; + } - The core of UsefulInputBuf -- consume bytes without going off end of buffer. + if(Tmp.len - uStart < uLen) { + return NULLUsefulBufC; + } - Code Reviewers: THIS FUNCTION DOES POINTER MATH + UsefulBufC SubString; + SubString.ptr = (const uint8_t *)Tmp.ptr + uStart; + SubString.len = uLen; + + return SubString; +} + + +/* + * Public function -- see UsefulBuf.h + * + * The core of UsefulInputBuf -- consume bytes without going off end of buffer. + * + * Code Reviewers: THIS FUNCTION DOES POINTER MATH */ const void * UsefulInputBuf_GetBytes(UsefulInputBuf *pMe, size_t uAmount) { - // Already in error state. Do nothing. + /* Already in error state. Do nothing. */ if(pMe->err) { return NULL; } if(!UsefulInputBuf_BytesAvailable(pMe, uAmount)) { - // Number of bytes asked for at current position are more than available + /* Number of bytes asked for is more than available */ pMe->err = 1; return NULL; } - // This is going to succeed + /* This is going to succeed */ const void * const result = ((const uint8_t *)pMe->UB.ptr) + pMe->cursor; - // Will not overflow because of check using UsefulInputBuf_BytesAvailable() + /* Won't overflow because of check using UsefulInputBuf_BytesAvailable() */ pMe->cursor += uAmount; return result; } - diff --git a/3rdparty/exported/QCBOR/src/ieee754.c b/3rdparty/exported/QCBOR/src/ieee754.c index a8079f8cff0c..17443680c1e2 100644 --- a/3rdparty/exported/QCBOR/src/ieee754.c +++ b/3rdparty/exported/QCBOR/src/ieee754.c @@ -1,71 +1,63 @@ -/*============================================================================== - ieee754.c -- floating-point conversion between half, double & single-precision - - Copyright (c) 2018-2020, Laurence Lundblade. All rights reserved. - Copyright (c) 2021, Arm Limited. All rights reserved. - - SPDX-License-Identifier: BSD-3-Clause - - See BSD-3-Clause license in README.md - - Created on 7/23/18 - =============================================================================*/ +/* ========================================================================== + * ieee754.c -- floating-point conversion between half, double & single-precision + * + * Copyright (c) 2018-2024, Laurence Lundblade. All rights reserved. + * Copyright (c) 2021, Arm Limited. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + * + * See BSD-3-Clause license in file named "LICENSE" + * + * Created on 7/23/18 + * ========================================================================== */ /* - Include before QCBOR_DISABLE_PREFERRED_FLOAT is checked as - QCBOR_DISABLE_PREFERRED_FLOAT might be defined in qcbor/qcbor_common.h + * Include before QCBOR_DISABLE_PREFERRED_FLOAT is checked as + * QCBOR_DISABLE_PREFERRED_FLOAT might be defined in qcbor/qcbor_common.h */ #include "qcbor/qcbor_common.h" #ifndef QCBOR_DISABLE_PREFERRED_FLOAT #include "ieee754.h" -#include // For memcpy() +#include /* For memcpy() */ /* - This code is written for clarity and verifiability, not for size, on - the assumption that the optimizer will do a good job. The LLVM - optimizer, -Os, does seem to do the job and the resulting object code - is smaller from combining code for the many different cases (normal, - subnormal, infinity, zero...) for the conversions. GCC is no where near - as good. - - This code has really long lines and is much easier to read because of - them. Some coding guidelines prefer 80 column lines (can they not afford - big displays?). It would make this code much worse even to wrap at 120 - columns. - - Dead stripping is also really helpful to get code size down when - floating-point encoding is not needed. (If this is put in a library - and linking is against the library, then dead stripping is automatic). - - This code works solely using shifts and masks and thus has no - dependency on any math libraries. It can even work if the CPU doesn't - have any floating-point support, though that isn't the most useful - thing to do. - - The memcpy() dependency is only for CopyFloatToUint32() and friends - which only is needed to avoid type punning when converting the actual - float bits to an unsigned value so the bit shifts and masks can work. + * This code has long lines and is easier to read because of + * them. Some coding guidelines prefer 80 column lines (can they not + * afford big displays?). + * + * This code works solely using shifts and masks and thus has no + * dependency on any math libraries. It can even work if the CPU + * doesn't have any floating-point support, though that isn't the most + * useful thing to do. + * + * The memcpy() dependency is only for CopyFloatToUint32() and friends + * which only is needed to avoid type punning when converting the + * actual float bits to an unsigned value so the bit shifts and masks + * can work. + * + * The references used to write this code: + * + * IEEE 754-2008, particularly section 3.6 and 6.2.1 + * + * https://en.wikipedia.org/wiki/IEEE_754 and subordinate pages + * + * https://stackoverflow.com/questions/19800415/why-does-ieee-754-reserve-so-many-nan-values + * + * https://stackoverflow.com/questions/46073295/implicit-type-promotion-rules + * + * https://stackoverflow.com/questions/589575/what-does-the-c-standard-state-the-size-of-int-long-type-to-be + * + * IEEE754_FloatToDouble(uint32_t uFloat) was created but is not + * needed. It can be retrieved from github history if needed. */ -/* - The references used to write this code: - - - IEEE 754-2008, particularly section 3.6 and 6.2.1 - - - https://en.wikipedia.org/wiki/IEEE_754 and subordinate pages - - - https://stackoverflow.com/questions/19800415/why-does-ieee-754-reserve-so-many-nan-values - - https://stackoverflow.com/questions/46073295/implicit-type-promotion-rules - - - https://stackoverflow.com/questions/589575/what-does-the-c-standard-state-the-size-of-int-long-type-to-be - */ -// ----- Half Precsion ----------- +/* ----- Half Precsion ----------- */ #define HALF_NUM_SIGNIFICAND_BITS (10) #define HALF_NUM_EXPONENT_BITS (5) #define HALF_NUM_SIGN_BITS (1) @@ -74,16 +66,16 @@ #define HALF_EXPONENT_SHIFT (HALF_NUM_SIGNIFICAND_BITS) #define HALF_SIGN_SHIFT (HALF_NUM_SIGNIFICAND_BITS + HALF_NUM_EXPONENT_BITS) -#define HALF_SIGNIFICAND_MASK (0x3ffU) // The lower 10 bits // 0x03ff +#define HALF_SIGNIFICAND_MASK (0x3ffU) // The lower 10 bits #define HALF_EXPONENT_MASK (0x1fU << HALF_EXPONENT_SHIFT) // 0x7c00 5 bits of exponent -#define HALF_SIGN_MASK (0x01U << HALF_SIGN_SHIFT) // // 0x8000 1 bit of sign +#define HALF_SIGN_MASK (0x01U << HALF_SIGN_SHIFT) // 0x8000 1 bit of sign #define HALF_QUIET_NAN_BIT (0x01U << (HALF_NUM_SIGNIFICAND_BITS-1)) // 0x0200 /* Biased Biased Unbiased Use - 0x00 0 -15 0 and subnormal - 0x01 1 -14 Smallest normal exponent - 0x1e 30 15 Largest normal exponent - 0x1F 31 16 NaN and Infinity */ + * 0x00 0 -15 0 and subnormal + * 0x01 1 -14 Smallest normal exponent + * 0x1e 30 15 Largest normal exponent + * 0x1F 31 16 NaN and Infinity */ #define HALF_EXPONENT_BIAS (15) #define HALF_EXPONENT_MAX (HALF_EXPONENT_BIAS) // 15 Unbiased #define HALF_EXPONENT_MIN (-HALF_EXPONENT_BIAS+1) // -14 Unbiased @@ -91,7 +83,7 @@ #define HALF_EXPONENT_INF_OR_NAN (HALF_EXPONENT_BIAS+1) // 16 Unbiased -// ------ Single-Precision -------- +/* ------ Single-Precision -------- */ #define SINGLE_NUM_SIGNIFICAND_BITS (23) #define SINGLE_NUM_EXPONENT_BITS (8) #define SINGLE_NUM_SIGN_BITS (1) @@ -106,19 +98,19 @@ #define SINGLE_QUIET_NAN_BIT (0x01U << (SINGLE_NUM_SIGNIFICAND_BITS-1)) /* Biased Biased Unbiased Use - 0x0000 0 -127 0 and subnormal - 0x0001 1 -126 Smallest normal exponent - 0x7f 127 0 1 - 0xfe 254 127 Largest normal exponent - 0xff 255 128 NaN and Infinity */ + * 0x0000 0 -127 0 and subnormal + * 0x0001 1 -126 Smallest normal exponent + * 0x7f 127 0 1 + * 0xfe 254 127 Largest normal exponent + * 0xff 255 128 NaN and Infinity */ #define SINGLE_EXPONENT_BIAS (127) -#define SINGLE_EXPONENT_MAX (SINGLE_EXPONENT_BIAS) // 127 unbiased -#define SINGLE_EXPONENT_MIN (-SINGLE_EXPONENT_BIAS+1) // -126 unbiased -#define SINGLE_EXPONENT_ZERO (-SINGLE_EXPONENT_BIAS) // -127 unbiased -#define SINGLE_EXPONENT_INF_OR_NAN (SINGLE_EXPONENT_BIAS+1) // 128 unbiased +#define SINGLE_EXPONENT_MAX (SINGLE_EXPONENT_BIAS) +#define SINGLE_EXPONENT_MIN (-SINGLE_EXPONENT_BIAS+1) +#define SINGLE_EXPONENT_ZERO (-SINGLE_EXPONENT_BIAS) +#define SINGLE_EXPONENT_INF_OR_NAN (SINGLE_EXPONENT_BIAS+1) -// --------- Double-Precision ---------- +/* --------- Double-Precision ---------- */ #define DOUBLE_NUM_SIGNIFICAND_BITS (52) #define DOUBLE_NUM_EXPONENT_BITS (11) #define DOUBLE_NUM_SIGN_BITS (1) @@ -134,372 +126,518 @@ /* Biased Biased Unbiased Use - 0x00000000 0 -1023 0 and subnormal - 0x00000001 1 -1022 Smallest normal exponent - 0x000007fe 2046 1023 Largest normal exponent - 0x000007ff 2047 1024 NaN and Infinity */ + * 0x00000000 0 -1023 0 and subnormal + * 0x00000001 1 -1022 Smallest normal exponent + * 0x000007fe 2046 1023 Largest normal exponent + * 0x000007ff 2047 1024 NaN and Infinity */ #define DOUBLE_EXPONENT_BIAS (1023) -#define DOUBLE_EXPONENT_MAX (DOUBLE_EXPONENT_BIAS) // unbiased -#define DOUBLE_EXPONENT_MIN (-DOUBLE_EXPONENT_BIAS+1) // unbiased -#define DOUBLE_EXPONENT_ZERO (-DOUBLE_EXPONENT_BIAS) // unbiased -#define DOUBLE_EXPONENT_INF_OR_NAN (DOUBLE_EXPONENT_BIAS+1) // unbiased +#define DOUBLE_EXPONENT_MAX (DOUBLE_EXPONENT_BIAS) +#define DOUBLE_EXPONENT_MIN (-DOUBLE_EXPONENT_BIAS+1) +#define DOUBLE_EXPONENT_ZERO (-DOUBLE_EXPONENT_BIAS) +#define DOUBLE_EXPONENT_INF_OR_NAN (DOUBLE_EXPONENT_BIAS+1) -/* - Convenient functions to avoid type punning, compiler warnings and - such. The optimizer reduces them to a simple assignment. This is a - crusty corner of C. It shouldn't be this hard. - These are also in UsefulBuf.h under a different name. They are copied - here to avoid a dependency on UsefulBuf.h. There is no object code - size impact because these always optimze down to a simple assignment. +/* + * Convenient functions to avoid type punning, compiler warnings and + * such. The optimizer reduces them to a simple assignment. This is a + * crusty corner of C. It shouldn't be this hard. + * + * These are also in UsefulBuf.h under a different name. They are copied + * here to avoid a dependency on UsefulBuf.h. There is no object code + * size impact because these always optimze down to a simple assignment. */ -static inline uint32_t CopyFloatToUint32(float f) +static inline uint32_t +CopyFloatToUint32(float f) { - uint32_t u32; - memcpy(&u32, &f, sizeof(uint32_t)); - return u32; + uint32_t u32; + memcpy(&u32, &f, sizeof(uint32_t)); + return u32; } -static inline uint64_t CopyDoubleToUint64(double d) +static inline uint64_t +CopyDoubleToUint64(double d) { - uint64_t u64; - memcpy(&u64, &d, sizeof(uint64_t)); - return u64; + uint64_t u64; + memcpy(&u64, &d, sizeof(uint64_t)); + return u64; } -static inline double CopyUint64ToDouble(uint64_t u64) +static inline double +CopyUint64ToDouble(uint64_t u64) { - double d; - memcpy(&d, &u64, sizeof(uint64_t)); - return d; + double d; + memcpy(&d, &u64, sizeof(uint64_t)); + return d; } - -// Public function; see ieee754.h -uint16_t IEEE754_FloatToHalf(float f) +static inline float +CopyUint32ToSingle(uint32_t u32) { - // Pull the three parts out of the single-precision float - const uint32_t uSingle = CopyFloatToUint32(f); - const int32_t nSingleUnbiasedExponent = (int32_t)((uSingle & SINGLE_EXPONENT_MASK) >> SINGLE_EXPONENT_SHIFT) - SINGLE_EXPONENT_BIAS; - const uint32_t uSingleSign = (uSingle & SINGLE_SIGN_MASK) >> SINGLE_SIGN_SHIFT; - const uint32_t uSingleSignificand = uSingle & SINGLE_SIGNIFICAND_MASK; - - - // Now convert the three parts to half-precision. - - // All works is done on uint32_t with conversion to uint16_t at - // the end. This avoids integer promotions that static analyzers - // complain about and reduces code size. - uint32_t uHalfSign, uHalfSignificand, uHalfBiasedExponent; - - if(nSingleUnbiasedExponent == SINGLE_EXPONENT_INF_OR_NAN) { - // +/- Infinity and NaNs -- single biased exponent is 0xff - uHalfBiasedExponent = HALF_EXPONENT_INF_OR_NAN + HALF_EXPONENT_BIAS; - if(!uSingleSignificand) { - // Infinity - uHalfSignificand = 0; - } else { - // Copy the LSBs of the NaN payload that will fit from the - // single to the half - uHalfSignificand = uSingleSignificand & (HALF_SIGNIFICAND_MASK & ~HALF_QUIET_NAN_BIT); - if(uSingleSignificand & SINGLE_QUIET_NAN_BIT) { - // It's a qNaN; copy the qNaN bit - uHalfSignificand |= HALF_QUIET_NAN_BIT; - } else { - // It's an sNaN; make sure the significand is not zero - // so it stays a NaN This is needed because not all - // significand bits are copied from single - if(!uHalfSignificand) { - // Set the LSB. This is what wikipedia shows for - // sNAN. - uHalfSignificand |= 0x01; - } - } - } - } else if(nSingleUnbiasedExponent == SINGLE_EXPONENT_ZERO) { - // 0 or a subnormal number -- singled biased exponent is 0 - uHalfBiasedExponent = 0; - uHalfSignificand = 0; // Any subnormal single will be too small to express as a half precision - } else if(nSingleUnbiasedExponent > HALF_EXPONENT_MAX) { - // Exponent is too large to express in half-precision; round - // up to infinity - uHalfBiasedExponent = HALF_EXPONENT_INF_OR_NAN + HALF_EXPONENT_BIAS; - uHalfSignificand = 0; - } else if(nSingleUnbiasedExponent < HALF_EXPONENT_MIN) { - // Exponent is too small to express in half-precision normal; - // make it a half-precision subnormal - uHalfBiasedExponent = HALF_EXPONENT_ZERO + HALF_EXPONENT_BIAS; - uHalfSignificand = 0; - // Could convert some of these values to a half-precision - // subnormal, but the layer above this will never use it. See - // layer above. There is code to do this in github history - // for this file, but it was removed because it was never - // invoked. - } else { - // The normal case, exponent is in range for half-precision - uHalfBiasedExponent = (uint32_t)(nSingleUnbiasedExponent + HALF_EXPONENT_BIAS); - uHalfSignificand = uSingleSignificand >> (SINGLE_NUM_SIGNIFICAND_BITS - HALF_NUM_SIGNIFICAND_BITS); - } - uHalfSign = uSingleSign; - - // Put the 3 values in the right place for a half precision - const uint32_t uHalfPrecision = uHalfSignificand | - (uHalfBiasedExponent << HALF_EXPONENT_SHIFT) | - (uHalfSign << HALF_SIGN_SHIFT); - // Cast is safe because all the masks and shifts above work to - // make a half precision value which is only 16 bits. - return (uint16_t)uHalfPrecision; + float f; + memcpy(&f, &u32, sizeof(uint32_t)); + return f; } -// Public function; see ieee754.h -uint16_t IEEE754_DoubleToHalf(double d) + + +/** + * @brief Assemble sign, significand and exponent into single precision float. + * + * @param[in] uDoubleSign 0 if positive, 1 if negative + * @pararm[in] uDoubleSignificand Bits of the significand + * @param[in] nDoubleUnBiasedExponent Exponent + * + * This returns the bits for a single-precision float, a binary64 + * as specified in IEEE754. + */ +static double +IEEE754_AssembleDouble(uint64_t uDoubleSign, + uint64_t uDoubleSignificand, + int64_t nDoubleUnBiasedExponent) { - // Pull the three parts out of the double-precision float - const uint64_t uDouble = CopyDoubleToUint64(d); - const int64_t nDoubleUnbiasedExponent = (int64_t)((uDouble & DOUBLE_EXPONENT_MASK) >> DOUBLE_EXPONENT_SHIFT) - DOUBLE_EXPONENT_BIAS; - const uint64_t uDoubleSign = (uDouble & DOUBLE_SIGN_MASK) >> DOUBLE_SIGN_SHIFT; - const uint64_t uDoubleSignificand = uDouble & DOUBLE_SIGNIFICAND_MASK; - - // Now convert the three parts to half-precision. - - // All works is done on uint64_t with conversion to uint16_t at - // the end. This avoids integer promotions that static analyzers - // complain about. Other options are for these to be unsigned int - // or fast_int16_t. Code size doesn't vary much between all these - // options for 64-bit LLVM, 64-bit GCC and 32-bit Armv7 LLVM. - uint64_t uHalfSign, uHalfSignificand, uHalfBiasedExponent; - - if(nDoubleUnbiasedExponent == DOUBLE_EXPONENT_INF_OR_NAN) { - // +/- Infinity and NaNs -- single biased exponent is 0xff - uHalfBiasedExponent = HALF_EXPONENT_INF_OR_NAN + HALF_EXPONENT_BIAS; - if(!uDoubleSignificand) { - // Infinity - uHalfSignificand = 0; - } else { - // Copy the LSBs of the NaN payload that will fit from the - // double to the half - uHalfSignificand = uDoubleSignificand & (HALF_SIGNIFICAND_MASK & ~HALF_QUIET_NAN_BIT); - if(uDoubleSignificand & DOUBLE_QUIET_NAN_BIT) { - // It's a qNaN; copy the qNaN bit - uHalfSignificand |= HALF_QUIET_NAN_BIT; - } else { - // It's an sNaN; make sure the significand is not zero - // so it stays a NaN This is needed because not all - // significand bits are copied from single - if(!uHalfSignificand) { - // Set the LSB. This is what wikipedia shows for - // sNAN. - uHalfSignificand |= 0x01; - } - } - } - } else if(nDoubleUnbiasedExponent == DOUBLE_EXPONENT_ZERO) { - // 0 or a subnormal number -- double biased exponent is 0 - uHalfBiasedExponent = 0; - uHalfSignificand = 0; // Any subnormal single will be too small to express as a half precision; TODO, is this really true? - } else if(nDoubleUnbiasedExponent > HALF_EXPONENT_MAX) { - // Exponent is too large to express in half-precision; round - // up to infinity; TODO, is this really true? - uHalfBiasedExponent = HALF_EXPONENT_INF_OR_NAN + HALF_EXPONENT_BIAS; - uHalfSignificand = 0; - } else if(nDoubleUnbiasedExponent < HALF_EXPONENT_MIN) { - // Exponent is too small to express in half-precision; round - // down to zero - uHalfBiasedExponent = HALF_EXPONENT_ZERO + HALF_EXPONENT_BIAS; - uHalfSignificand = 0; - // Could convert some of these values to a half-precision - // subnormal, but the layer above this will never use it. See - // layer above. There is code to do this in github history - // for this file, but it was removed because it was never - // invoked. - } else { - // The normal case, exponent is in range for half-precision - uHalfBiasedExponent = (uint32_t)(nDoubleUnbiasedExponent + HALF_EXPONENT_BIAS); - uHalfSignificand = uDoubleSignificand >> (DOUBLE_NUM_SIGNIFICAND_BITS - HALF_NUM_SIGNIFICAND_BITS); - } - uHalfSign = uDoubleSign; + uint64_t uDoubleBiasedExponent; + uDoubleBiasedExponent = (uint64_t)(nDoubleUnBiasedExponent + DOUBLE_EXPONENT_BIAS); - // Put the 3 values in the right place for a half precision - const uint64_t uHalfPrecision = uHalfSignificand | - (uHalfBiasedExponent << HALF_EXPONENT_SHIFT) | - (uHalfSign << HALF_SIGN_SHIFT); - // Cast is safe because all the masks and shifts above work to - // make a half precision value which is only 16 bits. - return (uint16_t)uHalfPrecision; + return CopyUint64ToDouble(uDoubleSignificand | + (uDoubleBiasedExponent << DOUBLE_EXPONENT_SHIFT) | + (uDoubleSign << DOUBLE_SIGN_SHIFT)); } -/* - EEE754_HalfToFloat() was created but is not needed. It can be retrieved from - github history if needed. - */ +double +IEEE754_HalfToDouble(uint16_t uHalfPrecision) +{ + uint64_t uDoubleSignificand; + int64_t nDoubleUnBiasedExponent; + double dResult; + + /* Pull out the three parts of the half-precision float. Do all + * the work in 64 bits because that is what the end result is. It + * may give smaller code size and will keep static analyzers + * happier. + */ + const uint64_t uHalfSignificand = uHalfPrecision & HALF_SIGNIFICAND_MASK; + const uint64_t uHalfBiasedExponent = (uHalfPrecision & HALF_EXPONENT_MASK) >> HALF_EXPONENT_SHIFT; + const int64_t nHalfUnBiasedExponent = (int64_t)uHalfBiasedExponent - HALF_EXPONENT_BIAS; + const uint64_t uHalfSign = (uHalfPrecision & HALF_SIGN_MASK) >> HALF_SIGN_SHIFT; + + if(nHalfUnBiasedExponent == HALF_EXPONENT_ZERO) { + /* 0 or subnormal */ + if(uHalfSignificand) { + /* --- SUBNORMAL --- */ + /* A half-precision subnormal can always be converted to a + * normal double-precision float because the ranges line up. + * The exponent of a subnormal starts out at the min exponent + * for a normal. As the sub normal significand bits are + * shifted, left to normalize, the exponent is + * decremented. Shifting continues until fully normalized. + */ + nDoubleUnBiasedExponent = HALF_EXPONENT_MIN; + uDoubleSignificand = uHalfSignificand; + do { + uDoubleSignificand <<= 1; + nDoubleUnBiasedExponent--; + } while ((uDoubleSignificand & (1ULL << HALF_NUM_SIGNIFICAND_BITS)) == 0); + /* A normal has an implied 1 in the most significant + * position that a subnormal doesn't. */ + uDoubleSignificand -= 1ULL << HALF_NUM_SIGNIFICAND_BITS; + /* Must shift into place for a double significand */ + uDoubleSignificand <<= DOUBLE_NUM_SIGNIFICAND_BITS - HALF_NUM_SIGNIFICAND_BITS; + + dResult = IEEE754_AssembleDouble(uHalfSign, + uDoubleSignificand, + nDoubleUnBiasedExponent); + } else { + /* --- ZERO --- */ + dResult = IEEE754_AssembleDouble(uHalfSign, + 0, + DOUBLE_EXPONENT_ZERO); + } + } else if(nHalfUnBiasedExponent == HALF_EXPONENT_INF_OR_NAN) { + /* NaN or Inifinity */ + if(uHalfSignificand) { + /* --- NaN --- */ + /* Half-precision payloads always fit into double precision + * payloads. They are shifted left the same as a normal + * number significand. + */ + uDoubleSignificand = uHalfSignificand << (DOUBLE_NUM_SIGNIFICAND_BITS - HALF_NUM_SIGNIFICAND_BITS); + dResult = IEEE754_AssembleDouble(uHalfSign, + uDoubleSignificand, + DOUBLE_EXPONENT_INF_OR_NAN); + } else { + /* --- INFINITY --- */ + dResult = IEEE754_AssembleDouble(uHalfSign, + 0, + DOUBLE_EXPONENT_INF_OR_NAN); + } + } else { + /* --- NORMAL NUMBER --- */ + uDoubleSignificand = uHalfSignificand << (DOUBLE_NUM_SIGNIFICAND_BITS - HALF_NUM_SIGNIFICAND_BITS); + dResult = IEEE754_AssembleDouble(uHalfSign, + uDoubleSignificand, + nHalfUnBiasedExponent); + } + + return dResult; +} -// Public function; see ieee754.h -double IEEE754_HalfToDouble(uint16_t uHalfPrecision) +/** + * @brief Assemble sign, significand and exponent into single precision float. + * + * @param[in] uHalfSign 0 if positive, 1 if negative + * @pararm[in] uHalfSignificand Bits of the significand + * @param[in] nHalfUnBiasedExponent Exponent + * + * This returns the bits for a single-precision float, a binary32 as + * specified in IEEE754. It is returned as a uint64_t rather than a + * uint32_t or a float for convenience of usage. + */ +static uint32_t +IEEE754_AssembleHalf(uint32_t uHalfSign, + uint32_t uHalfSignificand, + int32_t nHalfUnBiasedExponent) { - // Pull out the three parts of the half-precision float. Do all - // the work in 64 bits because that is what the end result is. It - // may give smaller code size and will keep static analyzers - // happier. - const uint64_t uHalfSignificand = uHalfPrecision & HALF_SIGNIFICAND_MASK; - const int64_t nHalfUnBiasedExponent = (int64_t)((uHalfPrecision & HALF_EXPONENT_MASK) >> HALF_EXPONENT_SHIFT) - HALF_EXPONENT_BIAS; - const uint64_t uHalfSign = (uHalfPrecision & HALF_SIGN_MASK) >> HALF_SIGN_SHIFT; - - - // Make the three parts of hte single-precision number - uint64_t uDoubleSignificand, uDoubleSign, uDoubleBiasedExponent; - if(nHalfUnBiasedExponent == HALF_EXPONENT_ZERO) { - // 0 or subnormal - uDoubleBiasedExponent = DOUBLE_EXPONENT_ZERO + DOUBLE_EXPONENT_BIAS; - if(uHalfSignificand) { - // Subnormal case - uDoubleBiasedExponent = -HALF_EXPONENT_BIAS + DOUBLE_EXPONENT_BIAS +1; - // A half-precision subnormal can always be converted to a - // normal double-precision float because the ranges line - // up - uDoubleSignificand = uHalfSignificand; - // Shift bits from right of the decimal to left, reducing - // the exponent by 1 each time - do { - uDoubleSignificand <<= 1; - uDoubleBiasedExponent--; - } while ((uDoubleSignificand & 0x400) == 0); - uDoubleSignificand &= HALF_SIGNIFICAND_MASK; - uDoubleSignificand <<= (DOUBLE_NUM_SIGNIFICAND_BITS - HALF_NUM_SIGNIFICAND_BITS); - } else { - // Just zero - uDoubleSignificand = 0; - } - } else if(nHalfUnBiasedExponent == HALF_EXPONENT_INF_OR_NAN) { - // NaN or Inifinity - uDoubleBiasedExponent = DOUBLE_EXPONENT_INF_OR_NAN + DOUBLE_EXPONENT_BIAS; - if(uHalfSignificand) { - // NaN - // First preserve the NaN payload from half to single - uDoubleSignificand = uHalfSignificand & ~HALF_QUIET_NAN_BIT; - if(uHalfSignificand & HALF_QUIET_NAN_BIT) { - // Next, set qNaN if needed since half qNaN bit is not - // copied above - uDoubleSignificand |= DOUBLE_QUIET_NAN_BIT; - } - } else { - // Infinity - uDoubleSignificand = 0; - } - } else { - // Normal number - uDoubleBiasedExponent = (uint64_t)(nHalfUnBiasedExponent + DOUBLE_EXPONENT_BIAS); - uDoubleSignificand = uHalfSignificand << (DOUBLE_NUM_SIGNIFICAND_BITS - HALF_NUM_SIGNIFICAND_BITS); - } - uDoubleSign = uHalfSign; + uint32_t uHalfUnbiasedExponent; + uHalfUnbiasedExponent = (uint32_t)(nHalfUnBiasedExponent + HALF_EXPONENT_BIAS); - // Shift the 3 parts into place as a double-precision - const uint64_t uDouble = uDoubleSignificand | - (uDoubleBiasedExponent << DOUBLE_EXPONENT_SHIFT) | - (uDoubleSign << DOUBLE_SIGN_SHIFT); - return CopyUint64ToDouble(uDouble); + return uHalfSignificand | + (uHalfUnbiasedExponent << HALF_EXPONENT_SHIFT) | + (uHalfSign << HALF_SIGN_SHIFT); } +/* Public function; see ieee754.h */ +IEEE754_union +IEEE754_SingleToHalf(float f) +{ + IEEE754_union result; + uint32_t uDroppedBits; + int32_t nExponentDifference; + int32_t nShiftAmount; + uint32_t uHalfSignificand; + + /* Pull the three parts out of the double-precision float Most work + * is done with uint32_t which helps avoid integer promotions and + * static analyzer complaints. + */ + const uint32_t uSingle = CopyFloatToUint32(f); + const uint32_t uSingleBiasedExponent = (uSingle & SINGLE_EXPONENT_MASK) >> SINGLE_EXPONENT_SHIFT; + const int32_t nSingleUnbiasedExponent = (int32_t)uSingleBiasedExponent - SINGLE_EXPONENT_BIAS; + const uint32_t uSingleSignificand = uSingle & SINGLE_SIGNIFICAND_MASK; + const uint32_t uSingleSign = (uSingle & SINGLE_SIGN_MASK) >> SINGLE_SIGN_SHIFT; + + if(nSingleUnbiasedExponent == SINGLE_EXPONENT_ZERO) { + if(uSingleSignificand == 0) { + /* --- IS ZERO --- */ + result.uSize = IEEE754_UNION_IS_HALF; + result.uValue = IEEE754_AssembleHalf(uSingleSign, + 0, + HALF_EXPONENT_ZERO); + } else { + /* --- IS SINGLE SUBNORMAL --- */ + /* The largest single subnormal is slightly less than the + * largest single normal which is 2^-149 or + * 2.2040517676619426e-38. The smallest half subnormal is + * 2^-14 or 5.9604644775390625E-8. There is no overlap so + * single subnormals can't be converted to halfs of any sort. + */ + result.uSize = IEEE754_UNION_IS_SINGLE; + result.uValue = uSingle; + } + } else if(nSingleUnbiasedExponent == SINGLE_EXPONENT_INF_OR_NAN) { + if(uSingleSignificand == 0) { + /* ---- IS INFINITY ---- */ + result.uSize = IEEE754_UNION_IS_HALF; + result.uValue = IEEE754_AssembleHalf(uSingleSign, 0, HALF_EXPONENT_INF_OR_NAN); + } else { + /* The NaN can only be converted if no payload bits are lost + * per RFC 8949 section 4.1 that defines Preferred + * Serializaton. Note that Deterministically Encode CBOR in + * section 4.2 allows for some variation of this rule, but at + * the moment this implementation is of Preferred + * Serialization, not CDE. As of December 2023, we are also + * expecting an update to CDE. This code may need to be + * updated for CDE. + */ + uDroppedBits = uSingleSignificand & (SINGLE_SIGNIFICAND_MASK >> HALF_NUM_SIGNIFICAND_BITS); + if(uDroppedBits == 0) { + /* --- IS CONVERTABLE NAN --- */ + uHalfSignificand = uSingleSignificand >> (SINGLE_NUM_SIGNIFICAND_BITS - HALF_NUM_SIGNIFICAND_BITS); + result.uSize = IEEE754_UNION_IS_HALF; + result.uValue = IEEE754_AssembleHalf(uSingleSign, + uHalfSignificand, + HALF_EXPONENT_INF_OR_NAN); + + } else { + /* --- IS UNCONVERTABLE NAN --- */ + result.uSize = IEEE754_UNION_IS_SINGLE; + result.uValue = uSingle; + } + } + } else { + /* ---- REGULAR NUMBER ---- */ + /* A regular single can be converted to a regular half if the + * single's exponent is in the smaller range of a half and if no + * precision is lost in the significand. + */ + if(nSingleUnbiasedExponent >= HALF_EXPONENT_MIN && + nSingleUnbiasedExponent <= HALF_EXPONENT_MAX && + (uSingleSignificand & (SINGLE_SIGNIFICAND_MASK >> HALF_NUM_SIGNIFICAND_BITS)) == 0) { + uHalfSignificand = uSingleSignificand >> (SINGLE_NUM_SIGNIFICAND_BITS - HALF_NUM_SIGNIFICAND_BITS); + + /* --- CONVERT TO HALF NORMAL --- */ + result.uSize = IEEE754_UNION_IS_HALF; + result.uValue = IEEE754_AssembleHalf(uSingleSign, + uHalfSignificand, + nSingleUnbiasedExponent); + } else { + /* Unable to convert to a half normal. See if it can be + * converted to a half subnormal. To do that, the exponent + * must be in range and no precision can be lost in the + * signficand. + * + * This is more complicated because the number is not + * normalized. The signficand must be shifted proprotionally + * to the exponent and 1 must be added in. See + * https://en.wikipedia.org/wiki/Single-precision_floating-point_format#Exponent_encoding + * + * Exponents -14 to -24 map to a shift of 0 to 10 of the + * significand. The largest value of a half subnormal has an + * exponent of -14. Subnormals are not normalized like + * normals meaning they lose precision as the numbers get + * smaller. Normals don't lose precision because the exponent + * allows all the bits of the significand to be significant. + */ + /* The exponent of the largest possible half-precision + * subnormal is HALF_EXPONENT_MIN (-14). Exponents larger + * than this are normal and handled above. We're going to + * shift the significand right by at least this amount. + */ + nExponentDifference = -(nSingleUnbiasedExponent - HALF_EXPONENT_MIN); + + /* In addition to the shift based on the exponent's value, + * the single significand has to be shifted right to fit into + * a half-precision significand */ + nShiftAmount = nExponentDifference + (SINGLE_NUM_SIGNIFICAND_BITS - HALF_NUM_SIGNIFICAND_BITS); + + /* Must add 1 in to the possible significand because there is + * an implied 1 for normal values and not for subnormal + * values. See equations here: + * https://en.wikipedia.org/wiki/Single-precision_floating-point_format#Exponent_encoding + */ + uHalfSignificand = (uSingleSignificand + (1 << SINGLE_NUM_SIGNIFICAND_BITS)) >> nShiftAmount; + + /* If only zero bits get shifted out, this can be converted + * to subnormal */ + if(nSingleUnbiasedExponent < HALF_EXPONENT_MIN && + nSingleUnbiasedExponent >= HALF_EXPONENT_MIN - HALF_NUM_SIGNIFICAND_BITS && + uHalfSignificand << nShiftAmount == uSingleSignificand + (1 << SINGLE_NUM_SIGNIFICAND_BITS)) { + /* --- CONVERTABLE TO HALF SUBNORMAL --- */ + result.uSize = IEEE754_UNION_IS_HALF; + result.uValue = IEEE754_AssembleHalf(uSingleSign, + uHalfSignificand, + HALF_EXPONENT_ZERO); + } else { + /* --- DO NOT CONVERT --- */ + result.uSize = IEEE754_UNION_IS_SINGLE; + result.uValue = uSingle; + } + } + } + + return result; +} -/* - IEEE754_FloatToDouble(uint32_t uFloat) was created but is not needed. It can be retrieved from -github history if needed. -*/ +/** + * @brief Assemble sign, significand and exponent into single precision float. + * + * @param[in] uSingleSign 0 if positive, 1 if negative + * @pararm[in] uSingleSignificand Bits of the significand + * @param[in] nSingleUnBiasedExponent Exponent + * + * This returns the bits for a single-precision float, a binary32 as + * specified in IEEE754. It is returned as a uint64_t rather than a + * uint32_t or a float for convenience of usage. + */ +static uint64_t +IEEE754_AssembleSingle(uint64_t uSingleSign, + uint64_t uSingleSignificand, + int64_t nSingleUnBiasedExponent) +{ + uint64_t uSingleBiasedExponent; + uSingleBiasedExponent = (uint64_t)(nSingleUnBiasedExponent + SINGLE_EXPONENT_BIAS); + + return uSingleSignificand | + (uSingleBiasedExponent << SINGLE_EXPONENT_SHIFT) | + (uSingleSign << SINGLE_SIGN_SHIFT); +} -// Public function; see ieee754.h -IEEE754_union IEEE754_FloatToSmallest(float f) + +/** + * @brief Convert a double-precision float to single-precision. + * + * @param[in] d The value to convert. + * + * @returns Either unconverted value or value converted to single-precision. + * + * This always succeeds. If the value cannot be converted without the + * loss of precision, it is not converted. + * + * This handles all subnormals and NaN payloads. + */ +static IEEE754_union +IEEE754_DoubleToSingle(double d) { - IEEE754_union result; - - // Pull the neeed two parts out of the single-precision float - const uint32_t uSingle = CopyFloatToUint32(f); - const int32_t nSingleExponent = (int32_t)((uSingle & SINGLE_EXPONENT_MASK) >> SINGLE_EXPONENT_SHIFT) - SINGLE_EXPONENT_BIAS; - const uint32_t uSingleSignificand = uSingle & SINGLE_SIGNIFICAND_MASK; - - // Bit mask that is the significand bits that would be lost when - // converting from single-precision to half-precision - const uint64_t uDroppedSingleBits = SINGLE_SIGNIFICAND_MASK >> HALF_NUM_SIGNIFICAND_BITS; - - // Optimizer will re organize so there is only one call to - // IEEE754_FloatToHalf() in the final code. - if(uSingle == 0) { - // Value is 0.0000, not a a subnormal - result.uSize = IEEE754_UNION_IS_HALF; - result.uValue = IEEE754_FloatToHalf(f); - } else if(nSingleExponent == SINGLE_EXPONENT_INF_OR_NAN) { - // NaN, +/- infinity - result.uSize = IEEE754_UNION_IS_HALF; - result.uValue = IEEE754_FloatToHalf(f); - } else if((nSingleExponent >= HALF_EXPONENT_MIN) && nSingleExponent <= HALF_EXPONENT_MAX && (!(uSingleSignificand & uDroppedSingleBits))) { - // Normal number in exponent range and precision won't be lost - result.uSize = IEEE754_UNION_IS_HALF; - result.uValue = IEEE754_FloatToHalf(f); + IEEE754_union Result; + int64_t nExponentDifference; + int64_t nShiftAmount; + uint64_t uSingleSignificand; + uint64_t uDroppedBits; + + + /* Pull the three parts out of the double-precision float. Most + * work is done with uint64_t which helps avoid integer promotions + * and static analyzer complaints. + */ + const uint64_t uDouble = CopyDoubleToUint64(d); + const uint64_t uDoubleBiasedExponent = (uDouble & DOUBLE_EXPONENT_MASK) >> DOUBLE_EXPONENT_SHIFT; + const int64_t nDoubleUnbiasedExponent = (int64_t)uDoubleBiasedExponent - DOUBLE_EXPONENT_BIAS; + const uint64_t uDoubleSign = (uDouble & DOUBLE_SIGN_MASK) >> DOUBLE_SIGN_SHIFT; + const uint64_t uDoubleSignificand = uDouble & DOUBLE_SIGNIFICAND_MASK; + + + if(nDoubleUnbiasedExponent == DOUBLE_EXPONENT_ZERO) { + if(uDoubleSignificand == 0) { + /* --- IS ZERO --- */ + Result.uSize = IEEE754_UNION_IS_SINGLE; + Result.uValue = IEEE754_AssembleSingle(uDoubleSign, + 0, + SINGLE_EXPONENT_ZERO); + } else { + /* --- IS DOUBLE SUBNORMAL --- */ + /* The largest double subnormal is slightly less than the + * largest double normal which is 2^-1022 or + * 2.2250738585072014e-308. The smallest single subnormal + * is 2^-149 or 1.401298464324817e-45. There is no + * overlap so double subnormals can't be converted to + * singles of any sort. + */ + Result.uSize = IEEE754_UNION_IS_DOUBLE; + Result.uValue = uDouble; + } + } else if(nDoubleUnbiasedExponent == DOUBLE_EXPONENT_INF_OR_NAN) { + if(uDoubleSignificand == 0) { + /* ---- IS INFINITY ---- */ + Result.uSize = IEEE754_UNION_IS_SINGLE; + Result.uValue = IEEE754_AssembleSingle(uDoubleSign, + 0, + SINGLE_EXPONENT_INF_OR_NAN); + } else { + /* The NaN can only be converted if no payload bits are + * lost per RFC 8949 section 4.1 that defines Preferred + * Serializaton. Note that Deterministically Encode CBOR + * in section 4.2 allows for some variation of this rule, + * but at the moment this implementation is of Preferred + * Serialization, not CDE. As of December 2023, we are + * also expecting an update to CDE. This code may need to + * be updated for CDE. + */ + uDroppedBits = uDoubleSignificand & (DOUBLE_SIGNIFICAND_MASK >> SINGLE_NUM_SIGNIFICAND_BITS); + if(uDroppedBits == 0) { + /* --- IS CONVERTABLE NAN --- */ + uSingleSignificand = uDoubleSignificand >> (DOUBLE_NUM_SIGNIFICAND_BITS - SINGLE_NUM_SIGNIFICAND_BITS); + Result.uSize = IEEE754_UNION_IS_SINGLE; + Result.uValue = IEEE754_AssembleSingle(uDoubleSign, + uSingleSignificand, + SINGLE_EXPONENT_INF_OR_NAN); + } else { + /* --- IS UNCONVERTABLE NAN --- */ + Result.uSize = IEEE754_UNION_IS_DOUBLE; + Result.uValue = uDouble; + } + } } else { - // Subnormal, exponent out of range, or precision will be lost - result.uSize = IEEE754_UNION_IS_SINGLE; - result.uValue = uSingle; + /* ---- REGULAR NUMBER ---- */ + /* A regular double can be converted to a regular single if + * the double's exponent is in the smaller range of a single + * and if no precision is lost in the significand. + */ + uDroppedBits = uDoubleSignificand & (DOUBLE_SIGNIFICAND_MASK >> SINGLE_NUM_SIGNIFICAND_BITS); + if(nDoubleUnbiasedExponent >= SINGLE_EXPONENT_MIN && + nDoubleUnbiasedExponent <= SINGLE_EXPONENT_MAX && + uDroppedBits == 0) { + /* --- IS CONVERTABLE TO SINGLE --- */ + uSingleSignificand = uDoubleSignificand >> (DOUBLE_NUM_SIGNIFICAND_BITS - SINGLE_NUM_SIGNIFICAND_BITS); + Result.uSize = IEEE754_UNION_IS_SINGLE; + Result.uValue = IEEE754_AssembleSingle(uDoubleSign, + uSingleSignificand, + nDoubleUnbiasedExponent); + } else { + /* Unable to convert to a single normal. See if it can be + * converted to a single subnormal. To do that, the + * exponent must be in range and no precision can be lost + * in the signficand. + * + * This is more complicated because the number is not + * normalized. The signficand must be shifted + * proprotionally to the exponent and 1 must be added + * in. See + * https://en.wikipedia.org/wiki/Single-precision_floating-point_format#Exponent_encoding + */ + nExponentDifference = -(nDoubleUnbiasedExponent - SINGLE_EXPONENT_MIN); + nShiftAmount = nExponentDifference + (DOUBLE_NUM_SIGNIFICAND_BITS - SINGLE_NUM_SIGNIFICAND_BITS); + uSingleSignificand = (uDoubleSignificand + (1ULL << DOUBLE_NUM_SIGNIFICAND_BITS)) >> nShiftAmount; + + if(nDoubleUnbiasedExponent < SINGLE_EXPONENT_MIN && + nDoubleUnbiasedExponent >= SINGLE_EXPONENT_MIN - SINGLE_NUM_SIGNIFICAND_BITS && + uSingleSignificand << nShiftAmount == uDoubleSignificand + (1ULL << DOUBLE_NUM_SIGNIFICAND_BITS)) { + /* --- IS CONVERTABLE TO SINGLE SUBNORMAL --- */ + Result.uSize = IEEE754_UNION_IS_SINGLE; + Result.uValue = IEEE754_AssembleSingle(uDoubleSign, + uSingleSignificand, + SINGLE_EXPONENT_ZERO); + } else { + /* --- CAN NOT BE CONVERTED --- */ + Result.uSize = IEEE754_UNION_IS_DOUBLE; + Result.uValue = uDouble; + } + } } - return result; + return Result; } -// Public function; see ieee754.h -IEEE754_union IEEE754_DoubleToSmallestInternal(double d, int bAllowHalfPrecision) + +/* Public function; see ieee754.h */ +IEEE754_union +IEEE754_DoubleToSmaller(double d, int bAllowHalfPrecision) { - IEEE754_union result; - - // Pull the needed two parts out of the double-precision float - const uint64_t uDouble = CopyDoubleToUint64(d); - const int64_t nDoubleExponent = (int64_t)((uDouble & DOUBLE_EXPONENT_MASK) >> DOUBLE_EXPONENT_SHIFT) - DOUBLE_EXPONENT_BIAS; - const uint64_t uDoubleSignificand = uDouble & DOUBLE_SIGNIFICAND_MASK; - - // Masks to check whether dropped significand bits are zero or not - const uint64_t uDroppedHalfBits = DOUBLE_SIGNIFICAND_MASK >> HALF_NUM_SIGNIFICAND_BITS; - const uint64_t uDroppedSingleBits = DOUBLE_SIGNIFICAND_MASK >> SINGLE_NUM_SIGNIFICAND_BITS; - - // This will not convert to half-precion or single-precision - // subnormals. Values that could be converted will be output as - // the double they are or occasionally to a normal single. This - // could be implemented, but it is more code and would rarely be - // used and rarely reduce the output size. - - // The various cases - if(d == 0.0) { // Take care of positive and negative zero - // Value is 0.0000, not a a subnormal - result.uSize = IEEE754_UNION_IS_HALF; - result.uValue = IEEE754_DoubleToHalf(d); - } else if(nDoubleExponent == DOUBLE_EXPONENT_INF_OR_NAN) { - // NaN, +/- infinity - result.uSize = IEEE754_UNION_IS_HALF; - result.uValue = IEEE754_DoubleToHalf(d); - } else if(bAllowHalfPrecision && (nDoubleExponent >= HALF_EXPONENT_MIN) && nDoubleExponent <= HALF_EXPONENT_MAX && (!(uDoubleSignificand & uDroppedHalfBits))) { - // Can convert to half without precision loss - result.uSize = IEEE754_UNION_IS_HALF; - result.uValue = IEEE754_DoubleToHalf(d); - } else if((nDoubleExponent >= SINGLE_EXPONENT_MIN) && nDoubleExponent <= SINGLE_EXPONENT_MAX && (!(uDoubleSignificand & uDroppedSingleBits))) { - // Can convert to single without precision loss - result.uSize = IEEE754_UNION_IS_SINGLE; - result.uValue = CopyFloatToUint32((float)d); - } else { - // Can't convert without precision loss - result.uSize = IEEE754_UNION_IS_DOUBLE; - result.uValue = uDouble; - } + IEEE754_union result; - return result; + result = IEEE754_DoubleToSingle(d); + + if(result.uSize == IEEE754_UNION_IS_SINGLE && bAllowHalfPrecision) { + /* Cast to uint32_t is OK, because value was just successfully + * converted to single. */ + float uSingle = CopyUint32ToSingle((uint32_t)result.uValue); + result = IEEE754_SingleToHalf(uSingle); + } + + return result; } -#else -int x; +#else /* QCBOR_DISABLE_PREFERRED_FLOAT */ + +int ieee754_dummy_place_holder; #endif /* QCBOR_DISABLE_PREFERRED_FLOAT */ diff --git a/3rdparty/exported/QCBOR/src/ieee754.h b/3rdparty/exported/QCBOR/src/ieee754.h index d37532a092c6..3013dc6fd547 100644 --- a/3rdparty/exported/QCBOR/src/ieee754.h +++ b/3rdparty/exported/QCBOR/src/ieee754.h @@ -1,14 +1,14 @@ -/*============================================================================== - ieee754.c -- floating-point conversion between half, double & single-precision - - Copyright (c) 2018-2020, Laurence Lundblade. All rights reserved. - - SPDX-License-Identifier: BSD-3-Clause - - See BSD-3-Clause license in README.md - - Created on 7/23/18 - =============================================================================*/ +/* ========================================================================== + * ieee754.h -- Conversion between half, double & single-precision floats + * + * Copyright (c) 2018-2024, Laurence Lundblade. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + * + * See BSD-3-Clause license in file named "LICENSE" + * + * Created on 7/23/18 + * ========================================================================== */ #ifndef QCBOR_DISABLE_PREFERRED_FLOAT @@ -18,130 +18,109 @@ #include - -/* - General comments - - This is a complete in that it handles all conversion cases including - +/- infinity, +/- zero, subnormal numbers, qNaN, sNaN and NaN - payloads. - - This conforms to IEEE 754-2008, but note that this doesn't specify - conversions, just the encodings. - - NaN payloads are preserved with alignment on the LSB. The qNaN bit is - handled differently and explicity copied. It is always the MSB of the - significand. The NaN payload MSBs (except the qNaN bit) are truncated - when going from double or single to half. - - TODO: what does the C cast do with NaN payloads from - double to single? It probably depends entirely on the - CPU. - - */ - -/* - Most simply just explicilty encode the type you want, single or - double. This works easily everywhere since standard C supports both - these types and so does qcbor. This encoder also supports half - precision and there's a few ways to use it to encode floating-point - numbers in less space. - - Without losing precision, you can encode a single or double such that - the special values of 0, NaN and Infinity encode as half-precision. - This CBOR decodoer and most others should handle this properly. - - If you don't mind losing precision, then you can use half-precision. - One way to do this is to set up your environment to use - ___fp_16. Some compilers and CPUs support it even though it is not - standard C. What is nice about this is that your program will use - less memory and floating-point operations like multiplying, adding - and such will be faster. - - Another way to make use of half-precision is to represent the values - in your program as single or double, but encode them in CBOR as - half-precision. This cuts the size of the encoded messages by 2 or 4, - but doesn't reduce memory needs or speed because you are still using - single or double in your code. - - */ - - - -/* - Convert single-precision float to half-precision float. Precision - and NaN payload bits will be lost. Too-large values will round up to - infinity and too small to zero. +/** @file ieee754.h + * + * This implements floating-point conversion between half, single and + * double precision floating-point numbers, in particular convesion to + * smaller representation (e.g., double to single) that does not lose + * precision for CBOR preferred serialization. + * + * This implementation works entirely with shifts and masks and does + * not require any floating-point HW or library. + * + * This conforms to IEEE 754-2008, but note that it doesn't specify + * conversions, just the encodings. + * + * This is complete, supporting +/- infinity, +/- zero, subnormals and + * NaN payloads. NaN payloads are converted to smaller by dropping the + * right most bits if they are zero and shifting to the right. If the + * rightmost bits are not zero the conversion is not performed. When + * converting from smaller to larger, the payload is shifted left and + * zero-padded. This is what is specified by CBOR preferred + * serialization and what modern HW conversion instructions do. CBOR + * CDE handling for NaN is not clearly specified, but upcoming + * documents may clarify this. + * + * There is no special handling of silent and quiet NaNs. It probably + * isn't necessary to transmit these special NaNs as there purpose is + * more for propgating errors up through some calculation. In many + * cases the handlng of the NaN payload will work for silent and quiet + * NaNs. + * + * A previous version of this was usable as a general library for + * conversion. This version is reduced to what is needed for CBOR. */ -uint16_t IEEE754_FloatToHalf(float f); -/* - Convert double-precision float to half-precision float. Precision - and NaN payload bits will be lost. Too-large values will round up to - infinity and too small to zero. +/** + * @brief Convert half-precision float to double-precision float. + * + * @param[in] uHalfPrecision Half-prevision number to convert. + * + * @returns double-presion value. + * + * This is a lossless conversion because every half-precision value + * can be represented as a double. There is no error condition. + * + * There is no half-precision type in C, so it is represented here as + * a @c uint16_t. The bits of @c uHalfPrecision are as described for + * half-precision by IEEE 754. */ -uint16_t IEEE754_DoubleToHalf(double d); +double +IEEE754_HalfToDouble(uint16_t uHalfPrecision); -/* - Convert half-precision float to double-precision float. - This is a loss-less conversion. +/** Holds a floating-point value that could be half, single or + * double-precision. The value is in a @c uint64_t that may be copied + * to a float or double. Simply casting uValue will usually work but + * may generate compiler or static analyzer warnings. Using + * UsefulBufUtil_CopyUint64ToDouble() or + * UsefulBufUtil_CopyUint32ToFloat() will not (and will not generate + * any extra code). */ -double IEEE754_HalfToDouble(uint16_t uHalfPrecision); - - -// Both tags the value and gives the size -#define IEEE754_UNION_IS_HALF 2 -#define IEEE754_UNION_IS_SINGLE 4 -#define IEEE754_UNION_IS_DOUBLE 8 - typedef struct { - uint8_t uSize; // One of IEEE754_IS_xxxx - uint64_t uValue; + enum {IEEE754_UNION_IS_HALF = 2, + IEEE754_UNION_IS_SINGLE = 4, + IEEE754_UNION_IS_DOUBLE = 8, + } uSize; /* Size of uValue */ + uint64_t uValue; } IEEE754_union; -/* - Converts double-precision to single-precision or half-precision if - possible without loss of precisions. If not, leaves it as a - double. Only converts to single-precision unless bAllowHalfPrecision - is set. - */ -IEEE754_union IEEE754_DoubleToSmallestInternal(double d, int bAllowHalfPrecision); - -/* - Converts double-precision to single-precision if possible without - loss of precision. If not, leaves it as a double. - */ -static inline IEEE754_union IEEE754_DoubleToSmall(double d) -{ - return IEEE754_DoubleToSmallestInternal(d, 0); -} - - -/* - Converts double-precision to single-precision or half-precision if - possible without loss of precisions. If not, leaves it as a double. +/** + * @brief Convert a double to either single or half-precision. + * + * @param[in] d The value to convert. + * @param[in] bAllowHalfPrecision If true, convert to either half or + * single precision. + * + * @returns Unconverted value, or value converted to single or half-precision. + * + * This always succeeds. If the value cannot be converted without the + * loss of precision, it is not converted. + * + * This handles all subnormals and NaN payloads. */ -static inline IEEE754_union IEEE754_DoubleToSmallest(double d) -{ - return IEEE754_DoubleToSmallestInternal(d, 1); -} - - -/* - Converts single-precision to half-precision if possible without loss - of precision. If not leaves as single-precision. +IEEE754_union +IEEE754_DoubleToSmaller(double d, int bAllowHalfPrecision); + + +/** + * @brief Convert a single-precision float to half-precision. + * + * @param[in] f The value to convert. + * + * @returns Either unconverted value or value converted to half-precision. + * + * This always succeeds. If the value cannot be converted without the + * loss of precision, it is not converted. + * + * This handles all subnormals and NaN payloads. */ -IEEE754_union IEEE754_FloatToSmallest(float f); +IEEE754_union +IEEE754_SingleToHalf(float f); #endif /* ieee754_h */ - #endif /* QCBOR_DISABLE_PREFERRED_FLOAT */ - - - - diff --git a/3rdparty/exported/QCBOR/src/qcbor_decode.c b/3rdparty/exported/QCBOR/src/qcbor_decode.c index 8a547eef0a66..0f4d5c026716 100644 --- a/3rdparty/exported/QCBOR/src/qcbor_decode.c +++ b/3rdparty/exported/QCBOR/src/qcbor_decode.c @@ -1,6 +1,6 @@ /*============================================================================== Copyright (c) 2016-2018, The Linux Foundation. - Copyright (c) 2018-2022, Laurence Lundblade. + Copyright (c) 2018-2024, Laurence Lundblade. Copyright (c) 2021, Arm Limited. All rights reserved. @@ -46,52 +46,150 @@ IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #endif /* QCBOR_DISABLE_FLOAT_HW_USE */ +#if (defined(__GNUC__) && !defined(__clang__)) +/* + * This is how the -Wmaybe-uninitialized compiler warning is + * handled. It can’t be ignored because some version of gcc enable it + * with -Wall which is a common and useful gcc warning option. It also + * can’t be ignored because it is the goal of QCBOR to compile clean + * out of the box in all environments. + * + * The big problem with -Wmaybe-uninitialized is that it generates + * false positives. It complains things are uninitialized when they + * are not. This is because it is not a thorough static analyzer. This + * is why “maybe” is in its name. The problem is it is just not + * thorough enough to understand all the code (and someone saw fit to + * put it in gcc and worse to enable it with -Wall). + * + * One solution would be to change the code so -Wmaybe-uninitialized + * doesn’t get confused, for example adding an unnecessary extra + * initialization to zero. (If variables were truly uninitialized, the + * correct path is to understand the code thoroughly and set them to + * the correct value at the correct time; in essence this is already + * done; -Wmaybe-uninitialized just can’t tell). This path is not + * taken because it makes the code bigger and is kind of the tail + * wagging the dog. + * + * The solution here is to just use a pragma to disable it for the + * whole file. Disabling it for each line makes the code fairly ugly + * requiring #pragma to push, pop and ignore. Another reason is the + * warnings issues vary by version of gcc and which optimization + * optimizations are selected. Another reason is that compilers other + * than gcc don’t have -Wmaybe-uninitialized. + * + * One may ask how to be sure these warnings are false positives and + * not real issues. 1) The code has been read carefully to check. 2) + * Testing is pretty thorough. 3) This code has been run through + * thorough high-quality static analyzers. + * + * In particularly, most of the warnings are about + * Item.Item->uDataType being uninitialized. QCBORDecode_GetNext() + * *always* sets this value and test case confirm + * this. -Wmaybe-uninitialized just can't tell. + * + * https://stackoverflow.com/questions/5080848/disable-gcc-may-be-used-uninitialized-on-a-particular-variable + */ +#pragma GCC diagnostic ignored "-Wmaybe-uninitialized" +#endif + + + #define SIZEOF_C_ARRAY(array,type) (sizeof(array)/sizeof(type)) -static inline bool -QCBORItem_IsMapOrArray(const QCBORItem *pMe) +static bool +QCBORItem_IsMapOrArray(const QCBORItem Item) { - const uint8_t uDataType = pMe->uDataType; + const uint8_t uDataType = Item.uDataType; return uDataType == QCBOR_TYPE_MAP || - uDataType == QCBOR_TYPE_ARRAY || - uDataType == QCBOR_TYPE_MAP_AS_ARRAY; +#ifndef QCBOR_DISABLE_NON_INTEGER_LABELS + uDataType == QCBOR_TYPE_MAP_AS_ARRAY || +#endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */ + uDataType == QCBOR_TYPE_ARRAY; } -static inline bool -QCBORItem_IsEmptyDefiniteLengthMapOrArray(const QCBORItem *pMe) +static bool +QCBORItem_IsEmptyDefiniteLengthMapOrArray(const QCBORItem Item) { - if(!QCBORItem_IsMapOrArray(pMe)){ + if(!QCBORItem_IsMapOrArray(Item)){ return false; } - if(pMe->val.uCount != 0) { + if(Item.val.uCount != 0) { return false; } return true; } -static inline bool -QCBORItem_IsIndefiniteLengthMapOrArray(const QCBORItem *pMe) +static bool +QCBORItem_IsIndefiniteLengthMapOrArray(const QCBORItem Item) { #ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS - if(!QCBORItem_IsMapOrArray(pMe)){ + if(!QCBORItem_IsMapOrArray(Item)){ return false; } - if(pMe->val.uCount != QCBOR_COUNT_INDICATES_INDEFINITE_LENGTH) { + if(Item.val.uCount != QCBOR_COUNT_INDICATES_INDEFINITE_LENGTH) { return false; } return true; #else /* QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS */ - (void)pMe; + (void)Item; return false; #endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS */ } +/* Return true if the labels in Item1 and Item2 are the same. + Works only for integer and string labels. Returns false + for any other type. */ +static bool +QCBORItem_MatchLabel(const QCBORItem Item1, const QCBORItem Item2) +{ + if(Item1.uLabelType == QCBOR_TYPE_INT64) { + if(Item2.uLabelType == QCBOR_TYPE_INT64 && Item1.label.int64 == Item2.label.int64) { + return true; + } +#ifndef QCBOR_DISABLE_NON_INTEGER_LABELS + } else if(Item1.uLabelType == QCBOR_TYPE_TEXT_STRING) { + if(Item2.uLabelType == QCBOR_TYPE_TEXT_STRING && !UsefulBuf_Compare(Item1.label.string, Item2.label.string)) { + return true; + } + } else if(Item1.uLabelType == QCBOR_TYPE_BYTE_STRING) { + if(Item2.uLabelType == QCBOR_TYPE_BYTE_STRING && !UsefulBuf_Compare(Item1.label.string, Item2.label.string)) { + return true; + } + } else if(Item1.uLabelType == QCBOR_TYPE_UINT64) { + if(Item2.uLabelType == QCBOR_TYPE_UINT64 && Item1.label.uint64 == Item2.label.uint64) { + return true; + } +#endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */ + } + + /* Other label types are never matched */ + return false; +} + + +/* + Returns true if Item1 and Item2 are the same type + or if either are of QCBOR_TYPE_ANY. + */ +static bool +QCBORItem_MatchType(const QCBORItem Item1, const QCBORItem Item2) +{ + if(Item1.uDataType == Item2.uDataType) { + return true; + } else if(Item1.uDataType == QCBOR_TYPE_ANY) { + return true; + } else if(Item2.uDataType == QCBOR_TYPE_ANY) { + return true; + } + return false; +} + /*=========================================================================== DecodeNesting -- Tracking array/map/sequence/bstr-wrapped nesting @@ -103,7 +201,7 @@ QCBORItem_IsIndefiniteLengthMapOrArray(const QCBORItem *pMe) */ -static inline uint8_t +static uint8_t DecodeNesting_GetCurrentLevel(const QCBORDecodeNesting *pNesting) { const ptrdiff_t nLevel = pNesting->pCurrent - &(pNesting->pLevels[0]); @@ -114,7 +212,7 @@ DecodeNesting_GetCurrentLevel(const QCBORDecodeNesting *pNesting) } -static inline uint8_t +static uint8_t DecodeNesting_GetBoundedModeLevel(const QCBORDecodeNesting *pNesting) { const ptrdiff_t nLevel = pNesting->pCurrentBounded - &(pNesting->pLevels[0]); @@ -125,14 +223,14 @@ DecodeNesting_GetBoundedModeLevel(const QCBORDecodeNesting *pNesting) } -static inline uint32_t +static uint32_t DecodeNesting_GetMapOrArrayStart(const QCBORDecodeNesting *pNesting) { return pNesting->pCurrentBounded->u.ma.uStartOffset; } -static inline bool +static bool DecodeNesting_IsBoundedEmpty(const QCBORDecodeNesting *pNesting) { if(pNesting->pCurrentBounded->u.ma.uCountCursor == QCBOR_COUNT_INDICATES_ZERO_LENGTH) { @@ -143,7 +241,7 @@ DecodeNesting_IsBoundedEmpty(const QCBORDecodeNesting *pNesting) } -static inline bool +static bool DecodeNesting_IsCurrentAtTop(const QCBORDecodeNesting *pNesting) { if(pNesting->pCurrent == &(pNesting->pLevels[0])) { @@ -154,7 +252,7 @@ DecodeNesting_IsCurrentAtTop(const QCBORDecodeNesting *pNesting) } -static inline bool +static bool DecodeNesting_IsCurrentDefiniteLength(const QCBORDecodeNesting *pNesting) { if(pNesting->pCurrent->uLevelType == QCBOR_TYPE_BYTE_STRING) { @@ -174,7 +272,7 @@ DecodeNesting_IsCurrentDefiniteLength(const QCBORDecodeNesting *pNesting) return true; } -static inline bool +static bool DecodeNesting_IsCurrentBstrWrapped(const QCBORDecodeNesting *pNesting) { if(pNesting->pCurrent->uLevelType == QCBOR_TYPE_BYTE_STRING) { @@ -185,7 +283,8 @@ DecodeNesting_IsCurrentBstrWrapped(const QCBORDecodeNesting *pNesting) } -static inline bool DecodeNesting_IsCurrentBounded(const QCBORDecodeNesting *pNesting) +static bool +DecodeNesting_IsCurrentBounded(const QCBORDecodeNesting *pNesting) { if(pNesting->pCurrent->uLevelType == QCBOR_TYPE_BYTE_STRING) { return true; @@ -197,7 +296,8 @@ static inline bool DecodeNesting_IsCurrentBounded(const QCBORDecodeNesting *pNes } -static inline void DecodeNesting_SetMapOrArrayBoundedMode(QCBORDecodeNesting *pNesting, bool bIsEmpty, size_t uStart) +static void +DecodeNesting_SetMapOrArrayBoundedMode(QCBORDecodeNesting *pNesting, bool bIsEmpty, size_t uStart) { /* Should be only called on maps and arrays */ /* @@ -213,13 +313,14 @@ static inline void DecodeNesting_SetMapOrArrayBoundedMode(QCBORDecodeNesting *pN } -static inline void DecodeNesting_ClearBoundedMode(QCBORDecodeNesting *pNesting) +static void +DecodeNesting_ClearBoundedMode(QCBORDecodeNesting *pNesting) { pNesting->pCurrent->u.ma.uStartOffset = QCBOR_NON_BOUNDED_OFFSET; } -static inline bool +static bool DecodeNesting_IsAtEndOfBoundedLevel(const QCBORDecodeNesting *pNesting) { if(pNesting->pCurrentBounded == NULL) { @@ -245,7 +346,7 @@ DecodeNesting_IsAtEndOfBoundedLevel(const QCBORDecodeNesting *pNesting) } -static inline bool +static bool DecodeNesting_IsEndOfDefiniteLengthMapOrArray(const QCBORDecodeNesting *pNesting) { /* Must only be called on map / array */ @@ -257,7 +358,7 @@ DecodeNesting_IsEndOfDefiniteLengthMapOrArray(const QCBORDecodeNesting *pNesting } -static inline bool +static bool DecodeNesting_IsCurrentTypeMap(const QCBORDecodeNesting *pNesting) { if(pNesting->pCurrent->uLevelType == CBOR_MAJOR_TYPE_MAP) { @@ -268,14 +369,21 @@ DecodeNesting_IsCurrentTypeMap(const QCBORDecodeNesting *pNesting) } -static inline bool +static bool DecodeNesting_IsBoundedType(const QCBORDecodeNesting *pNesting, uint8_t uType) { if(pNesting->pCurrentBounded == NULL) { return false; } - if(pNesting->pCurrentBounded->uLevelType != uType) { + uint8_t uItemDataType = pNesting->pCurrentBounded->uLevelType; +#ifndef QCBOR_DISABLE_NON_INTEGER_LABELS + if(uItemDataType == QCBOR_TYPE_MAP_AS_ARRAY) { + uItemDataType = QCBOR_TYPE_ARRAY; + } +#endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */ + + if(uItemDataType != uType) { return false; } @@ -283,7 +391,7 @@ DecodeNesting_IsBoundedType(const QCBORDecodeNesting *pNesting, uint8_t uType) } -static inline void +static void DecodeNesting_DecrementDefiniteLengthMapOrArrayCount(QCBORDecodeNesting *pNesting) { /* Only call on a definite-length array / map */ @@ -291,7 +399,7 @@ DecodeNesting_DecrementDefiniteLengthMapOrArrayCount(QCBORDecodeNesting *pNestin } -static inline void +static void DecodeNesting_ReverseDecrement(QCBORDecodeNesting *pNesting) { /* Only call on a definite-length array / map */ @@ -299,7 +407,7 @@ DecodeNesting_ReverseDecrement(QCBORDecodeNesting *pNesting) } -static inline void +static void DecodeNesting_Ascend(QCBORDecodeNesting *pNesting) { pNesting->pCurrent--; @@ -323,7 +431,7 @@ DecodeNesting_Descend(QCBORDecodeNesting *pNesting, uint8_t uType) } -static inline QCBORError +static QCBORError DecodeNesting_EnterBoundedMapOrArray(QCBORDecodeNesting *pNesting, bool bIsEmpty, size_t uOffset) @@ -351,10 +459,10 @@ DecodeNesting_EnterBoundedMapOrArray(QCBORDecodeNesting *pNesting, } -static inline QCBORError +static QCBORError DecodeNesting_DescendMapOrArray(QCBORDecodeNesting *pNesting, - uint8_t uQCBORType, - uint64_t uCount) + const uint8_t uQCBORType, + const uint16_t uCount) { QCBORError uError = QCBOR_SUCCESS; @@ -366,21 +474,16 @@ DecodeNesting_DescendMapOrArray(QCBORDecodeNesting *pNesting, /* Empty indefinite-length maps and arrays are handled elsewhere */ } - /* Error out if arrays is too long to handle */ - if(uCount != QCBOR_COUNT_INDICATES_INDEFINITE_LENGTH && - uCount > QCBOR_MAX_ITEMS_IN_ARRAY) { - uError = QCBOR_ERR_ARRAY_DECODE_TOO_LONG; - goto Done; - } + /* Rely on check in QCBOR_Private_DecodeArrayOrMap() for definite-length + * arrays and maps that are too long */ uError = DecodeNesting_Descend(pNesting, uQCBORType); if(uError != QCBOR_SUCCESS) { goto Done; } - /* Fill in the new map/array level. Check above makes casts OK. */ - pNesting->pCurrent->u.ma.uCountCursor = (uint16_t)uCount; - pNesting->pCurrent->u.ma.uCountTotal = (uint16_t)uCount; + pNesting->pCurrent->u.ma.uCountCursor = uCount; + pNesting->pCurrent->u.ma.uCountTotal = uCount; DecodeNesting_ClearBoundedMode(pNesting); @@ -389,14 +492,14 @@ DecodeNesting_DescendMapOrArray(QCBORDecodeNesting *pNesting, } -static inline void +static void DecodeNesting_LevelUpCurrent(QCBORDecodeNesting *pNesting) { pNesting->pCurrent = pNesting->pCurrentBounded - 1; } -static inline void +static void DecodeNesting_LevelUpBounded(QCBORDecodeNesting *pNesting) { while(pNesting->pCurrentBounded != &(pNesting->pLevels[0])) { @@ -408,14 +511,14 @@ DecodeNesting_LevelUpBounded(QCBORDecodeNesting *pNesting) } -static inline void +static void DecodeNesting_SetCurrentToBoundedLevel(QCBORDecodeNesting *pNesting) { pNesting->pCurrent = pNesting->pCurrentBounded; } -static inline QCBORError +static QCBORError DecodeNesting_DescendIntoBstrWrapped(QCBORDecodeNesting *pNesting, uint32_t uEndOffset, uint32_t uStartOffset) @@ -439,14 +542,14 @@ DecodeNesting_DescendIntoBstrWrapped(QCBORDecodeNesting *pNesting, } -static inline void +static void DecodeNesting_ZeroMapOrArrayCount(QCBORDecodeNesting *pNesting) { pNesting->pCurrent->u.ma.uCountCursor = 0; } -static inline void +static void DecodeNesting_ResetMapOrArrayCount(QCBORDecodeNesting *pNesting) { if(pNesting->pCurrent->u.ma.uCountCursor != QCBOR_COUNT_INDICATES_ZERO_LENGTH) { @@ -455,7 +558,7 @@ DecodeNesting_ResetMapOrArrayCount(QCBORDecodeNesting *pNesting) } -static inline void +static void DecodeNesting_Init(QCBORDecodeNesting *pNesting) { /* Assumes that *pNesting has been zero'd before this call. */ @@ -464,7 +567,7 @@ DecodeNesting_Init(QCBORDecodeNesting *pNesting) } -static inline void +static void DecodeNesting_PrepareForMapSearch(QCBORDecodeNesting *pNesting, QCBORDecodeNesting *pSave) { @@ -472,7 +575,7 @@ DecodeNesting_PrepareForMapSearch(QCBORDecodeNesting *pNesting, } -static inline void +static void DecodeNesting_RestoreFromMapSearch(QCBORDecodeNesting *pNesting, const QCBORDecodeNesting *pSave) { @@ -480,7 +583,7 @@ DecodeNesting_RestoreFromMapSearch(QCBORDecodeNesting *pNesting, } -static inline uint32_t +static uint32_t DecodeNesting_GetPreviousBoundedEnd(const QCBORDecodeNesting *pMe) { return pMe->pCurrentBounded->u.bs.uSavedEndOffset; @@ -498,7 +601,7 @@ DecodeNesting_GetPreviousBoundedEnd(const QCBORDecodeNesting *pMe) ===========================================================================*/ -static inline void +static void StringAllocator_Free(const QCBORInternalAllocator *pMe, const void *pMem) { /* This cast to uintptr_t suppresses the "-Wcast-qual" warnings. @@ -510,7 +613,7 @@ StringAllocator_Free(const QCBORInternalAllocator *pMe, const void *pMem) // StringAllocator_Reallocate called with pMem NULL is // equal to StringAllocator_Allocate() -static inline UsefulBuf +static UsefulBuf StringAllocator_Reallocate(const QCBORInternalAllocator *pMe, const void *pMem, size_t uSize) @@ -519,13 +622,13 @@ StringAllocator_Reallocate(const QCBORInternalAllocator *pMe, return (pMe->pfAllocator)(pMe->pAllocateCxt, (void *)(uintptr_t)pMem, uSize); } -static inline UsefulBuf +static UsefulBuf StringAllocator_Allocate(const QCBORInternalAllocator *pMe, size_t uSize) { return (pMe->pfAllocator)(pMe->pAllocateCxt, NULL, uSize); } -static inline void +static void StringAllocator_Destruct(const QCBORInternalAllocator *pMe) { /* See comment in StringAllocator_Free() */ @@ -547,9 +650,10 @@ StringAllocator_Destruct(const QCBORInternalAllocator *pMe) /* * Public function, see header file */ -void QCBORDecode_Init(QCBORDecodeContext *pMe, - UsefulBufC EncodedCBOR, - QCBORDecodeMode nDecodeMode) +void +QCBORDecode_Init(QCBORDecodeContext *pMe, + UsefulBufC EncodedCBOR, + QCBORDecodeMode nDecodeMode) { memset(pMe, 0, sizeof(QCBORDecodeContext)); UsefulInputBuf_Init(&(pMe->InBuf), EncodedCBOR); @@ -570,10 +674,11 @@ void QCBORDecode_Init(QCBORDecodeContext *pMe, /* * Public function, see header file */ -void QCBORDecode_SetUpAllocator(QCBORDecodeContext *pMe, - QCBORStringAllocate pfAllocateFunction, - void *pAllocateContext, - bool bAllStrings) +void +QCBORDecode_SetUpAllocator(QCBORDecodeContext *pMe, + QCBORStringAllocate pfAllocateFunction, + void *pAllocateContext, + bool bAllStrings) { pMe->StringAllocator.pfAllocator = pfAllocateFunction; pMe->StringAllocator.pAllocateCxt = pAllocateContext; @@ -587,8 +692,9 @@ void QCBORDecode_SetUpAllocator(QCBORDecodeContext *pMe, /* * Deprecated public function, see header file */ -void QCBORDecode_SetCallerConfiguredTagList(QCBORDecodeContext *pMe, - const QCBORTagListIn *pTagList) +void +QCBORDecode_SetCallerConfiguredTagList(QCBORDecodeContext *pMe, + const QCBORTagListIn *pTagList) { /* This does nothing now. It is retained for backwards compatibility */ (void)pMe; @@ -603,43 +709,44 @@ void QCBORDecode_SetCallerConfiguredTagList(QCBORDecodeContext *pMe, * down. If a layer has no work to do for a particular item, it * returns quickly. * - * 1. QCBORDecode_GetNextTagContent - The top layer processes tagged - * data items, turning them into the local C representation. For the - * most simple it is just associating a QCBOR_TYPE with the data. For - * the complex ones that an aggregate of data items, there is some - * further decoding and some limited recursion. + * 1. QCBORDecode_Private_GetNextTagContent - The top layer processes + * tagged data items, turning them into the local C representation. + * For the most simple it is just associating a QCBOR_TYPE with the + * data. For the complex ones that an aggregate of data items, there + * is some further decoding and some limited recursion. * - * 2. QCBORDecode_GetNextMapOrArray - This manages the beginnings and - * ends of maps and arrays. It tracks descending into and ascending - * out of maps/arrays. It processes breaks that terminate - * indefinite-length maps and arrays. + * 2. QCBORDecode_Private_GetNextMapOrArray - This manages the + * beginnings and ends of maps and arrays. It tracks descending into + * and ascending out of maps/arrays. It processes breaks that + * terminate indefinite-length maps and arrays. * - * 3. QCBORDecode_GetNextMapEntry - This handles the combining of two - * items, the label and the data, that make up a map entry. It only - * does work on maps. It combines the label and data items into one - * labeled item. + * 3. QCBORDecode_Private_GetNextMapEntry - This handles the combining + * of two items, the label and the data, that make up a map entry. It + * only does work on maps. It combines the label and data items into + * one labeled item. * - * 4. QCBORDecode_GetNextTagNumber - This decodes type 6 tag + * 4. QCBORDecode_Private_GetNextTagNumber - This decodes type 6 tag * numbers. It turns the tag numbers into bit flags associated with * the data item. No actual decoding of the contents of the tag is * performed here. * - * 5. QCBORDecode_GetNextFullString - This assembles the sub-items - * that make up an indefinite-length string into one string item. It - * uses the string allocator to create contiguous space for the - * item. It processes all breaks that are part of indefinite-length - * strings. - * - * 6. DecodeAtomicDataItem - This decodes the atomic data items in - * CBOR. Each atomic data item has a "major type", an integer - * "argument" and optionally some content. For text and byte strings, - * the content is the bytes that make up the string. These are the - * smallest data items that are considered to be well-formed. The - * content may also be other data items in the case of aggregate + * 5. QCBORDecode_Private_GetNextFullString - This assembles the + * sub-items that make up an indefinite-length string into one string + * item. It uses the string allocator to create contiguous space for + * the item. It processes all breaks that are part of + * indefinite-length strings. + * + * 6. QCBOR_Private_DecodeAtomicDataItem - This decodes the atomic + * data items in CBOR. Each atomic data item has a "major type", an + * integer "argument" and optionally some content. For text and byte + * strings, the content is the bytes that make up the string. These + * are the smallest data items that are considered to be well-formed. + * The content may also be other data items in the case of aggregate * types. They are not handled in this layer. * - * Roughly this takes 300 bytes of stack for vars. TODO: evaluate this - * more carefully and correctly. + * This uses about 350 bytes of stack. This number comes from + * instrumenting (printf address of stack variables) the code on x86 + * compiled for size optimization. */ @@ -665,8 +772,8 @@ void QCBORDecode_SetCallerConfiguredTagList(QCBORDecodeContext *pMe, * @param[out] puArgument The decoded argument. * @param[out] pnAdditionalInfo The decoded Lower 5 bits of initial byte. * - * @retval QCBOR_ERR_UNSUPPORTED - * @retval QCBOR_ERR_HIT_END + * @retval QCBOR_ERR_UNSUPPORTED Encountered unsupported/reserved features + * @retval QCBOR_ERR_HIT_END Unexpected end of input * * This decodes the CBOR "head" that every CBOR data item has. See * longer explaination of the head in documentation for @@ -680,11 +787,11 @@ void QCBORDecode_SetCallerConfiguredTagList(QCBORDecodeContext *pMe, * avoids integer promotions, can reduce code size and makes static * analyzers happier. */ -static inline QCBORError -DecodeHead(UsefulInputBuf *pUInBuf, - int *pnMajorType, - uint64_t *puArgument, - int *pnAdditionalInfo) +static QCBORError +QCBOR_Private_DecodeHead(UsefulInputBuf *pUInBuf, + int *pnMajorType, + uint64_t *puArgument, + int *pnAdditionalInfo) { QCBORError uReturn; @@ -739,11 +846,13 @@ DecodeHead(UsefulInputBuf *pUInBuf, /** * @brief Decode integer types, major types 0 and 1. * - * @param[in] nMajorType The CBOR major type (0 or 1). - * @param[in] uArgument The argument from the head. - * @param[out] pDecodedItem The filled in decoded item. + * @param[in] nMajorType The CBOR major type (0 or 1). + * @param[in] uArgument The argument from the head. + * @param[in] nAdditionalInfo So it can be error-checked. + * @param[out] pDecodedItem The filled in decoded item. * - * @retval QCBOR_ERR_INT_OVERFLOW + * @retval QCBOR_ERR_INT_OVERFLOW Too-large negative encountered. + * @retval QCBOR_ERR_BAD_INT nAdditionalInfo indicated indefinte. * * Must only be called when major type is 0 or 1. * @@ -756,11 +865,19 @@ DecodeHead(UsefulInputBuf *pUInBuf, * away from zero than positive. Stdint, as far as I can tell, uses * two's compliment to represent negative integers. */ -static inline QCBORError -DecodeInteger(int nMajorType, uint64_t uArgument, QCBORItem *pDecodedItem) +static QCBORError +QCBOR_Private_DecodeInteger(const int nMajorType, + const uint64_t uArgument, + const int nAdditionalInfo, + QCBORItem *pDecodedItem) { QCBORError uReturn = QCBOR_SUCCESS; + if(nAdditionalInfo == LEN_IS_INDEFINITE) { + uReturn = QCBOR_ERR_BAD_INT; + goto Done; + } + if(nMajorType == CBOR_MAJOR_TYPE_POSITIVE_INT) { if (uArgument <= INT64_MAX) { pDecodedItem->val.int64 = (int64_t)uArgument; @@ -789,10 +906,226 @@ DecodeInteger(int nMajorType, uint64_t uArgument, QCBORItem *pDecodedItem) } } +Done: + return uReturn; +} + + +/** + * @brief Decode text and byte strings + * + * @param[in] pMe Decoder context. + * @param[in] bAllocate Whether to allocate and copy string. + * @param[in] nMajorType Whether it is a byte or text string. + * @param[in] uStrLen The length of the string. + * @param[in] nAdditionalInfo Whether it is an indefinite-length string. + * @param[out] pDecodedItem The filled-in decoded item. + * + * @retval QCBOR_ERR_HIT_END Unexpected end of input. + * @retval QCBOR_ERR_STRING_ALLOCATE Out of memory. + * @retval QCBOR_ERR_STRING_TOO_LONG String longer than SIZE_MAX - 4. + * @retval QCBOR_ERR_NO_STRING_ALLOCATOR Allocation requested, but no allocator + * + * This reads @c uStrlen bytes from the input and fills in @c + * pDecodedItem. If @c bAllocate is true, then memory for the string + * is allocated. + */ +static QCBORError +QCBOR_Private_DecodeString(QCBORDecodeContext *pMe, + const bool bAllocate, + const int nMajorType, + const uint64_t uStrLen, + const int nAdditionalInfo, + QCBORItem *pDecodedItem) +{ + QCBORError uReturn = QCBOR_SUCCESS; + + /* ---- Figure out the major type ---- */ + #if CBOR_MAJOR_TYPE_BYTE_STRING + 4 != QCBOR_TYPE_BYTE_STRING + #error QCBOR_TYPE_BYTE_STRING not lined up with major type + #endif + + #if CBOR_MAJOR_TYPE_TEXT_STRING + 4 != QCBOR_TYPE_TEXT_STRING + #error QCBOR_TYPE_TEXT_STRING not lined up with major type + #endif + pDecodedItem->uDataType = (uint8_t)(nMajorType + 4); + + if(nAdditionalInfo == LEN_IS_INDEFINITE) { + /* --- Just the head of an indefinite-length string --- */ + pDecodedItem->val.string = (UsefulBufC){NULL, QCBOR_STRING_LENGTH_INDEFINITE}; + + } else { + /* --- A definite-length string --- */ + /* --- (which might be a chunk of an indefinte-length string) --- */ + + /* CBOR lengths can be 64 bits, but size_t is not 64 bits on all + * CPUs. This check makes the casts to size_t below safe. + * + * The max is 4 bytes less than the largest sizeof() so this can be + * tested by putting a SIZE_MAX length in the CBOR test input (no + * one will care the limit on strings is 4 bytes shorter). + */ + if(uStrLen > SIZE_MAX-4) { + uReturn = QCBOR_ERR_STRING_TOO_LONG; + goto Done; + } + + const UsefulBufC Bytes = UsefulInputBuf_GetUsefulBuf(&(pMe->InBuf), (size_t)uStrLen); + if(UsefulBuf_IsNULLC(Bytes)) { + /* Failed to get the bytes for this string item */ + uReturn = QCBOR_ERR_HIT_END; + goto Done; + } + + if(bAllocate) { +#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS + /* --- Put string in allocated memory --- */ + + /* Note that this is not where allocation to coalesce + * indefinite-length strings is done. This is for when the + * caller has requested all strings be allocated. Disabling + * indefinite length strings also disables this allocate-all + * option. + */ + + if(pMe->StringAllocator.pfAllocator == NULL) { + uReturn = QCBOR_ERR_NO_STRING_ALLOCATOR; + goto Done; + } + UsefulBuf NewMem = StringAllocator_Allocate(&(pMe->StringAllocator), (size_t)uStrLen); + if(UsefulBuf_IsNULL(NewMem)) { + uReturn = QCBOR_ERR_STRING_ALLOCATE; + goto Done; + } + pDecodedItem->val.string = UsefulBuf_Copy(NewMem, Bytes); + pDecodedItem->uDataAlloc = 1; +#else + uReturn = QCBOR_ERR_INDEF_LEN_STRINGS_DISABLED; +#endif /* ! QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS */ + } else { + /* --- Normal case with no string allocator --- */ + pDecodedItem->val.string = Bytes; + } + } + +Done: + return uReturn; +} + + +/** + * @brief Decode array or map. + * + * @param[in] uMode Decoder mode. + * @param[in] nMajorType Whether it is a byte or text string. + * @param[in] uItemCount The length of the string. + * @param[in] nAdditionalInfo Whether it is an indefinite-length. + * @param[out] pDecodedItem The filled-in decoded item. + * + * @retval QCBOR_ERR_INDEF_LEN_ARRAYS_DISABLED Indefinites disabled. + * @retval QCBOR_ERR_ARRAY_DECODE_TOO_LONG Too many items in array/map. + * + * Not much to do for arrays and maps. Just the type item count (but a + * little messy because of ifdefs for indefinite-lengths and + * map-as-array decoding). + * + * This also does the bulk of the work for @ref + * QCBOR_DECODE_MODE_MAP_AS_ARRAY, a special mode to handle + * arbitrarily complex map labels. This ifdefs out with + * QCBOR_DISABLE_NON_INTEGER_LABELS. + */ +static QCBORError +QCBOR_Private_DecodeArrayOrMap(const uint8_t uMode, + const int nMajorType, + uint64_t uItemCount, + const int nAdditionalInfo, + QCBORItem *pDecodedItem) +{ + QCBORError uReturn; + + /* ------ Sort out the data type ------ */ + #if QCBOR_TYPE_ARRAY != CBOR_MAJOR_TYPE_ARRAY + #error QCBOR_TYPE_ARRAY value not lined up with major type + #endif + + #if QCBOR_TYPE_MAP != CBOR_MAJOR_TYPE_MAP + #error QCBOR_TYPE_MAP value not lined up with major type + #endif + pDecodedItem->uDataType = (uint8_t)nMajorType; +#ifndef QCBOR_DISABLE_NON_INTEGER_LABELS + if(uMode == QCBOR_DECODE_MODE_MAP_AS_ARRAY && nMajorType == QCBOR_TYPE_MAP) { + pDecodedItem->uDataType = QCBOR_TYPE_MAP_AS_ARRAY; + } +#else + (void)uMode; +#endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */ + + uReturn = QCBOR_SUCCESS; + + if(nAdditionalInfo == LEN_IS_INDEFINITE) { + /* ------ Indefinite-length array/map ----- */ +#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS + pDecodedItem->val.uCount = QCBOR_COUNT_INDICATES_INDEFINITE_LENGTH; +#else /* QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS */ + uReturn = QCBOR_ERR_INDEF_LEN_ARRAYS_DISABLED; +#endif /* ! QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS */ + } else { + /* ----- Definite-length array/map ----- */ + if(uItemCount > (nMajorType == QCBOR_TYPE_MAP ? QCBOR_MAX_ITEMS_IN_MAP : QCBOR_MAX_ITEMS_IN_ARRAY)) { + uReturn = QCBOR_ERR_ARRAY_DECODE_TOO_LONG; + + } else { +#ifndef QCBOR_DISABLE_NON_INTEGER_LABELS + if(uMode == QCBOR_DECODE_MODE_MAP_AS_ARRAY && nMajorType == QCBOR_TYPE_MAP) { + /* ------ Map as array ------ */ + uItemCount *= 2; + } +#endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */ + + /* cast OK because of check above */ + pDecodedItem->val.uCount = (uint16_t)uItemCount; + } + } + return uReturn; } +/** + * @brief Decode a tag number. + * + * @param[in] uTagNumber The length of the string. + * @param[in] nAdditionalInfo So this can be error-checked. + * @param[out] pDecodedItem The filled-in decoded item. + * + * @retval QCBOR_ERR_BAD_INT nAdditionalInfo is LEN_IS_INDEFINITE. + * @retval QCBOR_ERR_TAGS_DISABLED QCBOR_DISABLE_TAGS is defined. + * + * Not much to do for tags, but fill in pDecodedItem and check for + * error in nAdditionalInfo. + */ +static QCBORError +QCBOR_Private_DecodeTag(const uint64_t uTagNumber, + const int nAdditionalInfo, + QCBORItem *pDecodedItem) +{ +#ifndef QCBOR_DISABLE_TAGS + if(nAdditionalInfo == LEN_IS_INDEFINITE) { + return QCBOR_ERR_BAD_INT; + } else { + pDecodedItem->val.uTagV = uTagNumber; + pDecodedItem->uDataType = QCBOR_TYPE_TAG; + return QCBOR_SUCCESS; + } +#else /* QCBOR_DISABLE_TAGS */ + (void)nAdditionalInfo; + (void)uTagNumber; + (void)pDecodedItem; + return QCBOR_ERR_TAGS_DISABLED; +#endif /* QCBOR_DISABLE_TAGS */ +} + + /* Make sure #define value line up as DecodeSimple counts on this. */ #if QCBOR_TYPE_FALSE != CBOR_SIMPLEV_FALSE #error QCBOR_TYPE_FALSE macro value wrong @@ -830,13 +1163,17 @@ DecodeInteger(int nMajorType, uint64_t uArgument, QCBORItem *pDecodedItem) * @param[in] uArgument The argument from the head. * @param[out] pDecodedItem The filled in decoded item. * - * @retval QCBOR_ERR_HALF_PRECISION_DISABLED - * @retval QCBOR_ERR_ALL_FLOAT_DISABLED - * @retval QCBOR_ERR_BAD_TYPE_7 + * @retval QCBOR_ERR_HALF_PRECISION_DISABLED Half-precision in input, but decode + * of half-precision disabled + * @retval QCBOR_ERR_ALL_FLOAT_DISABLED Float-point in input, but all float + * decode is disabled. + * @retval QCBOR_ERR_BAD_TYPE_7 Not-allowed representation of simple + * type in input. */ - -static inline QCBORError -DecodeType7(int nAdditionalInfo, uint64_t uArgument, QCBORItem *pDecodedItem) +static QCBORError +QCBOR_Private_DecodeType7(const int nAdditionalInfo, + const uint64_t uArgument, + QCBORItem *pDecodedItem) { QCBORError uReturn = QCBOR_SUCCESS; @@ -937,236 +1274,90 @@ DecodeType7(int nAdditionalInfo, uint64_t uArgument, QCBORItem *pDecodedItem) } -/** - * @brief Decode text and byte strings - * - * @param[in] pAllocator The string allocator or NULL. - * @param[in] uStrLen The length of the string. - * @param[in] pUInBuf The surce from which to read the string's bytes. - * @param[out] pDecodedItem The filled in decoded item. - * - * @retval QCBOR_ERR_HIT_END - * @retval QCBOR_ERR_STRING_ALLOCATE - * @retval QCBOR_ERR_STRING_TOO_LONG - * - * The reads @c uStrlen bytes from @c pUInBuf and fills in @c - * pDecodedItem. If @c pAllocator is not NULL then memory for the - * string is allocated. - */ -static inline QCBORError -DecodeBytes(const QCBORInternalAllocator *pAllocator, - uint64_t uStrLen, - UsefulInputBuf *pUInBuf, - QCBORItem *pDecodedItem) -{ - QCBORError uReturn = QCBOR_SUCCESS; - - /* CBOR lengths can be 64 bits, but size_t is not 64 bits on all - * CPUs. This check makes the casts to size_t below safe. - * - * The max is 4 bytes less than the largest sizeof() so this can be - * tested by putting a SIZE_MAX length in the CBOR test input (no - * one will care the limit on strings is 4 bytes shorter). - */ - if(uStrLen > SIZE_MAX-4) { - uReturn = QCBOR_ERR_STRING_TOO_LONG; - goto Done; - } - - const UsefulBufC Bytes = UsefulInputBuf_GetUsefulBuf(pUInBuf, (size_t)uStrLen); - if(UsefulBuf_IsNULLC(Bytes)) { - /* Failed to get the bytes for this string item */ - uReturn = QCBOR_ERR_HIT_END; - goto Done; - } - -#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS - /* Note that this is not where allocation to coalesce - * indefinite-length strings is done. This is for when the caller - * has requested all strings be allocated. Disabling indefinite - * length strings also disables this allocate-all option. - */ - if(pAllocator) { - /* request to use the string allocator to make a copy */ - UsefulBuf NewMem = StringAllocator_Allocate(pAllocator, (size_t)uStrLen); - if(UsefulBuf_IsNULL(NewMem)) { - uReturn = QCBOR_ERR_STRING_ALLOCATE; - goto Done; - } - pDecodedItem->val.string = UsefulBuf_Copy(NewMem, Bytes); - pDecodedItem->uDataAlloc = 1; - goto Done; - } -#else /* QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS */ - (void)pAllocator; -#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS */ - - /* Normal case with no string allocator */ - pDecodedItem->val.string = Bytes; - -Done: - return uReturn; -} - - -/** - * @brief Map the CBOR major types for strings to the QCBOR types. - * - * @param[in] nCBORMajorType The CBOR major type to convert. - * @retturns QCBOR type number. - * - * This only works for the two string types. - */ -static inline uint8_t ConvertStringMajorTypes(int nCBORMajorType) -{ - #if CBOR_MAJOR_TYPE_BYTE_STRING + 4 != QCBOR_TYPE_BYTE_STRING - #error QCBOR_TYPE_BYTE_STRING no lined up with major type - #endif - - #if CBOR_MAJOR_TYPE_TEXT_STRING + 4 != QCBOR_TYPE_TEXT_STRING - #error QCBOR_TYPE_TEXT_STRING no lined up with major type - #endif - - return (uint8_t)(nCBORMajorType + 4); -} - - -/** - * @brief Map the CBOR major types for arrays/maps to the QCBOR types. - * - * @param[in] nCBORMajorType The CBOR major type to convert. - * @retturns QCBOR type number. - * - * This only works for the two aggregate types. - */ -static inline uint8_t ConvertArrayOrMapType(int nCBORMajorType) -{ - #if QCBOR_TYPE_ARRAY != CBOR_MAJOR_TYPE_ARRAY - #error QCBOR_TYPE_ARRAY value not lined up with major type - #endif - - #if QCBOR_TYPE_MAP != CBOR_MAJOR_TYPE_MAP - #error QCBOR_TYPE_MAP value not lined up with major type - #endif - - return (uint8_t)(nCBORMajorType); -} - - /** * @brief Decode a single primitive data item (decode layer 6). * - * @param[in] pUInBuf Input buffer to read data item from. - * @param[out] pDecodedItem The filled-in decoded item. - * @param[in] pAllocator The allocator to use for strings or NULL. - * - * @retval QCBOR_ERR_UNSUPPORTED - * @retval QCBOR_ERR_HIT_END - * @retval QCBOR_ERR_INT_OVERFLOW - * @retval QCBOR_ERR_STRING_ALLOCATE - * @retval QCBOR_ERR_STRING_TOO_LONG - * @retval QCBOR_ERR_HALF_PRECISION_DISABLED - * @retval QCBOR_ERR_ALL_FLOAT_DISABLED - * @retval QCBOR_ERR_BAD_TYPE_7 - * @retval QCBOR_ERR_INDEF_LEN_ARRAYS_DISABLED - * - * This decodes the most primitive / atomic data item. It does - * no combing of data items. + * @param[in] pMe Decoder context. + * @param[in] bAllocateStrings If true, use allocator for strings. + * @param[out] pDecodedItem The filled-in decoded item. + * + * @retval QCBOR_ERR_UNSUPPORTED Encountered unsupported/reserved + * features + * @retval QCBOR_ERR_HIT_END Unexpected end of input + * @retval QCBOR_ERR_INT_OVERFLOW Too-large negative encountered + * @retval QCBOR_ERR_STRING_ALLOCATE Out of memory. + * @retval QCBOR_ERR_STRING_TOO_LONG String longer than SIZE_MAX - 4. + * @retval QCBOR_ERR_NO_STRING_ALLOCATOR Allocation requested, but no allocator + * @retval QCBOR_ERR_HALF_PRECISION_DISABLED Half-precision in input, but decode + * of half-precision disabled + * @retval QCBOR_ERR_ALL_FLOAT_DISABLED Float-point in input, but all + * float decode is disabled. + * @retval QCBOR_ERR_BAD_TYPE_7 Not-allowed representation of + * simple type in input. + * @retval QCBOR_ERR_INDEF_LEN_ARRAYS_DISABLED Indefinite length map/array + * in input, but indefinite + * lengths disabled. + * @retval QCBOR_ERR_BAD_INT nAdditionalInfo indicated indefinte. + * @retval QCBOR_ERR_ARRAY_DECODE_TOO_LONG Too many items in array/map. + * @retval QCBOR_ERR_TAGS_DISABLED QCBOR_DISABLE_TAGS is defined. + * + * This decodes the most primitive/atomic data item. It does no + * combining of data items. */ static QCBORError -DecodeAtomicDataItem(UsefulInputBuf *pUInBuf, - QCBORItem *pDecodedItem, - const QCBORInternalAllocator *pAllocator) +QCBOR_Private_DecodeAtomicDataItem(QCBORDecodeContext *pMe, + const bool bAllocateStrings, + QCBORItem *pDecodedItem) { QCBORError uReturn; - - /* Get the major type and the argument. The argument could be - * length of more bytes or the value depending on the major - * type. nAdditionalInfo is an encoding of the length of the - * uNumber and is needed to decode floats and doubles. - */ - int nMajorType = 0; - uint64_t uArgument = 0; - int nAdditionalInfo = 0; + int nMajorType = 0; + uint64_t uArgument = 0; + int nAdditionalInfo = 0; memset(pDecodedItem, 0, sizeof(QCBORItem)); - uReturn = DecodeHead(pUInBuf, &nMajorType, &uArgument, &nAdditionalInfo); - if(uReturn) { - goto Done; + /* Decode the "head" that every CBOR item has into the major type, + * argument and the additional info. + */ + uReturn = QCBOR_Private_DecodeHead(&(pMe->InBuf), &nMajorType, &uArgument, &nAdditionalInfo); + if(uReturn != QCBOR_SUCCESS) { + return uReturn; } - /* At this point the major type and the argument are valid. We've - * got the type and the argument that starts every CBOR data item. + /* All the functions below get inlined by the optimizer. This code + * is easier to read with them all being similar functions, even if + * some functions don't do much. */ switch (nMajorType) { case CBOR_MAJOR_TYPE_POSITIVE_INT: /* Major type 0 */ case CBOR_MAJOR_TYPE_NEGATIVE_INT: /* Major type 1 */ - if(nAdditionalInfo == LEN_IS_INDEFINITE) { - uReturn = QCBOR_ERR_BAD_INT; - } else { - uReturn = DecodeInteger(nMajorType, uArgument, pDecodedItem); - } + return QCBOR_Private_DecodeInteger(nMajorType, uArgument, nAdditionalInfo, pDecodedItem); break; case CBOR_MAJOR_TYPE_BYTE_STRING: /* Major type 2 */ case CBOR_MAJOR_TYPE_TEXT_STRING: /* Major type 3 */ - pDecodedItem->uDataType = ConvertStringMajorTypes(nMajorType); - if(nAdditionalInfo == LEN_IS_INDEFINITE) { - pDecodedItem->val.string = (UsefulBufC){NULL, QCBOR_STRING_LENGTH_INDEFINITE}; - } else { - uReturn = DecodeBytes(pAllocator, uArgument, pUInBuf, pDecodedItem); - } + return QCBOR_Private_DecodeString(pMe, bAllocateStrings, nMajorType, uArgument, nAdditionalInfo, pDecodedItem); break; case CBOR_MAJOR_TYPE_ARRAY: /* Major type 4 */ case CBOR_MAJOR_TYPE_MAP: /* Major type 5 */ - if(nAdditionalInfo == LEN_IS_INDEFINITE) { - /* Indefinite-length string. */ -#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS - pDecodedItem->val.uCount = QCBOR_COUNT_INDICATES_INDEFINITE_LENGTH; -#else /* QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS */ - uReturn = QCBOR_ERR_INDEF_LEN_ARRAYS_DISABLED; - break; -#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS */ - } else { - /* Definite-length string. */ - if(uArgument > QCBOR_MAX_ITEMS_IN_ARRAY) { - uReturn = QCBOR_ERR_ARRAY_DECODE_TOO_LONG; - goto Done; - } - /* cast OK because of check above */ - pDecodedItem->val.uCount = (uint16_t)uArgument; - } - pDecodedItem->uDataType = ConvertArrayOrMapType(nMajorType); + return QCBOR_Private_DecodeArrayOrMap(pMe->uDecodeMode, nMajorType, uArgument, nAdditionalInfo, pDecodedItem); break; case CBOR_MAJOR_TYPE_TAG: /* Major type 6, tag numbers */ -#ifndef QCBOR_DISABLE_TAGS - if(nAdditionalInfo == LEN_IS_INDEFINITE) { - uReturn = QCBOR_ERR_BAD_INT; - } else { - pDecodedItem->val.uTagV = uArgument; - pDecodedItem->uDataType = QCBOR_TYPE_TAG; - } -#else /* QCBOR_DISABLE_TAGS */ - uReturn = QCBOR_ERR_TAGS_DISABLED; -#endif /* QCBOR_DISABLE_TAGS */ + return QCBOR_Private_DecodeTag(uArgument, nAdditionalInfo, pDecodedItem); break; case CBOR_MAJOR_TYPE_SIMPLE: /* Major type 7: float, double, true, false, null... */ - uReturn = DecodeType7(nAdditionalInfo, uArgument, pDecodedItem); + return QCBOR_Private_DecodeType7(nAdditionalInfo, uArgument, pDecodedItem); break; default: /* Never happens because DecodeHead() should never return > 7 */ - uReturn = QCBOR_ERR_UNSUPPORTED; + return QCBOR_ERR_UNSUPPORTED; break; } - -Done: - return uReturn; } @@ -1176,18 +1367,27 @@ DecodeAtomicDataItem(UsefulInputBuf *pUInBuf, * @param[in] pMe Decoder context * @param[out] pDecodedItem The decoded item that work is done on. * - * @retval QCBOR_ERR_UNSUPPORTED - * @retval QCBOR_ERR_HIT_END - * @retval QCBOR_ERR_INT_OVERFLOW - * @retval QCBOR_ERR_STRING_ALLOCATE - * @retval QCBOR_ERR_STRING_TOO_LONG - * @retval QCBOR_ERR_HALF_PRECISION_DISABLED - * @retval QCBOR_ERR_ALL_FLOAT_DISABLED - * @retval QCBOR_ERR_BAD_TYPE_7 - * @retval QCBOR_ERR_INDEF_LEN_ARRAYS_DISABLED - * @retval QCBOR_ERR_NO_STRING_ALLOCATOR - * @retval QCBOR_ERR_INDEFINITE_STRING_CHUNK - * @retval QCBOR_ERR_INDEF_LEN_STRINGS_DISABLED + * @retval QCBOR_ERR_UNSUPPORTED Encountered unsupported/reserved + * features + * @retval QCBOR_ERR_HIT_END Unexpected end of input + * @retval QCBOR_ERR_INT_OVERFLOW Too-large negative encountered + * @retval QCBOR_ERR_STRING_ALLOCATE Out of memory. + * @retval QCBOR_ERR_STRING_TOO_LONG String longer than SIZE_MAX - 4. + * @retval QCBOR_ERR_HALF_PRECISION_DISABLED Half-precision in input, but decode + * of half-precision disabled + * @retval QCBOR_ERR_ALL_FLOAT_DISABLED Float-point in input, but all + * float decode is disabled. + * @retval QCBOR_ERR_BAD_TYPE_7 Not-allowed representation of + * simple type in input. + * @retval QCBOR_ERR_INDEF_LEN_ARRAYS_DISABLED Indefinite length map/array + * in input, but indefinite + * lengths disabled. + * @retval QCBOR_ERR_NO_STRING_ALLOCATOR Indefinite-length string in input, + * but no string allocator. + * @retval QCBOR_ERR_INDEFINITE_STRING_CHUNK Error in indefinite-length string. + * @retval QCBOR_ERR_INDEF_LEN_STRINGS_DISABLED Indefinite-length string in + * input, but indefinite-length + * strings are disabled. * * If @c pDecodedItem is not an indefinite-length string, this does nothing. * @@ -1198,8 +1398,9 @@ DecodeAtomicDataItem(UsefulInputBuf *pUInBuf, * * Code Reviewers: THIS FUNCTION DOES A LITTLE POINTER MATH */ -static inline QCBORError -QCBORDecode_GetNextFullString(QCBORDecodeContext *pMe, QCBORItem *pDecodedItem) +static QCBORError +QCBORDecode_Private_GetNextFullString(QCBORDecodeContext *pMe, + QCBORItem *pDecodedItem) { /* Aproximate stack usage * 64-bit 32-bit @@ -1208,57 +1409,53 @@ QCBORDecode_GetNextFullString(QCBORDecodeContext *pMe, QCBORItem *pDecodedItem) * QCBORItem 56 52 * TOTAL 120 74 */ + QCBORError uReturn; - /* The string allocator is used here for two purposes: 1) - * coalescing the chunks of an indefinite-length string, 2) - * allocating storage for every string returned when requested. - * - * The first use is below in this function. Indefinite-length - * strings cannot be processed at all without a string allocator. - * - * The second used is in DecodeBytes() which is called by - * GetNext_Item() below. This second use unneccessary for most use - * and only happens when requested in the call to - * QCBORDecode_SetMemPool(). If the second use not requested then - * NULL is passed for the string allocator to GetNext_Item(). - * - * QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS disables the string - * allocator altogether and thus both of these uses. It reduced the - * decoder object code by about 400 bytes. + /* A note about string allocation -- Memory for strings is + * allocated either because 1) indefinte-length string chunks are + * being coalecsed or 2) caller has requested all strings be + * allocated. The first case is handed below here. The second case + * is handled in DecodeString if the bAllocate is true. That + * boolean originates here with pMe->bStringAllocateAll immediately + * below. That is, QCBOR_Private_DecodeAtomicDataItem() is called + * in two different contexts here 1) main-line processing which is + * where definite-length strings need to be allocated if + * bStringAllocateAll is true and 2) processing chunks of + * indefinite-lengths strings in in which case there must be no + * allocation. */ - const QCBORInternalAllocator *pAllocatorForGetNext = NULL; -#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS - const QCBORInternalAllocator *pAllocator = NULL; - if(pMe->StringAllocator.pfAllocator) { - pAllocator = &(pMe->StringAllocator); - if(pMe->bStringAllocateAll) { - pAllocatorForGetNext = pAllocator; - } + uReturn = QCBOR_Private_DecodeAtomicDataItem(pMe, pMe->bStringAllocateAll, pDecodedItem); + if(uReturn != QCBOR_SUCCESS) { + goto Done; } -#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS */ - QCBORError uReturn; - uReturn = DecodeAtomicDataItem(&(pMe->InBuf), pDecodedItem, pAllocatorForGetNext); - if(uReturn != QCBOR_SUCCESS) { + + /* This is where out-of-place break is detected for the whole + * decoding stack. Break is an error for everything that calls + * QCBORDecode_Private_GetNextFullString(), so the check is + * centralized here. + */ + if(pDecodedItem->uDataType == QCBOR_TYPE_BREAK) { + uReturn = QCBOR_ERR_BAD_BREAK; goto Done; } - /* Only do indefinite-length processing on strings */ + + /* Skip out if not an indefinite-length string */ const uint8_t uStringType = pDecodedItem->uDataType; - if(uStringType!= QCBOR_TYPE_BYTE_STRING && uStringType != QCBOR_TYPE_TEXT_STRING) { + if(uStringType != QCBOR_TYPE_BYTE_STRING && + uStringType != QCBOR_TYPE_TEXT_STRING) { goto Done; } - - /* Is this a string with an indefinite length? */ if(pDecodedItem->val.string.len != QCBOR_STRING_LENGTH_INDEFINITE) { goto Done; } #ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS /* Can't decode indefinite-length strings without a string allocator */ - if(pAllocator == NULL) { + if(!pMe->StringAllocator.pfAllocator) { uReturn = QCBOR_ERR_NO_STRING_ALLOCATOR; goto Done; } @@ -1269,12 +1466,12 @@ QCBORDecode_GetNextFullString(QCBORDecodeContext *pMe, QCBORItem *pDecodedItem) for(;;) { /* Get QCBORItem for next chunk */ QCBORItem StringChunkItem; - /* Pass a NULL string allocator to GetNext_Item() because the - * individual string chunks in an indefinite-length should not - * be allocated. They are always copied in the the contiguous - * buffer allocated here. + /* Pass false to DecodeAtomicDataItem() because the individual + * string chunks in an indefinite-length must not be + * allocated. They are always copied into the allocated + * contiguous buffer allocated here. */ - uReturn = DecodeAtomicDataItem(&(pMe->InBuf), &StringChunkItem, NULL); + uReturn = QCBOR_Private_DecodeAtomicDataItem(pMe, false, &StringChunkItem); if(uReturn) { break; } @@ -1303,15 +1500,14 @@ QCBORDecode_GetNextFullString(QCBORDecodeContext *pMe, QCBORItem *pDecodedItem) * equivalent to StringAllocator_Allocate(). Subsequently it is * not NULL and a reallocation happens. */ - UsefulBuf NewMem = StringAllocator_Reallocate(pAllocator, + UsefulBuf NewMem = StringAllocator_Reallocate(&(pMe->StringAllocator), FullString.ptr, FullString.len + StringChunkItem.val.string.len); - if(UsefulBuf_IsNULL(NewMem)) { uReturn = QCBOR_ERR_STRING_ALLOCATE; break; } - + /* Copy new string chunk to the end of accumulated string */ FullString = UsefulBuf_CopyOffset(NewMem, FullString.len, StringChunkItem.val.string); } @@ -1319,7 +1515,7 @@ QCBORDecode_GetNextFullString(QCBORDecodeContext *pMe, QCBORItem *pDecodedItem) if(uReturn != QCBOR_SUCCESS && !UsefulBuf_IsNULLC(FullString)) { /* Getting the item failed, clean up the allocated memory */ - StringAllocator_Free(pAllocator, FullString.ptr); + StringAllocator_Free(&(pMe->StringAllocator), FullString.ptr); } #else /* QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS */ uReturn = QCBOR_ERR_INDEF_LEN_STRINGS_DISABLED; @@ -1349,8 +1545,10 @@ QCBORDecode_GetNextFullString(QCBORDecodeContext *pMe, QCBORItem *pDecodedItem) * * See also UnMapTagNumber() and @ref QCBORItem. */ -static inline QCBORError -MapTagNumber(QCBORDecodeContext *pMe, uint64_t uUnMappedTag, uint16_t *puMappedTagNumer) +static QCBORError +QCBORDecode_Private_MapTagNumber(QCBORDecodeContext *pMe, + const uint64_t uUnMappedTag, + uint16_t *puMappedTagNumer) { if(uUnMappedTag > QCBOR_LAST_UNMAPPED_TAG) { unsigned uTagMapIndex; @@ -1391,7 +1589,8 @@ MapTagNumber(QCBORDecodeContext *pMe, uint64_t uUnMappedTag, uint16_t *puMappedT * This is the reverse of MapTagNumber() */ static uint64_t -UnMapTagNumber(const QCBORDecodeContext *pMe, uint16_t uMappedTagNumber) +QCBORDecode_Private_UnMapTagNumber(const QCBORDecodeContext *pMe, + const uint16_t uMappedTagNumber) { if(uMappedTagNumber <= QCBOR_LAST_UNMAPPED_TAG) { return uMappedTagNumber; @@ -1413,27 +1612,37 @@ UnMapTagNumber(const QCBORDecodeContext *pMe, uint16_t uMappedTagNumber) * * @param[in] pMe Decoder context * @param[out] pDecodedItem The decoded item that work is done on. - - * @retval QCBOR_ERR_UNSUPPORTED - * @retval QCBOR_ERR_HIT_END - * @retval QCBOR_ERR_INT_OVERFLOW - * @retval QCBOR_ERR_STRING_ALLOCATE - * @retval QCBOR_ERR_STRING_TOO_LONG - * @retval QCBOR_ERR_HALF_PRECISION_DISABLED - * @retval QCBOR_ERR_ALL_FLOAT_DISABLED - * @retval QCBOR_ERR_BAD_TYPE_7 - * @retval QCBOR_ERR_INDEF_LEN_ARRAYS_DISABLED - * @retval QCBOR_ERR_NO_STRING_ALLOCATOR - * @retval QCBOR_ERR_INDEFINITE_STRING_CHUNK - * @retval QCBOR_ERR_INDEF_LEN_STRINGS_DISABLED - * @retval QCBOR_ERR_TOO_MANY_TAGS + * + * @retval QCBOR_ERR_UNSUPPORTED Encountered unsupported/reserved + * features + * @retval QCBOR_ERR_HIT_END Unexpected end of input + * @retval QCBOR_ERR_INT_OVERFLOW Too-large negative encountered + * @retval QCBOR_ERR_STRING_ALLOCATE Out of memory. + * @retval QCBOR_ERR_STRING_TOO_LONG String longer than SIZE_MAX - 4. + * @retval QCBOR_ERR_HALF_PRECISION_DISABLED Half-precision in input, but decode + * of half-precision disabled + * @retval QCBOR_ERR_ALL_FLOAT_DISABLED Float-point in input, but all + * float decode is disabled. + * @retval QCBOR_ERR_BAD_TYPE_7 Not-allowed representation of + * simple type in input. + * @retval QCBOR_ERR_INDEF_LEN_ARRAYS_DISABLED Indefinite length map/array + * in input, but indefinite + * lengths disabled. + * @retval QCBOR_ERR_NO_STRING_ALLOCATOR Indefinite-length string in input, + * but no string allocator. + * @retval QCBOR_ERR_INDEFINITE_STRING_CHUNK Error in indefinite-length string. + * @retval QCBOR_ERR_INDEF_LEN_STRINGS_DISABLED Indefinite-length string in + * input, but indefinite-length + * strings are disabled. + * @retval QCBOR_ERR_TOO_MANY_TAGS Too many tag numbers on item. * * This loops getting atomic data items until one is not a tag * number. Usually this is largely pass-through because most * item are not tag numbers. */ static QCBORError -QCBORDecode_GetNextTagNumber(QCBORDecodeContext *pMe, QCBORItem *pDecodedItem) +QCBORDecode_Private_GetNextTagNumber(QCBORDecodeContext *pMe, + QCBORItem *pDecodedItem) { #ifndef QCBOR_DISABLE_TAGS /* Accummulate the tags from multiple items here and then copy them @@ -1452,7 +1661,7 @@ QCBORDecode_GetNextTagNumber(QCBORDecodeContext *pMe, QCBORItem *pDecodedItem) /* Loop fetching data items until the item fetched is not a tag */ for(;;) { - QCBORError uErr = QCBORDecode_GetNextFullString(pMe, pDecodedItem); + QCBORError uErr = QCBORDecode_Private_GetNextFullString(pMe, pDecodedItem); if(uErr != QCBOR_SUCCESS) { uReturn = uErr; goto Done; @@ -1484,7 +1693,7 @@ QCBORDecode_GetNextTagNumber(QCBORDecodeContext *pMe, QCBORItem *pDecodedItem) /* Map the tag */ uint16_t uMappedTagNumber = 0; - uReturn = MapTagNumber(pMe, pDecodedItem->val.uTagV, &uMappedTagNumber); + uReturn = QCBORDecode_Private_MapTagNumber(pMe, pDecodedItem->val.uTagV, &uMappedTagNumber); /* Continue even on error so as to consume all tags wrapping * this data item so decoding can go on. If MapTagNumber() * errors once it will continue to error. @@ -1497,119 +1706,120 @@ QCBORDecode_GetNextTagNumber(QCBORDecodeContext *pMe, QCBORItem *pDecodedItem) #else /* QCBOR_DISABLE_TAGS */ - return QCBORDecode_GetNextFullString(pMe, pDecodedItem); + return QCBORDecode_Private_GetNextFullString(pMe, pDecodedItem); #endif /* QCBOR_DISABLE_TAGS */ } + /** * @brief Combine a map entry label and value into one item (decode layer 3). * * @param[in] pMe Decoder context * @param[out] pDecodedItem The decoded item that work is done on. * - * @retval QCBOR_ERR_UNSUPPORTED - * @retval QCBOR_ERR_HIT_END - * @retval QCBOR_ERR_INT_OVERFLOW - * @retval QCBOR_ERR_STRING_ALLOCATE - * @retval QCBOR_ERR_STRING_TOO_LONG - * @retval QCBOR_ERR_HALF_PRECISION_DISABLED - * @retval QCBOR_ERR_ALL_FLOAT_DISABLED - * @retval QCBOR_ERR_BAD_TYPE_7 - * @retval QCBOR_ERR_INDEF_LEN_ARRAYS_DISABLED - * @retval QCBOR_ERR_NO_STRING_ALLOCATOR - * @retval QCBOR_ERR_INDEFINITE_STRING_CHUNK - * @retval QCBOR_ERR_INDEF_LEN_STRINGS_DISABLED - * @retval QCBOR_ERR_TOO_MANY_TAGS - * @retval QCBOR_ERR_ARRAY_DECODE_TOO_LONG - * @retval QCBOR_ERR_MAP_LABEL_TYPE - * - * If a the current nesting level is a map, then this - * combines pairs of items into one data item with a label - * and value. - * - * This is passthrough if the current nesting level is - * not a map. - * - * This also implements maps-as-array mode where a map - * is treated like an array to allow caller to do their - * own label processing. - */ -static inline QCBORError -QCBORDecode_GetNextMapEntry(QCBORDecodeContext *pMe, QCBORItem *pDecodedItem) -{ - QCBORError uReturn = QCBORDecode_GetNextTagNumber(pMe, pDecodedItem); - if(uReturn != QCBOR_SUCCESS) { + * @retval QCBOR_ERR_UNSUPPORTED Encountered unsupported/reserved + * features + * @retval QCBOR_ERR_HIT_END Unexpected end of input + * @retval QCBOR_ERR_INT_OVERFLOW Too-large negative encountered + * @retval QCBOR_ERR_STRING_ALLOCATE Out of memory. + * @retval QCBOR_ERR_STRING_TOO_LONG String longer than SIZE_MAX - 4. + * @retval QCBOR_ERR_HALF_PRECISION_DISABLED Half-precision in input, but decode + * of half-precision disabled + * @retval QCBOR_ERR_ALL_FLOAT_DISABLED Float-point in input, but all + * float decode is disabled. + * @retval QCBOR_ERR_BAD_TYPE_7 Not-allowed representation of + * simple type in input. + * @retval QCBOR_ERR_INDEF_LEN_ARRAYS_DISABLED Indefinite length map/array + * in input, but indefinite + * lengths disabled. + * @retval QCBOR_ERR_NO_STRING_ALLOCATOR Indefinite-length string in input, + * but no string allocator. + * @retval QCBOR_ERR_INDEFINITE_STRING_CHUNK Error in indefinite-length string. + * @retval QCBOR_ERR_INDEF_LEN_STRINGS_DISABLED Indefinite-length string in + * input, but indefinite-length + * strings are disabled. + * @retval QCBOR_ERR_TOO_MANY_TAGS Too many tag numbers on item. + * @retval QCBOR_ERR_ARRAY_DECODE_TOO_LONG Too many items in array. + * @retval QCBOR_ERR_MAP_LABEL_TYPE Map label not string or integer. + * + * If the current nesting level is a map, then this combines pairs of + * items into one data item with a label and value. + * + * This is passthrough if the current nesting level is not a map. + * + * This also implements maps-as-array mode where a map is treated like + * an array to allow caller to do their own label processing. + */ + +static QCBORError +QCBORDecode_Private_GetNextMapEntry(QCBORDecodeContext *pMe, + QCBORItem *pDecodedItem) +{ + QCBORItem LabelItem; + QCBORError uErr; + + uErr = QCBORDecode_Private_GetNextTagNumber(pMe, pDecodedItem); + if(QCBORDecode_IsUnrecoverableError(uErr)) { goto Done; } - if(pDecodedItem->uDataType == QCBOR_TYPE_BREAK) { - /* Break can't be a map entry */ + if(!DecodeNesting_IsCurrentTypeMap(&(pMe->nesting))) { + /* Not decoding a map. Nothing to do. */ + /* When decoding maps-as-arrays, the type will be + * QCBOR_TYPE_MAP_AS_ARRAY and this function will exit + * here. This is now map processing for maps-as-arrays is not + * done. */ goto Done; } - if(pMe->uDecodeMode != QCBOR_DECODE_MODE_MAP_AS_ARRAY) { - /* Normal decoding of maps -- combine label and value into one item. */ + /* Decoding a map entry, so the item decoded above was the label */ + LabelItem = *pDecodedItem; - if(DecodeNesting_IsCurrentTypeMap(&(pMe->nesting))) { - /* Save label in pDecodedItem and get the next which will - * be the real data item. - */ - QCBORItem LabelItem = *pDecodedItem; - uReturn = QCBORDecode_GetNextTagNumber(pMe, pDecodedItem); - if(QCBORDecode_IsUnrecoverableError(uReturn)) { - goto Done; - } + /* Get the value of the map item */ + uErr = QCBORDecode_Private_GetNextTagNumber(pMe, pDecodedItem); + if(QCBORDecode_IsUnrecoverableError(uErr)) { + goto Done; + } - pDecodedItem->uLabelAlloc = LabelItem.uDataAlloc; + /* Combine the label item and value item into one */ + pDecodedItem->uLabelAlloc = LabelItem.uDataAlloc; + pDecodedItem->uLabelType = LabelItem.uDataType; - if(LabelItem.uDataType == QCBOR_TYPE_TEXT_STRING) { - /* strings are always good labels */ - pDecodedItem->label.string = LabelItem.val.string; - pDecodedItem->uLabelType = QCBOR_TYPE_TEXT_STRING; - } else if (QCBOR_DECODE_MODE_MAP_STRINGS_ONLY == pMe->uDecodeMode) { - /* It's not a string and we only want strings */ - uReturn = QCBOR_ERR_MAP_LABEL_TYPE; - goto Done; - } else if(LabelItem.uDataType == QCBOR_TYPE_INT64) { - pDecodedItem->label.int64 = LabelItem.val.int64; - pDecodedItem->uLabelType = QCBOR_TYPE_INT64; - } else if(LabelItem.uDataType == QCBOR_TYPE_UINT64) { - pDecodedItem->label.uint64 = LabelItem.val.uint64; - pDecodedItem->uLabelType = QCBOR_TYPE_UINT64; - } else if(LabelItem.uDataType == QCBOR_TYPE_BYTE_STRING) { - pDecodedItem->label.string = LabelItem.val.string; - pDecodedItem->uLabelAlloc = LabelItem.uDataAlloc; - pDecodedItem->uLabelType = QCBOR_TYPE_BYTE_STRING; - } else { - /* label is not an int or a string. It is an arrray - * or a float or such and this implementation doesn't handle that. - * Also, tags on labels are ignored. - */ - uReturn = QCBOR_ERR_MAP_LABEL_TYPE; - goto Done; - } - } - } else { - /* Decoding of maps as arrays to let the caller decide what to do - * about labels, particularly lables that are not integers or - * strings. - */ - if(pDecodedItem->uDataType == QCBOR_TYPE_MAP) { - if(pDecodedItem->val.uCount > QCBOR_MAX_ITEMS_IN_ARRAY/2) { - uReturn = QCBOR_ERR_ARRAY_DECODE_TOO_LONG; - goto Done; - } - pDecodedItem->uDataType = QCBOR_TYPE_MAP_AS_ARRAY; - /* Cast is safe because of check against QCBOR_MAX_ITEMS_IN_ARRAY/2. - * Cast is needed because of integer promotion. - */ - pDecodedItem->val.uCount = (uint16_t)(pDecodedItem->val.uCount * 2); - } +#ifndef QCBOR_DISABLE_NON_INTEGER_LABELS + /* QCBOR_DECODE_MODE_MAP_STRINGS_ONLY might have been a bad idea. Maybe + * get rid of it in QCBOR 2.0 + */ + if(pMe->uDecodeMode == QCBOR_DECODE_MODE_MAP_STRINGS_ONLY && + LabelItem.uDataType != QCBOR_TYPE_TEXT_STRING) { + uErr = QCBOR_ERR_MAP_LABEL_TYPE; + goto Done; + } +#endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */ + + switch(LabelItem.uDataType) { + case QCBOR_TYPE_INT64: + pDecodedItem->label.int64 = LabelItem.val.int64; + break; + +#ifndef QCBOR_DISABLE_NON_INTEGER_LABELS + case QCBOR_TYPE_UINT64: + pDecodedItem->label.uint64 = LabelItem.val.uint64; + break; + + case QCBOR_TYPE_TEXT_STRING: + case QCBOR_TYPE_BYTE_STRING: + pDecodedItem->label.string = LabelItem.val.string; + break; +#endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */ + + default: + uErr = QCBOR_ERR_MAP_LABEL_TYPE; + goto Done; } Done: - return uReturn; + return uErr; } @@ -1617,7 +1827,7 @@ QCBORDecode_GetNextMapEntry(QCBORDecodeContext *pMe, QCBORItem *pDecodedItem) /** * @brief Peek and see if next data item is a break; * - * @param[in] pUIB UsefulInputBuf to read from. + * param[in] pUIB UsefulInputBuf to read from. * @param[out] pbNextIsBreak Indicate if next was a break or not. * * @return Any decoding error. @@ -1625,20 +1835,20 @@ QCBORDecode_GetNextMapEntry(QCBORDecodeContext *pMe, QCBORItem *pDecodedItem) * See if next item is a CBOR break. If it is, it is consumed, * if not it is not consumed. */ -static inline QCBORError -NextIsBreak(UsefulInputBuf *pUIB, bool *pbNextIsBreak) +static QCBORError +QCBOR_Private_NextIsBreak(QCBORDecodeContext *pMe, bool *pbNextIsBreak) { *pbNextIsBreak = false; - if(UsefulInputBuf_BytesUnconsumed(pUIB) != 0) { + if(UsefulInputBuf_BytesUnconsumed(&(pMe->InBuf)) != 0) { QCBORItem Peek; - size_t uPeek = UsefulInputBuf_Tell(pUIB); - QCBORError uReturn = DecodeAtomicDataItem(pUIB, &Peek, NULL); + size_t uPeek = UsefulInputBuf_Tell(&(pMe->InBuf)); + QCBORError uReturn = QCBOR_Private_DecodeAtomicDataItem(pMe, false, &Peek); if(uReturn != QCBOR_SUCCESS) { return uReturn; } if(Peek.uDataType != QCBOR_TYPE_BREAK) { /* It is not a break, rewind so it can be processed normally. */ - UsefulInputBuf_Seek(pUIB, uPeek); + UsefulInputBuf_Seek(&(pMe->InBuf), uPeek); } else { *pbNextIsBreak = true; } @@ -1654,18 +1864,30 @@ NextIsBreak(UsefulInputBuf *pUIB, bool *pbNextIsBreak) * * @param[in] pMe The decode context. * @param[in] bMarkEnd If true mark end of maps/arrays with count of zero. + * @param[out] pbBreak Set to true if extra break was consumed. * * An item was just consumed, now figure out if it was the * end of an array/map map that can be closed out. That * may in turn close out the above array/map... -*/ + * + * When ascending indefinite-length arrays and maps, this will correctly + * consume the break for the level above. This is a problem for the + * implementation of QCBORDecode_GetArray() that must not return + * that break. @c pbBreak is set to true to indicate that one + * byte should be removed. + * + * Improvement: this could reduced further if indef is disabled + */ static QCBORError -QCBORDecode_NestLevelAscender(QCBORDecodeContext *pMe, bool bMarkEnd) +QCBORDecode_Private_NestLevelAscender(QCBORDecodeContext *pMe, bool bMarkEnd, bool *pbBreak) { QCBORError uReturn; /* Loop ascending nesting levels as long as there is ascending to do */ while(!DecodeNesting_IsCurrentAtTop(&(pMe->nesting))) { + if(pbBreak) { + *pbBreak = false; + } if(DecodeNesting_IsCurrentBstrWrapped(&(pMe->nesting))) { /* Nesting level is bstr-wrapped CBOR */ @@ -1694,7 +1916,7 @@ QCBORDecode_NestLevelAscender(QCBORDecodeContext *pMe, bool bMarkEnd) /* Check for a break which is what ends indefinite-length arrays/maps */ bool bIsBreak = false; - uReturn = NextIsBreak(&(pMe->InBuf), &bIsBreak); + uReturn = QCBOR_Private_NextIsBreak(pMe, &bIsBreak); if(uReturn != QCBOR_SUCCESS) { goto Done; } @@ -1707,6 +1929,9 @@ QCBORDecode_NestLevelAscender(QCBORDecodeContext *pMe, bool bMarkEnd) /* It was a break in an indefinitelength map / array so * it is time to ascend one level. */ + if(pbBreak) { + *pbBreak = true; + } #endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS */ } @@ -1746,26 +1971,38 @@ QCBORDecode_NestLevelAscender(QCBORDecodeContext *pMe, bool bMarkEnd) * @brief Ascending & Descending out of nesting levels (decode layer 2). * * @param[in] pMe Decoder context + * @param[out] pbBreak Set to true if extra break was consumed. * @param[out] pDecodedItem The decoded item that work is done on. - * - * @retval QCBOR_ERR_UNSUPPORTED - * @retval QCBOR_ERR_HIT_END - * @retval QCBOR_ERR_INT_OVERFLOW - * @retval QCBOR_ERR_STRING_ALLOCATE - * @retval QCBOR_ERR_STRING_TOO_LONG - * @retval QCBOR_ERR_HALF_PRECISION_DISABLED - * @retval QCBOR_ERR_ALL_FLOAT_DISABLED - * @retval QCBOR_ERR_BAD_TYPE_7 - * @retval QCBOR_ERR_INDEF_LEN_ARRAYS_DISABLED - * @retval QCBOR_ERR_NO_STRING_ALLOCATOR - * @retval QCBOR_ERR_INDEFINITE_STRING_CHUNK - * @retval QCBOR_ERR_INDEF_LEN_STRINGS_DISABLED - * @retval QCBOR_ERR_TOO_MANY_TAGS - * @retval QCBOR_ERR_ARRAY_DECODE_TOO_LONG - * @retval QCBOR_ERR_MAP_LABEL_TYPE - * @retval QCBOR_ERR_NO_MORE_ITEMS - * @retval QCBOR_ERR_BAD_BREAK - * @retval QCBOR_ERR_ARRAY_DECODE_NESTING_TOO_DEEP + + * @retval QCBOR_ERR_UNSUPPORTED Encountered unsupported/reserved + * features + * @retval QCBOR_ERR_HIT_END Unexpected end of input + * @retval QCBOR_ERR_INT_OVERFLOW Too-large negative encountered + * @retval QCBOR_ERR_STRING_ALLOCATE Out of memory. + * @retval QCBOR_ERR_STRING_TOO_LONG String longer than SIZE_MAX - 4. + * @retval QCBOR_ERR_HALF_PRECISION_DISABLED Half-precision in input, but decode + * of half-precision disabled + * @retval QCBOR_ERR_ALL_FLOAT_DISABLED Float-point in input, but all + * float decode is disabled. + * @retval QCBOR_ERR_BAD_TYPE_7 Not-allowed representation of + * simple type in input. + * @retval QCBOR_ERR_INDEF_LEN_ARRAYS_DISABLED Indefinite length map/array + * in input, but indefinite + * lengths disabled. + * @retval QCBOR_ERR_NO_STRING_ALLOCATOR Indefinite-length string in input, + * but no string allocator. + * @retval QCBOR_ERR_INDEFINITE_STRING_CHUNK Error in indefinite-length string. + * @retval QCBOR_ERR_INDEF_LEN_STRINGS_DISABLED Indefinite-length string in + * input, but indefinite-length + * strings are disabled. + * @retval QCBOR_ERR_TOO_MANY_TAGS Too many tag numbers on item. + * @retval QCBOR_ERR_ARRAY_DECODE_TOO_LONG Too many items in array. + * @retval QCBOR_ERR_MAP_LABEL_TYPE Map label not string or integer. + * @retval QCBOR_ERR_NO_MORE_ITEMS Need more items for map or array. + * @retval QCBOR_ERR_BAD_BREAK Indefinite-length break in wrong + * place. + * @retval QCBOR_ERR_ARRAY_DECODE_NESTING_TOO_DEEP Nesting deeper than QCBOR + * can handle. * * This handles the traversal descending into and asecnding out of * maps, arrays and bstr-wrapped CBOR. It figures out the ends of @@ -1774,7 +2011,9 @@ QCBORDecode_NestLevelAscender(QCBORDecodeContext *pMe, bool bMarkEnd) * top-level sequence and of bstr-wrapped CBOR by byte count. */ static QCBORError -QCBORDecode_GetNextMapOrArray(QCBORDecodeContext *pMe, QCBORItem *pDecodedItem) +QCBORDecode_Private_GetNextMapOrArray(QCBORDecodeContext *pMe, + bool *pbBreak, + QCBORItem *pDecodedItem) { QCBORError uReturn; /* ==== First: figure out if at the end of a traversal ==== */ @@ -1802,20 +2041,12 @@ QCBORDecode_GetNextMapOrArray(QCBORDecodeContext *pMe, QCBORItem *pDecodedItem) } /* ==== Next: not at the end, so get another item ==== */ - uReturn = QCBORDecode_GetNextMapEntry(pMe, pDecodedItem); + uReturn = QCBORDecode_Private_GetNextMapEntry(pMe, pDecodedItem); if(QCBORDecode_IsUnrecoverableError(uReturn)) { /* Error is so bad that traversal is not possible. */ goto Done; } - /* Breaks ending arrays/maps are processed later in the call to - * QCBORDecode_NestLevelAscender(). They should never show up here. - */ - if(pDecodedItem->uDataType == QCBOR_TYPE_BREAK) { - uReturn = QCBOR_ERR_BAD_BREAK; - goto Done; - } - /* Record the nesting level for this data item before processing * any of decrementing and descending. */ @@ -1823,7 +2054,7 @@ QCBORDecode_GetNextMapOrArray(QCBORDecodeContext *pMe, QCBORItem *pDecodedItem) /* ==== Next: Process the item for descent, ascent, decrement... ==== */ - if(QCBORItem_IsMapOrArray(pDecodedItem)) { + if(QCBORItem_IsMapOrArray(*pDecodedItem)) { /* If the new item is a map or array, descend. * * Empty indefinite-length maps and arrays are descended into, @@ -1837,8 +2068,8 @@ QCBORDecode_GetNextMapOrArray(QCBORDecodeContext *pMe, QCBORItem *pDecodedItem) */ QCBORError uDescendErr; uDescendErr = DecodeNesting_DescendMapOrArray(&(pMe->nesting), - pDecodedItem->uDataType, - pDecodedItem->val.uCount); + pDecodedItem->uDataType, + pDecodedItem->val.uCount); if(uDescendErr != QCBOR_SUCCESS) { /* This error is probably a traversal error and it overrides * the non-traversal error. @@ -1848,9 +2079,9 @@ QCBORDecode_GetNextMapOrArray(QCBORDecodeContext *pMe, QCBORItem *pDecodedItem) } } - if(!QCBORItem_IsMapOrArray(pDecodedItem) || - QCBORItem_IsEmptyDefiniteLengthMapOrArray(pDecodedItem) || - QCBORItem_IsIndefiniteLengthMapOrArray(pDecodedItem)) { + if(!QCBORItem_IsMapOrArray(*pDecodedItem) || + QCBORItem_IsEmptyDefiniteLengthMapOrArray(*pDecodedItem) || + QCBORItem_IsIndefiniteLengthMapOrArray(*pDecodedItem)) { /* The following cases are handled here: * - A non-aggregate item like an integer or string * - An empty definite-length map or array @@ -1863,7 +2094,7 @@ QCBORDecode_GetNextMapOrArray(QCBORDecodeContext *pMe, QCBORItem *pDecodedItem) * to the top level. */ QCBORError uAscendErr; - uAscendErr = QCBORDecode_NestLevelAscender(pMe, true); + uAscendErr = QCBORDecode_Private_NestLevelAscender(pMe, true, pbBreak); if(uAscendErr != QCBOR_SUCCESS) { /* This error is probably a traversal error and it overrides * the non-traversal error. @@ -1897,28 +2128,32 @@ QCBORDecode_GetNextMapOrArray(QCBORDecodeContext *pMe, QCBORItem *pDecodedItem) * * pDecodedItem[in,out] The data item to convert. * - * The 0th tag is discarded. \ref CBOR_TAG_INVALID16 is + * The 0th tag is discarded. @ref CBOR_TAG_INVALID16 is * shifted into empty slot at the end of the tag list. */ -static inline void ShiftTags(QCBORItem *pDecodedItem) +static void +QCBOR_Private_ShiftTags(QCBORItem *pDecodedItem) { for(int i = 0; i < QCBOR_MAX_TAGS_PER_ITEM-1; i++) { pDecodedItem->uTags[i] = pDecodedItem->uTags[i+1]; } pDecodedItem->uTags[QCBOR_MAX_TAGS_PER_ITEM-1] = CBOR_TAG_INVALID16; } - #endif /* QCBOR_DISABLE_TAGS */ + /** * @brief Convert different epoch date formats in to the QCBOR epoch date format * * pDecodedItem[in,out] The data item to convert. * - * @retval QCBOR_ERR_DATE_OVERFLOW - * @retval QCBOR_ERR_FLOAT_DATE_DISABLED - * @retval QCBOR_ERR_ALL_FLOAT_DISABLED - * @retval QCBOR_ERR_UNRECOVERABLE_TAG_CONTENT + * @retval QCBOR_ERR_DATE_OVERFLOW 65-bit negative integer. + * @retval QCBOR_ERR_FLOAT_DATE_DISABLED Float-point date in input, + * floating-point date disabled. + * @retval QCBOR_ERR_ALL_FLOAT_DISABLED Float-point date in input, + * all floating-point disabled. + * @retval QCBOR_ERR_UNRECOVERABLE_TAG_CONTENT Unexpected and unrecoverable + * error decoding date. * * The epoch date tag defined in QCBOR allows for floating-point * dates. It even allows a protocol to flop between date formats when @@ -1928,7 +2163,8 @@ static inline void ShiftTags(QCBORItem *pDecodedItem) * This converts all the date formats into one format of an unsigned * integer plus a floating-point fraction. */ -static QCBORError DecodeDateEpoch(QCBORItem *pDecodedItem) +static QCBORError +QCBOR_Private_DecodeDateEpoch(QCBORItem *pDecodedItem) { QCBORError uReturn = QCBOR_SUCCESS; @@ -2023,15 +2259,19 @@ static QCBORError DecodeDateEpoch(QCBORItem *pDecodedItem) * * pDecodedItem[in,out] The data item to convert. * - * @retval QCBOR_ERR_DATE_OVERFLOW - * @retval QCBOR_ERR_FLOAT_DATE_DISABLED - * @retval QCBOR_ERR_ALL_FLOAT_DISABLED - * @retval QCBOR_ERR_UNRECOVERABLE_TAG_CONTENT + * @retval QCBOR_ERR_DATE_OVERFLOW 65-bit negative integer. + * @retval QCBOR_ERR_FLOAT_DATE_DISABLED Float-point date in input, + * floating-point date disabled. + * @retval QCBOR_ERR_ALL_FLOAT_DISABLED Float-point date in input, + * all floating-point disabled. + * @retval QCBOR_ERR_UNRECOVERABLE_TAG_CONTENT Unexpected and unrecoverable + * error decoding date. * * This is much simpler than the other epoch date format because * floating-porint is not allowed. This is mostly a simple type check. */ -static QCBORError DecodeDaysEpoch(QCBORItem *pDecodedItem) +static QCBORError +QCBOR_Private_DecodeDaysEpoch(QCBORItem *pDecodedItem) { QCBORError uReturn = QCBOR_SUCCESS; @@ -2076,7 +2316,8 @@ static QCBORError DecodeDaysEpoch(QCBORItem *pDecodedItem) * correctly and the correct error is returned. */ static QCBORError -QCBORDecode_GetNextTagContent(QCBORDecodeContext *pMe, QCBORItem *pDecodedItem); +QCBORDecode_Private_GetNextTagContent(QCBORDecodeContext *pMe, + QCBORItem *pDecodedItem); /** @@ -2089,7 +2330,7 @@ QCBORDecode_GetNextTagContent(QCBORDecodeContext *pMe, QCBORItem *pDecodedItem); * exponent. * * @returns Decoding errors from getting primitive data items or - * \ref QCBOR_ERR_BAD_EXP_AND_MANTISSA. + * @ref QCBOR_ERR_BAD_EXP_AND_MANTISSA. * * When called pDecodedItem must be the array with two members, the * exponent and mantissa. @@ -2104,7 +2345,8 @@ QCBORDecode_GetNextTagContent(QCBORDecodeContext *pMe, QCBORItem *pDecodedItem); * the caller will process it. */ static QCBORError -QCBORDecode_MantissaAndExponent(QCBORDecodeContext *pMe, QCBORItem *pDecodedItem) +QCBORDecode_Private_ExpMantissa(QCBORDecodeContext *pMe, + QCBORItem *pDecodedItem) { QCBORError uReturn; @@ -2115,7 +2357,7 @@ QCBORDecode_MantissaAndExponent(QCBORDecodeContext *pMe, QCBORItem *pDecodedItem } /* A check for pDecodedItem->val.uCount == 2 would work for - * definite-length arrays, but not for indefinite. Instead remember + * definite-length arrays, but not for indefinite. Instead remember * the nesting level the two integers must be at, which is one * deeper than that of the array. */ @@ -2123,7 +2365,7 @@ QCBORDecode_MantissaAndExponent(QCBORDecodeContext *pMe, QCBORItem *pDecodedItem /* --- Get the exponent --- */ QCBORItem exponentItem; - uReturn = QCBORDecode_GetNextMapOrArray(pMe, &exponentItem); + uReturn = QCBORDecode_GetNext(pMe, &exponentItem); if(uReturn != QCBOR_SUCCESS) { goto Done; } @@ -2148,7 +2390,7 @@ QCBORDecode_MantissaAndExponent(QCBORDecodeContext *pMe, QCBORItem *pDecodedItem /* --- Get the mantissa --- */ QCBORItem mantissaItem; - uReturn = QCBORDecode_GetNextTagContent(pMe, &mantissaItem); + uReturn = QCBORDecode_GetNext(pMe, &mantissaItem); if(uReturn != QCBOR_SUCCESS) { goto Done; } @@ -2211,7 +2453,8 @@ QCBORDecode_MantissaAndExponent(QCBORDecodeContext *pMe, QCBORItem *pDecodedItem * f or ProcessTaggedString() because the RFC 7049 MIME type was * incorreclty text-only. */ -static inline QCBORError DecodeMIME(QCBORItem *pDecodedItem) +static QCBORError +QCBOR_Private_DecodeMIME(QCBORItem *pDecodedItem) { if(pDecodedItem->uDataType == QCBOR_TYPE_TEXT_STRING) { pDecodedItem->uDataType = QCBOR_TYPE_MIME; @@ -2243,7 +2486,7 @@ struct StringTagMapEntry { #define IS_BYTE_STRING_BIT 0x80 #define QCBOR_TYPE_MASK ~IS_BYTE_STRING_BIT -static const struct StringTagMapEntry StringTagMap[] = { +static const struct StringTagMapEntry QCBOR_Private_StringTagMap[] = { {CBOR_TAG_DATE_STRING, QCBOR_TYPE_DATE_STRING}, {CBOR_TAG_DAYS_STRING, QCBOR_TYPE_DAYS_STRING}, {CBOR_TAG_POS_BIGNUM, QCBOR_TYPE_POSBIGNUM | IS_BYTE_STRING_BIT}, @@ -2268,8 +2511,8 @@ static const struct StringTagMapEntry StringTagMap[] = { * @param[in,out] pDecodedItem The data item. * * @returns This returns QCBOR_SUCCESS if the tag was procssed, - * \ref QCBOR_ERR_UNSUPPORTED if the tag was not processed and - * \ref QCBOR_ERR_UNRECOVERABLE_TAG_CONTENT if the content type was wrong for the tag. + * @ref QCBOR_ERR_UNSUPPORTED if the tag was not processed and + * @ref QCBOR_ERR_UNRECOVERABLE_TAG_CONTENT if the content type was wrong for the tag. * * Process the CBOR tags that whose content is a byte string or a text * string and for which the string is just passed on to the caller. @@ -2279,8 +2522,8 @@ static const struct StringTagMapEntry StringTagMap[] = { * functionality, but it part of implementing as much of RFC 8949 as * possible. */ -static inline QCBORError -ProcessTaggedString(uint16_t uTag, QCBORItem *pDecodedItem) +static QCBORError +QCBOR_Private_ProcessTaggedString(uint16_t uTag, QCBORItem *pDecodedItem) { /* This only works on tags that were not mapped; no need for other yet */ if(uTag > QCBOR_LAST_UNMAPPED_TAG) { @@ -2288,13 +2531,13 @@ ProcessTaggedString(uint16_t uTag, QCBORItem *pDecodedItem) } unsigned uIndex; - for(uIndex = 0; StringTagMap[uIndex].uTagNumber != CBOR_TAG_INVALID16; uIndex++) { - if(StringTagMap[uIndex].uTagNumber == uTag) { + for(uIndex = 0; QCBOR_Private_StringTagMap[uIndex].uTagNumber != CBOR_TAG_INVALID16; uIndex++) { + if(QCBOR_Private_StringTagMap[uIndex].uTagNumber == uTag) { break; } } - const uint8_t uQCBORType = StringTagMap[uIndex].uQCBORtype; + const uint8_t uQCBORType = QCBOR_Private_StringTagMap[uIndex].uQCBORtype; if(uQCBORType == QCBOR_TYPE_NONE) { /* repurpose this error to mean not handled here */ return QCBOR_ERR_UNSUPPORTED; @@ -2320,17 +2563,25 @@ ProcessTaggedString(uint16_t uTag, QCBORItem *pDecodedItem) #ifndef QCBOR_CONFIG_DISABLE_EXP_AND_MANTISSA -/* - * This returns the QCBOR_TYPE for a mantissa and exponent. - -Called in one context where there is always a tag - - Called in another context where there might be a tag or the caller might say what they are expecting. - - 6 possible outputs +/** + * @brief Figures out data type for exponent mantissa tags. + * + * @param[in] uTagToProcess Either @ref CBOR_TAG_DECIMAL_FRACTION or + * @ref CBOR_TAG_BIG_FLOAT. + * @param[in] pDecodedItem Item being decoded. + * + * @returns One of the 6 values between @ref QCBOR_TYPE_DECIMAL_FRACTION + * and @ref QCBOR_TYPE_BIGFLOAT_NEG_BIGNUM. + * + * Does mapping between a CBOR tag number and a QCBOR type. with a + * little bit of logic and arithmatic. + * + * Used in serveral contexts. Does the work where sometimes the data + * item is explicitly tagged and sometimes not. */ -static inline uint8_t -MantissaExponentDataType(const uint16_t uTagToProcess, const QCBORItem *pDecodedItem) +static uint8_t +QCBOR_Private_ExpMantissaDataType(const uint16_t uTagToProcess, + const QCBORItem *pDecodedItem) { uint8_t uBase = uTagToProcess == CBOR_TAG_DECIMAL_FRACTION ? QCBOR_TYPE_DECIMAL_FRACTION : @@ -2357,11 +2608,12 @@ MantissaExponentDataType(const uint16_t uTagToProcess, const QCBORItem *pDecoded * quick pass through for items that are not tags. */ static QCBORError -QCBORDecode_GetNextTagContent(QCBORDecodeContext *pMe, QCBORItem *pDecodedItem) +QCBORDecode_Private_GetNextTagContent(QCBORDecodeContext *pMe, + QCBORItem *pDecodedItem) { QCBORError uReturn; - uReturn = QCBORDecode_GetNextMapOrArray(pMe, pDecodedItem); + uReturn = QCBORDecode_Private_GetNextMapOrArray(pMe, NULL, pDecodedItem); if(uReturn != QCBOR_SUCCESS) { goto Done; } @@ -2387,28 +2639,28 @@ QCBORDecode_GetNextTagContent(QCBORDecodeContext *pMe, QCBORItem *pDecodedItem) break; } else if(uTagToProcess == CBOR_TAG_DATE_EPOCH) { - uReturn = DecodeDateEpoch(pDecodedItem); + uReturn = QCBOR_Private_DecodeDateEpoch(pDecodedItem); } else if(uTagToProcess == CBOR_TAG_DAYS_EPOCH) { - uReturn = DecodeDaysEpoch(pDecodedItem); + uReturn = QCBOR_Private_DecodeDaysEpoch(pDecodedItem); #ifndef QCBOR_DISABLE_EXP_AND_MANTISSA } else if(uTagToProcess == CBOR_TAG_DECIMAL_FRACTION || uTagToProcess == CBOR_TAG_BIGFLOAT) { - uReturn = QCBORDecode_MantissaAndExponent(pMe, pDecodedItem); + uReturn = QCBORDecode_Private_ExpMantissa(pMe, pDecodedItem); /* --- Which is it, decimal fraction or a bigfloat? --- */ - pDecodedItem->uDataType = MantissaExponentDataType(uTagToProcess, pDecodedItem); + pDecodedItem->uDataType = QCBOR_Private_ExpMantissaDataType(uTagToProcess, pDecodedItem); #endif /* QCBOR_DISABLE_EXP_AND_MANTISSA */ #ifndef QCBOR_DISABLE_UNCOMMON_TAGS } else if(uTagToProcess == CBOR_TAG_MIME || uTagToProcess == CBOR_TAG_BINARY_MIME) { - uReturn = DecodeMIME(pDecodedItem); + uReturn = QCBOR_Private_DecodeMIME(pDecodedItem); #endif /* QCBOR_DISABLE_UNCOMMON_TAGS */ } else { /* See if it is a passthrough byte/text string tag; process if so */ - uReturn = ProcessTaggedString(pDecodedItem->uTags[0], pDecodedItem); + uReturn = QCBOR_Private_ProcessTaggedString(pDecodedItem->uTags[0], pDecodedItem); if(uReturn == QCBOR_ERR_UNSUPPORTED) { /* It wasn't a passthrough byte/text string tag so it is @@ -2428,7 +2680,7 @@ QCBORDecode_GetNextTagContent(QCBORDecodeContext *pMe, QCBORItem *pDecodedItem) /* A tag was successfully processed, shift it out of the list of * tags returned. This is the loop increment. */ - ShiftTags(pDecodedItem); + QCBOR_Private_ShiftTags(pDecodedItem); } #endif /* QCBOR_DISABLE_TAGS */ @@ -2444,7 +2696,7 @@ QCBORError QCBORDecode_GetNext(QCBORDecodeContext *pMe, QCBORItem *pDecodedItem) { QCBORError uErr; - uErr = QCBORDecode_GetNextTagContent(pMe, pDecodedItem); + uErr = QCBORDecode_Private_GetNextTagContent(pMe, pDecodedItem); if(uErr != QCBOR_SUCCESS) { pDecodedItem->uDataType = QCBOR_TYPE_NONE; pDecodedItem->uLabelType = QCBOR_TYPE_NONE; @@ -2478,6 +2730,8 @@ void QCBORDecode_VPeekNext(QCBORDecodeContext *pMe, QCBORItem *pDecodedItem) { if(pMe->uLastError != QCBOR_SUCCESS) { + pDecodedItem->uDataType = QCBOR_TYPE_NONE; + pDecodedItem->uLabelType = QCBOR_TYPE_NONE; return; } @@ -2485,16 +2739,31 @@ QCBORDecode_VPeekNext(QCBORDecodeContext *pMe, QCBORItem *pDecodedItem) } +static void +QCBORDecode_Private_CopyTags(QCBORDecodeContext *pMe, const QCBORItem *pItem) +{ +#ifndef QCBOR_DISABLE_TAGS + memcpy(pMe->uLastTags, pItem->uTags, sizeof(pItem->uTags)); +#else + (void)pMe; + (void)pItem; +#endif +} + /* * Public function, see header qcbor/qcbor_decode.h file */ -void QCBORDecode_VGetNext(QCBORDecodeContext *pMe, QCBORItem *pDecodedItem) +void +QCBORDecode_VGetNext(QCBORDecodeContext *pMe, QCBORItem *pDecodedItem) { if(pMe->uLastError != QCBOR_SUCCESS) { + pDecodedItem->uDataType = QCBOR_TYPE_NONE; + pDecodedItem->uLabelType = QCBOR_TYPE_NONE; return; } pMe->uLastError = (uint8_t)QCBORDecode_GetNext(pMe, pDecodedItem); + QCBORDecode_Private_CopyTags(pMe, pDecodedItem); } @@ -2525,7 +2794,7 @@ QCBORDecode_GetNextWithTags(QCBORDecodeContext *pMe, if(pTags->uNumUsed >= pTags->uNumAllocated) { return QCBOR_ERR_TOO_MANY_TAGS; } - pTags->puTags[pTags->uNumUsed] = UnMapTagNumber(pMe,pDecodedItem->uTags[nTagIndex]); + pTags->puTags[pTags->uNumUsed] = QCBORDecode_Private_UnMapTagNumber(pMe,pDecodedItem->uTags[nTagIndex]); pTags->uNumUsed++; } } @@ -2544,16 +2813,17 @@ QCBORDecode_GetNextWithTags(QCBORDecodeContext *pMe, /* * Public function, see header qcbor/qcbor_decode.h file */ -bool QCBORDecode_IsTagged(QCBORDecodeContext *pMe, - const QCBORItem *pItem, - uint64_t uTag) +bool +QCBORDecode_IsTagged(QCBORDecodeContext *pMe, + const QCBORItem *pItem, + uint64_t uTag) { #ifndef QCBOR_DISABLE_TAGS for(unsigned uTagIndex = 0; uTagIndex < QCBOR_MAX_TAGS_PER_ITEM; uTagIndex++) { if(pItem->uTags[uTagIndex] == CBOR_TAG_INVALID16) { break; } - if(UnMapTagNumber(pMe, pItem->uTags[uTagIndex]) == uTag) { + if(QCBORDecode_Private_UnMapTagNumber(pMe, pItem->uTags[uTagIndex]) == uTag) { return true; } } @@ -2570,7 +2840,8 @@ bool QCBORDecode_IsTagged(QCBORDecodeContext *pMe, /* * Public function, see header qcbor/qcbor_decode.h file */ -QCBORError QCBORDecode_PartialFinish(QCBORDecodeContext *pMe, size_t *puConsumed) +QCBORError +QCBORDecode_PartialFinish(QCBORDecodeContext *pMe, size_t *puConsumed) { if(puConsumed != NULL) { *puConsumed = pMe->InBuf.cursor; @@ -2601,7 +2872,8 @@ QCBORError QCBORDecode_PartialFinish(QCBORDecodeContext *pMe, size_t *puConsumed /* * Public function, see header qcbor/qcbor_decode.h file */ -QCBORError QCBORDecode_Finish(QCBORDecodeContext *pMe) +QCBORError +QCBORDecode_Finish(QCBORDecodeContext *pMe) { #ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS /* Call the destructor for the string allocator if there is one. @@ -2617,10 +2889,10 @@ QCBORError QCBORDecode_Finish(QCBORDecodeContext *pMe) /* * Public function, see header qcbor/qcbor_decode.h file */ -// Improvement: make these inline? -uint64_t QCBORDecode_GetNthTag(QCBORDecodeContext *pMe, - const QCBORItem *pItem, - uint32_t uIndex) +uint64_t +QCBORDecode_GetNthTag(QCBORDecodeContext *pMe, + const QCBORItem *pItem, + uint32_t uIndex) { #ifndef QCBOR_DISABLE_TAGS if(pItem->uDataType == QCBOR_TYPE_NONE) { @@ -2629,7 +2901,7 @@ uint64_t QCBORDecode_GetNthTag(QCBORDecodeContext *pMe, if(uIndex >= QCBOR_MAX_TAGS_PER_ITEM) { return CBOR_TAG_INVALID64; } else { - return UnMapTagNumber(pMe, pItem->uTags[uIndex]); + return QCBORDecode_Private_UnMapTagNumber(pMe, pItem->uTags[uIndex]); } #else /* QCBOR_DISABLE_TAGS */ (void)pMe; @@ -2644,8 +2916,9 @@ uint64_t QCBORDecode_GetNthTag(QCBORDecodeContext *pMe, /* * Public function, see header qcbor/qcbor_decode.h file */ -uint64_t QCBORDecode_GetNthTagOfLast(const QCBORDecodeContext *pMe, - uint32_t uIndex) +uint64_t +QCBORDecode_GetNthTagOfLast(const QCBORDecodeContext *pMe, + uint32_t uIndex) { #ifndef QCBOR_DISABLE_TAGS @@ -2655,7 +2928,7 @@ uint64_t QCBORDecode_GetNthTagOfLast(const QCBORDecodeContext *pMe, if(uIndex >= QCBOR_MAX_TAGS_PER_ITEM) { return CBOR_TAG_INVALID64; } else { - return UnMapTagNumber(pMe, pMe->uLastTags[uIndex]); + return QCBORDecode_Private_UnMapTagNumber(pMe, pMe->uLastTags[uIndex]); } #else /* QCBOR_DISABLE_TAGS */ (void)pMe; @@ -2697,7 +2970,7 @@ uint64_t QCBORDecode_GetNthTagOfLast(const QCBORDecodeContext *pMe, ========================================================================== */ -static inline int +static int MemPool_Unpack(const void *pMem, uint32_t *puPoolSize, uint32_t *puFreeOffset) { // Use of UsefulInputBuf is overkill, but it is convenient. @@ -2712,7 +2985,7 @@ MemPool_Unpack(const void *pMem, uint32_t *puPoolSize, uint32_t *puFreeOffset) } -static inline int +static int MemPool_Pack(UsefulBuf Pool, uint32_t uFreeOffset) { // Use of UsefulOutBuf is overkill, but convenient. The @@ -2817,11 +3090,12 @@ MemPool_Function(void *pPool, void *pMem, size_t uNewSize) /* - Public function, see header qcbor/qcbor_decode.h file + * Public function, see header qcbor/qcbor_decode.h file */ -QCBORError QCBORDecode_SetMemPool(QCBORDecodeContext *pMe, - UsefulBuf Pool, - bool bAllStrings) +QCBORError +QCBORDecode_SetMemPool(QCBORDecodeContext *pMe, + UsefulBuf Pool, + bool bAllStrings) { // The pool size and free mem offset are packed into the beginning // of the pool memory. This compile time check makes sure the @@ -2858,17 +3132,6 @@ QCBORError QCBORDecode_SetMemPool(QCBORDecodeContext *pMe, -static inline void -CopyTags(QCBORDecodeContext *pMe, const QCBORItem *pItem) -{ -#ifndef QCBOR_DISABLE_TAGS - memcpy(pMe->uLastTags, pItem->uTags, sizeof(pItem->uTags)); -#else - (void)pMe; - (void)pItem; -#endif -} - /** * @brief Consume an entire map or array including its contents. @@ -2883,10 +3146,11 @@ CopyTags(QCBORDecodeContext *pMe, const QCBORItem *pItem) * map. In that case, this is just a pass through for @c puNextNestLevel * since there is nothing to do. */ -static inline QCBORError -ConsumeItem(QCBORDecodeContext *pMe, - const QCBORItem *pItemToConsume, - uint8_t *puNextNestLevel) +static QCBORError +QCBORDecode_Private_ConsumeItem(QCBORDecodeContext *pMe, + const QCBORItem *pItemToConsume, + bool *pbBreak, + uint8_t *puNextNestLevel) { QCBORError uReturn; QCBORItem Item; @@ -2894,14 +3158,14 @@ ConsumeItem(QCBORDecodeContext *pMe, /* If it is a map or array, this will tell if it is empty. */ const bool bIsEmpty = (pItemToConsume->uNextNestLevel <= pItemToConsume->uNestingLevel); - if(QCBORItem_IsMapOrArray(pItemToConsume) && !bIsEmpty) { + if(QCBORItem_IsMapOrArray(*pItemToConsume) && !bIsEmpty) { /* There is only real work to do for non-empty maps and arrays */ /* This works for definite- and indefinite-length maps and * arrays by using the nesting level */ do { - uReturn = QCBORDecode_GetNext(pMe, &Item); + uReturn = QCBORDecode_Private_GetNextMapOrArray(pMe, pbBreak, &Item); if(QCBORDecode_IsUnrecoverableError(uReturn) || uReturn == QCBOR_ERR_NO_MORE_ITEMS) { goto Done; @@ -2913,7 +3177,7 @@ ConsumeItem(QCBORDecodeContext *pMe, uReturn = QCBOR_SUCCESS; } else { - /* pItemToConsume is not a map or array. Just pass the nesting + /* pItemToConsume is not a map or array. Just pass the nesting * level through. */ *puNextNestLevel = pItemToConsume->uNextNestLevel; @@ -2925,22 +3189,54 @@ ConsumeItem(QCBORDecodeContext *pMe, } -void QCBORDecode_VGetNextConsume(QCBORDecodeContext *pMe, QCBORItem *pDecodedItem) +/* + * Public function, see header qcbor/qcbor_decode.h file + */ +void +QCBORDecode_VGetNextConsume(QCBORDecodeContext *pMe, QCBORItem *pDecodedItem) { QCBORDecode_VGetNext(pMe, pDecodedItem); if(pMe->uLastError == QCBOR_SUCCESS) { - pMe->uLastError = (uint8_t)ConsumeItem(pMe, pDecodedItem, + pMe->uLastError = (uint8_t)QCBORDecode_Private_ConsumeItem(pMe, pDecodedItem, NULL, &pDecodedItem->uNextNestLevel); } } +/* + * Public function, see header qcbor/qcbor_decode.h file + */ +QCBORError +QCBORDecode_EndCheck(QCBORDecodeContext *pMe) +{ + size_t uCursorOffset; + QCBORError uErr; + + uErr = QCBORDecode_GetError(pMe); + if(uErr != QCBOR_SUCCESS) { + return uErr; + } + + uCursorOffset = UsefulInputBuf_Tell(&(pMe->InBuf)); + + if(uCursorOffset == UsefulInputBuf_GetBufferLength(&(pMe->InBuf))) { + return QCBOR_ERR_NO_MORE_ITEMS; + } + + return QCBOR_SUCCESS; +} + -/* Call only on maps and arrays. Rewinds the cursor - * to the start as if it was just entered. +/** + * @brief Rewind cursor to start as if map or array were just entered. + * + * @param[in] pMe The decoding context + * + * This affects the nesting tracking and the UsefulInputBuf. */ -static void RewindMapOrArray(QCBORDecodeContext *pMe) +static void +QCBORDecode_Private_RewindMapOrArray(QCBORDecodeContext *pMe) { /* Reset nesting tracking to the deepest bounded level */ DecodeNesting_SetCurrentToBoundedLevel(&(pMe->nesting)); @@ -2954,9 +3250,10 @@ static void RewindMapOrArray(QCBORDecodeContext *pMe) /* - Public function, see header qcbor/qcbor_decode.h file + * Public function, see header qcbor/qcbor_decode.h file */ -void QCBORDecode_Rewind(QCBORDecodeContext *pMe) +void +QCBORDecode_Rewind(QCBORDecodeContext *pMe) { if(pMe->nesting.pCurrentBounded != NULL) { /* In a bounded map, array or bstr-wrapped CBOR */ @@ -2971,7 +3268,7 @@ void QCBORDecode_Rewind(QCBORDecodeContext *pMe) } else { /* In a map or array */ - RewindMapOrArray(pMe); + QCBORDecode_Private_RewindMapOrArray(pMe); } } else { @@ -2988,91 +3285,56 @@ void QCBORDecode_Rewind(QCBORDecodeContext *pMe) } -/* Return true if the labels in Item1 and Item2 are the same. - Works only for integer and string labels. Returns false - for any other type. */ -static inline bool -MatchLabel(QCBORItem Item1, QCBORItem Item2) -{ - if(Item1.uLabelType == QCBOR_TYPE_INT64) { - if(Item2.uLabelType == QCBOR_TYPE_INT64 && Item1.label.int64 == Item2.label.int64) { - return true; - } - } else if(Item1.uLabelType == QCBOR_TYPE_TEXT_STRING) { - if(Item2.uLabelType == QCBOR_TYPE_TEXT_STRING && !UsefulBuf_Compare(Item1.label.string, Item2.label.string)) { - return true; - } - } else if(Item1.uLabelType == QCBOR_TYPE_BYTE_STRING) { - if(Item2.uLabelType == QCBOR_TYPE_BYTE_STRING && !UsefulBuf_Compare(Item1.label.string, Item2.label.string)) { - return true; - } - } else if(Item1.uLabelType == QCBOR_TYPE_UINT64) { - if(Item2.uLabelType == QCBOR_TYPE_UINT64 && Item1.label.uint64 == Item2.label.uint64) { - return true; - } - } - - /* Other label types are never matched */ - return false; -} - - -/* - Returns true if Item1 and Item2 are the same type - or if either are of QCBOR_TYPE_ANY. - */ -static inline bool -MatchType(QCBORItem Item1, QCBORItem Item2) -{ - if(Item1.uDataType == Item2.uDataType) { - return true; - } else if(Item1.uDataType == QCBOR_TYPE_ANY) { - return true; - } else if(Item2.uDataType == QCBOR_TYPE_ANY) { - return true; - } - return false; -} - - -/** - @brief Search a map for a set of items. - - @param[in] pMe The decode context to search. - @param[in,out] pItemArray The items to search for and the items found. - @param[out] puOffset Byte offset of last item matched. - @param[in] pCBContext Context for the not-found item call back. - @param[in] pfCallback Function to call on items not matched in pItemArray. - - @retval QCBOR_ERR_NOT_ENTERED Trying to search without having entered a map - @retval QCBOR_ERR_DUPLICATE_LABEL Duplicate items (items with the same label) - were found for one of the labels being - search for. This duplicate detection is - only performed for items in pItemArray, - not every item in the map. - @retval QCBOR_ERR_UNEXPECTED_TYPE A label was matched, but the type was - wrong for the matchd label. - @retval Also errors returned by QCBORDecode_GetNext(). +typedef struct { + void *pCBContext; + QCBORItemCallback pfCallback; +} MapSearchCallBack; - On input pItemArray contains a list of labels and data types - of items to be found. +typedef struct { + size_t uStartOffset; + uint16_t uItemCount; +} MapSearchInfo; - On output the fully retrieved items are filled in with - values and such. The label was matched, so it never changes. - If an item was not found, its data type is set to QCBOR_TYPE_NONE. - - This also finds the ends of maps and arrays when they are exited. +/** + * @brief Search a map for a set of items. + * + * @param[in] pMe The decode context to search. + * @param[in,out] pItemArray The items to search for and the items found. + * @param[out] pInfo Several bits of meta-info returned by search. + * @param[in] pCallBack Callback object or @c NULL. + * + * @retval QCBOR_ERR_NOT_ENTERED Trying to search without entering a map. + * + * @retval QCBOR_ERR_DUPLICATE_LABEL Duplicate items (items with the same label) + * were found for one of the labels being + * search for. This duplicate detection is + * only performed for items in pItemArray, + * not every item in the map. + * + * @retval QCBOR_ERR_UNEXPECTED_TYPE A label was matched, but the type was + * wrong for the matchd label. + * + * @retval Also errors returned by QCBORDecode_GetNext(). + * + * On input, @c pItemArray contains a list of labels and data types of + * items to be found. + * + * On output, the fully retrieved items are filled in with values and + * such. The label was matched, so it never changes. + * + * If an item was not found, its data type is set to @ref QCBOR_TYPE_NONE. + * + * This also finds the ends of maps and arrays when they are exited. */ static QCBORError -MapSearch(QCBORDecodeContext *pMe, - QCBORItem *pItemArray, - size_t *puOffset, - void *pCBContext, - QCBORItemCallback pfCallback) +QCBORDecode_Private_MapSearch(QCBORDecodeContext *pMe, + QCBORItem *pItemArray, + MapSearchInfo *pInfo, + MapSearchCallBack *pCallBack) { QCBORError uReturn; uint64_t uFoundItemBitMap = 0; @@ -3105,10 +3367,11 @@ MapSearch(QCBORDecodeContext *pMe, } QCBORDecodeNesting SaveNesting; + size_t uSavePos = UsefulInputBuf_Tell(&(pMe->InBuf)); DecodeNesting_PrepareForMapSearch(&(pMe->nesting), &SaveNesting); /* Reposition to search from the start of the map / array */ - RewindMapOrArray(pMe); + QCBORDecode_Private_RewindMapOrArray(pMe); /* Loop over all the items in the map or array. Each item @@ -3128,6 +3391,9 @@ MapSearch(QCBORDecodeContext *pMe, that error code is returned. */ const uint8_t uMapNestLevel = DecodeNesting_GetBoundedModeLevel(&(pMe->nesting)); + if(pInfo) { + pInfo->uItemCount = 0; + } uint8_t uNextNestLevel; do { /* Remember offset of the item because sometimes it has to be returned */ @@ -3135,14 +3401,17 @@ MapSearch(QCBORDecodeContext *pMe, /* Get the item */ QCBORItem Item; - QCBORError uResult = QCBORDecode_GetNextTagContent(pMe, &Item); + /* QCBORDecode_Private_GetNextTagContent() rather than GetNext() + * because a label match is performed on recoverable errors to + * be able to return the the error code for the found item. */ + QCBORError uResult = QCBORDecode_Private_GetNextTagContent(pMe, &Item); if(QCBORDecode_IsUnrecoverableError(uResult)) { - /* Unrecoverable error so map can't even be decoded. */ + /* The map/array can't be decoded when unrecoverable errors occur */ uReturn = uResult; goto Done; } if(uResult == QCBOR_ERR_NO_MORE_ITEMS) { - // Unexpected end of map or array. + /* Unexpected end of map or array. */ uReturn = uResult; goto Done; } @@ -3150,18 +3419,20 @@ MapSearch(QCBORDecodeContext *pMe, /* See if item has one of the labels that are of interest */ bool bMatched = false; for(int nIndex = 0; pItemArray[nIndex].uLabelType != QCBOR_TYPE_NONE; nIndex++) { - if(MatchLabel(Item, pItemArray[nIndex])) { + if(QCBORItem_MatchLabel(Item, pItemArray[nIndex])) { /* A label match has been found */ if(uFoundItemBitMap & (0x01ULL << nIndex)) { uReturn = QCBOR_ERR_DUPLICATE_LABEL; goto Done; } if(uResult != QCBOR_SUCCESS) { - /* The label matches, but the data item is in error */ + /* The label matches, but the data item is in error. + * It is OK to have recoverable errors on items that + * are not matched. */ uReturn = uResult; goto Done; } - if(!MatchType(Item, pItemArray[nIndex])) { + if(!QCBORItem_MatchType(Item, pItemArray[nIndex])) { /* The data item is not of the type(s) requested */ uReturn = QCBOR_ERR_UNEXPECTED_TYPE; goto Done; @@ -3170,22 +3441,22 @@ MapSearch(QCBORDecodeContext *pMe, /* Successful match. Return the item. */ pItemArray[nIndex] = Item; uFoundItemBitMap |= 0x01ULL << nIndex; - if(puOffset) { - *puOffset = uOffset; + if(pInfo) { + pInfo->uStartOffset = uOffset; } bMatched = true; } } - if(!bMatched && pfCallback != NULL) { + if(!bMatched && pCallBack != NULL) { /* Call the callback on unmatched labels. (It is tempting to do duplicate detection here, but that would require dynamic memory allocation because the number of labels that might be encountered is unbounded.) */ - uReturn = (*pfCallback)(pCBContext, &Item); + uReturn = (*(pCallBack->pfCallback))(pCallBack->pCBContext, &Item); if(uReturn != QCBOR_SUCCESS) { goto Done; } @@ -3198,11 +3469,15 @@ MapSearch(QCBORDecodeContext *pMe, items at the current nesting level are examined to match the labels. */ - uReturn = ConsumeItem(pMe, &Item, &uNextNestLevel); + uReturn = QCBORDecode_Private_ConsumeItem(pMe, &Item, NULL, &uNextNestLevel); if(uReturn != QCBOR_SUCCESS) { goto Done; } + if(pInfo) { + pInfo->uItemCount++; + } + } while (uNextNestLevel >= uMapNestLevel); uReturn = QCBOR_SUCCESS; @@ -3222,6 +3497,7 @@ MapSearch(QCBORDecodeContext *pMe, Done: DecodeNesting_RestoreFromMapSearch(&(pMe->nesting), &SaveNesting); + UsefulInputBuf_Seek(&(pMe->InBuf), uSavePos); Done2: /* For all items not found, set the data and label type to QCBOR_TYPE_NONE */ @@ -3237,12 +3513,13 @@ MapSearch(QCBORDecodeContext *pMe, /* - Public function, see header qcbor/qcbor_decode.h file -*/ -void QCBORDecode_GetItemInMapN(QCBORDecodeContext *pMe, - int64_t nLabel, - uint8_t uQcborType, - QCBORItem *pItem) + * Public function, see header qcbor/qcbor_decode.h file + */ +void +QCBORDecode_GetItemInMapN(QCBORDecodeContext *pMe, + int64_t nLabel, + uint8_t uQcborType, + QCBORItem *pItem) { if(pMe->uLastError != QCBOR_SUCCESS) { return; @@ -3254,42 +3531,51 @@ void QCBORDecode_GetItemInMapN(QCBORDecodeContext *pMe, OneItemSeach[0].uDataType = uQcborType; OneItemSeach[1].uLabelType = QCBOR_TYPE_NONE; // Indicates end of array - QCBORError uReturn = MapSearch(pMe, OneItemSeach, NULL, NULL, NULL); - - *pItem = OneItemSeach[0]; + QCBORError uReturn = QCBORDecode_Private_MapSearch(pMe, OneItemSeach, NULL, NULL); if(uReturn != QCBOR_SUCCESS) { + pItem->uDataType = QCBOR_TYPE_NONE; + pItem->uLabelType = QCBOR_TYPE_NONE; goto Done; } + if(OneItemSeach[0].uDataType == QCBOR_TYPE_NONE) { uReturn = QCBOR_ERR_LABEL_NOT_FOUND; } + *pItem = OneItemSeach[0]; + QCBORDecode_Private_CopyTags(pMe, pItem); + Done: pMe->uLastError = (uint8_t)uReturn; } /* - Public function, see header qcbor/qcbor_decode.h file -*/ -void QCBORDecode_GetItemInMapSZ(QCBORDecodeContext *pMe, - const char *szLabel, - uint8_t uQcborType, - QCBORItem *pItem) + * Public function, see header qcbor/qcbor_decode.h file + */ +void +QCBORDecode_GetItemInMapSZ(QCBORDecodeContext *pMe, + const char *szLabel, + uint8_t uQcborType, + QCBORItem *pItem) { if(pMe->uLastError != QCBOR_SUCCESS) { return; } +#ifndef QCBOR_DISABLE_NON_INTEGER_LABELS QCBORItem OneItemSeach[2]; OneItemSeach[0].uLabelType = QCBOR_TYPE_TEXT_STRING; OneItemSeach[0].label.string = UsefulBuf_FromSZ(szLabel); OneItemSeach[0].uDataType = uQcborType; OneItemSeach[1].uLabelType = QCBOR_TYPE_NONE; // Indicates end of array - QCBORError uReturn = MapSearch(pMe, OneItemSeach, NULL, NULL, NULL); + QCBORError uReturn = QCBORDecode_Private_MapSearch(pMe, OneItemSeach, NULL, NULL); + if(uReturn != QCBOR_SUCCESS) { + pItem->uDataType = QCBOR_TYPE_NONE; + pItem->uLabelType = QCBOR_TYPE_NONE; goto Done; } if(OneItemSeach[0].uDataType == QCBOR_TYPE_NONE) { @@ -3298,56 +3584,225 @@ void QCBORDecode_GetItemInMapSZ(QCBORDecodeContext *pMe, } *pItem = OneItemSeach[0]; + QCBORDecode_Private_CopyTags(pMe, pItem); Done: +#else + (void)pMe; + (void)szLabel; + (void)uQcborType; + (void)pItem; + QCBORError uReturn = QCBOR_ERR_LABEL_NOT_FOUND; +#endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */ + pMe->uLastError = (uint8_t)uReturn; } -static QCBORError -CheckTypeList(int uDataType, const uint8_t puTypeList[QCBOR_TAGSPEC_NUM_TYPES]) -{ - for(size_t i = 0; i < QCBOR_TAGSPEC_NUM_TYPES; i++) { - if(uDataType == puTypeList[i]) { - return QCBOR_SUCCESS; - } - } - return QCBOR_ERR_UNEXPECTED_TYPE; -} - /** - * Match a tag/type specification against the type of the item. - * - * @param[in] TagSpec Specification for matching tags. - * @param[in] pItem The item to check. - * - * @retval QCBOR_SUCCESS \c uDataType is allowed by @c TagSpec - * @retval QCBOR_ERR_UNEXPECTED_TYPE \c uDataType is not allowed by @c TagSpec + * @brief Semi-private. Get pointer, length and item for an array or map. * - * This checks the item data type of untagged items as well as of - * tagged items against a specification to see if decoding should - * proceed. + * @param[in] pMe The decode context. + * @param[in] uType CBOR major type, either array/map. + * @param[out] pItem The item for the array/map. + * @param[out] pEncodedCBOR Pointer and length of the encoded map or array. * - * This relies on the automatic tag decoding done by QCBOR that turns - * tag numbers into particular QCBOR_TYPEs so there is no actual - * comparsion of tag numbers, just of QCBOR_TYPEs. + * The next item to be decoded must be a map or array as specified by @c uType. * - * This checks the data item type as possibly representing the tag - * number or as the tag content type. + * @c pItem will be filled in with the label and tags of the array or map + * in addition to @c pEncodedCBOR giving the pointer and length of the + * encoded CBOR. * - * If QCBOR_DISABLE_TAGS is #defined, this primarily checks the item - * data type against the allowed tag content types. It will also error out - * if the caller tries to require a tag because there is no way that can - * ever be fulfilled. + * When this is complete, the traversal cursor is at the end of the array or + * map that was retrieved. */ -static QCBORError -CheckTagRequirement(const TagSpecification TagSpec, const QCBORItem *pItem) +void +QCBORDecode_Private_GetArrayOrMap(QCBORDecodeContext *pMe, + const uint8_t uType, + QCBORItem *pItem, + UsefulBufC *pEncodedCBOR) +{ + QCBORError uErr; + uint8_t uNestLevel; + size_t uStartingCursor; + size_t uStartOfReturned; + size_t uEndOfReturned; + size_t uTempSaveCursor; + bool bInMap; + QCBORItem LabelItem; + bool EndedByBreak; + + uStartingCursor = UsefulInputBuf_Tell(&(pMe->InBuf)); + bInMap = DecodeNesting_IsCurrentTypeMap(&(pMe->nesting)); + + /* Could call GetNext here, but don't need to because this + * is only interested in arrays and maps. */ + uErr = QCBORDecode_Private_GetNextMapOrArray(pMe, NULL, pItem); + if(uErr != QCBOR_SUCCESS) { + pMe->uLastError = (uint8_t)uErr; + return; + } + + uint8_t uItemDataType = pItem->uDataType; +#ifndef QCBOR_DISABLE_NON_INTEGER_LABELS + if(uItemDataType == QCBOR_TYPE_MAP_AS_ARRAY) { + uItemDataType = QCBOR_TYPE_ARRAY; + } +#endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */ + + if(uItemDataType != uType) { + pMe->uLastError = QCBOR_ERR_UNEXPECTED_TYPE; + return; + } + + if(bInMap) { + /* If the item is in a map, the start of the array/map + * itself, not the label, must be found. Do this by + * rewinding to the starting position and fetching + * just the label data item. QCBORDecode_Private_GetNextTagNumber() + * doesn't do any of the array/map item counting or nesting + * level tracking. Used here it will just fetech the label + * data item. + * + * Have to save the cursor and put it back to the position + * after the full item once the label as been fetched by + * itself. + */ + uTempSaveCursor = UsefulInputBuf_Tell(&(pMe->InBuf)); + UsefulInputBuf_Seek(&(pMe->InBuf), uStartingCursor); + + /* Item has been fetched once so safe to ignore error */ + (void)QCBORDecode_Private_GetNextTagNumber(pMe, &LabelItem); + + uStartOfReturned = UsefulInputBuf_Tell(&(pMe->InBuf)); + UsefulInputBuf_Seek(&(pMe->InBuf), uTempSaveCursor); + } else { + uStartOfReturned = uStartingCursor; + } + + /* Consume the entire array/map to find the end */ + uErr = QCBORDecode_Private_ConsumeItem(pMe, pItem, &EndedByBreak, &uNestLevel); + if(uErr != QCBOR_SUCCESS) { + pMe->uLastError = (uint8_t)uErr; + goto Done; + } + + /* Fill in returned values */ + uEndOfReturned = UsefulInputBuf_Tell(&(pMe->InBuf)); + if(EndedByBreak) { + /* When ascending nesting levels, a break for the level above + * was consumed. That break is not a part of what is consumed here. */ + uEndOfReturned--; + } + pEncodedCBOR->ptr = UsefulInputBuf_OffsetToPointer(&(pMe->InBuf), uStartOfReturned); + pEncodedCBOR->len = uEndOfReturned - uStartOfReturned; + +Done: + return; +} + + +/** + * @brief Semi-private. Get pointer, length and item count of an array or map. + * + * @param[in] pMe The decode context. + * @param[in] pTarget The label and type of the array or map to retrieve. + * @param[out] pItem The item for the array/map. + * @param[out] pEncodedCBOR Pointer and length of the encoded map or array. + * + * The next item to be decoded must be a map or array as specified by @c uType. + * + * When this is complete, the traversal cursor is unchanged. + */void +QCBORDecode_Private_SearchAndGetArrayOrMap(QCBORDecodeContext *pMe, + QCBORItem *pTarget, + QCBORItem *pItem, + UsefulBufC *pEncodedCBOR) { - const int nItemType = pItem->uDataType; + MapSearchInfo Info; + QCBORDecodeNesting SaveNesting; + size_t uSaveCursor; + + pMe->uLastError = (uint8_t)QCBORDecode_Private_MapSearch(pMe, pTarget, &Info, NULL); + if(pMe->uLastError != QCBOR_SUCCESS) { + return; + } + + /* Save the whole position of things so they can be restored. + * so the cursor position is unchanged by this operation, like + * all the other GetXxxxInMap() operations. */ + DecodeNesting_PrepareForMapSearch(&(pMe->nesting), &SaveNesting); + uSaveCursor = UsefulInputBuf_Tell(&(pMe->InBuf)); + + DecodeNesting_ResetMapOrArrayCount(&(pMe->nesting)); + UsefulInputBuf_Seek(&(pMe->InBuf), Info.uStartOffset); + QCBORDecode_Private_GetArrayOrMap(pMe, pTarget[0].uDataType, pItem, pEncodedCBOR); + + UsefulInputBuf_Seek(&(pMe->InBuf), uSaveCursor); + DecodeNesting_RestoreFromMapSearch(&(pMe->nesting), &SaveNesting); +} + + + + +/** + * @brief Is a QCBOR_TYPE in the type list? + * + * @param[in] uDataType Type to check for. + * @param[in] puTypeList List to check. + * + * @retval QCBOR_SUCCESS If in the list. + * @retval QCBOR_ERR_UNEXPECTED_TYPE Not in the list. + */ +static QCBORError +QCBOR_Private_CheckTypeList(const int uDataType, + const uint8_t puTypeList[QCBOR_TAGSPEC_NUM_TYPES]) +{ + for(size_t i = 0; i < QCBOR_TAGSPEC_NUM_TYPES; i++) { + if(uDataType == puTypeList[i]) { /* -Wmaybe-uninitialized falsly warns here */ + return QCBOR_SUCCESS; + } + } + return QCBOR_ERR_UNEXPECTED_TYPE; +} + + +/** + * Match a tag/type specification against the type of the item. + * + * @param[in] TagSpec Specification for matching tags. + * @param[in] pItem The item to check. + * + * @retval QCBOR_SUCCESS @c uDataType is allowed by @c TagSpec + * @retval QCBOR_ERR_UNEXPECTED_TYPE @c uDataType is not allowed by @c TagSpec + * + * This checks the item data type of untagged items as well as of + * tagged items against a specification to see if decoding should + * proceed. + * + * This relies on the automatic tag decoding done by QCBOR that turns + * tag numbers into particular QCBOR_TYPEs so there is no actual + * comparsion of tag numbers, just of QCBOR_TYPEs. + * + * This checks the data item type as possibly representing the tag + * number or as the tag content type. + * + * If QCBOR_DISABLE_TAGS is #defined, this primarily checks the item + * data type against the allowed tag content types, but also checks + * against the tagged types. The QCBOR_TYPEs checked will never be + * associated with tag numbers, but this checking is needed for the + * text and byte string use cases . + */ +static QCBORError +QCBOR_Private_CheckTagRequirement(const QCBOR_Private_TagSpec TagSpec, + const QCBORItem *pItem) +{ + const int nItemType = pItem->uDataType; /* -Wmaybe-uninitialized falsly warns here */ const int nTagReq = TagSpec.uTagRequirement & ~QCBOR_TAG_REQUIREMENT_ALLOW_ADDITIONAL_TAGS; #ifndef QCBOR_DISABLE_TAGS + /* -Wmaybe-uninitialized falsly warns here */ if(!(TagSpec.uTagRequirement & QCBOR_TAG_REQUIREMENT_ALLOW_ADDITIONAL_TAGS) && pItem->uTags[0] != CBOR_TAG_INVALID16) { /* There are tags that QCBOR couldn't process on this item and @@ -3358,10 +3813,10 @@ CheckTagRequirement(const TagSpecification TagSpec, const QCBORItem *pItem) if(nTagReq == QCBOR_TAG_REQUIREMENT_TAG) { /* Must match the tag number and only the tag */ - return CheckTypeList(nItemType, TagSpec.uTaggedTypes); + return QCBOR_Private_CheckTypeList(nItemType, TagSpec.uTaggedTypes); } - QCBORError uReturn = CheckTypeList(nItemType, TagSpec.uAllowedContentTypes); + QCBORError uReturn = QCBOR_Private_CheckTypeList(nItemType, TagSpec.uAllowedContentTypes); if(uReturn == QCBOR_SUCCESS) { return QCBOR_SUCCESS; } @@ -3372,61 +3827,99 @@ CheckTagRequirement(const TagSpecification TagSpec, const QCBORItem *pItem) return QCBOR_ERR_UNEXPECTED_TYPE; } - /* QCBOR_TAG_REQUIREMENT_OPTIONAL_TAG: If here it can match either the tag or the content - * and it hasn't matched the content, so the end - * result is whether it matches the tag. This is - * the tag optional case that the CBOR standard discourages. + /* QCBOR_TAG_REQUIREMENT_OPTIONAL_TAG: If here it can match either + * the tag or the content and it hasn't matched the content, so the + * end result is whether it matches the tag. This is the tag + * optional case that the CBOR standard discourages. */ - return CheckTypeList(nItemType, TagSpec.uTaggedTypes); + return QCBOR_Private_CheckTypeList(nItemType, TagSpec.uTaggedTypes); #else /* QCBOR_DISABLE_TAGS */ if(nTagReq == QCBOR_TAG_REQUIREMENT_TAG) { - return QCBOR_ERR_UNEXPECTED_TYPE; + /* This is only checking base QCBOR types, not those associated + * with tag numbers since you can get here with tag numbers. + */ + return QCBOR_Private_CheckTypeList(nItemType, TagSpec.uTaggedTypes); } - return CheckTypeList(nItemType, TagSpec.uAllowedContentTypes); + return QCBOR_Private_CheckTypeList(nItemType, TagSpec.uAllowedContentTypes); #endif /* QCBOR_DISABLE_TAGS */ } -// This could be semi-private if need be -static inline -void QCBORDecode_GetTaggedItemInMapN(QCBORDecodeContext *pMe, - const int64_t nLabel, - const TagSpecification TagSpec, - QCBORItem *pItem) +/** + * @brief Get an item by label to match a tag specification. + * + * @param[in] pMe The decode context. + * @param[in] nLabel The label to search map for. + * @param[in] TagSpec The tag number specification to match. + * @param[out] pItem The item found. + * + * This finds the item with the given label in currently open + * map. Then checks that its tag number and types matches the tag + * specification. If not, an error is set in the decode context. + */ +static void +QCBORDecode_GetTaggedItemInMapN(QCBORDecodeContext *pMe, + const int64_t nLabel, + const QCBOR_Private_TagSpec TagSpec, + QCBORItem *pItem) { QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, pItem); if(pMe->uLastError != QCBOR_SUCCESS) { return; } - pMe->uLastError = (uint8_t)CheckTagRequirement(TagSpec, pItem); + pMe->uLastError = (uint8_t)QCBOR_Private_CheckTagRequirement(TagSpec, pItem); } -// This could be semi-private if need be -static inline -void QCBORDecode_GetTaggedItemInMapSZ(QCBORDecodeContext *pMe, - const char *szLabel, - const TagSpecification TagSpec, - QCBORItem *pItem) +/** + * @brief Get an item by label to match a tag specification. + * + * @param[in] pMe The decode context. + * @param[in] szLabel The label to search map for. + * @param[in] TagSpec The tag number specification to match. + * @param[out] pItem The item found. + * + * This finds the item with the given label in currently open + * map. Then checks that its tag number and types matches the tag + * specification. If not, an error is set in the decode context. + */ +static void +QCBORDecode_GetTaggedItemInMapSZ(QCBORDecodeContext *pMe, + const char *szLabel, + const QCBOR_Private_TagSpec TagSpec, + QCBORItem *pItem) { QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, pItem); if(pMe->uLastError != QCBOR_SUCCESS) { return; } - pMe->uLastError = (uint8_t)CheckTagRequirement(TagSpec, pItem); + pMe->uLastError = (uint8_t)QCBOR_Private_CheckTagRequirement(TagSpec, pItem); } -// Semi-private -void QCBORDecode_GetTaggedStringInMapN(QCBORDecodeContext *pMe, - int64_t nLabel, - TagSpecification TagSpec, - UsefulBufC *pString) + +/** + * @brief Semi-private to get an string by label to match a tag specification. + * + * @param[in] pMe The decode context. + * @param[in] nLabel The label to search map for. + * @param[in] TagSpec The tag number specification to match. + * @param[out] pString The string found. + * + * This finds the string with the given label in currently open + * map. Then checks that its tag number and types matches the tag + * specification. If not, an error is set in the decode context. + */ +void +QCBORDecode_Private_GetTaggedStringInMapN(QCBORDecodeContext *pMe, + const int64_t nLabel, + const QCBOR_Private_TagSpec TagSpec, + UsefulBufC *pString) { QCBORItem Item; QCBORDecode_GetTaggedItemInMapN(pMe, nLabel, TagSpec, &Item); @@ -3435,11 +3928,23 @@ void QCBORDecode_GetTaggedStringInMapN(QCBORDecodeContext *pMe, } } -// Semi-private -void QCBORDecode_GetTaggedStringInMapSZ(QCBORDecodeContext *pMe, - const char * szLabel, - TagSpecification TagSpec, - UsefulBufC *pString) + +/** + * @brief Semi-private to get an string by label to match a tag specification. + * + * @param[in] pMe The decode context. + * @param[in] szLabel The label to search map for. + * @param[in] TagSpec The tag number specification to match. + * @param[out] pString The string found. + * + * This finds the string with the given label in currently open + * map. Then checks that its tag number and types matches the tag + * specification. If not, an error is set in the decode context. + */void +QCBORDecode_Private_GetTaggedStringInMapSZ(QCBORDecodeContext *pMe, + const char * szLabel, + const QCBOR_Private_TagSpec TagSpec, + UsefulBufC *pString) { QCBORItem Item; QCBORDecode_GetTaggedItemInMapSZ(pMe, szLabel, TagSpec, &Item); @@ -3448,24 +3953,32 @@ void QCBORDecode_GetTaggedStringInMapSZ(QCBORDecodeContext *pMe, } } + /* - Public function, see header qcbor/qcbor_decode.h file -*/ -void QCBORDecode_GetItemsInMap(QCBORDecodeContext *pMe, QCBORItem *pItemList) + * Public function, see header qcbor/qcbor_decode.h file + */ +void +QCBORDecode_GetItemsInMap(QCBORDecodeContext *pMe, QCBORItem *pItemList) { - QCBORError uErr = MapSearch(pMe, pItemList, NULL, NULL, NULL); + QCBORError uErr = QCBORDecode_Private_MapSearch(pMe, pItemList, NULL, NULL); pMe->uLastError = (uint8_t)uErr; } /* - Public function, see header qcbor/qcbor_decode.h file -*/ -void QCBORDecode_GetItemsInMapWithCallback(QCBORDecodeContext *pMe, - QCBORItem *pItemList, - void *pCallbackCtx, - QCBORItemCallback pfCB) + * Public function, see header qcbor/qcbor_decode.h file + */ +void +QCBORDecode_GetItemsInMapWithCallback(QCBORDecodeContext *pMe, + QCBORItem *pItemList, + void *pCallbackCtx, + QCBORItemCallback pfCB) { - QCBORError uErr = MapSearch(pMe, pItemList, NULL, pCallbackCtx, pfCB); + MapSearchCallBack CallBack; + CallBack.pCBContext = pCallbackCtx; + CallBack.pfCallback = pfCB; + + QCBORError uErr = QCBORDecode_Private_MapSearch(pMe, pItemList, NULL, &CallBack); + pMe->uLastError = (uint8_t)uErr; } @@ -3483,7 +3996,8 @@ void QCBORDecode_GetItemsInMapWithCallback(QCBORDecodeContext *pMe, * If the label is not found, or the item found is not a map or array, * the error state is set. */ -static void SearchAndEnter(QCBORDecodeContext *pMe, QCBORItem pSearch[]) +static void +QCBORDecode_Private_SearchAndEnter(QCBORDecodeContext *pMe, QCBORItem pSearch[]) { // The first item in pSearch is the one that is to be // entered. It should be the only one filled in. Any other @@ -3492,8 +4006,8 @@ static void SearchAndEnter(QCBORDecodeContext *pMe, QCBORItem pSearch[]) return; } - size_t uOffset; - pMe->uLastError = (uint8_t)MapSearch(pMe, pSearch, &uOffset, NULL, NULL); + MapSearchInfo Info; + pMe->uLastError = (uint8_t)QCBORDecode_Private_MapSearch(pMe, pSearch, &Info, NULL); if(pMe->uLastError != QCBOR_SUCCESS) { return; } @@ -3523,20 +4037,21 @@ static void SearchAndEnter(QCBORDecodeContext *pMe, QCBORItem pSearch[]) * to be used to get one item and MapSearch() has already found it * confirming it exists. */ - UsefulInputBuf_Seek(&(pMe->InBuf), uOffset); + UsefulInputBuf_Seek(&(pMe->InBuf), Info.uStartOffset); DecodeNesting_ResetMapOrArrayCount(&(pMe->nesting)); DecodeNesting_SetCurrentToBoundedLevel(&(pMe->nesting)); - QCBORDecode_EnterBoundedMapOrArray(pMe, pSearch->uDataType, NULL); + QCBORDecode_Private_EnterBoundedMapOrArray(pMe, pSearch->uDataType, NULL); } /* - Public function, see header qcbor/qcbor_decode.h file -*/ -void QCBORDecode_EnterMapFromMapN(QCBORDecodeContext *pMe, int64_t nLabel) + * Public function, see header qcbor/qcbor_decode.h file + */ +void +QCBORDecode_EnterMapFromMapN(QCBORDecodeContext *pMe, int64_t nLabel) { QCBORItem OneItemSeach[2]; OneItemSeach[0].uLabelType = QCBOR_TYPE_INT64; @@ -3545,28 +4060,35 @@ void QCBORDecode_EnterMapFromMapN(QCBORDecodeContext *pMe, int64_t nLabel) OneItemSeach[1].uLabelType = QCBOR_TYPE_NONE; /* The map to enter was found, now finish off entering it. */ - SearchAndEnter(pMe, OneItemSeach); + QCBORDecode_Private_SearchAndEnter(pMe, OneItemSeach); } /* - Public function, see header qcbor/qcbor_decode.h file -*/ -void QCBORDecode_EnterMapFromMapSZ(QCBORDecodeContext *pMe, const char *szLabel) + * Public function, see header qcbor/qcbor_decode.h file + */ +void +QCBORDecode_EnterMapFromMapSZ(QCBORDecodeContext *pMe, const char *szLabel) { +#ifndef QCBOR_DISABLE_NON_INTEGER_LABELS QCBORItem OneItemSeach[2]; OneItemSeach[0].uLabelType = QCBOR_TYPE_TEXT_STRING; OneItemSeach[0].label.string = UsefulBuf_FromSZ(szLabel); OneItemSeach[0].uDataType = QCBOR_TYPE_MAP; OneItemSeach[1].uLabelType = QCBOR_TYPE_NONE; - SearchAndEnter(pMe, OneItemSeach); + QCBORDecode_Private_SearchAndEnter(pMe, OneItemSeach); +#else + (void)szLabel; + pMe->uLastError = QCBOR_ERR_LABEL_NOT_FOUND; +#endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */ } /* - Public function, see header qcbor/qcbor_decode.h file -*/ -void QCBORDecode_EnterArrayFromMapN(QCBORDecodeContext *pMe, int64_t nLabel) + * Public function, see header qcbor/qcbor_decode.h file + */ +void +QCBORDecode_EnterArrayFromMapN(QCBORDecodeContext *pMe, int64_t nLabel) { QCBORItem OneItemSeach[2]; OneItemSeach[0].uLabelType = QCBOR_TYPE_INT64; @@ -3574,26 +4096,45 @@ void QCBORDecode_EnterArrayFromMapN(QCBORDecodeContext *pMe, int64_t nLabel) OneItemSeach[0].uDataType = QCBOR_TYPE_ARRAY; OneItemSeach[1].uLabelType = QCBOR_TYPE_NONE; - SearchAndEnter(pMe, OneItemSeach); + QCBORDecode_Private_SearchAndEnter(pMe, OneItemSeach); } /* - Public function, see header qcbor/qcbor_decode.h file -*/ -void QCBORDecode_EnterArrayFromMapSZ(QCBORDecodeContext *pMe, const char *szLabel) + * Public function, see header qcbor/qcbor_decode.h file + */ +void +QCBORDecode_EnterArrayFromMapSZ(QCBORDecodeContext *pMe, const char *szLabel) { +#ifndef QCBOR_DISABLE_NON_INTEGER_LABELS QCBORItem OneItemSeach[2]; OneItemSeach[0].uLabelType = QCBOR_TYPE_TEXT_STRING; OneItemSeach[0].label.string = UsefulBuf_FromSZ(szLabel); OneItemSeach[0].uDataType = QCBOR_TYPE_ARRAY; OneItemSeach[1].uLabelType = QCBOR_TYPE_NONE; - SearchAndEnter(pMe, OneItemSeach); + QCBORDecode_Private_SearchAndEnter(pMe, OneItemSeach); +#else + (void)szLabel; + pMe->uLastError = QCBOR_ERR_LABEL_NOT_FOUND; +#endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */ } -// Semi-private function -void QCBORDecode_EnterBoundedMapOrArray(QCBORDecodeContext *pMe, uint8_t uType, QCBORItem *pItem) +/** + * @brief Semi-private to do the the work for EnterMap() and EnterArray(). + * + * @param[in] pMe The decode context + * @param[in] uType QCBOR_TYPE_MAP or QCBOR_TYPE_ARRAY. + * @param[out] pItem The data item for the map or array entered. + * + * The next item in the traversal must be a map or array. This + * consumes that item and does the book keeping to enter the map or + * array. + */ +void +QCBORDecode_Private_EnterBoundedMapOrArray(QCBORDecodeContext *pMe, + const uint8_t uType, + QCBORItem *pItem) { QCBORError uErr; @@ -3609,12 +4150,21 @@ void QCBORDecode_EnterBoundedMapOrArray(QCBORDecodeContext *pMe, uint8_t uType, if(uErr != QCBOR_SUCCESS) { goto Done; } - if(Item.uDataType != uType) { + + uint8_t uItemDataType = Item.uDataType; + +#ifndef QCBOR_DISABLE_NON_INTEGER_LABELS + if(uItemDataType == QCBOR_TYPE_MAP_AS_ARRAY ) { + uItemDataType = QCBOR_TYPE_ARRAY; + } +#endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */ + + if(uItemDataType != uType) { uErr = QCBOR_ERR_UNEXPECTED_TYPE; goto Done; } - CopyTags(pMe, &Item); + QCBORDecode_Private_CopyTags(pMe, &Item); const bool bIsEmpty = (Item.uNextNestLevel <= Item.uNestingLevel); @@ -3643,52 +4193,60 @@ void QCBORDecode_EnterBoundedMapOrArray(QCBORDecodeContext *pMe, uint8_t uType, } -/* - This is the common work for exiting a level that is a bounded map, - array or bstr wrapped CBOR. - - One chunk of work is to set up the pre-order traversal so it is at - the item just after the bounded map, array or bstr that is being - exited. This is somewhat complex. - - The other work is to level-up the bounded mode to next higest bounded - mode or the top level if there isn't one. +/** + * @brief Exit a bounded map, array or bstr (semi-private). + * + * @param[in] pMe Decode context. + * @param[in] uEndOffset The input buffer offset of the end of item exited. + * + * @returns QCBOR_SUCCESS or an error code. + * + * This is the common work for exiting a level that is a bounded map, + * array or bstr wrapped CBOR. + * + * One chunk of work is to set up the pre-order traversal so it is at + * the item just after the bounded map, array or bstr that is being + * exited. This is somewhat complex. + * + * The other work is to level-up the bounded mode to next higest + * bounded mode or the top level if there isn't one. */ static QCBORError -ExitBoundedLevel(QCBORDecodeContext *pMe, uint32_t uEndOffset) +QCBORDecode_Private_ExitBoundedLevel(QCBORDecodeContext *pMe, + const uint32_t uEndOffset) { QCBORError uErr; /* - First the pre-order-traversal byte offset is positioned to the - item just after the bounded mode item that was just consumed. + * First the pre-order-traversal byte offset is positioned to the + * item just after the bounded mode item that was just consumed. */ UsefulInputBuf_Seek(&(pMe->InBuf), uEndOffset); /* - Next, set the current nesting level to one above the bounded level - that was just exited. - - DecodeNesting_CheckBoundedType() is always called before this and - makes sure pCurrentBounded is valid. + * Next, set the current nesting level to one above the bounded + * level that was just exited. + * + * DecodeNesting_CheckBoundedType() is always called before this + * and makes sure pCurrentBounded is valid. */ DecodeNesting_LevelUpCurrent(&(pMe->nesting)); /* - This does the complex work of leveling up the pre-order traversal - when the end of a map or array or another bounded level is - reached. It may do nothing, or ascend all the way to the top - level. + * This does the complex work of leveling up the pre-order + * traversal when the end of a map or array or another bounded + * level is reached. It may do nothing, or ascend all the way to + * the top level. */ - uErr = QCBORDecode_NestLevelAscender(pMe, false); + uErr = QCBORDecode_Private_NestLevelAscender(pMe, NULL, false); if(uErr != QCBOR_SUCCESS) { goto Done; } /* - This makes the next highest bounded level the current bounded - level. If there is no next highest level, then no bounded mode is - in effect. + * This makes the next highest bounded level the current bounded + * level. If there is no next highest level, then no bounded mode + * is in effect. */ DecodeNesting_LevelUpBounded(&(pMe->nesting)); @@ -3699,8 +4257,19 @@ ExitBoundedLevel(QCBORDecodeContext *pMe, uint32_t uEndOffset) } -// Semi-private function -void QCBORDecode_ExitBoundedMapOrArray(QCBORDecodeContext *pMe, uint8_t uType) +/** + * @brief Get started exiting a map or array (semi-private) + * + * @param[in] pMe The decode context + * @param[in] uType QCBOR_TYPE_ARRAY or QCBOR_TYPE_MAP + * + * This does some work for map and array exiting (but not + * bstr exiting). Then QCBORDecode_Private_ExitBoundedLevel() + * is called to do the rest. + */ +void +QCBORDecode_Private_ExitBoundedMapOrArray(QCBORDecodeContext *pMe, + const uint8_t uType) { if(pMe->uLastError != QCBOR_SUCCESS) { /* Already in error state; do nothing. */ @@ -3722,25 +4291,38 @@ void QCBORDecode_ExitBoundedMapOrArray(QCBORDecodeContext *pMe, uint8_t uType) if(pMe->uMapEndOffsetCache == QCBOR_MAP_OFFSET_CACHE_INVALID) { QCBORItem Dummy; Dummy.uLabelType = QCBOR_TYPE_NONE; - uErr = MapSearch(pMe, &Dummy, NULL, NULL, NULL); + uErr = QCBORDecode_Private_MapSearch(pMe, &Dummy, NULL, NULL); if(uErr != QCBOR_SUCCESS) { goto Done; } } - uErr = ExitBoundedLevel(pMe, pMe->uMapEndOffsetCache); + uErr = QCBORDecode_Private_ExitBoundedLevel(pMe, pMe->uMapEndOffsetCache); Done: pMe->uLastError = (uint8_t)uErr; } - +/** + * @brief The main work of entering some byte-string wrapped CBOR. + * + * @param[in] pMe The decode context. + * @param[in] pItem The byte string item. + * @param[in] uTagRequirement One of @c QCBOR_TAG_REQUIREMENT_XXX + * @param[out] pBstr Pointer and length of byte string entered. + * + * This is called once the byte string item has been decoded to do all + * the book keeping work for descending a nesting level into the + * nested CBOR. + * + * See QCBORDecode_EnterBstrWrapped() for details on uTagRequirement. + */ static QCBORError -InternalEnterBstrWrapped(QCBORDecodeContext *pMe, - const QCBORItem *pItem, - const uint8_t uTagRequirement, - UsefulBufC *pBstr) +QCBORDecode_Private_EnterBstrWrapped(QCBORDecodeContext *pMe, + const QCBORItem *pItem, + const uint8_t uTagRequirement, + UsefulBufC *pBstr) { if(pBstr) { *pBstr = NULLUsefulBufC; @@ -3753,14 +4335,14 @@ InternalEnterBstrWrapped(QCBORDecodeContext *pMe, QCBORError uError; - const TagSpecification TagSpec = + const QCBOR_Private_TagSpec TagSpec = { uTagRequirement, {QBCOR_TYPE_WRAPPED_CBOR, QBCOR_TYPE_WRAPPED_CBOR_SEQUENCE, QCBOR_TYPE_NONE}, {QCBOR_TYPE_BYTE_STRING, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE} }; - uError = CheckTagRequirement(TagSpec, pItem); + uError = QCBOR_Private_CheckTagRequirement(TagSpec, pItem); if(uError != QCBOR_SUCCESS) { goto Done; } @@ -3817,11 +4399,12 @@ InternalEnterBstrWrapped(QCBORDecodeContext *pMe, /* - Public function, see header qcbor/qcbor_decode.h file + * Public function, see header qcbor/qcbor_decode.h file */ -void QCBORDecode_EnterBstrWrapped(QCBORDecodeContext *pMe, - uint8_t uTagRequirement, - UsefulBufC *pBstr) +void +QCBORDecode_EnterBstrWrapped(QCBORDecodeContext *pMe, + const uint8_t uTagRequirement, + UsefulBufC *pBstr) { if(pMe->uLastError != QCBOR_SUCCESS) { // Already in error state; do nothing. @@ -3835,53 +4418,61 @@ void QCBORDecode_EnterBstrWrapped(QCBORDecodeContext *pMe, return; } - pMe->uLastError = (uint8_t)InternalEnterBstrWrapped(pMe, - &Item, - uTagRequirement, - pBstr); + if(Item.uDataAlloc) { + pMe->uLastError = QCBOR_ERR_CANNOT_ENTER_ALLOCATED_STRING; + return; + } + + pMe->uLastError = (uint8_t)QCBORDecode_Private_EnterBstrWrapped(pMe, + &Item, + uTagRequirement, + pBstr); } /* - Public function, see header qcbor/qcbor_decode.h file + * Public function, see header qcbor/qcbor_decode.h file */ -void QCBORDecode_EnterBstrWrappedFromMapN(QCBORDecodeContext *pMe, - int64_t nLabel, - uint8_t uTagRequirement, - UsefulBufC *pBstr) +void +QCBORDecode_EnterBstrWrappedFromMapN(QCBORDecodeContext *pMe, + const int64_t nLabel, + const uint8_t uTagRequirement, + UsefulBufC *pBstr) { QCBORItem Item; QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, &Item); - pMe->uLastError = (uint8_t)InternalEnterBstrWrapped(pMe, - &Item, - uTagRequirement, - pBstr); + pMe->uLastError = (uint8_t)QCBORDecode_Private_EnterBstrWrapped(pMe, + &Item, + uTagRequirement, + pBstr); } /* - Public function, see header qcbor/qcbor_decode.h file + * Public function, see header qcbor/qcbor_decode.h file */ -void QCBORDecode_EnterBstrWrappedFromMapSZ(QCBORDecodeContext *pMe, - const char *szLabel, - uint8_t uTagRequirement, - UsefulBufC *pBstr) +void +QCBORDecode_EnterBstrWrappedFromMapSZ(QCBORDecodeContext *pMe, + const char *szLabel, + const uint8_t uTagRequirement, + UsefulBufC *pBstr) { QCBORItem Item; QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item); - pMe->uLastError = (uint8_t)InternalEnterBstrWrapped(pMe, - &Item, - uTagRequirement, - pBstr); + pMe->uLastError = (uint8_t)QCBORDecode_Private_EnterBstrWrapped(pMe, + &Item, + uTagRequirement, + pBstr); } /* - Public function, see header qcbor/qcbor_decode.h file + * Public function, see header qcbor/qcbor_decode.h file */ -void QCBORDecode_ExitBstrWrapped(QCBORDecodeContext *pMe) +void +QCBORDecode_ExitBstrWrapped(QCBORDecodeContext *pMe) { if(pMe->uLastError != QCBOR_SUCCESS) { // Already in error state; do nothing. @@ -3903,15 +4494,26 @@ void QCBORDecode_ExitBstrWrapped(QCBORDecodeContext *pMe) DecodeNesting_GetPreviousBoundedEnd(&(pMe->nesting))); - QCBORError uErr = ExitBoundedLevel(pMe, uEndOfBstr); + QCBORError uErr = QCBORDecode_Private_ExitBoundedLevel(pMe, uEndOfBstr); pMe->uLastError = (uint8_t)uErr; } - -static inline void -ProcessBool(QCBORDecodeContext *pMe, const QCBORItem *pItem, bool *pBool) +/** + * @brief Process simple type true and false, a boolean + * + * @param[in] pMe The decode context. + * @param[in] pItem The item with either true or false. + * @param[out] pBool The boolean value output. + * + * Sets the internal error if the item isn't a true or a false. Also + * records any tag numbers as the tag numbers of the last item. + */ +static void +QCBORDecode_Private_ProcessBool(QCBORDecodeContext *pMe, + const QCBORItem *pItem, + bool *pBool) { if(pMe->uLastError != QCBOR_SUCCESS) { /* Already in error state, do nothing */ @@ -3931,58 +4533,154 @@ ProcessBool(QCBORDecodeContext *pMe, const QCBORItem *pItem, bool *pBool) pMe->uLastError = QCBOR_ERR_UNEXPECTED_TYPE; break; } - CopyTags(pMe, pItem); } /* * Public function, see header qcbor/qcbor_decode.h file */ -void QCBORDecode_GetBool(QCBORDecodeContext *pMe, bool *pValue) +void +QCBORDecode_GetBool(QCBORDecodeContext *pMe, bool *pValue) +{ + QCBORItem Item; + QCBORDecode_VGetNext(pMe, &Item); + QCBORDecode_Private_ProcessBool(pMe, &Item, pValue); +} + + +/* + * Public function, see header qcbor/qcbor_decode.h file + */ +void +QCBORDecode_GetBoolInMapN(QCBORDecodeContext *pMe, + const int64_t nLabel, + bool *pValue) +{ + QCBORItem Item; + QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, &Item); + QCBORDecode_Private_ProcessBool(pMe, &Item, pValue); +} + + +/* + * Public function, see header qcbor/qcbor_decode.h file + */ +void +QCBORDecode_GetBoolInMapSZ(QCBORDecodeContext *pMe, + const char *szLabel, + bool *pValue) +{ + QCBORItem Item; + QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item); + QCBORDecode_Private_ProcessBool(pMe, &Item, pValue); +} + + +/** + * @brief Process simple values. + * + * @param[in] pMe The decode context. + * @param[in] pItem The item with the simple value. + * @param[out] puSimple The simple value output. + * + * Sets the internal error if the item isn't a true or a false. Also + * records any tag numbers as the tag numbers of the last item. + */ +static void +QCBORDecode_Private_ProcessSimple(QCBORDecodeContext *pMe, + const QCBORItem *pItem, + uint8_t *puSimple) { if(pMe->uLastError != QCBOR_SUCCESS) { - /* Already in error state, do nothing */ return; } - QCBORItem Item; + /* It's kind of lame to remap true...undef back to simple values, but + * this function isn't used much and to not do it would require + * changing GetNext() behavior in an incompatible way. + */ + switch(pItem->uDataType) { + case QCBOR_TYPE_UKNOWN_SIMPLE: + *puSimple = pItem->val.uSimple; + break; - pMe->uLastError = (uint8_t)QCBORDecode_GetNext(pMe, &Item); + case QCBOR_TYPE_TRUE: + *puSimple = CBOR_SIMPLEV_TRUE; + break; + + case QCBOR_TYPE_FALSE: + *puSimple = CBOR_SIMPLEV_FALSE; + break; - ProcessBool(pMe, &Item, pValue); + case QCBOR_TYPE_NULL: + *puSimple = CBOR_SIMPLEV_NULL; + break; + + case QCBOR_TYPE_UNDEF: + *puSimple = CBOR_SIMPLEV_UNDEF; + break; + + default: + pMe->uLastError = QCBOR_ERR_UNEXPECTED_TYPE; + return; + } } +/* + * Public function, see header qcbor/qcbor_decode.h file + */ +void +QCBORDecode_GetSimple(QCBORDecodeContext *pMe, uint8_t *puSimple) +{ + QCBORItem Item; + QCBORDecode_VGetNext(pMe, &Item); + QCBORDecode_Private_ProcessSimple(pMe, &Item, puSimple); +} /* * Public function, see header qcbor/qcbor_decode.h file */ -void QCBORDecode_GetBoolInMapN(QCBORDecodeContext *pMe, int64_t nLabel, bool *pValue) +void +QCBORDecode_GetSimpleInMapN(QCBORDecodeContext *pMe, + int64_t nLabel, + uint8_t *puSimpleValue) { QCBORItem Item; QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, &Item); - - ProcessBool(pMe, &Item, pValue); + QCBORDecode_Private_ProcessSimple(pMe, &Item, puSimpleValue); } - /* * Public function, see header qcbor/qcbor_decode.h file */ -void QCBORDecode_GetBoolInMapSZ(QCBORDecodeContext *pMe, const char *szLabel, bool *pValue) +void +QCBORDecode_GetSimpleInMapSZ(QCBORDecodeContext *pMe, + const char *szLabel, + uint8_t *puSimpleValue) { QCBORItem Item; QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item); - - ProcessBool(pMe, &Item, pValue); + QCBORDecode_Private_ProcessSimple(pMe, &Item, puSimpleValue); } - -static void ProcessEpochDate(QCBORDecodeContext *pMe, - QCBORItem *pItem, - const uint8_t uTagRequirement, - int64_t *pnTime) +/** + * @brief Common processing for an epoch date. + * + * @param[in] pMe The decode context. + * @param[in] pItem The item with the date. + * @param[in] uTagRequirement One of @c QCBOR_TAG_REQUIREMENT_XXX. + * @param[out] pnTime The returned date. + * + * Common processing for the date tag. Mostly make sure the tag + * content is correct and copy forward any further other tag numbers. + */ +static void +QCBORDecode_Private_ProcessEpochDate(QCBORDecodeContext *pMe, + QCBORItem *pItem, + const uint8_t uTagRequirement, + int64_t *pnTime) { if(pMe->uLastError != QCBOR_SUCCESS) { // Already in error state, do nothing @@ -3991,29 +4689,25 @@ static void ProcessEpochDate(QCBORDecodeContext *pMe, QCBORError uErr; - const TagSpecification TagSpec = + const QCBOR_Private_TagSpec TagSpec = { uTagRequirement, {QCBOR_TYPE_DATE_EPOCH, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}, {QCBOR_TYPE_INT64, QCBOR_TYPE_DOUBLE, QCBOR_TYPE_FLOAT, QCBOR_TYPE_UINT64} }; - uErr = CheckTagRequirement(TagSpec, pItem); + uErr = QCBOR_Private_CheckTagRequirement(TagSpec, pItem); if(uErr != QCBOR_SUCCESS) { goto Done; } if(pItem->uDataType != QCBOR_TYPE_DATE_EPOCH) { - uErr = DecodeDateEpoch(pItem); + uErr = QCBOR_Private_DecodeDateEpoch(pItem); if(uErr != QCBOR_SUCCESS) { goto Done; } } - // Save the tags in the last item's tags in the decode context - // for QCBORDecode_GetNthTagOfLast() - CopyTags(pMe, pItem); - *pnTime = pItem->val.epochDate.nSeconds; Done: @@ -4021,22 +4715,24 @@ static void ProcessEpochDate(QCBORDecodeContext *pMe, } -void QCBORDecode_GetEpochDate(QCBORDecodeContext *pMe, - uint8_t uTagRequirement, - int64_t *pnTime) -{ - if(pMe->uLastError != QCBOR_SUCCESS) { - // Already in error state, do nothing - return; - } +/* + * Public function, see header qcbor/qcbor_spiffy_decode.h file + */ +void +QCBORDecode_GetEpochDate(QCBORDecodeContext *pMe, + uint8_t uTagRequirement, + int64_t *pnTime) +{ QCBORItem Item; - pMe->uLastError = (uint8_t)QCBORDecode_GetNext(pMe, &Item); - - ProcessEpochDate(pMe, &Item, uTagRequirement, pnTime); + QCBORDecode_VGetNext(pMe, &Item); + QCBORDecode_Private_ProcessEpochDate(pMe, &Item, uTagRequirement, pnTime); } +/* + * Public function, see header qcbor/qcbor_spiffy_decode.h file + */ void QCBORDecode_GetEpochDateInMapN(QCBORDecodeContext *pMe, int64_t nLabel, @@ -4045,10 +4741,13 @@ QCBORDecode_GetEpochDateInMapN(QCBORDecodeContext *pMe, { QCBORItem Item; QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, &Item); - ProcessEpochDate(pMe, &Item, uTagRequirement, pnTime); + QCBORDecode_Private_ProcessEpochDate(pMe, &Item, uTagRequirement, pnTime); } +/* + * Public function, see header qcbor/qcbor_spiffy_decode.h file + */ void QCBORDecode_GetEpochDateInMapSZ(QCBORDecodeContext *pMe, const char *szLabel, @@ -4057,20 +4756,28 @@ QCBORDecode_GetEpochDateInMapSZ(QCBORDecodeContext *pMe, { QCBORItem Item; QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item); - ProcessEpochDate(pMe, &Item, uTagRequirement, pnTime); + QCBORDecode_Private_ProcessEpochDate(pMe, &Item, uTagRequirement, pnTime); } -/* - * Common processing for the RFC 8943 day-count tag. Mostly - * make sure the tag content is correct and copy forward any - * further other tag numbers. +/** + * @brief Common processing for an epoch date. + * + * @param[in] pMe The decode context. + * @param[in] pItem The item with the date. + * @param[in] uTagRequirement One of @c QCBOR_TAG_REQUIREMENT_XXX. + * @param[out] pnDays The returned day count. + * + * Common processing for the RFC 8943 day-count tag. Mostly make sure + * the tag content is correct and copy forward any further other tag + * numbers. */ -static void ProcessEpochDays(QCBORDecodeContext *pMe, - QCBORItem *pItem, - uint8_t uTagRequirement, - int64_t *pnDays) +static void +QCBORDecode_Private_ProcessEpochDays(QCBORDecodeContext *pMe, + QCBORItem *pItem, + uint8_t uTagRequirement, + int64_t *pnDays) { if(pMe->uLastError != QCBOR_SUCCESS) { /* Already in error state, do nothing */ @@ -4079,30 +4786,25 @@ static void ProcessEpochDays(QCBORDecodeContext *pMe, QCBORError uErr; - const TagSpecification TagSpec = + const QCBOR_Private_TagSpec TagSpec = { uTagRequirement, {QCBOR_TYPE_DAYS_EPOCH, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}, {QCBOR_TYPE_INT64, QCBOR_TYPE_UINT64, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE} }; - uErr = CheckTagRequirement(TagSpec, pItem); + uErr = QCBOR_Private_CheckTagRequirement(TagSpec, pItem); if(uErr != QCBOR_SUCCESS) { goto Done; } if(pItem->uDataType != QCBOR_TYPE_DAYS_EPOCH) { - uErr = DecodeDaysEpoch(pItem); + uErr = QCBOR_Private_DecodeDaysEpoch(pItem); if(uErr != QCBOR_SUCCESS) { goto Done; } } - /* Save the tags in the last item's tags in the decode context - * for QCBORDecode_GetNthTagOfLast() - */ - CopyTags(pMe, pItem); - *pnDays = pItem->val.epochDays; Done: @@ -4113,19 +4815,14 @@ static void ProcessEpochDays(QCBORDecodeContext *pMe, /* * Public function, see header qcbor/qcbor_decode.h */ -void QCBORDecode_GetEpochDays(QCBORDecodeContext *pMe, - uint8_t uTagRequirement, - int64_t *pnDays) +void +QCBORDecode_GetEpochDays(QCBORDecodeContext *pMe, + uint8_t uTagRequirement, + int64_t *pnDays) { - if(pMe->uLastError != QCBOR_SUCCESS) { - /* Already in error state, do nothing */ - return; - } - QCBORItem Item; - pMe->uLastError = (uint8_t)QCBORDecode_GetNext(pMe, &Item); - - ProcessEpochDays(pMe, &Item, uTagRequirement, pnDays); + QCBORDecode_VGetNext(pMe, &Item); + QCBORDecode_Private_ProcessEpochDays(pMe, &Item, uTagRequirement, pnDays); } @@ -4140,7 +4837,7 @@ QCBORDecode_GetEpochDaysInMapN(QCBORDecodeContext *pMe, { QCBORItem Item; QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, &Item); - ProcessEpochDays(pMe, &Item, uTagRequirement, pnDays); + QCBORDecode_Private_ProcessEpochDays(pMe, &Item, uTagRequirement, pnDays); } @@ -4155,7 +4852,7 @@ QCBORDecode_GetEpochDaysInMapSZ(QCBORDecodeContext *pMe, { QCBORItem Item; QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item); - ProcessEpochDays(pMe, &Item, uTagRequirement, pnDays); + QCBORDecode_Private_ProcessEpochDays(pMe, &Item, uTagRequirement, pnDays); } @@ -4164,25 +4861,18 @@ QCBORDecode_GetEpochDaysInMapSZ(QCBORDecodeContext *pMe, * @brief Get a string that matches the type/tag specification. */ void -QCBORDecode_GetTaggedStringInternal(QCBORDecodeContext *pMe, - const TagSpecification TagSpec, - UsefulBufC *pBstr) +QCBORDecode_Private_GetTaggedString(QCBORDecodeContext *pMe, + const QCBOR_Private_TagSpec TagSpec, + UsefulBufC *pBstr) { - if(pMe->uLastError != QCBOR_SUCCESS) { - /* Already in error state, do nothing */ - return; - } - - QCBORError uError; QCBORItem Item; - uError = QCBORDecode_GetNext(pMe, &Item); - if(uError != QCBOR_SUCCESS) { - pMe->uLastError = (uint8_t)uError; + QCBORDecode_VGetNext(pMe, &Item); + if(pMe->uLastError) { return; } - pMe->uLastError = (uint8_t)CheckTagRequirement(TagSpec, &Item); + pMe->uLastError = (uint8_t)QCBOR_Private_CheckTagRequirement(TagSpec, &Item); if(pMe->uLastError == QCBOR_SUCCESS) { *pBstr = Item.val.string; @@ -4194,20 +4884,32 @@ QCBORDecode_GetTaggedStringInternal(QCBORDecodeContext *pMe, +/** + * @brief Common processing for a big number tag. + * + * @param[in] uTagRequirement One of @c QCBOR_TAG_REQUIREMENT_XXX. + * @param[in] pItem The item with the date. + * @param[out] pValue The returned big number + * @param[out] pbIsNegative The returned sign of the big number. + * + * Common processing for the big number tag. Mostly make sure + * the tag content is correct and copy forward any further other tag + * numbers. + */ static QCBORError -ProcessBigNum(const uint8_t uTagRequirement, - const QCBORItem *pItem, - UsefulBufC *pValue, - bool *pbIsNegative) +QCBOR_Private_ProcessBigNum(const uint8_t uTagRequirement, + const QCBORItem *pItem, + UsefulBufC *pValue, + bool *pbIsNegative) { - const TagSpecification TagSpec = + const QCBOR_Private_TagSpec TagSpec = { uTagRequirement, {QCBOR_TYPE_POSBIGNUM, QCBOR_TYPE_NEGBIGNUM, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}, {QCBOR_TYPE_BYTE_STRING, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE} }; - QCBORError uErr = CheckTagRequirement(TagSpec, pItem); + QCBORError uErr = QCBOR_Private_CheckTagRequirement(TagSpec, pItem); if(uErr != QCBOR_SUCCESS) { return uErr; } @@ -4225,37 +4927,36 @@ ProcessBigNum(const uint8_t uTagRequirement, /* - Public function, see header qcbor/qcbor_decode.h + * Public function, see header qcbor/qcbor_spiffy_decode.h */ -void QCBORDecode_GetBignum(QCBORDecodeContext *pMe, - uint8_t uTagRequirement, - UsefulBufC *pValue, - bool *pbIsNegative) +void +QCBORDecode_GetBignum(QCBORDecodeContext *pMe, + const uint8_t uTagRequirement, + UsefulBufC *pValue, + bool *pbIsNegative) { - if(pMe->uLastError != QCBOR_SUCCESS) { - // Already in error state, do nothing - return; - } - QCBORItem Item; - QCBORError uError = QCBORDecode_GetNext(pMe, &Item); - if(uError != QCBOR_SUCCESS) { - pMe->uLastError = (uint8_t)uError; + QCBORDecode_VGetNext(pMe, &Item); + if(pMe->uLastError) { return; } - pMe->uLastError = (uint8_t)ProcessBigNum(uTagRequirement, &Item, pValue, pbIsNegative); + pMe->uLastError = (uint8_t)QCBOR_Private_ProcessBigNum(uTagRequirement, + &Item, + pValue, + pbIsNegative); } /* - Public function, see header qcbor/qcbor_decode.h -*/ -void QCBORDecode_GetBignumInMapN(QCBORDecodeContext *pMe, - int64_t nLabel, - uint8_t uTagRequirement, - UsefulBufC *pValue, - bool *pbIsNegative) + * Public function, see header qcbor/qcbor_spiffy_decode.h + */ +void +QCBORDecode_GetBignumInMapN(QCBORDecodeContext *pMe, + const int64_t nLabel, + const uint8_t uTagRequirement, + UsefulBufC *pValue, + bool *pbIsNegative) { QCBORItem Item; QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, &Item); @@ -4263,18 +4964,22 @@ void QCBORDecode_GetBignumInMapN(QCBORDecodeContext *pMe, return; } - pMe->uLastError = (uint8_t)ProcessBigNum(uTagRequirement, &Item, pValue, pbIsNegative); + pMe->uLastError = (uint8_t)QCBOR_Private_ProcessBigNum(uTagRequirement, + &Item, + pValue, + pbIsNegative); } /* - Public function, see header qcbor/qcbor_decode.h -*/ -void QCBORDecode_GetBignumInMapSZ(QCBORDecodeContext *pMe, - const char *szLabel, - uint8_t uTagRequirement, - UsefulBufC *pValue, - bool *pbIsNegative) + * Public function, see header qcbor/qcbor_spiffy_decode.h + */ +void +QCBORDecode_GetBignumInMapSZ(QCBORDecodeContext *pMe, + const char *szLabel, + const uint8_t uTagRequirement, + UsefulBufC *pValue, + bool *pbIsNegative) { QCBORItem Item; QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item); @@ -4282,26 +4987,39 @@ void QCBORDecode_GetBignumInMapSZ(QCBORDecodeContext *pMe, return; } - pMe->uLastError = (uint8_t)ProcessBigNum(uTagRequirement, &Item, pValue, pbIsNegative); + pMe->uLastError = (uint8_t)QCBOR_Private_ProcessBigNum(uTagRequirement, + &Item, + pValue, + pbIsNegative); } - -// Semi private +/** + * @brief Common processing for MIME tag (semi-private). + * + * @param[in] uTagRequirement One of @c QCBOR_TAG_REQUIREMENT_XXX. + * @param[in] pItem The item with the date. + * @param[out] pMessage The returned MIME message. + * @param[out] pbIsTag257 If true, binary MIME, if not, text MIME. + * + * Common processing for the MIME tag. Mostly make sure the tag + * content is correct and copy forward any further other tag + * numbers. See QCBORDecode_GetMIMEMessage(). + */ QCBORError -QCBORDecode_GetMIMEInternal(const uint8_t uTagRequirement, +QCBORDecode_Private_GetMIME(const uint8_t uTagRequirement, const QCBORItem *pItem, UsefulBufC *pMessage, bool *pbIsTag257) { - const TagSpecification TagSpecText = + const QCBOR_Private_TagSpec TagSpecText = { uTagRequirement, {QCBOR_TYPE_MIME, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}, {QCBOR_TYPE_TEXT_STRING, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE} }; - const TagSpecification TagSpecBinary = + const QCBOR_Private_TagSpec TagSpecBinary = { uTagRequirement, {QCBOR_TYPE_BINARY_MIME, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}, @@ -4310,13 +5028,13 @@ QCBORDecode_GetMIMEInternal(const uint8_t uTagRequirement, QCBORError uReturn; - if(CheckTagRequirement(TagSpecText, pItem) == QCBOR_SUCCESS) { + if(QCBOR_Private_CheckTagRequirement(TagSpecText, pItem) == QCBOR_SUCCESS) { *pMessage = pItem->val.string; if(pbIsTag257 != NULL) { *pbIsTag257 = false; } uReturn = QCBOR_SUCCESS; - } else if(CheckTagRequirement(TagSpecBinary, pItem) == QCBOR_SUCCESS) { + } else if(QCBOR_Private_CheckTagRequirement(TagSpecBinary, pItem) == QCBOR_SUCCESS) { *pMessage = pItem->val.string; if(pbIsTag257 != NULL) { *pbIsTag257 = true; @@ -4338,6 +5056,16 @@ QCBORDecode_GetMIMEInternal(const uint8_t uTagRequirement, #ifndef QCBOR_DISABLE_EXP_AND_MANTISSA +/** + * @brief Prototype for conversion of exponent and mantissa to unsigned integer. + * + * @param[in] uMantissa The mantissa. + * @param[in] nExponent The exponent. + * @param[out] puResult The resulting integer. + * + * Concrete implementations of this are for exponent base 10 and 2 supporting + * decimal fractions and big floats. + */ typedef QCBORError (*fExponentiator)(uint64_t uMantissa, int64_t nExponent, uint64_t *puResult); @@ -4352,11 +5080,13 @@ typedef QCBORError (*fExponentiator)(uint64_t uMantissa, int64_t nExponent, uint * unsigned integer. * * There are many inputs for which the result will not fit in the - * 64-bit integer and \ref QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW will + * 64-bit integer and @ref QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW will * be returned. */ static QCBORError -Exponentitate10(uint64_t uMantissa, int64_t nExponent, uint64_t *puResult) +QCBOR_Private_Exponentitate10(const uint64_t uMantissa, + int64_t nExponent, + uint64_t *puResult) { uint64_t uResult = uMantissa; @@ -4398,11 +5128,13 @@ Exponentitate10(uint64_t uMantissa, int64_t nExponent, uint64_t *puResult) * output is a 64-bit unsigned integer. * * There are many inputs for which the result will not fit in the - * 64-bit integer and \ref QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW will + * 64-bit integer and @ref QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW will * be returned. */ static QCBORError -Exponentitate2(uint64_t uMantissa, int64_t nExponent, uint64_t *puResult) +QCBOR_Private_Exponentitate2(const uint64_t uMantissa, + int64_t nExponent, + uint64_t *puResult) { uint64_t uResult; @@ -4443,16 +5175,16 @@ Exponentitate2(uint64_t uMantissa, int64_t nExponent, uint64_t *puResult) * * @returns Error code * - * \c pfExp performs exponentiation on and unsigned mantissa and + * @c pfExp performs exponentiation on and unsigned mantissa and * produces an unsigned result. This converts the mantissa from signed * and converts the result to signed. The exponentiation function is * either for base 2 or base 10 (and could be other if needed). */ static QCBORError -ExponentiateNN(int64_t nMantissa, - int64_t nExponent, - int64_t *pnResult, - fExponentiator pfExp) +QCBOR_Private_ExponentiateNN(const int64_t nMantissa, + const int64_t nExponent, + int64_t *pnResult, + fExponentiator pfExp) { uint64_t uResult; uint64_t uMantissa; @@ -4531,15 +5263,15 @@ ExponentiateNN(int64_t nMantissa, * * @returns Error code * - * \c pfExp performs exponentiation on and unsigned mantissa and + * @c pfExp performs exponentiation on and unsigned mantissa and * produces an unsigned result. This errors out if the mantissa * is negative because the output is unsigned. */ static QCBORError -ExponentitateNU(int64_t nMantissa, - int64_t nExponent, - uint64_t *puResult, - fExponentiator pfExp) +QCBOR_Private_ExponentitateNU(const int64_t nMantissa, + const int64_t nExponent, + uint64_t *puResult, + fExponentiator pfExp) { if(nMantissa < 0) { return QCBOR_ERR_NUMBER_SIGN_CONVERSION; @@ -4563,15 +5295,15 @@ ExponentitateNU(int64_t nMantissa, * * @returns Error code * - * \c pfExp performs exponentiation on and unsigned mantissa and + * @c pfExp performs exponentiation on and unsigned mantissa and * produces an unsigned result so this is just a wrapper that does * nothing (and is likely inlined). */ static QCBORError -ExponentitateUU(uint64_t uMantissa, - int64_t nExponent, - uint64_t *puResult, - fExponentiator pfExp) +QCBOR_Private_ExponentitateUU(const uint64_t uMantissa, + const int64_t nExponent, + uint64_t *puResult, + fExponentiator pfExp) { return (*pfExp)(uMantissa, nExponent, puResult); } @@ -4594,7 +5326,9 @@ ExponentitateUU(uint64_t uMantissa, * larger range than uint64_t. */ static QCBORError -ConvertBigNumToUnsigned(const UsefulBufC BigNum, const uint64_t uMax, uint64_t *pResult) +QCBOR_Private_ConvertBigNumToUnsigned(const UsefulBufC BigNum, + const uint64_t uMax, + uint64_t *pResult) { uint64_t uResult; @@ -4625,9 +5359,10 @@ ConvertBigNumToUnsigned(const UsefulBufC BigNum, const uint64_t uMax, uint64_t * * larger range than uint64_t. */ static QCBORError -ConvertPositiveBigNumToUnsigned(const UsefulBufC BigNum, uint64_t *pResult) +QCBOR_Private_ConvertPositiveBigNumToUnsigned(const UsefulBufC BigNum, + uint64_t *pResult) { - return ConvertBigNumToUnsigned(BigNum, UINT64_MAX, pResult); + return QCBOR_Private_ConvertBigNumToUnsigned(BigNum, UINT64_MAX, pResult); } @@ -4643,14 +5378,17 @@ ConvertPositiveBigNumToUnsigned(const UsefulBufC BigNum, uint64_t *pResult) * larger range than int64_t. */ static QCBORError -ConvertPositiveBigNumToSigned(const UsefulBufC BigNum, int64_t *pResult) +QCBOR_Private_ConvertPositiveBigNumToSigned(const UsefulBufC BigNum, + int64_t *pResult) { uint64_t uResult; - QCBORError uError = ConvertBigNumToUnsigned(BigNum, INT64_MAX, &uResult); + QCBORError uError = QCBOR_Private_ConvertBigNumToUnsigned(BigNum, + INT64_MAX, + &uResult); if(uError) { return uError; } - /* Cast is safe because ConvertBigNumToUnsigned is told to limit to INT64_MAX */ + /* Cast is safe because ConvertBigNumToUnsigned limits to INT64_MAX */ *pResult = (int64_t)uResult; return QCBOR_SUCCESS; } @@ -4668,7 +5406,8 @@ ConvertPositiveBigNumToSigned(const UsefulBufC BigNum, int64_t *pResult) * larger range than int64_t. */ static QCBORError -ConvertNegativeBigNumToSigned(const UsefulBufC BigNum, int64_t *pnResult) +QCBOR_Private_ConvertNegativeBigNumToSigned(const UsefulBufC BigNum, + int64_t *pnResult) { uint64_t uResult; /* The negative integer furthest from zero for a C int64_t is @@ -4683,7 +5422,9 @@ ConvertNegativeBigNumToSigned(const UsefulBufC BigNum, int64_t *pnResult) * -n - 1 <= -INT64_MAX - 1 * n <= INT64_MAX. */ - QCBORError uError = ConvertBigNumToUnsigned(BigNum, INT64_MAX, &uResult); + QCBORError uError = QCBOR_Private_ConvertBigNumToUnsigned(BigNum, + INT64_MAX, + &uResult); if(uError != QCBOR_SUCCESS) { return uError; } @@ -4700,22 +5441,23 @@ ConvertNegativeBigNumToSigned(const UsefulBufC BigNum, int64_t *pnResult) - -/* -Convert integers and floats to an int64_t. - -\param[in] uConvertTypes Bit mask list of conversion options. - -\retval QCBOR_ERR_UNEXPECTED_TYPE Conversion, possible, but not requested - in uConvertTypes. - -\retval QCBOR_ERR_UNEXPECTED_TYPE Of a type that can't be converted - -\retval QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW Conversion result is too large - or too small. -*/ +/** + * @brief Convert integers and floats to an int64_t. + * + * @param[in] pItem The item to convert. + * @param[in] uConvertTypes Bit mask list of conversion options. + * @param[out] pnValue The resulting converted value. + * + * @retval QCBOR_ERR_UNEXPECTED_TYPE Conversion, possible, but not requested + * in uConvertTypes. + * @retval QCBOR_ERR_UNEXPECTED_TYPE Of a type that can't be converted + * @retval QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW Conversion result is too large + * or too small. + */ static QCBORError -ConvertInt64(const QCBORItem *pItem, uint32_t uConvertTypes, int64_t *pnValue) +QCBOR_Private_ConvertInt64(const QCBORItem *pItem, + const uint32_t uConvertTypes, + int64_t *pnValue) { switch(pItem->uDataType) { case QCBOR_TYPE_FLOAT: @@ -4774,81 +5516,112 @@ ConvertInt64(const QCBORItem *pItem, uint32_t uConvertTypes, int64_t *pnValue) } -void QCBORDecode_GetInt64ConvertInternal(QCBORDecodeContext *pMe, - uint32_t uConvertTypes, - int64_t *pnValue, - QCBORItem *pItem) +/** + * @brief Almost-public method to decode a number and convert to int64_t (semi-private). + * + * @param[in] pMe The decode context. + * @param[in] uConvertTypes Bit mask list of conversion options. + * @param[out] pnValue Result of the conversion. + * @param[in,out] pItem Temporary space to store Item, returned item. + * + * See QCBORDecode_GetInt64Convert(). + */ +void +QCBORDecode_Private_GetInt64Convert(QCBORDecodeContext *pMe, + uint32_t uConvertTypes, + int64_t *pnValue, + QCBORItem *pItem) { - if(pMe->uLastError != QCBOR_SUCCESS) { + QCBORDecode_VGetNext(pMe, pItem); + if(pMe->uLastError) { return; } - QCBORItem Item; - QCBORError uError = QCBORDecode_GetNext(pMe, &Item); - if(uError) { - pMe->uLastError = (uint8_t)uError; - return; - } - - if(pItem) { - *pItem = Item; - } - - pMe->uLastError = (uint8_t)ConvertInt64(&Item, uConvertTypes, pnValue); + pMe->uLastError = (uint8_t)QCBOR_Private_ConvertInt64(pItem, + uConvertTypes, + pnValue); } - -void QCBORDecode_GetInt64ConvertInternalInMapN(QCBORDecodeContext *pMe, - int64_t nLabel, - uint32_t uConvertTypes, - int64_t *pnValue, - QCBORItem *pItem) +/** + * @brief Almost-public method to decode a number and convert to int64_t (semi-private). + * + * @param[in] pMe The decode context. + * @param[in] nLabel Label to find in map. + * @param[in] uConvertTypes Bit mask list of conversion options. + * @param[out] pnValue Result of the conversion. + * @param[in,out] pItem Temporary space to store Item, returned item. + * + * See QCBORDecode_GetInt64ConvertInMapN(). + */ +void +QCBORDecode_Private_GetInt64ConvertInMapN(QCBORDecodeContext *pMe, + int64_t nLabel, + uint32_t uConvertTypes, + int64_t *pnValue, + QCBORItem *pItem) { QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, pItem); if(pMe->uLastError != QCBOR_SUCCESS) { return; } - pMe->uLastError = (uint8_t)ConvertInt64(pItem, uConvertTypes, pnValue); + pMe->uLastError = (uint8_t)QCBOR_Private_ConvertInt64(pItem, + uConvertTypes, + pnValue); } - -void QCBORDecode_GetInt64ConvertInternalInMapSZ(QCBORDecodeContext *pMe, - const char * szLabel, - uint32_t uConvertTypes, - int64_t *pnValue, - QCBORItem *pItem) +/** + * @brief Almost-public method to decode a number and convert to int64_t (semi-private). + * + * @param[in] pMe The decode context. + * @param[in] szLabel Label to find in map. + * @param[in] uConvertTypes Bit mask list of conversion options. + * @param[out] pnValue Result of the conversion. + * @param[in,out] pItem Temporary space to store Item, returned item. + * + * See QCBORDecode_GetInt64ConvertInMapSZ(). + */ +void +QCBORDecode_Private_GetInt64ConvertInMapSZ(QCBORDecodeContext *pMe, + const char * szLabel, + uint32_t uConvertTypes, + int64_t *pnValue, + QCBORItem *pItem) { QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, pItem); if(pMe->uLastError != QCBOR_SUCCESS) { return; } - pMe->uLastError = (uint8_t)ConvertInt64(pItem, uConvertTypes, pnValue); + pMe->uLastError = (uint8_t)QCBOR_Private_ConvertInt64(pItem, + uConvertTypes, + pnValue); } -/* - Convert a large variety of integer types to an int64_t. - - \param[in] uConvertTypes Bit mask list of conversion options. - - \retval QCBOR_ERR_UNEXPECTED_TYPE Conversion, possible, but not requested - in uConvertTypes. - - \retval QCBOR_ERR_UNEXPECTED_TYPE Of a type that can't be converted - - \retval QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW Conversion result is too large - or too small. +/** + * @brief Convert many number types to an int64_t. + * + * @param[in] pItem The item to convert. + * @param[in] uConvertTypes Bit mask list of conversion options. + * @param[out] pnValue The resulting converted value. + * + * @retval QCBOR_ERR_UNEXPECTED_TYPE Conversion, possible, but not requested + * in uConvertTypes. + * @retval QCBOR_ERR_UNEXPECTED_TYPE Of a type that can't be converted + * @retval QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW Conversion result is too large + * or too small. */ static QCBORError -Int64ConvertAll(const QCBORItem *pItem, uint32_t uConvertTypes, int64_t *pnValue) +QCBOR_Private_Int64ConvertAll(const QCBORItem *pItem, + const uint32_t uConvertTypes, + int64_t *pnValue) { switch(pItem->uDataType) { case QCBOR_TYPE_POSBIGNUM: if(uConvertTypes & QCBOR_CONVERT_TYPE_BIG_NUM) { - return ConvertPositiveBigNumToSigned(pItem->val.bigNum, pnValue); + return QCBOR_Private_ConvertPositiveBigNumToSigned(pItem->val.bigNum, pnValue); } else { return QCBOR_ERR_UNEXPECTED_TYPE; } @@ -4856,7 +5629,7 @@ Int64ConvertAll(const QCBORItem *pItem, uint32_t uConvertTypes, int64_t *pnValue case QCBOR_TYPE_NEGBIGNUM: if(uConvertTypes & QCBOR_CONVERT_TYPE_BIG_NUM) { - return ConvertNegativeBigNumToSigned(pItem->val.bigNum, pnValue); + return QCBOR_Private_ConvertNegativeBigNumToSigned(pItem->val.bigNum, pnValue); } else { return QCBOR_ERR_UNEXPECTED_TYPE; } @@ -4865,10 +5638,10 @@ Int64ConvertAll(const QCBORItem *pItem, uint32_t uConvertTypes, int64_t *pnValue #ifndef QCBOR_DISABLE_EXP_AND_MANTISSA case QCBOR_TYPE_DECIMAL_FRACTION: if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) { - return ExponentiateNN(pItem->val.expAndMantissa.Mantissa.nInt, + return QCBOR_Private_ExponentiateNN(pItem->val.expAndMantissa.Mantissa.nInt, pItem->val.expAndMantissa.nExponent, pnValue, - &Exponentitate10); + &QCBOR_Private_Exponentitate10); } else { return QCBOR_ERR_UNEXPECTED_TYPE; } @@ -4876,10 +5649,10 @@ Int64ConvertAll(const QCBORItem *pItem, uint32_t uConvertTypes, int64_t *pnValue case QCBOR_TYPE_BIGFLOAT: if(uConvertTypes & QCBOR_CONVERT_TYPE_BIGFLOAT) { - return ExponentiateNN(pItem->val.expAndMantissa.Mantissa.nInt, + return QCBOR_Private_ExponentiateNN(pItem->val.expAndMantissa.Mantissa.nInt, pItem->val.expAndMantissa.nExponent, pnValue, - Exponentitate2); + QCBOR_Private_Exponentitate2); } else { return QCBOR_ERR_UNEXPECTED_TYPE; } @@ -4889,14 +5662,14 @@ Int64ConvertAll(const QCBORItem *pItem, uint32_t uConvertTypes, int64_t *pnValue if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) { int64_t nMantissa; QCBORError uErr; - uErr = ConvertPositiveBigNumToSigned(pItem->val.expAndMantissa.Mantissa.bigNum, &nMantissa); + uErr = QCBOR_Private_ConvertPositiveBigNumToSigned(pItem->val.expAndMantissa.Mantissa.bigNum, &nMantissa); if(uErr) { return uErr; } - return ExponentiateNN(nMantissa, + return QCBOR_Private_ExponentiateNN(nMantissa, pItem->val.expAndMantissa.nExponent, pnValue, - Exponentitate10); + QCBOR_Private_Exponentitate10); } else { return QCBOR_ERR_UNEXPECTED_TYPE; } @@ -4906,14 +5679,14 @@ Int64ConvertAll(const QCBORItem *pItem, uint32_t uConvertTypes, int64_t *pnValue if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) { int64_t nMantissa; QCBORError uErr; - uErr = ConvertNegativeBigNumToSigned(pItem->val.expAndMantissa.Mantissa.bigNum, &nMantissa); + uErr = QCBOR_Private_ConvertNegativeBigNumToSigned(pItem->val.expAndMantissa.Mantissa.bigNum, &nMantissa); if(uErr) { return uErr; } - return ExponentiateNN(nMantissa, + return QCBOR_Private_ExponentiateNN(nMantissa, pItem->val.expAndMantissa.nExponent, pnValue, - Exponentitate10); + QCBOR_Private_Exponentitate10); } else { return QCBOR_ERR_UNEXPECTED_TYPE; } @@ -4923,14 +5696,14 @@ Int64ConvertAll(const QCBORItem *pItem, uint32_t uConvertTypes, int64_t *pnValue if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) { int64_t nMantissa; QCBORError uErr; - uErr = ConvertPositiveBigNumToSigned(pItem->val.expAndMantissa.Mantissa.bigNum, &nMantissa); + uErr = QCBOR_Private_ConvertPositiveBigNumToSigned(pItem->val.expAndMantissa.Mantissa.bigNum, &nMantissa); if(uErr) { return uErr; } - return ExponentiateNN(nMantissa, + return QCBOR_Private_ExponentiateNN(nMantissa, pItem->val.expAndMantissa.nExponent, pnValue, - Exponentitate2); + QCBOR_Private_Exponentitate2); } else { return QCBOR_ERR_UNEXPECTED_TYPE; } @@ -4940,14 +5713,14 @@ Int64ConvertAll(const QCBORItem *pItem, uint32_t uConvertTypes, int64_t *pnValue if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) { int64_t nMantissa; QCBORError uErr; - uErr = ConvertNegativeBigNumToSigned(pItem->val.expAndMantissa.Mantissa.bigNum, &nMantissa); + uErr = QCBOR_Private_ConvertNegativeBigNumToSigned(pItem->val.expAndMantissa.Mantissa.bigNum, &nMantissa); if(uErr) { return uErr; } - return ExponentiateNN(nMantissa, + return QCBOR_Private_ExponentiateNN(nMantissa, pItem->val.expAndMantissa.nExponent, pnValue, - Exponentitate2); + QCBOR_Private_Exponentitate2); } else { return QCBOR_ERR_UNEXPECTED_TYPE; } @@ -4961,13 +5734,16 @@ Int64ConvertAll(const QCBORItem *pItem, uint32_t uConvertTypes, int64_t *pnValue /* - Public function, see header qcbor/qcbor_decode.h file + * Public function, see header qcbor/qcbor_decode.h file */ -void QCBORDecode_GetInt64ConvertAll(QCBORDecodeContext *pMe, uint32_t uConvertTypes, int64_t *pnValue) +void +QCBORDecode_GetInt64ConvertAll(QCBORDecodeContext *pMe, + const uint32_t uConvertTypes, + int64_t *pnValue) { QCBORItem Item; - QCBORDecode_GetInt64ConvertInternal(pMe, uConvertTypes, pnValue, &Item); + QCBORDecode_Private_GetInt64Convert(pMe, uConvertTypes, pnValue, &Item); if(pMe->uLastError == QCBOR_SUCCESS) { // The above conversion succeeded @@ -4979,21 +5755,24 @@ void QCBORDecode_GetInt64ConvertAll(QCBORDecodeContext *pMe, uint32_t uConvertTy return; } - pMe->uLastError = (uint8_t)Int64ConvertAll(&Item, uConvertTypes, pnValue); + pMe->uLastError = (uint8_t)QCBOR_Private_Int64ConvertAll(&Item, + uConvertTypes, + pnValue); } /* -Public function, see header qcbor/qcbor_decode.h file -*/ -void QCBORDecode_GetInt64ConvertAllInMapN(QCBORDecodeContext *pMe, - int64_t nLabel, - uint32_t uConvertTypes, - int64_t *pnValue) + * Public function, see header qcbor/qcbor_decode.h file + */ +void +QCBORDecode_GetInt64ConvertAllInMapN(QCBORDecodeContext *pMe, + const int64_t nLabel, + const uint32_t uConvertTypes, + int64_t *pnValue) { QCBORItem Item; - QCBORDecode_GetInt64ConvertInternalInMapN(pMe, + QCBORDecode_Private_GetInt64ConvertInMapN(pMe, nLabel, uConvertTypes, pnValue, @@ -5009,20 +5788,23 @@ void QCBORDecode_GetInt64ConvertAllInMapN(QCBORDecodeContext *pMe, return; } - pMe->uLastError = (uint8_t)Int64ConvertAll(&Item, uConvertTypes, pnValue); + pMe->uLastError = (uint8_t)QCBOR_Private_Int64ConvertAll(&Item, + uConvertTypes, + pnValue); } /* -Public function, see header qcbor/qcbor_decode.h file -*/ -void QCBORDecode_GetInt64ConvertAllInMapSZ(QCBORDecodeContext *pMe, - const char *szLabel, - uint32_t uConvertTypes, - int64_t *pnValue) + * Public function, see header qcbor/qcbor_decode.h file + */ +void +QCBORDecode_GetInt64ConvertAllInMapSZ(QCBORDecodeContext *pMe, + const char *szLabel, + const uint32_t uConvertTypes, + int64_t *pnValue) { QCBORItem Item; - QCBORDecode_GetInt64ConvertInternalInMapSZ(pMe, + QCBORDecode_Private_GetInt64ConvertInMapSZ(pMe, szLabel, uConvertTypes, pnValue, @@ -5038,11 +5820,29 @@ void QCBORDecode_GetInt64ConvertAllInMapSZ(QCBORDecodeContext *pMe, return; } - pMe->uLastError = (uint8_t)Int64ConvertAll(&Item, uConvertTypes, pnValue); + pMe->uLastError = (uint8_t)QCBOR_Private_Int64ConvertAll(&Item, + uConvertTypes, + pnValue); } -static QCBORError ConvertUInt64(const QCBORItem *pItem, uint32_t uConvertTypes, uint64_t *puValue) +/** + * @brief Convert many number types to an uint64_t. + * + * @param[in] pItem The item to convert. + * @param[in] uConvertTypes Bit mask list of conversion options. + * @param[out] puValue The resulting converted value. + * + * @retval QCBOR_ERR_UNEXPECTED_TYPE Conversion, possible, but not requested + * in uConvertTypes. + * @retval QCBOR_ERR_UNEXPECTED_TYPE Of a type that can't be converted + * @retval QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW Conversion result is too large + * or too small. + */ +static QCBORError +QCBOR_Private_ConvertUInt64(const QCBORItem *pItem, + const uint32_t uConvertTypes, + uint64_t *puValue) { switch(pItem->uDataType) { case QCBOR_TYPE_DOUBLE: @@ -5126,74 +5926,114 @@ static QCBORError ConvertUInt64(const QCBORItem *pItem, uint32_t uConvertTypes, } -void QCBORDecode_GetUInt64ConvertInternal(QCBORDecodeContext *pMe, - uint32_t uConvertTypes, - uint64_t *puValue, - QCBORItem *pItem) +/** + * @brief Almost-public method to decode a number and convert to uint64_t (semi-private). + * + * @param[in] pMe The decode context. + * @param[in] uConvertTypes Bit mask list of conversion options. + * @param[out] puValue Result of the conversion. + * @param[in,out] pItem Temporary space to store Item, returned item. + * + * See QCBORDecode_GetUInt64Convert(). + */ +void +QCBORDecode_Private_GetUInt64Convert(QCBORDecodeContext *pMe, + const uint32_t uConvertTypes, + uint64_t *puValue, + QCBORItem *pItem) { - if(pMe->uLastError != QCBOR_SUCCESS) { + QCBORDecode_VGetNext(pMe, pItem); + if(pMe->uLastError) { return; } - QCBORItem Item; - - QCBORError uError = QCBORDecode_GetNext(pMe, &Item); - if(uError) { - pMe->uLastError = (uint8_t)uError; - return; - } - - if(pItem) { - *pItem = Item; - } - - pMe->uLastError = (uint8_t)ConvertUInt64(&Item, uConvertTypes, puValue); + pMe->uLastError = (uint8_t)QCBOR_Private_ConvertUInt64(pItem, + uConvertTypes, + puValue); } -void QCBORDecode_GetUInt64ConvertInternalInMapN(QCBORDecodeContext *pMe, - int64_t nLabel, - uint32_t uConvertTypes, - uint64_t *puValue, - QCBORItem *pItem) +/** + * @brief Almost-public method to decode a number and convert to uint64_t (semi-private). + * + * @param[in] pMe The decode context. + * @param[in] nLabel Label to find in map. + * @param[in] uConvertTypes Bit mask list of conversion options. + * @param[out] puValue Result of the conversion. + * @param[in,out] pItem Temporary space to store Item, returned item. + * + * See QCBORDecode_GetUInt64ConvertInMapN(). + */ +void +QCBORDecode_Private_GetUInt64ConvertInMapN(QCBORDecodeContext *pMe, + const int64_t nLabel, + const uint32_t uConvertTypes, + uint64_t *puValue, + QCBORItem *pItem) { QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, pItem); if(pMe->uLastError != QCBOR_SUCCESS) { return; } - pMe->uLastError = (uint8_t)ConvertUInt64(pItem, uConvertTypes, puValue); + pMe->uLastError = (uint8_t)QCBOR_Private_ConvertUInt64(pItem, + uConvertTypes, + puValue); } -void QCBORDecode_GetUInt64ConvertInternalInMapSZ(QCBORDecodeContext *pMe, - const char * szLabel, - uint32_t uConvertTypes, - uint64_t *puValue, - QCBORItem *pItem) +/** + * @brief Almost-public method to decode a number and convert to uint64_t (semi-private). + * + * @param[in] pMe The decode context. + * @param[in] szLabel Label to find in map. + * @param[in] uConvertTypes Bit mask list of conversion options. + * @param[out] puValue Result of the conversion. + * @param[in,out] pItem Temporary space to store Item, returned item. + * + * See QCBORDecode_GetUInt64ConvertInMapSZ(). + */ +void +QCBORDecode_Private_GetUInt64ConvertInMapSZ(QCBORDecodeContext *pMe, + const char *szLabel, + const uint32_t uConvertTypes, + uint64_t *puValue, + QCBORItem *pItem) { - if(pMe->uLastError != QCBOR_SUCCESS) { - return; - } - QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, pItem); if(pMe->uLastError != QCBOR_SUCCESS) { return; } - pMe->uLastError = (uint8_t)ConvertUInt64(pItem, uConvertTypes, puValue); + pMe->uLastError = (uint8_t)QCBOR_Private_ConvertUInt64(pItem, + uConvertTypes, + puValue); } - +/** + * @brief Convert many number types to an unt64_t. + * + * @param[in] pItem The item to convert. + * @param[in] uConvertTypes Bit mask list of conversion options. + * @param[out] puValue The resulting converted value. + * + * @retval QCBOR_ERR_UNEXPECTED_TYPE Conversion, possible, but not requested + * in uConvertTypes. + * @retval QCBOR_ERR_UNEXPECTED_TYPE Of a type that can't be converted + * @retval QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW Conversion result is too large + * or too small. + */ static QCBORError -UInt64ConvertAll(const QCBORItem *pItem, uint32_t uConvertTypes, uint64_t *puValue) +QCBOR_Private_UInt64ConvertAll(const QCBORItem *pItem, + const uint32_t uConvertTypes, + uint64_t *puValue) { - switch(pItem->uDataType) { + switch(pItem->uDataType) { /* -Wmaybe-uninitialized falsly warns here */ case QCBOR_TYPE_POSBIGNUM: if(uConvertTypes & QCBOR_CONVERT_TYPE_BIG_NUM) { - return ConvertPositiveBigNumToUnsigned(pItem->val.bigNum, puValue); + return QCBOR_Private_ConvertPositiveBigNumToUnsigned(pItem->val.bigNum, puValue); } else { return QCBOR_ERR_UNEXPECTED_TYPE; } @@ -5211,10 +6051,10 @@ UInt64ConvertAll(const QCBORItem *pItem, uint32_t uConvertTypes, uint64_t *puVal case QCBOR_TYPE_DECIMAL_FRACTION: if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) { - return ExponentitateNU(pItem->val.expAndMantissa.Mantissa.nInt, + return QCBOR_Private_ExponentitateNU(pItem->val.expAndMantissa.Mantissa.nInt, pItem->val.expAndMantissa.nExponent, puValue, - Exponentitate10); + QCBOR_Private_Exponentitate10); } else { return QCBOR_ERR_UNEXPECTED_TYPE; } @@ -5222,10 +6062,10 @@ UInt64ConvertAll(const QCBORItem *pItem, uint32_t uConvertTypes, uint64_t *puVal case QCBOR_TYPE_BIGFLOAT: if(uConvertTypes & QCBOR_CONVERT_TYPE_BIGFLOAT) { - return ExponentitateNU(pItem->val.expAndMantissa.Mantissa.nInt, + return QCBOR_Private_ExponentitateNU(pItem->val.expAndMantissa.Mantissa.nInt, pItem->val.expAndMantissa.nExponent, puValue, - Exponentitate2); + QCBOR_Private_Exponentitate2); } else { return QCBOR_ERR_UNEXPECTED_TYPE; } @@ -5235,14 +6075,14 @@ UInt64ConvertAll(const QCBORItem *pItem, uint32_t uConvertTypes, uint64_t *puVal if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) { uint64_t uMantissa; QCBORError uErr; - uErr = ConvertPositiveBigNumToUnsigned(pItem->val.expAndMantissa.Mantissa.bigNum, &uMantissa); + uErr = QCBOR_Private_ConvertPositiveBigNumToUnsigned(pItem->val.expAndMantissa.Mantissa.bigNum, &uMantissa); if(uErr != QCBOR_SUCCESS) { return uErr; } - return ExponentitateUU(uMantissa, - pItem->val.expAndMantissa.nExponent, - puValue, - Exponentitate10); + return QCBOR_Private_ExponentitateUU(uMantissa, + pItem->val.expAndMantissa.nExponent, + puValue, + QCBOR_Private_Exponentitate10); } else { return QCBOR_ERR_UNEXPECTED_TYPE; } @@ -5260,14 +6100,15 @@ UInt64ConvertAll(const QCBORItem *pItem, uint32_t uConvertTypes, uint64_t *puVal if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) { uint64_t uMantissa; QCBORError uErr; - uErr = ConvertPositiveBigNumToUnsigned(pItem->val.expAndMantissa.Mantissa.bigNum, &uMantissa); + uErr = QCBOR_Private_ConvertPositiveBigNumToUnsigned(pItem->val.expAndMantissa.Mantissa.bigNum, + &uMantissa); if(uErr != QCBOR_SUCCESS) { return uErr; } - return ExponentitateUU(uMantissa, - pItem->val.expAndMantissa.nExponent, - puValue, - Exponentitate2); + return QCBOR_Private_ExponentitateUU(uMantissa, + pItem->val.expAndMantissa.nExponent, + puValue, + QCBOR_Private_Exponentitate2); } else { return QCBOR_ERR_UNEXPECTED_TYPE; } @@ -5288,13 +6129,16 @@ UInt64ConvertAll(const QCBORItem *pItem, uint32_t uConvertTypes, uint64_t *puVal /* - Public function, see header qcbor/qcbor_decode.h file + * Public function, see header qcbor/qcbor_decode.h file */ -void QCBORDecode_GetUInt64ConvertAll(QCBORDecodeContext *pMe, uint32_t uConvertTypes, uint64_t *puValue) +void +QCBORDecode_GetUInt64ConvertAll(QCBORDecodeContext *pMe, + const uint32_t uConvertTypes, + uint64_t *puValue) { QCBORItem Item; - QCBORDecode_GetUInt64ConvertInternal(pMe, uConvertTypes, puValue, &Item); + QCBORDecode_Private_GetUInt64Convert(pMe, uConvertTypes, puValue, &Item); if(pMe->uLastError == QCBOR_SUCCESS) { // The above conversion succeeded @@ -5306,21 +6150,24 @@ void QCBORDecode_GetUInt64ConvertAll(QCBORDecodeContext *pMe, uint32_t uConvertT return; } - pMe->uLastError = (uint8_t)UInt64ConvertAll(&Item, uConvertTypes, puValue); + pMe->uLastError = (uint8_t)QCBOR_Private_UInt64ConvertAll(&Item, + uConvertTypes, + puValue); } /* - Public function, see header qcbor/qcbor_decode.h file -*/ -void QCBORDecode_GetUInt64ConvertAllInMapN(QCBORDecodeContext *pMe, - int64_t nLabel, - uint32_t uConvertTypes, - uint64_t *puValue) + * Public function, see header qcbor/qcbor_decode.h file + */ +void +QCBORDecode_GetUInt64ConvertAllInMapN(QCBORDecodeContext *pMe, + const int64_t nLabel, + const uint32_t uConvertTypes, + uint64_t *puValue) { QCBORItem Item; - QCBORDecode_GetUInt64ConvertInternalInMapN(pMe, + QCBORDecode_Private_GetUInt64ConvertInMapN(pMe, nLabel, uConvertTypes, puValue, @@ -5336,20 +6183,23 @@ void QCBORDecode_GetUInt64ConvertAllInMapN(QCBORDecodeContext *pMe, return; } - pMe->uLastError = (uint8_t)UInt64ConvertAll(&Item, uConvertTypes, puValue); + pMe->uLastError = (uint8_t)QCBOR_Private_UInt64ConvertAll(&Item, + uConvertTypes, + puValue); } /* - Public function, see header qcbor/qcbor_decode.h file -*/ -void QCBORDecode_GetUInt64ConvertAllInMapSZ(QCBORDecodeContext *pMe, - const char *szLabel, - uint32_t uConvertTypes, - uint64_t *puValue) + * Public function, see header qcbor/qcbor_decode.h file + */ +void +QCBORDecode_GetUInt64ConvertAllInMapSZ(QCBORDecodeContext *pMe, + const char *szLabel, + const uint32_t uConvertTypes, + uint64_t *puValue) { QCBORItem Item; - QCBORDecode_GetUInt64ConvertInternalInMapSZ(pMe, + QCBORDecode_Private_GetUInt64ConvertInMapSZ(pMe, szLabel, uConvertTypes, puValue, @@ -5365,16 +6215,32 @@ void QCBORDecode_GetUInt64ConvertAllInMapSZ(QCBORDecodeContext *pMe, return; } - pMe->uLastError = (uint8_t)UInt64ConvertAll(&Item, uConvertTypes, puValue); + pMe->uLastError = (uint8_t)QCBOR_Private_UInt64ConvertAll(&Item, + uConvertTypes, + puValue); } #ifndef USEFULBUF_DISABLE_ALL_FLOAT -static QCBORError ConvertDouble(const QCBORItem *pItem, - uint32_t uConvertTypes, - double *pdValue) +/** + * @brief Basic conversions to a double. + * + * @param[in] pItem The item to convert + * @param[in] uConvertTypes Bit flags indicating source types for conversion + * @param[out] pdValue The value converted to a double + * + * This does the conversions that don't need much object code, + * the conversions from int, uint and float to double. + * + * See QCBOR_Private_DoubleConvertAll() for the full set + * of conversions. + */ +static QCBORError +QCBOR_Private_ConvertDouble(const QCBORItem *pItem, + const uint32_t uConvertTypes, + double *pdValue) { switch(pItem->uDataType) { case QCBOR_TYPE_FLOAT: @@ -5439,67 +6305,106 @@ static QCBORError ConvertDouble(const QCBORItem *pItem, } -void QCBORDecode_GetDoubleConvertInternal(QCBORDecodeContext *pMe, - uint32_t uConvertTypes, - double *pdValue, - QCBORItem *pItem) +/** + * @brief Almost-public method to decode a number and convert to double (semi-private). + * + * @param[in] pMe The decode context. + * @param[in] uConvertTypes Bit mask list of conversion options + * @param[out] pdValue The output of the conversion. + * @param[in,out] pItem Temporary space to store Item, returned item. + * + * See QCBORDecode_GetDoubleConvert(). + */ +void +QCBORDecode_Private_GetDoubleConvert(QCBORDecodeContext *pMe, + const uint32_t uConvertTypes, + double *pdValue, + QCBORItem *pItem) { - if(pMe->uLastError != QCBOR_SUCCESS) { - return; - } - - QCBORItem Item; - - QCBORError uError = QCBORDecode_GetNext(pMe, &Item); - if(uError) { - pMe->uLastError = (uint8_t)uError; + QCBORDecode_VGetNext(pMe, pItem); + if(pMe->uLastError) { return; } - if(pItem) { - *pItem = Item; - } - - pMe->uLastError = (uint8_t)ConvertDouble(&Item, uConvertTypes, pdValue); + pMe->uLastError = (uint8_t)QCBOR_Private_ConvertDouble(pItem, + uConvertTypes, + pdValue); } -void QCBORDecode_GetDoubleConvertInternalInMapN(QCBORDecodeContext *pMe, - int64_t nLabel, - uint32_t uConvertTypes, - double *pdValue, - QCBORItem *pItem) +/** + * @brief Almost-public method to decode a number and convert to double (semi-private). + * + * @param[in] pMe The decode context. + * @param[in] nLabel Label to find in map. + * @param[in] uConvertTypes Bit mask list of conversion options + * @param[out] pdValue The output of the conversion. + * @param[in,out] pItem Temporary space to store Item, returned item. + * + * See QCBORDecode_GetDoubleConvertInMapN(). + */ +void +QCBORDecode_Private_GetDoubleConvertInMapN(QCBORDecodeContext *pMe, + const int64_t nLabel, + const uint32_t uConvertTypes, + double *pdValue, + QCBORItem *pItem) { QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, pItem); if(pMe->uLastError != QCBOR_SUCCESS) { return; } - pMe->uLastError = (uint8_t)ConvertDouble(pItem, uConvertTypes, pdValue); + pMe->uLastError = (uint8_t)QCBOR_Private_ConvertDouble(pItem, + uConvertTypes, + pdValue); } -void QCBORDecode_GetDoubleConvertInternalInMapSZ(QCBORDecodeContext *pMe, - const char * szLabel, - uint32_t uConvertTypes, - double *pdValue, - QCBORItem *pItem) +/** + * @brief Almost-public method to decode a number and convert to double (semi-private). + * + * @param[in] pMe The decode context. + * @param[in] szLabel Label to find in map. + * @param[in] uConvertTypes Bit mask list of conversion options + * @param[out] pdValue The output of the conversion. + * @param[in,out] pItem Temporary space to store Item, returned item. + * + * See QCBORDecode_GetDoubleConvertInMapSZ(). + */ +void +QCBORDecode_Private_GetDoubleConvertInMapSZ(QCBORDecodeContext *pMe, + const char *szLabel, + const uint32_t uConvertTypes, + double *pdValue, + QCBORItem *pItem) { - if(pMe->uLastError != QCBOR_SUCCESS) { - return; - } - QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, pItem); if(pMe->uLastError != QCBOR_SUCCESS) { return; } - pMe->uLastError = (uint8_t)ConvertDouble(pItem, uConvertTypes, pdValue); + pMe->uLastError = (uint8_t)QCBOR_Private_ConvertDouble(pItem, + uConvertTypes, + pdValue); } #ifndef QCBOR_DISABLE_FLOAT_HW_USE -static double ConvertBigNumToDouble(const UsefulBufC BigNum) +/** + * @brief Convert a big number to double-precision float. + * + * @param[in] BigNum The big number to convert + * + * @returns The double value. + * + * This will always succeed. It will lose precision for larger + * numbers. If the big number is too large to fit (more than + * 1.7976931348623157E+308) infinity will be returned. NaN is never + * returned. + */ +static double +QCBOR_Private_ConvertBigNumToDouble(const UsefulBufC BigNum) { double dResult; @@ -5507,7 +6412,7 @@ static double ConvertBigNumToDouble(const UsefulBufC BigNum) const uint8_t *pByte = BigNum.ptr; size_t uLen = BigNum.len; /* This will overflow and become the float value INFINITY if the number - is too large to fit. */ + * is too large to fit. */ while(uLen--) { dResult = (dResult * 256.0) + (double)*pByte++; } @@ -5517,8 +6422,25 @@ static double ConvertBigNumToDouble(const UsefulBufC BigNum) #endif /* QCBOR_DISABLE_FLOAT_HW_USE */ + + +/** + * @brief Convert many number types to a double. + * + * @param[in] pItem The item to convert. + * @param[in] uConvertTypes Bit mask list of conversion options. + * @param[out] pdValue The resulting converted value. + * + * @retval QCBOR_ERR_UNEXPECTED_TYPE Conversion, possible, but not requested + * in uConvertTypes. + * @retval QCBOR_ERR_UNEXPECTED_TYPE Of a type that can't be converted + * @retval QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW Conversion result is too large + * or too small. + */ static QCBORError -DoubleConvertAll(const QCBORItem *pItem, uint32_t uConvertTypes, double *pdValue) +QCBOR_Private_DoubleConvertAll(const QCBORItem *pItem, + const uint32_t uConvertTypes, + double *pdValue) { #ifndef QCBOR_DISABLE_FLOAT_HW_USE /* @@ -5547,11 +6469,11 @@ DoubleConvertAll(const QCBORItem *pItem, uint32_t uConvertTypes, double *pdValue return QCBOR_ERR_UNEXPECTED_TYPE; } break; -#endif /* ndef QCBOR_DISABLE_EXP_AND_MANTISSA */ +#endif /* ! QCBOR_DISABLE_EXP_AND_MANTISSA */ case QCBOR_TYPE_POSBIGNUM: if(uConvertTypes & QCBOR_CONVERT_TYPE_BIG_NUM) { - *pdValue = ConvertBigNumToDouble(pItem->val.bigNum); + *pdValue = QCBOR_Private_ConvertBigNumToDouble(pItem->val.bigNum); } else { return QCBOR_ERR_UNEXPECTED_TYPE; } @@ -5559,7 +6481,7 @@ DoubleConvertAll(const QCBORItem *pItem, uint32_t uConvertTypes, double *pdValue case QCBOR_TYPE_NEGBIGNUM: if(uConvertTypes & QCBOR_CONVERT_TYPE_BIG_NUM) { - *pdValue = -1-ConvertBigNumToDouble(pItem->val.bigNum); + *pdValue = -1-QCBOR_Private_ConvertBigNumToDouble(pItem->val.bigNum); } else { return QCBOR_ERR_UNEXPECTED_TYPE; } @@ -5568,7 +6490,7 @@ DoubleConvertAll(const QCBORItem *pItem, uint32_t uConvertTypes, double *pdValue #ifndef QCBOR_DISABLE_EXP_AND_MANTISSA case QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM: if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) { - double dMantissa = ConvertBigNumToDouble(pItem->val.expAndMantissa.Mantissa.bigNum); + double dMantissa = QCBOR_Private_ConvertBigNumToDouble(pItem->val.expAndMantissa.Mantissa.bigNum); *pdValue = dMantissa * pow(10, (double)pItem->val.expAndMantissa.nExponent); } else { return QCBOR_ERR_UNEXPECTED_TYPE; @@ -5576,32 +6498,33 @@ DoubleConvertAll(const QCBORItem *pItem, uint32_t uConvertTypes, double *pdValue break; case QCBOR_TYPE_DECIMAL_FRACTION_NEG_BIGNUM: - if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) { - double dMantissa = -ConvertBigNumToDouble(pItem->val.expAndMantissa.Mantissa.bigNum); - *pdValue = dMantissa * pow(10, (double)pItem->val.expAndMantissa.nExponent); + if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) { + /* Must subtract 1 for CBOR negative integer offset */ + double dMantissa = -1-QCBOR_Private_ConvertBigNumToDouble(pItem->val.expAndMantissa.Mantissa.bigNum); + *pdValue = dMantissa * pow(10, (double)pItem->val.expAndMantissa.nExponent); } else { return QCBOR_ERR_UNEXPECTED_TYPE; } break; case QCBOR_TYPE_BIGFLOAT_POS_BIGNUM: - if(uConvertTypes & QCBOR_CONVERT_TYPE_BIGFLOAT) { - double dMantissa = ConvertBigNumToDouble(pItem->val.expAndMantissa.Mantissa.bigNum); - *pdValue = dMantissa * exp2((double)pItem->val.expAndMantissa.nExponent); + if(uConvertTypes & QCBOR_CONVERT_TYPE_BIGFLOAT) { + double dMantissa = QCBOR_Private_ConvertBigNumToDouble(pItem->val.expAndMantissa.Mantissa.bigNum); + *pdValue = dMantissa * exp2((double)pItem->val.expAndMantissa.nExponent); } else { return QCBOR_ERR_UNEXPECTED_TYPE; } break; case QCBOR_TYPE_BIGFLOAT_NEG_BIGNUM: - if(uConvertTypes & QCBOR_CONVERT_TYPE_BIGFLOAT) { - double dMantissa = -1-ConvertBigNumToDouble(pItem->val.expAndMantissa.Mantissa.bigNum); - *pdValue = dMantissa * exp2((double)pItem->val.expAndMantissa.nExponent); + if(uConvertTypes & QCBOR_CONVERT_TYPE_BIGFLOAT) { + double dMantissa = -1-QCBOR_Private_ConvertBigNumToDouble(pItem->val.expAndMantissa.Mantissa.bigNum); + *pdValue = dMantissa * exp2((double)pItem->val.expAndMantissa.nExponent); } else { return QCBOR_ERR_UNEXPECTED_TYPE; } break; -#endif /* ndef QCBOR_DISABLE_EXP_AND_MANTISSA */ +#endif /* ! QCBOR_DISABLE_EXP_AND_MANTISSA */ default: return QCBOR_ERR_UNEXPECTED_TYPE; @@ -5620,16 +6543,17 @@ DoubleConvertAll(const QCBORItem *pItem, uint32_t uConvertTypes, double *pdValue /* - Public function, see header qcbor/qcbor_decode.h file -*/ -void QCBORDecode_GetDoubleConvertAll(QCBORDecodeContext *pMe, - uint32_t uConvertTypes, - double *pdValue) + * Public function, see header qcbor/qcbor_decode.h file + */ +void +QCBORDecode_GetDoubleConvertAll(QCBORDecodeContext *pMe, + const uint32_t uConvertTypes, + double *pdValue) { QCBORItem Item; - QCBORDecode_GetDoubleConvertInternal(pMe, uConvertTypes, pdValue, &Item); + QCBORDecode_Private_GetDoubleConvert(pMe, uConvertTypes, pdValue, &Item); if(pMe->uLastError == QCBOR_SUCCESS) { // The above conversion succeeded @@ -5641,21 +6565,28 @@ void QCBORDecode_GetDoubleConvertAll(QCBORDecodeContext *pMe, return; } - pMe->uLastError = (uint8_t)DoubleConvertAll(&Item, uConvertTypes, pdValue); + pMe->uLastError = (uint8_t)QCBOR_Private_DoubleConvertAll(&Item, + uConvertTypes, + pdValue); } /* - Public function, see header qcbor/qcbor_decode.h file -*/ -void QCBORDecode_GetDoubleConvertAllInMapN(QCBORDecodeContext *pMe, - int64_t nLabel, - uint32_t uConvertTypes, - double *pdValue) + * Public function, see header qcbor/qcbor_decode.h file + */ +void +QCBORDecode_GetDoubleConvertAllInMapN(QCBORDecodeContext *pMe, + const int64_t nLabel, + const uint32_t uConvertTypes, + double *pdValue) { QCBORItem Item; - QCBORDecode_GetDoubleConvertInternalInMapN(pMe, nLabel, uConvertTypes, pdValue, &Item); + QCBORDecode_Private_GetDoubleConvertInMapN(pMe, + nLabel, + uConvertTypes, + pdValue, + &Item); if(pMe->uLastError == QCBOR_SUCCESS) { // The above conversion succeeded @@ -5667,20 +6598,27 @@ void QCBORDecode_GetDoubleConvertAllInMapN(QCBORDecodeContext *pMe, return; } - pMe->uLastError = (uint8_t)DoubleConvertAll(&Item, uConvertTypes, pdValue); + pMe->uLastError = (uint8_t)QCBOR_Private_DoubleConvertAll(&Item, + uConvertTypes, + pdValue); } /* - Public function, see header qcbor/qcbor_decode.h file -*/ -void QCBORDecode_GetDoubleConvertAllInMapSZ(QCBORDecodeContext *pMe, - const char *szLabel, - uint32_t uConvertTypes, - double *pdValue) + * Public function, see header qcbor/qcbor_decode.h file + */ +void +QCBORDecode_GetDoubleConvertAllInMapSZ(QCBORDecodeContext *pMe, + const char *szLabel, + const uint32_t uConvertTypes, + double *pdValue) { QCBORItem Item; - QCBORDecode_GetDoubleConvertInternalInMapSZ(pMe, szLabel, uConvertTypes, pdValue, &Item); + QCBORDecode_Private_GetDoubleConvertInMapSZ(pMe, + szLabel, + uConvertTypes, + pdValue, + &Item); if(pMe->uLastError == QCBOR_SUCCESS) { // The above conversion succeeded @@ -5692,7 +6630,9 @@ void QCBORDecode_GetDoubleConvertAllInMapSZ(QCBORDecodeContext *pMe, return; } - pMe->uLastError = (uint8_t)DoubleConvertAll(&Item, uConvertTypes, pdValue); + pMe->uLastError = (uint8_t)QCBOR_Private_DoubleConvertAll(&Item, + uConvertTypes, + pdValue); } #endif /* USEFULBUF_DISABLE_ALL_FLOAT */ @@ -5700,7 +6640,18 @@ void QCBORDecode_GetDoubleConvertAllInMapSZ(QCBORDecodeContext *pMe, #ifndef QCBOR_DISABLE_EXP_AND_MANTISSA -static inline UsefulBufC ConvertIntToBigNum(uint64_t uInt, UsefulBuf Buffer) +/** + * @brief Convert an integer to a big number + * + * @param[in] uInt The integer to convert. + * @param[in] Buffer The buffer to output the big number to. + * + * @returns The big number or NULLUsefulBufC is the buffer is to small. + * + * This always succeeds unless the buffer is too small. + */ +static UsefulBufC +QCBOR_Private_ConvertIntToBigNum(uint64_t uInt, const UsefulBuf Buffer) { while((uInt & 0xff00000000000000UL) == 0) { uInt = uInt << 8; @@ -5711,10 +6662,8 @@ static inline UsefulBufC ConvertIntToBigNum(uint64_t uInt, UsefulBuf Buffer) UsefulOutBuf_Init(&UOB, Buffer); while(uInt) { - const uint64_t xx = uInt & 0xff00000000000000UL; UsefulOutBuf_AppendByte(&UOB, (uint8_t)((uInt & 0xff00000000000000UL) >> 56)); uInt = uInt << 8; - (void)xx; } return UsefulOutBuf_OutUBuf(&UOB); @@ -5722,48 +6671,50 @@ static inline UsefulBufC ConvertIntToBigNum(uint64_t uInt, UsefulBuf Buffer) /** - * @brief Check and/or complete mantissa and exponent item. + * @brief Check and/or complete exponent and mantissa item. * - * @param[in] pMe The decoder context - * @param[in] TagSpec Expected type(s) - * @param[in,out] pItem See below + * @param[in] pMe The decoder context. + * @param[in] TagSpec Expected type(s). + * @param[in,out] pItem See below. * - * This is for decimal fractions and big floats, both of which are a - * mantissa and exponent. + * This is for decimal fractions and big floats, both of which are an + * exponent and mantissa. * - * The input item is either a fully decoded decimal faction or big - * float, or a just the decoded first item of a decimal fraction or - * big float. + * If the item item had a tag number indicating it was a + * decimal fraction or big float, then the input @c pItem will + * have been decoded as exponent and mantissa. If there was + * no tag number, the caller is asking this be decoded as a + * big float or decimal fraction and @c pItem just has the + * first item in an exponent and mantissa. * * On output, the item is always a fully decoded decimal fraction or * big float. * * This errors out if the input type does not meet the TagSpec. */ -// TODO: document and see tests for the bug that was fixed by this rewrite static QCBORError -MantissaAndExponentTypeHandler(QCBORDecodeContext *pMe, - const TagSpecification TagSpec, - QCBORItem *pItem) +QCBOR_Private_ExpMantissaTypeHandler(QCBORDecodeContext *pMe, + const QCBOR_Private_TagSpec TagSpec, + QCBORItem *pItem) { QCBORError uErr; - /* pItem could either be an auto-decoded mantissa and exponent or - * the opening array of an undecoded mantissa and exponent. This + /* pItem could either be a decoded exponent and mantissa or + * the opening array of an undecoded exponent and mantissa. This * check will succeed on either, but doesn't say which it was. */ - uErr = CheckTagRequirement(TagSpec, pItem); + uErr = QCBOR_Private_CheckTagRequirement(TagSpec, pItem); if(uErr != QCBOR_SUCCESS) { goto Done; } if(pItem->uDataType == QCBOR_TYPE_ARRAY) { - /* The item is an array, which means is is an undecoded mantissa - * and exponent. This call consumes the items in the array and - * results in a decoded mantissa and exponent in pItem. This is + /* The item is an array, which means is is an undecoded exponent + * and mantissa. This call consumes the items in the array and + * results in a decoded exponent and mantissa in pItem. This is * the case where there was no tag. */ - uErr = QCBORDecode_MantissaAndExponent(pMe, pItem); + uErr = QCBORDecode_Private_ExpMantissa(pMe, pItem); if(uErr != QCBOR_SUCCESS) { goto Done; } @@ -5772,10 +6723,10 @@ MantissaAndExponentTypeHandler(QCBORDecodeContext *pMe, * fraction or big num. Which of these two depends on what the * caller wants it decoded as since there is no tag, so fish the * type out of the TagSpec. */ - pItem->uDataType = MantissaExponentDataType(TagSpec.uTaggedTypes[0], pItem); + pItem->uDataType = QCBOR_Private_ExpMantissaDataType(TagSpec.uTaggedTypes[0], pItem); /* No need to check the type again. All that we need to know was - * that it decoded correctly as a mantissa and exponent. The + * that it decoded correctly as a exponent and mantissa. The * QCBOR type is set out by what was requested. */ } @@ -5820,15 +6771,34 @@ MantissaAndExponentTypeHandler(QCBORDecodeContext *pMe, * first tier part of the public API. Some functions only * vary by a TagSpec. */ -static void ProcessMantissaAndExponent(QCBORDecodeContext *pMe, - TagSpecification TagSpec, - QCBORItem *pItem, - int64_t *pnMantissa, - int64_t *pnExponent) + +/** + * @brief Common processor for exponent and mantissa. + * + * @param[in] pMe The decode context. + * @param[in] TagSpec The expected/allowed tags. + * @param[in] pItem The data item to process. + * @param[out] pnMantissa The returned mantissa as an int64_t. + * @param[out] pnExponent The returned exponent as an int64_t. + * + * This handles exponent and mantissa for base 2 and 10. This + * is limited to a mantissa that is an int64_t. See also + * QCBORDecode_Private_ProcessExpMantissaBig(). + */ +static void +QCBOR_Private_ProcessExpMantissa(QCBORDecodeContext *pMe, + const QCBOR_Private_TagSpec TagSpec, + QCBORItem *pItem, + int64_t *pnMantissa, + int64_t *pnExponent) { QCBORError uErr; - uErr = MantissaAndExponentTypeHandler(pMe, TagSpec, pItem); + if(pMe->uLastError) { + return; + } + + uErr = QCBOR_Private_ExpMantissaTypeHandler(pMe, TagSpec, pItem); if(uErr != QCBOR_SUCCESS) { goto Done; } @@ -5846,13 +6816,13 @@ static void ProcessMantissaAndExponent(QCBORDecodeContext *pMe, case QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM: case QCBOR_TYPE_BIGFLOAT_POS_BIGNUM: *pnExponent = pItem->val.expAndMantissa.nExponent; - uErr = ConvertPositiveBigNumToSigned(pItem->val.expAndMantissa.Mantissa.bigNum, pnMantissa); + uErr = QCBOR_Private_ConvertPositiveBigNumToSigned(pItem->val.expAndMantissa.Mantissa.bigNum, pnMantissa); break; case QCBOR_TYPE_DECIMAL_FRACTION_NEG_BIGNUM: case QCBOR_TYPE_BIGFLOAT_NEG_BIGNUM: *pnExponent = pItem->val.expAndMantissa.nExponent; - uErr = ConvertNegativeBigNumToSigned(pItem->val.expAndMantissa.Mantissa.bigNum, pnMantissa); + uErr = QCBOR_Private_ConvertNegativeBigNumToSigned(pItem->val.expAndMantissa.Mantissa.bigNum, pnMantissa); break; #endif /* QCBOR_DISABLE_TAGS */ @@ -5865,39 +6835,65 @@ static void ProcessMantissaAndExponent(QCBORDecodeContext *pMe, } -static void ProcessMantissaAndExponentBig(QCBORDecodeContext *pMe, - TagSpecification TagSpec, - QCBORItem *pItem, - UsefulBuf BufferForMantissa, - UsefulBufC *pMantissa, - bool *pbIsNegative, - int64_t *pnExponent) +/** + * @brief Decode exponent and mantissa into a big number. + * + * @param[in] pMe The decode context. + * @param[in] TagSpec The expected/allowed tags. + * @param[in] pItem Item to decode and convert. + * @param[in] BufferForMantissa Buffer to output mantissa into. + * @param[out] pMantissa The output mantissa. + * @param[out] pbIsNegative The sign of the output. + * @param[out] pnExponent The mantissa of the output. + * + * This is the common processing of a decimal fraction or a big float + * into a big number. This will decode and consume all the CBOR items + * that make up the decimal fraction or big float. + */ +static void +QCBORDecode_Private_ProcessExpMantissaBig(QCBORDecodeContext *pMe, + const QCBOR_Private_TagSpec TagSpec, + QCBORItem *pItem, + const UsefulBuf BufferForMantissa, + UsefulBufC *pMantissa, + bool *pbIsNegative, + int64_t *pnExponent) { QCBORError uErr; + uint64_t uMantissa; + + if(pMe->uLastError != QCBOR_SUCCESS) { + return; + } - uErr = MantissaAndExponentTypeHandler(pMe, TagSpec, pItem); + uErr = QCBOR_Private_ExpMantissaTypeHandler(pMe, TagSpec, pItem); if(uErr != QCBOR_SUCCESS) { goto Done; } - uint64_t uMantissa; - switch (pItem->uDataType) { case QCBOR_TYPE_DECIMAL_FRACTION: case QCBOR_TYPE_BIGFLOAT: - /* See comments in ExponentiateNN() on handling INT64_MIN */ if(pItem->val.expAndMantissa.Mantissa.nInt >= 0) { uMantissa = (uint64_t)pItem->val.expAndMantissa.Mantissa.nInt; *pbIsNegative = false; - } else if(pItem->val.expAndMantissa.Mantissa.nInt != INT64_MIN) { - uMantissa = (uint64_t)-pItem->val.expAndMantissa.Mantissa.nInt; - *pbIsNegative = true; } else { - uMantissa = (uint64_t)INT64_MAX+1; + if(pItem->val.expAndMantissa.Mantissa.nInt != INT64_MIN) { + uMantissa = (uint64_t)-pItem->val.expAndMantissa.Mantissa.nInt; + } else { + /* Can't negate like above when int64_t is INT64_MIN because it + * will overflow. See ExponentNN() */ + uMantissa = (uint64_t)INT64_MAX+1; + } *pbIsNegative = true; } - *pMantissa = ConvertIntToBigNum(uMantissa, BufferForMantissa); + /* Reverse the offset by 1 for type 1 negative value to be consistent + * with big num case below which don't offset because it requires + * big number arithmetic. This is a bug fix for QCBOR v1.5. + */ + uMantissa--; + *pMantissa = QCBOR_Private_ConvertIntToBigNum(uMantissa, BufferForMantissa); *pnExponent = pItem->val.expAndMantissa.nExponent; break; @@ -5928,25 +6924,18 @@ static void ProcessMantissaAndExponentBig(QCBORDecodeContext *pMe, /* - Public function, see header qcbor/qcbor_decode.h file -*/ -void QCBORDecode_GetDecimalFraction(QCBORDecodeContext *pMe, - uint8_t uTagRequirement, - int64_t *pnMantissa, - int64_t *pnExponent) + * Public function, see header qcbor/qcbor_decode.h file + */ +void +QCBORDecode_GetDecimalFraction(QCBORDecodeContext *pMe, + const uint8_t uTagRequirement, + int64_t *pnMantissa, + int64_t *pnExponent) { - if(pMe->uLastError != QCBOR_SUCCESS) { - return; - } - QCBORItem Item; - QCBORError uError = QCBORDecode_GetNext(pMe, &Item); - if(uError) { - pMe->uLastError = (uint8_t)uError; - return; - } + QCBORDecode_VGetNext(pMe, &Item); - const TagSpecification TagSpec = + const QCBOR_Private_TagSpec TagSpec = { uTagRequirement, {QCBOR_TYPE_DECIMAL_FRACTION, QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM, @@ -5954,27 +6943,28 @@ void QCBORDecode_GetDecimalFraction(QCBORDecodeContext *pMe, {QCBOR_TYPE_ARRAY, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE} }; - ProcessMantissaAndExponent(pMe, TagSpec, &Item, pnMantissa, pnExponent); + QCBOR_Private_ProcessExpMantissa(pMe, + TagSpec, + &Item, + pnMantissa, + pnExponent); } /* - Public function, see header qcbor/qcbor_decode.h file -*/ -void QCBORDecode_GetDecimalFractionInMapN(QCBORDecodeContext *pMe, - int64_t nLabel, - uint8_t uTagRequirement, - int64_t *pnMantissa, - int64_t *pnExponent) + * Public function, see header qcbor/qcbor_decode.h file + */ +void +QCBORDecode_GetDecimalFractionInMapN(QCBORDecodeContext *pMe, + const int64_t nLabel, + const uint8_t uTagRequirement, + int64_t *pnMantissa, + int64_t *pnExponent) { - if(pMe->uLastError != QCBOR_SUCCESS) { - return; - } - QCBORItem Item; QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, &Item); - const TagSpecification TagSpec = + const QCBOR_Private_TagSpec TagSpec = { uTagRequirement, {QCBOR_TYPE_DECIMAL_FRACTION, QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM, @@ -5982,27 +6972,28 @@ void QCBORDecode_GetDecimalFractionInMapN(QCBORDecodeContext *pMe, {QCBOR_TYPE_ARRAY, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE} }; - ProcessMantissaAndExponent(pMe, TagSpec, &Item, pnMantissa, pnExponent); + QCBOR_Private_ProcessExpMantissa(pMe, + TagSpec, + &Item, + pnMantissa, + pnExponent); } /* - Public function, see header qcbor/qcbor_decode.h file -*/ -void QCBORDecode_GetDecimalFractionInMapSZ(QCBORDecodeContext *pMe, - const char *szLabel, - uint8_t uTagRequirement, - int64_t *pnMantissa, - int64_t *pnExponent) + * Public function, see header qcbor/qcbor_decode.h file + */ +void +QCBORDecode_GetDecimalFractionInMapSZ(QCBORDecodeContext *pMe, + const char *szLabel, + const uint8_t uTagRequirement, + int64_t *pnMantissa, + int64_t *pnExponent) { - if(pMe->uLastError != QCBOR_SUCCESS) { - return; - } - QCBORItem Item; QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item); - const TagSpecification TagSpec = + const QCBOR_Private_TagSpec TagSpec = { uTagRequirement, {QCBOR_TYPE_DECIMAL_FRACTION, QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM, @@ -6010,32 +7001,29 @@ void QCBORDecode_GetDecimalFractionInMapSZ(QCBORDecodeContext *pMe, {QCBOR_TYPE_ARRAY, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE} }; - ProcessMantissaAndExponent(pMe, TagSpec, &Item, pnMantissa, pnExponent); + QCBOR_Private_ProcessExpMantissa(pMe, + TagSpec, + &Item, + pnMantissa, + pnExponent); } /* - Public function, see header qcbor/qcbor_decode.h file -*/ -void QCBORDecode_GetDecimalFractionBig(QCBORDecodeContext *pMe, - uint8_t uTagRequirement, - UsefulBuf MantissaBuffer, - UsefulBufC *pMantissa, - bool *pbMantissaIsNegative, - int64_t *pnExponent) + * Public function, see header qcbor/qcbor_decode.h file + */ +void +QCBORDecode_GetDecimalFractionBig(QCBORDecodeContext *pMe, + const uint8_t uTagRequirement, + const UsefulBuf MantissaBuffer, + UsefulBufC *pMantissa, + bool *pbMantissaIsNegative, + int64_t *pnExponent) { - if(pMe->uLastError != QCBOR_SUCCESS) { - return; - } - QCBORItem Item; - QCBORError uError = QCBORDecode_GetNext(pMe, &Item); - if(uError) { - pMe->uLastError = (uint8_t)uError; - return; - } + QCBORDecode_VGetNext(pMe, &Item); - const TagSpecification TagSpec = + const QCBOR_Private_TagSpec TagSpec = { uTagRequirement, {QCBOR_TYPE_DECIMAL_FRACTION, QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM, @@ -6043,38 +7031,33 @@ void QCBORDecode_GetDecimalFractionBig(QCBORDecodeContext *pMe, {QCBOR_TYPE_ARRAY, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE} }; - ProcessMantissaAndExponentBig(pMe, - TagSpec, - &Item, - MantissaBuffer, - pMantissa, - pbMantissaIsNegative, - pnExponent); + QCBORDecode_Private_ProcessExpMantissaBig(pMe, + TagSpec, + &Item, + MantissaBuffer, + pMantissa, + pbMantissaIsNegative, + pnExponent); } /* - Public function, see header qcbor/qcbor_decode.h file -*/ -void QCBORDecode_GetDecimalFractionBigInMapN(QCBORDecodeContext *pMe, - int64_t nLabel, - uint8_t uTagRequirement, - UsefulBuf BufferForMantissa, - UsefulBufC *pMantissa, - bool *pbIsNegative, - int64_t *pnExponent) + * Public function, see header qcbor/qcbor_decode.h file + */ +void +QCBORDecode_GetDecimalFractionBigInMapN(QCBORDecodeContext *pMe, + const int64_t nLabel, + const uint8_t uTagRequirement, + const UsefulBuf BufferForMantissa, + UsefulBufC *pMantissa, + bool *pbIsNegative, + int64_t *pnExponent) { - if(pMe->uLastError != QCBOR_SUCCESS) { - return; - } QCBORItem Item; QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, &Item); - if(pMe->uLastError != QCBOR_SUCCESS) { - return; - } - const TagSpecification TagSpec = + const QCBOR_Private_TagSpec TagSpec = { uTagRequirement, {QCBOR_TYPE_DECIMAL_FRACTION, QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM, @@ -6082,38 +7065,32 @@ void QCBORDecode_GetDecimalFractionBigInMapN(QCBORDecodeContext *pMe, {QCBOR_TYPE_ARRAY, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE} }; - ProcessMantissaAndExponentBig(pMe, - TagSpec, - &Item, - BufferForMantissa, - pMantissa, - pbIsNegative, - pnExponent); + QCBORDecode_Private_ProcessExpMantissaBig(pMe, + TagSpec, + &Item, + BufferForMantissa, + pMantissa, + pbIsNegative, + pnExponent); } /* - Public function, see header qcbor/qcbor_decode.h file -*/ -void QCBORDecode_GetDecimalFractionBigInMapSZ(QCBORDecodeContext *pMe, - const char *szLabel, - uint8_t uTagRequirement, - UsefulBuf BufferForMantissa, - UsefulBufC *pMantissa, - bool *pbIsNegative, - int64_t *pnExponent) + * Public function, see header qcbor/qcbor_decode.h file + */ +void +QCBORDecode_GetDecimalFractionBigInMapSZ(QCBORDecodeContext *pMe, + const char *szLabel, + const uint8_t uTagRequirement, + const UsefulBuf BufferForMantissa, + UsefulBufC *pMantissa, + bool *pbIsNegative, + int64_t *pnExponent) { - if(pMe->uLastError != QCBOR_SUCCESS) { - return; - } - QCBORItem Item; QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item); - if(pMe->uLastError != QCBOR_SUCCESS) { - return; - } - const TagSpecification TagSpec = + const QCBOR_Private_TagSpec TagSpec = { uTagRequirement, {QCBOR_TYPE_DECIMAL_FRACTION, QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM, @@ -6121,29 +7098,29 @@ void QCBORDecode_GetDecimalFractionBigInMapSZ(QCBORDecodeContext *pMe, {QCBOR_TYPE_ARRAY, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE} }; - ProcessMantissaAndExponentBig(pMe, TagSpec, &Item, BufferForMantissa, pMantissa, pbIsNegative, pnExponent); + QCBORDecode_Private_ProcessExpMantissaBig(pMe, + TagSpec, + &Item, + BufferForMantissa, + pMantissa, + pbIsNegative, + pnExponent); } /* - Public function, see header qcbor/qcbor_decode.h file -*/ -void QCBORDecode_GetBigFloat(QCBORDecodeContext *pMe, - uint8_t uTagRequirement, - int64_t *pnMantissa, - int64_t *pnExponent) + * Public function, see header qcbor/qcbor_decode.h file + */ +void +QCBORDecode_GetBigFloat(QCBORDecodeContext *pMe, + const uint8_t uTagRequirement, + int64_t *pnMantissa, + int64_t *pnExponent) { - if(pMe->uLastError != QCBOR_SUCCESS) { - return; - } - QCBORItem Item; - QCBORError uError = QCBORDecode_GetNext(pMe, &Item); - if(uError) { - pMe->uLastError = (uint8_t)uError; - return; - } - const TagSpecification TagSpec = + QCBORDecode_VGetNext(pMe, &Item); + + const QCBOR_Private_TagSpec TagSpec = { uTagRequirement, {QCBOR_TYPE_BIGFLOAT, QCBOR_TYPE_BIGFLOAT_POS_BIGNUM, @@ -6151,30 +7128,28 @@ void QCBORDecode_GetBigFloat(QCBORDecodeContext *pMe, {QCBOR_TYPE_ARRAY, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE} }; - ProcessMantissaAndExponent(pMe, TagSpec, &Item, pnMantissa, pnExponent); + QCBOR_Private_ProcessExpMantissa(pMe, + TagSpec, + &Item, + pnMantissa, + pnExponent); } /* - Public function, see header qcbor/qcbor_decode.h file -*/ -void QCBORDecode_GetBigFloatInMapN(QCBORDecodeContext *pMe, - int64_t nLabel, - uint8_t uTagRequirement, - int64_t *pnMantissa, - int64_t *pnExponent) + * Public function, see header qcbor/qcbor_decode.h file + */ +void +QCBORDecode_GetBigFloatInMapN(QCBORDecodeContext *pMe, + const int64_t nLabel, + const uint8_t uTagRequirement, + int64_t *pnMantissa, + int64_t *pnExponent) { - if(pMe->uLastError != QCBOR_SUCCESS) { - return; - } - QCBORItem Item; QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, &Item); - if(pMe->uLastError != QCBOR_SUCCESS) { - return; - } - const TagSpecification TagSpec = + const QCBOR_Private_TagSpec TagSpec = { uTagRequirement, {QCBOR_TYPE_BIGFLOAT, QCBOR_TYPE_BIGFLOAT_POS_BIGNUM, @@ -6182,30 +7157,28 @@ void QCBORDecode_GetBigFloatInMapN(QCBORDecodeContext *pMe, {QCBOR_TYPE_ARRAY, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE} }; - ProcessMantissaAndExponent(pMe, TagSpec, &Item, pnMantissa, pnExponent); + QCBOR_Private_ProcessExpMantissa(pMe, + TagSpec, + &Item, + pnMantissa, + pnExponent); } /* - Public function, see header qcbor/qcbor_decode.h file -*/ -void QCBORDecode_GetBigFloatInMapSZ(QCBORDecodeContext *pMe, - const char *szLabel, - uint8_t uTagRequirement, - int64_t *pnMantissa, - int64_t *pnExponent) + * Public function, see header qcbor/qcbor_decode.h file + */ +void +QCBORDecode_GetBigFloatInMapSZ(QCBORDecodeContext *pMe, + const char *szLabel, + const uint8_t uTagRequirement, + int64_t *pnMantissa, + int64_t *pnExponent) { - if(pMe->uLastError != QCBOR_SUCCESS) { - return; - } - QCBORItem Item; QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item); - if(pMe->uLastError != QCBOR_SUCCESS) { - return; - } - const TagSpecification TagSpec = + const QCBOR_Private_TagSpec TagSpec = { uTagRequirement, {QCBOR_TYPE_BIGFLOAT, QCBOR_TYPE_BIGFLOAT_POS_BIGNUM, @@ -6213,32 +7186,29 @@ void QCBORDecode_GetBigFloatInMapSZ(QCBORDecodeContext *pMe, {QCBOR_TYPE_ARRAY, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE} }; - ProcessMantissaAndExponent(pMe, TagSpec, &Item, pnMantissa, pnExponent); + QCBOR_Private_ProcessExpMantissa(pMe, + TagSpec, + &Item, + pnMantissa, + pnExponent); } /* - Public function, see header qcbor/qcbor_decode.h file -*/ -void QCBORDecode_GetBigFloatBig(QCBORDecodeContext *pMe, - uint8_t uTagRequirement, - UsefulBuf MantissaBuffer, - UsefulBufC *pMantissa, - bool *pbMantissaIsNegative, - int64_t *pnExponent) + * Public function, see header qcbor/qcbor_decode.h file + */ +void +QCBORDecode_GetBigFloatBig(QCBORDecodeContext *pMe, + const uint8_t uTagRequirement, + const UsefulBuf MantissaBuffer, + UsefulBufC *pMantissa, + bool *pbMantissaIsNegative, + int64_t *pnExponent) { - if(pMe->uLastError != QCBOR_SUCCESS) { - return; - } - QCBORItem Item; - QCBORError uError = QCBORDecode_GetNext(pMe, &Item); - if(uError) { - pMe->uLastError = (uint8_t)uError; - return; - } + QCBORDecode_VGetNext(pMe, &Item); - const TagSpecification TagSpec = + const QCBOR_Private_TagSpec TagSpec = { uTagRequirement, {QCBOR_TYPE_BIGFLOAT, QCBOR_TYPE_BIGFLOAT_POS_BIGNUM, @@ -6246,32 +7216,32 @@ void QCBORDecode_GetBigFloatBig(QCBORDecodeContext *pMe, {QCBOR_TYPE_ARRAY, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE} }; - ProcessMantissaAndExponentBig(pMe, TagSpec, &Item, MantissaBuffer, pMantissa, pbMantissaIsNegative, pnExponent); + QCBORDecode_Private_ProcessExpMantissaBig(pMe, + TagSpec, + &Item, + MantissaBuffer, + pMantissa, + pbMantissaIsNegative, + pnExponent); } /* - Public function, see header qcbor/qcbor_decode.h file -*/ -void QCBORDecode_GetBigFloatBigInMapN(QCBORDecodeContext *pMe, - int64_t nLabel, - uint8_t uTagRequirement, - UsefulBuf BufferForMantissa, - UsefulBufC *pMantissa, - bool *pbIsNegative, - int64_t *pnExponent) + * Public function, see header qcbor/qcbor_decode.h file + */ +void +QCBORDecode_GetBigFloatBigInMapN(QCBORDecodeContext *pMe, + const int64_t nLabel, + const uint8_t uTagRequirement, + const UsefulBuf BufferForMantissa, + UsefulBufC *pMantissa, + bool *pbIsNegative, + int64_t *pnExponent) { - if(pMe->uLastError != QCBOR_SUCCESS) { - return; - } - QCBORItem Item; QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, &Item); - if(pMe->uLastError != QCBOR_SUCCESS) { - return; - } - const TagSpecification TagSpec = + const QCBOR_Private_TagSpec TagSpec = { uTagRequirement, {QCBOR_TYPE_BIGFLOAT, QCBOR_TYPE_BIGFLOAT_POS_BIGNUM, @@ -6279,38 +7249,32 @@ void QCBORDecode_GetBigFloatBigInMapN(QCBORDecodeContext *pMe, {QCBOR_TYPE_ARRAY, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE} }; - ProcessMantissaAndExponentBig(pMe, - TagSpec, - &Item, - BufferForMantissa, - pMantissa, - pbIsNegative, - pnExponent); + QCBORDecode_Private_ProcessExpMantissaBig(pMe, + TagSpec, + &Item, + BufferForMantissa, + pMantissa, + pbIsNegative, + pnExponent); } /* - Public function, see header qcbor/qcbor_decode.h file -*/ -void QCBORDecode_GetBigFloatBigInMapSZ(QCBORDecodeContext *pMe, - const char *szLabel, - uint8_t uTagRequirement, - UsefulBuf BufferForMantissa, - UsefulBufC *pMantissa, - bool *pbIsNegative, - int64_t *pnExponent) + * Public function, see header qcbor/qcbor_decode.h file + */ +void +QCBORDecode_GetBigFloatBigInMapSZ(QCBORDecodeContext *pMe, + const char *szLabel, + const uint8_t uTagRequirement, + const UsefulBuf BufferForMantissa, + UsefulBufC *pMantissa, + bool *pbIsNegative, + int64_t *pnExponent) { - if(pMe->uLastError != QCBOR_SUCCESS) { - return; - } - QCBORItem Item; QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item); - if(pMe->uLastError != QCBOR_SUCCESS) { - return; - } - const TagSpecification TagSpec = + const QCBOR_Private_TagSpec TagSpec = { uTagRequirement, {QCBOR_TYPE_BIGFLOAT, QCBOR_TYPE_BIGFLOAT_POS_BIGNUM, @@ -6318,13 +7282,13 @@ void QCBORDecode_GetBigFloatBigInMapSZ(QCBORDecodeContext *pMe, {QCBOR_TYPE_ARRAY, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE} }; - ProcessMantissaAndExponentBig(pMe, - TagSpec, - &Item, - BufferForMantissa, - pMantissa, - pbIsNegative, - pnExponent); + QCBORDecode_Private_ProcessExpMantissaBig(pMe, + TagSpec, + &Item, + BufferForMantissa, + pMantissa, + pbIsNegative, + pnExponent); } #endif /* QCBOR_DISABLE_EXP_AND_MANTISSA */ diff --git a/3rdparty/exported/QCBOR/src/qcbor_encode.c b/3rdparty/exported/QCBOR/src/qcbor_encode.c index 53df657cfbb7..c30cbce11691 100644 --- a/3rdparty/exported/QCBOR/src/qcbor_encode.c +++ b/3rdparty/exported/QCBOR/src/qcbor_encode.c @@ -1,35 +1,35 @@ -/*============================================================================== - Copyright (c) 2016-2018, The Linux Foundation. - Copyright (c) 2018-2022, Laurence Lundblade. - Copyright (c) 2021, Arm Limited. - All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following - disclaimer in the documentation and/or other materials provided - with the distribution. - * Neither the name of The Linux Foundation nor the names of its - contributors, nor the name "Laurence Lundblade" may be used to - endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED -WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT -ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS -BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR -BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, -WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE -OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN -IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - =============================================================================*/ +/* =========================================================================== + * Copyright (c) 2016-2018, The Linux Foundation. + * Copyright (c) 2018-2024, Laurence Lundblade. + * Copyright (c) 2021, Arm Limited. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * * Neither the name of The Linux Foundation nor the names of its + * contributors, nor the name "Laurence Lundblade" may be used to + * endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ========================================================================= */ #include "qcbor/qcbor_encode.h" @@ -72,7 +72,7 @@ IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * with the type CBOR_MAJOR_TYPE_BYTE_STRING and is tracked here. Byte * string wrapped CBOR is used by COSE for data that is to be hashed. */ -static inline void +static void Nesting_Init(QCBORTrackNesting *pNesting) { /* Assumes pNesting has been zeroed. */ @@ -83,10 +83,10 @@ Nesting_Init(QCBORTrackNesting *pNesting) pNesting->pCurrentNesting->uMajorType = CBOR_MAJOR_TYPE_ARRAY; } -static inline uint8_t +static uint8_t Nesting_Increase(QCBORTrackNesting *pNesting, - uint8_t uMajorType, - uint32_t uPos) + const uint8_t uMajorType, + const uint32_t uPos) { if(pNesting->pCurrentNesting == &pNesting->pArrays[QCBOR_MAX_ARRAY_NESTING]) { return QCBOR_ERR_ARRAY_NESTING_TOO_DEEP; @@ -99,7 +99,7 @@ Nesting_Increase(QCBORTrackNesting *pNesting, } } -static inline void +static void Nesting_Decrease(QCBORTrackNesting *pNesting) { if(pNesting->pCurrentNesting > &pNesting->pArrays[0]) { @@ -107,21 +107,21 @@ Nesting_Decrease(QCBORTrackNesting *pNesting) } } -static inline uint8_t +static uint8_t Nesting_Increment(QCBORTrackNesting *pNesting) { #ifndef QCBOR_DISABLE_ENCODE_USAGE_GUARDS - if(1 >= QCBOR_MAX_ITEMS_IN_ARRAY - pNesting->pCurrentNesting->uCount) { + if(pNesting->pCurrentNesting->uCount >= QCBOR_MAX_ITEMS_IN_ARRAY) { return QCBOR_ERR_ARRAY_TOO_LONG; } -#endif /* QCBOR_DISABLE_ENCODE_USAGE_GUARDS */ +#endif /* ! QCBOR_DISABLE_ENCODE_USAGE_GUARDS */ pNesting->pCurrentNesting->uCount++; return QCBOR_SUCCESS; } -static inline void +static void Nesting_Decrement(QCBORTrackNesting *pNesting) { /* No error check for going below 0 here needed because this @@ -130,7 +130,7 @@ Nesting_Decrement(QCBORTrackNesting *pNesting) pNesting->pCurrentNesting->uCount--; } -static inline uint16_t +static uint16_t Nesting_GetCount(QCBORTrackNesting *pNesting) { /* The nesting count recorded is always the actual number of @@ -148,25 +148,25 @@ Nesting_GetCount(QCBORTrackNesting *pNesting) } } -static inline uint32_t +static uint32_t Nesting_GetStartPos(QCBORTrackNesting *pNesting) { return pNesting->pCurrentNesting->uStart; } #ifndef QCBOR_DISABLE_ENCODE_USAGE_GUARDS -static inline uint8_t +static uint8_t Nesting_GetMajorType(QCBORTrackNesting *pNesting) { return pNesting->pCurrentNesting->uMajorType; } -static inline bool +static bool Nesting_IsInNest(QCBORTrackNesting *pNesting) { return pNesting->pCurrentNesting == &pNesting->pArrays[0] ? false : true; } -#endif /* QCBOR_DISABLE_ENCODE_USAGE_GUARDS */ +#endif /* ! QCBOR_DISABLE_ENCODE_USAGE_GUARDS */ @@ -223,7 +223,7 @@ Nesting_IsInNest(QCBORTrackNesting *pNesting) * * QCBOR_DISABLE_ENCODE_USAGE_GUARDS also disables the check for more * than QCBOR_MAX_ITEMS_IN_ARRAY in an array. Since - * QCBOR_MAX_ITEMS_IN_ARRAY is very large (65,535) it is very unlikely + * QCBOR_MAX_ITEMS_IN_ARRAY is very large (65,534) it is very unlikely * to be reached. If it is reached, the count will wrap around to zero * and CBOR that is not well formed will be produced, but there will * be no buffers overrun and new security issues in the code. @@ -249,23 +249,25 @@ Nesting_IsInNest(QCBORTrackNesting *pNesting) /* - Public function for initialization. See qcbor/qcbor_encode.h + * Public function for initialization. See qcbor/qcbor_encode.h */ -void QCBOREncode_Init(QCBOREncodeContext *me, UsefulBuf Storage) +void +QCBOREncode_Init(QCBOREncodeContext *pMe, UsefulBuf Storage) { - memset(me, 0, sizeof(QCBOREncodeContext)); - UsefulOutBuf_Init(&(me->OutBuf), Storage); - Nesting_Init(&(me->nesting)); + memset(pMe, 0, sizeof(QCBOREncodeContext)); + UsefulOutBuf_Init(&(pMe->OutBuf), Storage); + Nesting_Init(&(pMe->nesting)); } /* * Public function to encode a CBOR head. See qcbor/qcbor_encode.h */ -UsefulBufC QCBOREncode_EncodeHead(UsefulBuf buffer, - uint8_t uMajorType, - uint8_t uMinLen, - uint64_t uArgument) +UsefulBufC +QCBOREncode_EncodeHead(UsefulBuf Buffer, + uint8_t uMajorType, + uint8_t uMinLen, + uint64_t uArgument) { /* * == Description of the CBOR Head == @@ -412,18 +414,19 @@ UsefulBufC QCBOREncode_EncodeHead(UsefulBuf buffer, * extra. The one extra is needed for this code to work as it does * a pre-decrement. */ - if(buffer.len < QCBOR_HEAD_BUFFER_SIZE) { + if(Buffer.len < QCBOR_HEAD_BUFFER_SIZE) { return NULLUsefulBufC; } /* Pointer to last valid byte in the buffer */ - uint8_t * const pBufferEnd = &((uint8_t *)buffer.ptr)[QCBOR_HEAD_BUFFER_SIZE-1]; + uint8_t * const pBufferEnd = &((uint8_t *)Buffer.ptr)[QCBOR_HEAD_BUFFER_SIZE-1]; /* Point to the last byte and work backwards */ uint8_t *pByte = pBufferEnd; /* The 5 bits in the initial byte that are not the major type */ int nAdditionalInfo; +#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS if(uMajorType > QCBOR_INDEFINITE_LEN_TYPE_MODIFIER) { /* Special case for start & end of indefinite length */ uMajorType = uMajorType - QCBOR_INDEFINITE_LEN_TYPE_MODIFIER; @@ -436,7 +439,9 @@ UsefulBufC QCBOREncode_EncodeHead(UsefulBuf buffer, #endif nAdditionalInfo = CBOR_SIMPLE_BREAK; - } else if (uArgument < CBOR_TWENTY_FOUR && uMinLen == 0) { + } else +#endif /* ! QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS */ + if (uArgument < CBOR_TWENTY_FOUR && uMinLen == 0) { /* Simple case where argument is < 24 */ nAdditionalInfo = (int)uArgument; @@ -472,7 +477,7 @@ UsefulBufC QCBOREncode_EncodeHead(UsefulBuf buffer, /* This expression integer-promotes to type int. The code above in * function guarantees that nAdditionalInfo will never be larger * than 0x1f. The caller may pass in a too-large uMajor type. The - * conversion to unint8_t will cause an integer wrap around and + * conversion to uint8_t will cause an integer wrap around and * incorrect CBOR will be generated, but no security issue will * occur. */ @@ -498,161 +503,77 @@ UsefulBufC QCBOREncode_EncodeHead(UsefulBuf buffer, /** - * @brief Append the CBOR head, the major type and argument - * - * @param me Encoder context. - * @param uMajorType Major type to insert. - * @param uArgument The argument (an integer value or a length). - * @param uMinLen The minimum number of bytes for encoding the CBOR argument. - * - * This formats the CBOR "head" and appends it to the output. - */ -static void AppendCBORHead(QCBOREncodeContext *me, uint8_t uMajorType, uint64_t uArgument, uint8_t uMinLen) -{ - /* A stack buffer large enough for a CBOR head */ - UsefulBuf_MAKE_STACK_UB (pBufferForEncodedHead, QCBOR_HEAD_BUFFER_SIZE); - - UsefulBufC EncodedHead = QCBOREncode_EncodeHead(pBufferForEncodedHead, - uMajorType, - uMinLen, - uArgument); - - /* No check for EncodedHead == NULLUsefulBufC is performed here to - * save object code. It is very clear that pBufferForEncodedHead is - * the correct size. If EncodedHead == NULLUsefulBufC then - * UsefulOutBuf_AppendUsefulBuf() will do nothing so there is no - * security hole introduced. - */ - - UsefulOutBuf_AppendUsefulBuf(&(me->OutBuf), EncodedHead); -} - - -/** - * @brief Check for errors when decreasing nesting. + * @brief Increment item counter for maps and arrays. * * @param pMe QCBOR encoding context. - * @param uMajorType The major type of the nesting. - * - * Check that there is no previous error, that there is actually some - * nesting and that the major type of the opening of the nesting - * matches the major type of the nesting being closed. * - * This is called when closing maps, arrays, byte string wrapping and - * open/close of byte strings. + * This is mostly a separate function to make code more readable and + * to have fewer occurrences of #ifndef QCBOR_DISABLE_ENCODE_USAGE_GUARDS */ -bool -CheckDecreaseNesting(QCBOREncodeContext *pMe, uint8_t uMajorType) +static void +QCBOREncode_Private_IncrementMapOrArrayCount(QCBOREncodeContext *pMe) { #ifndef QCBOR_DISABLE_ENCODE_USAGE_GUARDS - if(pMe->uError != QCBOR_SUCCESS) { - return true; - } - - if(!Nesting_IsInNest(&(pMe->nesting))) { - pMe->uError = QCBOR_ERR_TOO_MANY_CLOSES; - return true; - } - - if(Nesting_GetMajorType(&(pMe->nesting)) != uMajorType) { - pMe->uError = QCBOR_ERR_CLOSE_MISMATCH; - return true; + if(pMe->uError == QCBOR_SUCCESS) { + pMe->uError = Nesting_Increment(&(pMe->nesting)); } - #else - /* None of these checks are performed if the encode guards are - * turned off as they all relate to correct calling. - * - * Turning off all these checks does not turn off any checking for - * buffer overflows or pointer issues. - */ - - (void)uMajorType; - (void)pMe; -#endif - - return false; + (void)Nesting_Increment(&(pMe->nesting)); +#endif /* ! QCBOR_DISABLE_ENCODE_USAGE_GUARDS */ } /** - * @brief Insert the CBOR head for a map, array or wrapped bstr + * @brief Append the CBOR head, the major type and argument * - * @param me QCBOR encoding context. - * @param uMajorType One of CBOR_MAJOR_TYPE_XXXX. - * @param uLen The length of the data item. + * @param pMe Encoder context. + * @param uMajorType Major type to insert. + * @param uArgument The argument (an integer value or a length). + * @param uMinLen The minimum number of bytes for encoding the CBOR argument. * - * When an array, map or bstr was opened, nothing was done but note - * the position. This function goes back to that position and inserts - * the CBOR Head with the major type and length. + * This formats the CBOR "head" and appends it to the output. + * + * This also increments the array/map item counter in most cases. */ -static void InsertCBORHead(QCBOREncodeContext *me, uint8_t uMajorType, size_t uLen) +void +QCBOREncode_Private_AppendCBORHead(QCBOREncodeContext *pMe, + const uint8_t uMajorType, + const uint64_t uArgument, + const uint8_t uMinLen) { - if(CheckDecreaseNesting(me, uMajorType)) { - return; - } - - if(uMajorType == CBOR_MAJOR_NONE_TYPE_OPEN_BSTR) { - uMajorType = CBOR_MAJOR_TYPE_BYTE_STRING; - } - - /* A stack buffer large enough for a CBOR head (9 bytes) */ - UsefulBuf_MAKE_STACK_UB(pBufferForEncodedHead, QCBOR_HEAD_BUFFER_SIZE); + /* A stack buffer large enough for a CBOR head */ + UsefulBuf_MAKE_STACK_UB (pBufferForEncodedHead, QCBOR_HEAD_BUFFER_SIZE); UsefulBufC EncodedHead = QCBOREncode_EncodeHead(pBufferForEncodedHead, - uMajorType, - 0, - uLen); + uMajorType, + uMinLen, + uArgument); /* No check for EncodedHead == NULLUsefulBufC is performed here to * save object code. It is very clear that pBufferForEncodedHead is * the correct size. If EncodedHead == NULLUsefulBufC then - * UsefulOutBuf_InsertUsefulBuf() will do nothing so there is no + * UsefulOutBuf_AppendUsefulBuf() will do nothing so there is no * security hole introduced. */ - UsefulOutBuf_InsertUsefulBuf(&(me->OutBuf), - EncodedHead, - Nesting_GetStartPos(&(me->nesting))); - - Nesting_Decrease(&(me->nesting)); -} + UsefulOutBuf_AppendUsefulBuf(&(pMe->OutBuf), EncodedHead); -/** - * @brief Increment item counter for maps and arrays. - * - * @param pMe QCBOR encoding context. - * - * This is mostly a separate function to make code more readable and - * to have fewer occurrences of #ifndef QCBOR_DISABLE_ENCODE_USAGE_GUARDS - */ -static inline void IncrementMapOrArrayCount(QCBOREncodeContext *pMe) -{ -#ifndef QCBOR_DISABLE_ENCODE_USAGE_GUARDS - if(pMe->uError == QCBOR_SUCCESS) { - pMe->uError = Nesting_Increment(&(pMe->nesting)); + if(!(uMajorType & QCBOR_INDEFINITE_LEN_TYPE_MODIFIER || uMajorType == CBOR_MAJOR_TYPE_TAG)) { + /* Don't increment the map count for tag or break because that is + * not needed. Don't do it for indefinite-length arrays and maps + * because it is done elsewhere. This is never called for definite-length + * arrays and maps. + */ + QCBOREncode_Private_IncrementMapOrArrayCount(pMe); } -#else - (void)Nesting_Increment(&(pMe->nesting)); -#endif /* QCBOR_DISABLE_ENCODE_USAGE_GUARDS */ -} - - -/* - * Public functions for adding unsigned integers. See qcbor/qcbor_encode.h - */ -void QCBOREncode_AddUInt64(QCBOREncodeContext *me, uint64_t uValue) -{ - AppendCBORHead(me, CBOR_MAJOR_TYPE_POSITIVE_INT, uValue, 0); - - IncrementMapOrArrayCount(me); } /* - * Public functions for adding signed integers. See qcbor/qcbor_encode.h + * Public function for adding signed integers. See qcbor/qcbor_encode.h */ -void QCBOREncode_AddInt64(QCBOREncodeContext *me, int64_t nNum) +void +QCBOREncode_AddInt64(QCBOREncodeContext *pMe, const int64_t nNum) { uint8_t uMajorType; uint64_t uValue; @@ -670,158 +591,119 @@ void QCBOREncode_AddInt64(QCBOREncodeContext *me, int64_t nNum) uValue = (uint64_t)nNum; uMajorType = CBOR_MAJOR_TYPE_POSITIVE_INT; } - AppendCBORHead(me, uMajorType, uValue, 0); - - IncrementMapOrArrayCount(me); + QCBOREncode_Private_AppendCBORHead(pMe, uMajorType, uValue, 0); } -/* - * Semi-private function. It is exposed to user of the interface, but - * one of its inline wrappers will usually be called instead of this. - * - * See qcbor/qcbor_encode.h +/** + * @brief Semi-private method to add a buffer full of bytes to encoded output. * - * This does the work of adding actual strings bytes to the CBOR - * output (as opposed to adding numbers and opening / closing - * aggregate types). - - * There are four use cases: - * CBOR_MAJOR_TYPE_BYTE_STRING -- Byte strings - * CBOR_MAJOR_TYPE_TEXT_STRING -- Text strings - * CBOR_MAJOR_NONE_TYPE_RAW -- Already-encoded CBOR - * CBOR_MAJOR_NONE_TYPE_BSTR_LEN_ONLY -- Special case + * @param[in] pMe The encoding context to add the string to. + * @param[in] uMajorType The CBOR major type of the bytes. + * @param[in] Bytes The bytes to add. * - * The first two add the head plus the actual bytes. The third just - * adds the bytes as the heas is presumed to be in the bytes. The - * fourth just adds the head for the very special case of - * QCBOREncode_AddBytesLenOnly(). - */ -void QCBOREncode_AddBuffer(QCBOREncodeContext *me, uint8_t uMajorType, UsefulBufC Bytes) -{ - /* If it is not Raw CBOR, add the type and the length */ - if(uMajorType != CBOR_MAJOR_NONE_TYPE_RAW) { - uint8_t uRealMajorType = uMajorType; - if(uRealMajorType == CBOR_MAJOR_NONE_TYPE_BSTR_LEN_ONLY) { - uRealMajorType = CBOR_MAJOR_TYPE_BYTE_STRING; - } - AppendCBORHead(me, uRealMajorType, Bytes.len, 0); - } - - if(uMajorType != CBOR_MAJOR_NONE_TYPE_BSTR_LEN_ONLY) { - /* Actually add the bytes */ - UsefulOutBuf_AppendUsefulBuf(&(me->OutBuf), Bytes); - } - - IncrementMapOrArrayCount(me); -} - - -/* - * Public functions for adding a tag. See qcbor/qcbor_encode.h - */ -void QCBOREncode_AddTag(QCBOREncodeContext *me, uint64_t uTag) -{ - AppendCBORHead(me, CBOR_MAJOR_TYPE_TAG, uTag, 0); -} - - -/* - * Semi-private function. It is exposed to user of the interface, but - * one of its inline wrappers will usually be called instead of this. + * Called by inline functions to add text and byte strings. * - * See header qcbor/qcbor_encode.h + * (This used to support QCBOREncode_AddEncoded() and + * QCBOREncode_AddBytesLenOnly(), but that was pulled out to make this + * smaller. This is one of the most used methods and they are some of + * the least used). */ -void QCBOREncode_AddType7(QCBOREncodeContext *me, uint8_t uMinLen, uint64_t uNum) +void +QCBOREncode_Private_AddBuffer(QCBOREncodeContext *pMe, + const uint8_t uMajorType, + const UsefulBufC Bytes) { -#ifndef QCBOR_DISABLE_ENCODE_USAGE_GUARDS - if(me->uError == QCBOR_SUCCESS) { - if(uNum >= CBOR_SIMPLEV_RESERVED_START && uNum <= CBOR_SIMPLEV_RESERVED_END) { - me->uError = QCBOR_ERR_ENCODE_UNSUPPORTED; - return; - } - } -#endif /* QCBOR_DISABLE_ENCODE_USAGE_GUARDS */ - - /* AppendCBORHead() does endian swapping for the float / double */ - AppendCBORHead(me, CBOR_MAJOR_TYPE_SIMPLE, uNum, uMinLen); - - IncrementMapOrArrayCount(me); + QCBOREncode_Private_AppendCBORHead(pMe, uMajorType, Bytes.len, 0); + UsefulOutBuf_AppendUsefulBuf(&(pMe->OutBuf), Bytes); } -#ifndef USEFULBUF_DISABLE_ALL_FLOAT /* - * Public functions for adding a double. See qcbor/qcbor_encode.h + * Public function for adding raw encoded CBOR. See qcbor/qcbor_encode.h */ -void QCBOREncode_AddDoubleNoPreferred(QCBOREncodeContext *me, double dNum) +void +QCBOREncode_AddEncoded(QCBOREncodeContext *pMe, const UsefulBufC Encoded) { - QCBOREncode_AddType7(me, - sizeof(uint64_t), - UsefulBufUtil_CopyDoubleToUint64(dNum)); + UsefulOutBuf_AppendUsefulBuf(&(pMe->OutBuf), Encoded); + QCBOREncode_Private_IncrementMapOrArrayCount(pMe); } -/* - * Public functions for adding a double. See qcbor/qcbor_encode.h - */ -void QCBOREncode_AddDouble(QCBOREncodeContext *me, double dNum) -{ #ifndef QCBOR_DISABLE_PREFERRED_FLOAT - const IEEE754_union uNum = IEEE754_DoubleToSmallest(dNum); - - QCBOREncode_AddType7(me, uNum.uSize, uNum.uValue); -#else /* QCBOR_DISABLE_PREFERRED_FLOAT */ - QCBOREncode_AddDoubleNoPreferred(me, dNum); -#endif /* QCBOR_DISABLE_PREFERRED_FLOAT */ -} - - -/* - * Public functions for adding a float. See qcbor/qcbor_encode.h +/** + * @brief Semi-private method to add a double using preferred encoding. + * + * @param[in] pMe The encode context. + * @param[in] dNum The double to add. + * + * This converts the double to a float or half-precision if it can be done + * without a loss of precision. See QCBOREncode_AddDouble(). */ -void QCBOREncode_AddFloatNoPreferred(QCBOREncodeContext *me, float fNum) +void +QCBOREncode_Private_AddPreferredDouble(QCBOREncodeContext *pMe, const double dNum) { - QCBOREncode_AddType7(me, - sizeof(uint32_t), - UsefulBufUtil_CopyFloatToUint32(fNum)); + const IEEE754_union uNum = IEEE754_DoubleToSmaller(dNum, true); + QCBOREncode_Private_AddType7(pMe, (uint8_t)uNum.uSize, uNum.uValue); } -/* - * Public functions for adding a float. See qcbor/qcbor_encode.h +/** + * @brief Semi-private method to add a float using preferred encoding. + * + * @param[in] pMe The encode context. + * @param[in] fNum The float to add. + * + * This converts the float to a half-precision if it can be done + * without a loss of precision. See QCBOREncode_AddFloat(). */ -void QCBOREncode_AddFloat(QCBOREncodeContext *me, float fNum) +void +QCBOREncode_Private_AddPreferredFloat(QCBOREncodeContext *pMe, const float fNum) { -#ifndef QCBOR_DISABLE_PREFERRED_FLOAT - const IEEE754_union uNum = IEEE754_FloatToSmallest(fNum); - - QCBOREncode_AddType7(me, uNum.uSize, uNum.uValue); -#else /* QCBOR_DISABLE_PREFERRED_FLOAT */ - QCBOREncode_AddFloatNoPreferred(me, fNum); -#endif /* QCBOR_DISABLE_PREFERRED_FLOAT */ + const IEEE754_union uNum = IEEE754_SingleToHalf(fNum); + QCBOREncode_Private_AddType7(pMe, (uint8_t)uNum.uSize, uNum.uValue); } -#endif /* USEFULBUF_DISABLE_ALL_FLOAT */ +#endif /* ! QCBOR_DISABLE_PREFERRED_FLOAT */ #ifndef QCBOR_DISABLE_EXP_AND_MANTISSA -/* - * Semi-public function. It is exposed to the user of the interface, - * but one of the inline wrappers will usually be called rather than - * this. +/** + * @brief Semi-private method to add bigfloats and decimal fractions. + * + * @param[in] pMe The encoding context to add the value to. + * @param[in] uTag The type 6 tag indicating what this is to be. + * @param[in] BigNumMantissa Is @ref NULLUsefulBufC if mantissa is an + * @c int64_t or the actual big number mantissa + * if not. + * @param[in] bBigNumIsNegative This is @c true if the big number is negative. + * @param[in] nMantissa The @c int64_t mantissa if it is not a big number. + * @param[in] nExponent The exponent. + * + * This outputs either the @ref CBOR_TAG_DECIMAL_FRACTION or + * @ref CBOR_TAG_BIGFLOAT tag. if @c uTag is @ref CBOR_TAG_INVALID64, + * then this outputs the "borrowed" content format. + * + * The tag content output by this is an array with two members, the + * exponent and then the mantissa. The mantissa can be either a big + * number or an @c int64_t. * - * See qcbor/qcbor_encode.h + * This implementation cannot output an exponent further from 0 than + * @c INT64_MAX. * - * Improvement: create another version of this that only takes a big - * number mantissa and converts the output to a type 0 or 1 integer - * when mantissa is small enough. + * To output a mantissa that is between INT64_MAX and UINT64_MAX from 0, + * it must be as a big number. + * + * Typically, QCBOREncode_AddTDecimalFraction(), QCBOREncode_AddTBigFloat(), + * QCBOREncode_AddTDecimalFractionBigNum() or QCBOREncode_AddTBigFloatBigNum() + * is called instead of this. */ -void QCBOREncode_AddExponentAndMantissa(QCBOREncodeContext *pMe, - uint64_t uTag, - UsefulBufC BigNumMantissa, - bool bBigNumIsNegative, - int64_t nMantissa, - int64_t nExponent) +void +QCBOREncode_Private_AddExpMantissa(QCBOREncodeContext *pMe, + const uint64_t uTag, + const UsefulBufC BigNumMantissa, + const bool bBigNumIsNegative, + const int64_t nMantissa, + const int64_t nExponent) { /* This is for encoding either a big float or a decimal fraction, * both of which are an array of two items, an exponent and a @@ -836,29 +718,33 @@ void QCBOREncode_AddExponentAndMantissa(QCBOREncodeContext *pMe, QCBOREncode_AddInt64(pMe, nExponent); if(!UsefulBuf_IsNULLC(BigNumMantissa)) { if(bBigNumIsNegative) { - QCBOREncode_AddNegativeBignum(pMe, BigNumMantissa); + QCBOREncode_AddTNegativeBignum(pMe, QCBOR_ENCODE_AS_TAG, BigNumMantissa); } else { - QCBOREncode_AddPositiveBignum(pMe, BigNumMantissa); + QCBOREncode_AddTPositiveBignum(pMe, QCBOR_ENCODE_AS_TAG, BigNumMantissa); } } else { QCBOREncode_AddInt64(pMe, nMantissa); } QCBOREncode_CloseArray(pMe); } -#endif /* QCBOR_DISABLE_EXP_AND_MANTISSA */ +#endif /* ! QCBOR_DISABLE_EXP_AND_MANTISSA */ -/* - * Semi-public function. It is exposed to the user of the interface, - * but one of the inline wrappers will usually be called rather than - * this. +/** + * @brief Semi-private method to open a map, array or bstr-wrapped CBOR + * + * @param[in] pMe The context to add to. + * @param[in] uMajorType The major CBOR type to close * - * See qcbor/qcbor_encode.h + * Call QCBOREncode_OpenArray(), QCBOREncode_OpenMap() or + * QCBOREncode_BstrWrap() instead of this. */ -void QCBOREncode_OpenMapOrArray(QCBOREncodeContext *me, uint8_t uMajorType) +void +QCBOREncode_Private_OpenMapOrArray(QCBOREncodeContext *pMe, + const uint8_t uMajorType) { /* Add one item to the nesting level we are in for the new map or array */ - IncrementMapOrArrayCount(me); + QCBOREncode_Private_IncrementMapOrArrayCount(pMe); /* The offset where the length of an array or map will get written * is stored in a uint32_t, not a size_t to keep stack usage @@ -868,7 +754,7 @@ void QCBOREncode_OpenMapOrArray(QCBOREncodeContext *me, uint8_t uMajorType) * past the 4GB mark, but the public interface says that the * maximum is 4GB to keep the discussion simpler. */ - size_t uEndPosition = UsefulOutBuf_GetEndPosition(&(me->OutBuf)); + size_t uEndPosition = UsefulOutBuf_GetEndPosition(&(pMe->OutBuf)); /* QCBOR_MAX_ARRAY_OFFSET is slightly less than UINT32_MAX so this * code can run on a 32-bit machine and tests can pass on a 32-bit @@ -877,53 +763,163 @@ void QCBOREncode_OpenMapOrArray(QCBOREncodeContext *me, uint8_t uMajorType) * size detection would be needed reducing portability. */ if(uEndPosition >= QCBOR_MAX_ARRAY_OFFSET) { - me->uError = QCBOR_ERR_BUFFER_TOO_LARGE; + pMe->uError = QCBOR_ERR_BUFFER_TOO_LARGE; } else { /* Increase nesting level because this is a map or array. Cast * from size_t to uin32_t is safe because of check above. */ - me->uError = Nesting_Increase(&(me->nesting), uMajorType, (uint32_t)uEndPosition); + pMe->uError = Nesting_Increase(&(pMe->nesting), uMajorType, (uint32_t)uEndPosition); } } -/* - * Semi-public function. It is exposed to the user of the interface, - * but one of the inline wrappers will usually be called rather than - * this. +#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS +/** + * @brief Semi-private method to open a map, array with indefinite length + * + * @param[in] pMe The context to add to. + * @param[in] uMajorType The major CBOR type to close * - * See qcbor/qcbor_encode.h + * Call QCBOREncode_OpenArrayIndefiniteLength() or + * QCBOREncode_OpenMapIndefiniteLength() instead of this. */ -void QCBOREncode_OpenMapOrArrayIndefiniteLength(QCBOREncodeContext *me, uint8_t uMajorType) +void +QCBOREncode_Private_OpenMapOrArrayIndefiniteLength(QCBOREncodeContext *pMe, + const uint8_t uMajorType) { /* Insert the indefinite length marker (0x9f for arrays, 0xbf for maps) */ - AppendCBORHead(me, uMajorType, 0, 0); + QCBOREncode_Private_AppendCBORHead(pMe, uMajorType, 0, 0); /* Call the definite-length opener just to do the bookkeeping for * nesting. It will record the position of the opening item in the * encoded output but this is not used when closing this open. */ - QCBOREncode_OpenMapOrArray(me, uMajorType); + QCBOREncode_Private_OpenMapOrArray(pMe, uMajorType); } +#endif /* ! QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS */ -/* - * Public functions for closing arrays and maps. See qcbor/qcbor_encode.h +/** + * @brief Check for errors when decreasing nesting. + * + * @param pMe QCBOR encoding context. + * @param uMajorType The major type of the nesting. + * + * Check that there is no previous error, that there is actually some + * nesting and that the major type of the opening of the nesting + * matches the major type of the nesting being closed. + * + * This is called when closing maps, arrays, byte string wrapping and + * open/close of byte strings. */ -void QCBOREncode_CloseMapOrArray(QCBOREncodeContext *me, uint8_t uMajorType) +static bool +QCBOREncode_Private_CheckDecreaseNesting(QCBOREncodeContext *pMe, + const uint8_t uMajorType) { - InsertCBORHead(me, uMajorType, Nesting_GetCount(&(me->nesting))); +#ifndef QCBOR_DISABLE_ENCODE_USAGE_GUARDS + if(pMe->uError != QCBOR_SUCCESS) { + return true; + } + + if(!Nesting_IsInNest(&(pMe->nesting))) { + pMe->uError = QCBOR_ERR_TOO_MANY_CLOSES; + return true; + } + + if(Nesting_GetMajorType(&(pMe->nesting)) != uMajorType) { + pMe->uError = QCBOR_ERR_CLOSE_MISMATCH; + return true; + } + +#else /* ! QCBOR_DISABLE_ENCODE_USAGE_GUARDS */ + /* None of these checks are performed if the encode guards are + * turned off as they all relate to correct calling. + * + * Turning off all these checks does not turn off any checking for + * buffer overflows or pointer issues. + */ + + (void)uMajorType; + (void)pMe; +#endif /* ! QCBOR_DISABLE_ENCODE_USAGE_GUARDS */ + + return false; +} + + +/** + * @brief Insert the CBOR head for a map, array or wrapped bstr. + * + * @param pMe QCBOR encoding context. + * @param uMajorType One of CBOR_MAJOR_TYPE_XXXX. + * @param uLen The length of the data item. + * + * When an array, map or bstr was opened, nothing was done but note + * the position. This function goes back to that position and inserts + * the CBOR Head with the major type and length. + */ +static void +QCBOREncode_Private_CloseAggregate(QCBOREncodeContext *pMe, + uint8_t uMajorType, + size_t uLen) +{ + if(QCBOREncode_Private_CheckDecreaseNesting(pMe, uMajorType)) { + return; + } + + if(uMajorType == CBOR_MAJOR_NONE_TYPE_OPEN_BSTR) { + uMajorType = CBOR_MAJOR_TYPE_BYTE_STRING; + } + + /* A stack buffer large enough for a CBOR head (9 bytes) */ + UsefulBuf_MAKE_STACK_UB(pBufferForEncodedHead, QCBOR_HEAD_BUFFER_SIZE); + + UsefulBufC EncodedHead = QCBOREncode_EncodeHead(pBufferForEncodedHead, + uMajorType, + 0, + uLen); + + /* No check for EncodedHead == NULLUsefulBufC is performed here to + * save object code. It is very clear that pBufferForEncodedHead is + * the correct size. If EncodedHead == NULLUsefulBufC then + * UsefulOutBuf_InsertUsefulBuf() will do nothing so there is no + * security hole introduced. + */ + UsefulOutBuf_InsertUsefulBuf(&(pMe->OutBuf), + EncodedHead, + Nesting_GetStartPos(&(pMe->nesting))); + + Nesting_Decrease(&(pMe->nesting)); +} + + +/** + * @brief Semi-private method to close a map, array or bstr wrapped CBOR + * + * @param[in] pMe The context to add to. + * @param[in] uMajorType The major CBOR type to close. + * + * Call QCBOREncode_CloseArray() or QCBOREncode_CloseMap() instead of this. + */ +void +QCBOREncode_Private_CloseMapOrArray(QCBOREncodeContext *pMe, + const uint8_t uMajorType) +{ + QCBOREncode_Private_CloseAggregate(pMe, uMajorType, Nesting_GetCount(&(pMe->nesting))); } /* - * Public functions for closing bstr wrapping. See qcbor/qcbor_encode.h + * Public function for closing bstr wrapping. See qcbor/qcbor_encode.h */ -void QCBOREncode_CloseBstrWrap2(QCBOREncodeContext *me, bool bIncludeCBORHead, UsefulBufC *pWrappedCBOR) +void +QCBOREncode_CloseBstrWrap2(QCBOREncodeContext *pMe, + const bool bIncludeCBORHead, + UsefulBufC *pWrappedCBOR) { - const size_t uInsertPosition = Nesting_GetStartPos(&(me->nesting)); - const size_t uEndPosition = UsefulOutBuf_GetEndPosition(&(me->OutBuf)); + const size_t uInsertPosition = Nesting_GetStartPos(&(pMe->nesting)); + const size_t uEndPosition = UsefulOutBuf_GetEndPosition(&(pMe->OutBuf)); /* This subtraction can't go negative because the UsefulOutBuf * always only grows and never shrinks. UsefulOutBut itself also @@ -933,7 +929,7 @@ void QCBOREncode_CloseBstrWrap2(QCBOREncodeContext *me, bool bIncludeCBORHead, U const size_t uBstrLen = uEndPosition - uInsertPosition; /* Actually insert */ - InsertCBORHead(me, CBOR_MAJOR_TYPE_BYTE_STRING, uBstrLen); + QCBOREncode_Private_CloseAggregate(pMe, CBOR_MAJOR_TYPE_BYTE_STRING, uBstrLen); if(pWrappedCBOR) { /* Return pointer and length to the enclosed encoded CBOR. The @@ -946,10 +942,10 @@ void QCBOREncode_CloseBstrWrap2(QCBOREncodeContext *me, bool bIncludeCBORHead, U size_t uStartOfNew = uInsertPosition; if(!bIncludeCBORHead) { /* Skip over the CBOR head to just get the inserted bstr */ - const size_t uNewEndPosition = UsefulOutBuf_GetEndPosition(&(me->OutBuf)); + const size_t uNewEndPosition = UsefulOutBuf_GetEndPosition(&(pMe->OutBuf)); uStartOfNew += uNewEndPosition - uEndPosition; } - const UsefulBufC PartialResult = UsefulOutBuf_OutUBuf(&(me->OutBuf)); + const UsefulBufC PartialResult = UsefulOutBuf_OutUBuf(&(pMe->OutBuf)); *pWrappedCBOR = UsefulBuf_Tail(PartialResult, uStartOfNew); } } @@ -958,9 +954,10 @@ void QCBOREncode_CloseBstrWrap2(QCBOREncodeContext *me, bool bIncludeCBORHead, U /* * Public function for canceling a bstr wrap. See qcbor/qcbor_encode.h */ -void QCBOREncode_CancelBstrWrap(QCBOREncodeContext *pMe) +void +QCBOREncode_CancelBstrWrap(QCBOREncodeContext *pMe) { - if(CheckDecreaseNesting(pMe, CBOR_MAJOR_TYPE_BYTE_STRING)) { + if(QCBOREncode_Private_CheckDecreaseNesting(pMe, CBOR_MAJOR_TYPE_BYTE_STRING)) { return; } @@ -971,14 +968,14 @@ void QCBOREncode_CancelBstrWrap(QCBOREncodeContext *pMe) return; } /* QCBOREncode_CancelBstrWrap() can't correctly undo - * QCBOREncode_BstrWrapInMap() or QCBOREncode_BstrWrapInMapN(). It + * QCBOREncode_BstrWrapInMapSZ() or QCBOREncode_BstrWrapInMapN(). It * can't undo the labels they add. It also doesn't catch the error * of using it this way. QCBOREncode_CancelBstrWrap() is used * infrequently and the the result is incorrect CBOR, not a * security hole, so no extra code or state is added to handle this * condition. */ -#endif /* QCBOR_DISABLE_ENCODE_USAGE_GUARDS */ +#endif /* ! QCBOR_DISABLE_ENCODE_USAGE_GUARDS */ Nesting_Decrease(&(pMe->nesting)); Nesting_Decrement(&(pMe->nesting)); @@ -988,26 +985,29 @@ void QCBOREncode_CancelBstrWrap(QCBOREncodeContext *pMe) /* * Public function for opening a byte string. See qcbor/qcbor_encode.h */ -void QCBOREncode_OpenBytes(QCBOREncodeContext *pMe, UsefulBuf *pPlace) +void +QCBOREncode_OpenBytes(QCBOREncodeContext *pMe, UsefulBuf *pPlace) { *pPlace = UsefulOutBuf_GetOutPlace(&(pMe->OutBuf)); #ifndef QCBOR_DISABLE_ENCODE_USAGE_GUARDS - // TODO: is this right? uint8_t uMajorType = Nesting_GetMajorType(&(pMe->nesting)); if(uMajorType == CBOR_MAJOR_NONE_TYPE_OPEN_BSTR) { + /* It's OK to nest a byte string in any type but + * another open byte string. */ pMe->uError = QCBOR_ERR_OPEN_BYTE_STRING; return; } -#endif /* QCBOR_DISABLE_ENCODE_USAGE_GUARDS */ +#endif /* ! QCBOR_DISABLE_ENCODE_USAGE_GUARDS */ - QCBOREncode_OpenMapOrArray(pMe, CBOR_MAJOR_NONE_TYPE_OPEN_BSTR); + QCBOREncode_Private_OpenMapOrArray(pMe, CBOR_MAJOR_NONE_TYPE_OPEN_BSTR); } /* * Public function for closing a byte string. See qcbor/qcbor_encode.h */ -void QCBOREncode_CloseBytes(QCBOREncodeContext *pMe, const size_t uAmount) +void +QCBOREncode_CloseBytes(QCBOREncodeContext *pMe, const size_t uAmount) { UsefulOutBuf_Advance(&(pMe->OutBuf), uAmount); if(UsefulOutBuf_GetError(&(pMe->OutBuf))) { @@ -1015,58 +1015,68 @@ void QCBOREncode_CloseBytes(QCBOREncodeContext *pMe, const size_t uAmount) return; } - InsertCBORHead(pMe, CBOR_MAJOR_NONE_TYPE_OPEN_BSTR, uAmount); + QCBOREncode_Private_CloseAggregate(pMe, CBOR_MAJOR_NONE_TYPE_OPEN_BSTR, uAmount); } -/* - * Public function for closing arrays and maps. See qcbor/qcbor_encode.h +#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS +/** + * @brief Semi-private method to close a map, array with indefinite length + * + * @param[in] pMe The context to add to. + * @param[in] uMajorType The major CBOR type to close. + * + * Call QCBOREncode_CloseArrayIndefiniteLength() or + * QCBOREncode_CloseMapIndefiniteLength() instead of this. */ -void QCBOREncode_CloseMapOrArrayIndefiniteLength(QCBOREncodeContext *pMe, uint8_t uMajorType) +void +QCBOREncode_Private_CloseMapOrArrayIndefiniteLength(QCBOREncodeContext *pMe, + const uint8_t uMajorType) { - if(CheckDecreaseNesting(pMe, uMajorType)) { + if(QCBOREncode_Private_CheckDecreaseNesting(pMe, uMajorType)) { return; } /* Append the break marker (0xff for both arrays and maps) */ - AppendCBORHead(pMe, CBOR_MAJOR_NONE_TYPE_SIMPLE_BREAK, CBOR_SIMPLE_BREAK, 0); + QCBOREncode_Private_AppendCBORHead(pMe, CBOR_MAJOR_NONE_TYPE_SIMPLE_BREAK, CBOR_SIMPLE_BREAK, 0); Nesting_Decrease(&(pMe->nesting)); } +#endif /* ! QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS */ /* * Public function to finish and get the encoded result. See qcbor/qcbor_encode.h */ -QCBORError QCBOREncode_Finish(QCBOREncodeContext *me, UsefulBufC *pEncodedCBOR) +QCBORError +QCBOREncode_Finish(QCBOREncodeContext *pMe, UsefulBufC *pEncodedCBOR) { - QCBORError uReturn = QCBOREncode_GetErrorState(me); - - if(uReturn != QCBOR_SUCCESS) { + if(QCBOREncode_GetErrorState(pMe) != QCBOR_SUCCESS) { goto Done; } #ifndef QCBOR_DISABLE_ENCODE_USAGE_GUARDS - if(Nesting_IsInNest(&(me->nesting))) { - uReturn = QCBOR_ERR_ARRAY_OR_MAP_STILL_OPEN; + if(Nesting_IsInNest(&(pMe->nesting))) { + pMe->uError = QCBOR_ERR_ARRAY_OR_MAP_STILL_OPEN; goto Done; } -#endif /* QCBOR_DISABLE_ENCODE_USAGE_GUARDS */ +#endif /* ! QCBOR_DISABLE_ENCODE_USAGE_GUARDS */ - *pEncodedCBOR = UsefulOutBuf_OutUBuf(&(me->OutBuf)); + *pEncodedCBOR = UsefulOutBuf_OutUBuf(&(pMe->OutBuf)); Done: - return uReturn; + return pMe->uError; } /* - * Public functions to get size of the encoded result. See qcbor/qcbor_encode.h + * Public function to get size of the encoded result. See qcbor/qcbor_encode.h */ -QCBORError QCBOREncode_FinishGetSize(QCBOREncodeContext *me, size_t *puEncodedLen) +QCBORError +QCBOREncode_FinishGetSize(QCBOREncodeContext *pMe, size_t *puEncodedLen) { UsefulBufC Enc; - QCBORError nReturn = QCBOREncode_Finish(me, &Enc); + QCBORError nReturn = QCBOREncode_Finish(pMe, &Enc); if(nReturn == QCBOR_SUCCESS) { *puEncodedLen = Enc.len; @@ -1074,3 +1084,28 @@ QCBORError QCBOREncode_FinishGetSize(QCBOREncodeContext *me, size_t *puEncodedLe return nReturn; } + + +/* + * Public function to get substring of encoded-so-far. See qcbor/qcbor_encode.h + */ +UsefulBufC +QCBOREncode_SubString(QCBOREncodeContext *pMe, const size_t uStart) +{ + if(pMe->uError) { + return NULLUsefulBufC; + } + + /* An attempt was made to detect usage errors by comparing uStart + * to offsets of open arrays and maps in pMe->nesting, but it is + * not possible because there's not enough information in just + * the offset. It's not possible to known if Tell() was called before + * or after an Open(). To detect this error, the nesting level + * would also need to be known. This is not frequently used, so + * it is not worth adding this complexity. + */ + + const size_t uEnd = QCBOREncode_Tell(pMe); + + return UsefulOutBuf_SubString(&(pMe->OutBuf), uStart, uEnd - uStart); +} diff --git a/3rdparty/exported/QCBOR/src/qcbor_err_to_str.c b/3rdparty/exported/QCBOR/src/qcbor_err_to_str.c index 4879f91d5b60..f9588e5c01a3 100644 --- a/3rdparty/exported/QCBOR/src/qcbor_err_to_str.c +++ b/3rdparty/exported/QCBOR/src/qcbor_err_to_str.c @@ -1,69 +1,92 @@ -/*============================================================================== - err_to_str.c -- strings names for errors +/* ========================================================================== + * err_to_str.c -- strings names for errors + * + * Copyright (c) 2020, Patrick Uiterwijk. All rights reserved. + * Copyright (c) 2020,2024, Laurence Lundblade. + * Copyright (c) 2021, Arm Limited. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + * + * See BSD-3-Clause license in file named "LICENSE" + * + * Created on 3/21/20 + * ========================================================================== */ - Copyright (c) 2020, Patrick Uiterwijk. All rights reserved. - Copyright (c) 2020, Laurence Lundblade. - Copyright (c) 2021, Arm Limited. All rights reserved. - - SPDX-License-Identifier: BSD-3-Clause - - See BSD-3-Clause license in README.md +#include "qcbor/qcbor_common.h" +#include - Created on 3/21/20 - =============================================================================*/ +#define ERR_TO_STR_CASE(errpart) case errpart: return #errpart; -#include "qcbor/qcbor_common.h" -#define _ERR_TO_STR(errpart) case QCBOR_##errpart: return "QCBOR_" #errpart; +const char * +qcbor_err_to_str(const QCBORError uErr) { + switch (uErr) { + ERR_TO_STR_CASE(QCBOR_SUCCESS) + ERR_TO_STR_CASE(QCBOR_ERR_BUFFER_TOO_SMALL) + ERR_TO_STR_CASE(QCBOR_ERR_ENCODE_UNSUPPORTED) + ERR_TO_STR_CASE(QCBOR_ERR_BUFFER_TOO_LARGE) + ERR_TO_STR_CASE(QCBOR_ERR_ARRAY_NESTING_TOO_DEEP) + ERR_TO_STR_CASE(QCBOR_ERR_CLOSE_MISMATCH) + ERR_TO_STR_CASE(QCBOR_ERR_ARRAY_TOO_LONG) + ERR_TO_STR_CASE(QCBOR_ERR_TOO_MANY_CLOSES) + ERR_TO_STR_CASE(QCBOR_ERR_ARRAY_OR_MAP_STILL_OPEN) + ERR_TO_STR_CASE(QCBOR_ERR_OPEN_BYTE_STRING) + ERR_TO_STR_CASE(QCBOR_ERR_CANNOT_CANCEL) + ERR_TO_STR_CASE(QCBOR_ERR_BAD_TYPE_7) + ERR_TO_STR_CASE(QCBOR_ERR_EXTRA_BYTES) + ERR_TO_STR_CASE(QCBOR_ERR_UNSUPPORTED) + ERR_TO_STR_CASE(QCBOR_ERR_ARRAY_OR_MAP_UNCONSUMED) + ERR_TO_STR_CASE(QCBOR_ERR_BAD_INT) + ERR_TO_STR_CASE(QCBOR_ERR_INDEFINITE_STRING_CHUNK) + ERR_TO_STR_CASE(QCBOR_ERR_HIT_END) + ERR_TO_STR_CASE(QCBOR_ERR_BAD_BREAK) + ERR_TO_STR_CASE(QCBOR_ERR_INPUT_TOO_LARGE) + ERR_TO_STR_CASE(QCBOR_ERR_ARRAY_DECODE_NESTING_TOO_DEEP) + ERR_TO_STR_CASE(QCBOR_ERR_ARRAY_DECODE_TOO_LONG) + ERR_TO_STR_CASE(QCBOR_ERR_STRING_TOO_LONG) + ERR_TO_STR_CASE(QCBOR_ERR_BAD_EXP_AND_MANTISSA) + ERR_TO_STR_CASE(QCBOR_ERR_NO_STRING_ALLOCATOR) + ERR_TO_STR_CASE(QCBOR_ERR_STRING_ALLOCATE) + ERR_TO_STR_CASE(QCBOR_ERR_MAP_LABEL_TYPE) + ERR_TO_STR_CASE(QCBOR_ERR_UNRECOVERABLE_TAG_CONTENT) + ERR_TO_STR_CASE(QCBOR_ERR_INDEF_LEN_STRINGS_DISABLED) + ERR_TO_STR_CASE(QCBOR_ERR_INDEF_LEN_ARRAYS_DISABLED) + ERR_TO_STR_CASE(QCBOR_ERR_TAGS_DISABLED) + ERR_TO_STR_CASE(QCBOR_ERR_TOO_MANY_TAGS) + ERR_TO_STR_CASE(QCBOR_ERR_UNEXPECTED_TYPE) + ERR_TO_STR_CASE(QCBOR_ERR_DUPLICATE_LABEL) + ERR_TO_STR_CASE(QCBOR_ERR_MEM_POOL_SIZE) + ERR_TO_STR_CASE(QCBOR_ERR_INT_OVERFLOW) + ERR_TO_STR_CASE(QCBOR_ERR_DATE_OVERFLOW) + ERR_TO_STR_CASE(QCBOR_ERR_EXIT_MISMATCH) + ERR_TO_STR_CASE(QCBOR_ERR_NO_MORE_ITEMS) + ERR_TO_STR_CASE(QCBOR_ERR_LABEL_NOT_FOUND) + ERR_TO_STR_CASE(QCBOR_ERR_NUMBER_SIGN_CONVERSION) + ERR_TO_STR_CASE(QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW) + ERR_TO_STR_CASE(QCBOR_ERR_MAP_NOT_ENTERED) + ERR_TO_STR_CASE(QCBOR_ERR_CALLBACK_FAIL) + ERR_TO_STR_CASE(QCBOR_ERR_FLOAT_DATE_DISABLED) + ERR_TO_STR_CASE(QCBOR_ERR_HALF_PRECISION_DISABLED) + ERR_TO_STR_CASE(QCBOR_ERR_HW_FLOAT_DISABLED) + ERR_TO_STR_CASE(QCBOR_ERR_FLOAT_EXCEPTION) + ERR_TO_STR_CASE(QCBOR_ERR_ALL_FLOAT_DISABLED) + ERR_TO_STR_CASE(QCBOR_ERR_RECOVERABLE_BAD_TAG_CONTENT) + ERR_TO_STR_CASE(QCBOR_ERR_CANNOT_ENTER_ALLOCATED_STRING) -const char *qcbor_err_to_str(QCBORError err) { - switch (err) { - _ERR_TO_STR(SUCCESS) - _ERR_TO_STR(ERR_BUFFER_TOO_SMALL) - _ERR_TO_STR(ERR_ENCODE_UNSUPPORTED) - _ERR_TO_STR(ERR_BUFFER_TOO_LARGE) - _ERR_TO_STR(ERR_ARRAY_NESTING_TOO_DEEP) - _ERR_TO_STR(ERR_CLOSE_MISMATCH) - _ERR_TO_STR(ERR_ARRAY_TOO_LONG) - _ERR_TO_STR(ERR_TOO_MANY_CLOSES) - _ERR_TO_STR(ERR_ARRAY_OR_MAP_STILL_OPEN) - _ERR_TO_STR(ERR_BAD_TYPE_7) - _ERR_TO_STR(ERR_EXTRA_BYTES) - _ERR_TO_STR(ERR_UNSUPPORTED) - _ERR_TO_STR(ERR_ARRAY_OR_MAP_UNCONSUMED) - _ERR_TO_STR(ERR_BAD_INT) - _ERR_TO_STR(ERR_INDEFINITE_STRING_CHUNK) - _ERR_TO_STR(ERR_HIT_END) - _ERR_TO_STR(ERR_BAD_BREAK) - _ERR_TO_STR(ERR_INPUT_TOO_LARGE) - _ERR_TO_STR(ERR_ARRAY_DECODE_NESTING_TOO_DEEP) - _ERR_TO_STR(ERR_ARRAY_DECODE_TOO_LONG) - _ERR_TO_STR(ERR_STRING_TOO_LONG) - _ERR_TO_STR(ERR_BAD_EXP_AND_MANTISSA) - _ERR_TO_STR(ERR_NO_STRING_ALLOCATOR) - _ERR_TO_STR(ERR_STRING_ALLOCATE) - _ERR_TO_STR(ERR_TOO_MANY_TAGS) - _ERR_TO_STR(ERR_MAP_LABEL_TYPE) - _ERR_TO_STR(ERR_UNEXPECTED_TYPE) - _ERR_TO_STR(ERR_BAD_OPT_TAG) - _ERR_TO_STR(ERR_DUPLICATE_LABEL) - _ERR_TO_STR(ERR_MEM_POOL_SIZE) - _ERR_TO_STR(ERR_INT_OVERFLOW) - _ERR_TO_STR(ERR_DATE_OVERFLOW) - _ERR_TO_STR(ERR_EXIT_MISMATCH) - _ERR_TO_STR(ERR_NO_MORE_ITEMS) - _ERR_TO_STR(ERR_LABEL_NOT_FOUND) - _ERR_TO_STR(ERR_NUMBER_SIGN_CONVERSION) - _ERR_TO_STR(ERR_CONVERSION_UNDER_OVER_FLOW) - _ERR_TO_STR(ERR_MAP_NOT_ENTERED) - _ERR_TO_STR(ERR_CALLBACK_FAIL) - _ERR_TO_STR(ERR_FLOAT_DATE_DISABLED) - _ERR_TO_STR(ERR_HALF_PRECISION_DISABLED) - _ERR_TO_STR(ERR_HW_FLOAT_DISABLED) - _ERR_TO_STR(ERR_FLOAT_EXCEPTION) - _ERR_TO_STR(ERR_ALL_FLOAT_DISABLED) + default: + if(uErr >= QCBOR_ERR_FIRST_USER_DEFINED && uErr <= QCBOR_ERR_LAST_USER_DEFINED) { + /* Static buffer is not thread safe, but this is only a diagnostic */ + static char buf[20]; + strcpy(buf, "USER_DEFINED_"); + size_t uEndOffset = strlen(buf); + buf[uEndOffset] = (char)(uErr/100 + '0'); + buf[uEndOffset+1] = (char)(((uErr/10) % 10) + '0'); + buf[uEndOffset+2] = (char)((uErr % 10 )+ '0'); + buf[uEndOffset+3] = '\0'; + return buf; - default: - return "Unidentified error"; - } + } else { + return "Unidentified QCBOR error"; + } + } } diff --git a/3rdparty/exported/QCBOR/test/UsefulBuf_Tests.c b/3rdparty/exported/QCBOR/test/UsefulBuf_Tests.c index e93a011b86f6..83e9a686dba8 100644 --- a/3rdparty/exported/QCBOR/test/UsefulBuf_Tests.c +++ b/3rdparty/exported/QCBOR/test/UsefulBuf_Tests.c @@ -1,35 +1,35 @@ -/*============================================================================== - Copyright (c) 2016-2018, The Linux Foundation. - Copyright (c) 2018-2022, Laurence Lundblade. - Copyright (c) 2021, Arm Limited. - All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following - disclaimer in the documentation and/or other materials provided - with the distribution. - * Neither the name of The Linux Foundation nor the names of its - contributors, nor the name "Laurence Lundblade" may be used to - endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED -WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT -ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS -BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR -BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, -WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE -OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN -IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - =============================================================================*/ +/* ========================================================================== + * Copyright (c) 2016-2018, The Linux Foundation. + * Copyright (c) 2018-2024, Laurence Lundblade. + * Copyright (c) 2021, Arm Limited. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * * Neither the name of The Linux Foundation nor the names of its + * contributors, nor the name "Laurence Lundblade" may be used to + * endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ========================================================================= */ #include "UsefulBuf.h" @@ -127,6 +127,30 @@ const char * UOBTest_NonAdversarial(void) goto Done; } + Out = UsefulOutBuf_SubString(&UOB, 10, 8); + if(UsefulBuf_IsNULLC(Out) || + UsefulBuf_Compare(UsefulBuf_FROM_SZ_LITERAL("unbounce"), Out) || + UsefulOutBuf_GetError(&UOB)) { + szReturn = "SubString substring"; + goto Done; + } + + Out = UsefulOutBuf_SubString(&UOB, 0, Expected.len); + if(UsefulBuf_IsNULLC(Out) || + UsefulBuf_Compare(Expected, Out) || + UsefulOutBuf_GetError(&UOB)) { + szReturn = "SubString all"; + goto Done; + } + + Out = UsefulOutBuf_SubString(&UOB, Expected.len, 0); + if(UsefulBuf_IsNULLC(Out) || + UsefulBuf_Compare(UsefulBuf_FROM_SZ_LITERAL(""), Out) || + UsefulOutBuf_GetError(&UOB)) { + szReturn = "SubString empty"; + goto Done; + } + /* Now test the size calculation mode */ UsefulOutBuf_Init(&UOB, SizeCalculateUsefulBuf); @@ -146,13 +170,12 @@ const char * UOBTest_NonAdversarial(void) /* - Append test utility. - pUOB is the buffer to append too - num is the amount to append - expected is the expected return code, 0 or 1 - - returns 0 if test passed - + * Append test utility. + * pUOB is the buffer to append too + * num is the amount to append + * expected is the expected return code, 0 or 1 + * + * returns 0 if test passed */ static int AppendTest(UsefulOutBuf *pUOB, size_t num, int expected) { @@ -175,7 +198,7 @@ static int AppendTest(UsefulOutBuf *pUOB, size_t num, int expected) /* - Same as append, but takes a position param too + * Same as append, but takes a position param too */ static int InsertTest(UsefulOutBuf *pUOB, size_t num, size_t pos, int expected) { @@ -196,15 +219,14 @@ static int InsertTest(UsefulOutBuf *pUOB, size_t num, size_t pos, int expected) /* - Boundary conditions to test - - around 0 - - around the buffer size - - around MAX size_t - - - Test these for the buffer size and the cursor, the insert amount, the - append amount and the insert position - + * Boundary conditions to test + * - around 0 + * - around the buffer size + * - around MAX size_t + * + * + * Test these for the buffer size and the cursor, the insert amount, the + * append amount and the insert position */ const char *UOBTest_BoundaryConditionsTest(void) @@ -248,7 +270,7 @@ const char *UOBTest_BoundaryConditionsTest(void) return "Bad insertion point not caught"; - UsefulBuf_MAKE_STACK_UB(outBuf2,10); + UsefulBuf_MAKE_STACK_UB(outBuf2, 10); UsefulOutBuf_Init(&UOB, outBuf2); @@ -262,6 +284,29 @@ const char *UOBTest_BoundaryConditionsTest(void) return "insert with data should have failed"; } + UsefulOutBuf_Init(&UOB, outBuf2); + UsefulOutBuf_AppendString(&UOB, "abc123"); + + UsefulBufC Out = UsefulOutBuf_SubString(&UOB, 7, 1); + if(!UsefulBuf_IsNULLC(Out)) { + return "SubString start should fail off end 1"; + } + Out = UsefulOutBuf_SubString(&UOB, 5, 3); + if(!UsefulBuf_IsNULLC(Out)) { + return "SubString len should fail off end 2"; + } + Out = UsefulOutBuf_SubString(&UOB, 0, 7); + if(!UsefulBuf_IsNULLC(Out)) { + return "SubString len should fail off end 3"; + } + Out = UsefulOutBuf_SubString(&UOB, 7, 0); + if(!UsefulBuf_IsNULLC(Out)) { + return "SubString len should fail off end 4"; + } + Out = UsefulOutBuf_SubString(&UOB, 6, 1); + if(!UsefulBuf_IsNULLC(Out)) { + return "SubString len should fail off end 5"; + } UsefulOutBuf_Init(&UOB, (UsefulBuf){NULL, SIZE_MAX - 5}); UsefulOutBuf_AppendData(&UOB, "123456789", SIZE_MAX -6); @@ -280,16 +325,31 @@ const char *UOBTest_BoundaryConditionsTest(void) if(!UsefulOutBuf_GetError(&UOB)) { return "lengths near max size"; } + UsefulBufC O = UsefulOutBuf_OutUBuf(&UOB); + if(!UsefulBuf_IsNULLC(O)) { + return "OutUBuf in error should have returned NULL"; + } UsefulOutBuf_Init(&UOB, (UsefulBuf){NULL, 100}); if(!UsefulOutBuf_IsBufferNULL(&UOB)) { return "NULL check failed"; } - return NULL; -} + UsefulOutBuf_Init(&UOB, outbuf); + UOB.magic = 99; // corrupt the UOB + O = UsefulOutBuf_OutUBuf(&UOB); + if(!UsefulBuf_IsNULLC(O)) { + return "OutUBuf on corrupted should have returned NULL"; + } + MakeUsefulBufOnStack(Tmp, 20); + O = UsefulOutBuf_CopyOut(&UOB, Tmp); + if(!UsefulBuf_IsNULLC(O)) { + return "CopyOut on corrupted should have returned NULL"; + } + return NULL; +} @@ -640,6 +700,10 @@ const char *UBUtilTests(void) return "Failed to find 3"; } + if(SIZE_MAX != UsefulBuf_FindBytes(Expected, ExpectedLonger)) { + return "Failed to find 4"; + } + const uint8_t pB[] = {0x01, 0x02, 0x03}; UsefulBufC Boo = UsefulBuf_FROM_BYTE_ARRAY_LITERAL(pB); @@ -673,6 +737,22 @@ const char *UBUtilTests(void) return "Incorrect pointer offset for start"; } + if(UsefulBuf_OffsetToPointer(Boo, 0) != &pB[0]) { + return "Wrong OffsetToPointer"; + } + + if(UsefulBuf_OffsetToPointer(Boo, 3) != NULL) { + return "Didn't validate offset correctly"; + } + + if(UsefulBuf_OffsetToPointer(Boo, 2) != &pB[2]) { + return "Wrong OffsetToPointer 2"; + } + + if(UsefulBuf_OffsetToPointer(NULLUsefulBufC, 2) != NULL) { + return "Failed OffsetToPtr on NULLUsefulBufC"; + } + return NULL; } @@ -688,7 +768,7 @@ const char * UIBTest_IntegerFormat(void) #ifndef USEFULBUF_DISABLE_ALL_FLOAT const float f = (float)314.15; const double d = 2.1e10; -#endif /* USEFULBUF_DISABLE_ALL_FLOAT */ +#endif /* ! USEFULBUF_DISABLE_ALL_FLOAT */ UsefulOutBuf_AppendUint32(&UOB, u32); // Also tests UsefulOutBuf_InsertUint64 and UsefulOutBuf_GetEndPosition @@ -698,7 +778,7 @@ const char * UIBTest_IntegerFormat(void) #ifndef USEFULBUF_DISABLE_ALL_FLOAT UsefulOutBuf_AppendFloat(&UOB, f); // Also tests UsefulOutBuf_InsertFloat UsefulOutBuf_AppendDouble(&UOB, d); // Also tests UsefulOutBuf_InsertDouble -#endif /* USEFULBUF_DISABLE_ALL_FLOAT */ +#endif /* ! USEFULBUF_DISABLE_ALL_FLOAT */ const UsefulBufC O = UsefulOutBuf_OutUBuf(&UOB); if(UsefulBuf_IsNULLC(O)) @@ -739,6 +819,16 @@ const char * UIBTest_IntegerFormat(void) } #endif /* USEFULBUF_DISABLE_ALL_FLOAT */ + if(UsefulInputBuf_GetUint16(&UIB) != 0) { + return "Didn't catch off end with GetUint16"; + } + if(UsefulInputBuf_GetUint32(&UIB) !=0 ) { + return "Didn't catch off end with GetUint32"; + } + if(UsefulInputBuf_GetUint64(&UIB) !=0 ) { + return "Didn't catch off end with GetUint64"; + } + // Reset and go again for a few more tests UsefulInputBuf_Init(&UIB, O); @@ -773,7 +863,7 @@ const char * UIBTest_IntegerFormat(void) if(UsefulInputBuf_BytesAvailable(&UIB, 12)){ return "Wrong number of bytes available II"; } -#endif /* USEFULBUF_DISABLE_ALL_FLOAT */ +#endif /* ! USEFULBUF_DISABLE_ALL_FLOAT */ UsefulInputBuf_Seek(&UIB, 0); @@ -800,6 +890,51 @@ const char * UIBTest_IntegerFormat(void) return "PointerToOffset not working"; } + + const uint8_t pB[] = {0x01, 0x02, 0x03}; + UsefulBufC Boo = UsefulBuf_FROM_BYTE_ARRAY_LITERAL(pB); + + UsefulInputBuf_Init(&UIB, Boo); + + if(UsefulInputBuf_OffsetToPointer(&UIB, 0) != &pB[0]) { + return "OffsetToPointer fail"; + } + + if(UsefulInputBuf_OffsetToPointer(&UIB, SIZE_MAX) != NULL) { + return "OffsetToPointer SIZE_MAX fail"; + } + + UsefulInputBuf_Init(&UIB, Boo); + UIB.magic = 88; + size_t uUnc = UsefulInputBuf_BytesUnconsumed(&UIB); + if(uUnc != 0) { + return "Didn't detect corrupted UsefulInputBuf"; + } + + UsefulInputBuf_Init(&UIB, Boo); + UIB.cursor = 500; + uUnc = UsefulInputBuf_BytesUnconsumed(&UIB); + if(uUnc != 0) { + return "Didn't detect bad UsefulInputBuf cursor"; + } + + if(!UsefulBuf_IsNULLC(UsefulInputBuf_GetUsefulBuf(&UIB, 5000))) { + return "Didn't detect off-end request of UsefulInputBuf"; + } + + if(!UsefulInputBuf_GetError(&UIB)) { + return "UIB Error state not reported"; + } + + UsefulInputBuf_Init(&UIB, Boo); + if(UsefulInputBuf_GetBufferLength(&UIB) != Boo.len) { + return "UIB length wrong"; + } + UsefulInputBuf_SetBufferLength(&UIB, 1); + if(UsefulInputBuf_GetBufferLength(&UIB) != 1) { + return "UIB SetBufferLength failed"; + } + return NULL; } @@ -825,7 +960,7 @@ const char *UBUTest_CopyUtil(void) return NULL; } -#endif /* USEFULBUF_DISABLE_ALL_FLOAT */ +#endif /* ! USEFULBUF_DISABLE_ALL_FLOAT */ const char *UBAdvanceTest(void) @@ -871,5 +1006,33 @@ const char *UBAdvanceTest(void) return "Advance off end didn't set error"; } + // Try to advance in error state + UsefulOutBuf_Reset(&UOB); + UsefulOutBuf_Advance(&UOB, 1); + Place = UsefulOutBuf_GetOutPlace(&UOB); + UsefulOutBuf_Advance(&UOB, 1000); + UsefulOutBuf_Advance(&UOB, 1); + UsefulBuf Place2; + Place2 = UsefulOutBuf_GetOutPlace(&UOB); + if(memcmp(&Place, &Place2, sizeof(Place))) { + return "Advance didn't noop in error state"; + } + + UsefulOutBuf_Reset(&UOB); + UOB.data_len = UOB.UB.len + 1; // React in and corrupt + UsefulOutBuf_Advance(&UOB, 1); + if(!UsefulOutBuf_GetError(&UOB)) { + return "didn't detect corrupted UOB"; + } + + UsefulOutBuf BadUOB; + memset(&BadUOB, 'x', sizeof(BadUOB)); + BadUOB.err = 0; + UsefulOutBuf_Advance(&BadUOB, 1); + if(!UsefulOutBuf_GetError(&BadUOB)) { + return "didn't detect bad UOB"; + } + + return NULL; } diff --git a/3rdparty/exported/QCBOR/test/UsefulBuf_Tests.h b/3rdparty/exported/QCBOR/test/UsefulBuf_Tests.h index 235358e82c8f..828f3f422287 100644 --- a/3rdparty/exported/QCBOR/test/UsefulBuf_Tests.h +++ b/3rdparty/exported/QCBOR/test/UsefulBuf_Tests.h @@ -1,35 +1,35 @@ -/*============================================================================== - Copyright (c) 2016-2018, The Linux Foundation. - Copyright (c) 2018, Laurence Lundblade. - Copyright (c) 2021, Arm Limited. - All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following - disclaimer in the documentation and/or other materials provided - with the distribution. - * Neither the name of The Linux Foundation nor the names of its - contributors, nor the name "Laurence Lundblade" may be used to - endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED -WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT -ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS -BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR -BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, -WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE -OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN -IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - ==============================================================================*/ +/* ========================================================================== + * Copyright (c) 2016-2018, The Linux Foundation. + * Copyright (c) 2018, Laurence Lundblade. + * Copyright (c) 2021, Arm Limited. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * * Neither the name of The Linux Foundation nor the names of its + * contributors, nor the name "Laurence Lundblade" may be used to + * endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ========================================================================= */ #ifndef UsefulBuf_UsefulBuf_Tests_h #define UsefulBuf_UsefulBuf_Tests_h @@ -48,7 +48,7 @@ const char * UIBTest_IntegerFormat(void); #ifndef USEFULBUF_DISABLE_ALL_FLOAT const char * UBUTest_CopyUtil(void); -#endif /* USEFULBUF_DISABLE_ALL_FLOAT */ +#endif /* ! USEFULBUF_DISABLE_ALL_FLOAT */ const char * UBAdvanceTest(void); diff --git a/3rdparty/exported/QCBOR/test/float_tests.c b/3rdparty/exported/QCBOR/test/float_tests.c index 2bf5fad311b7..6e00472a0032 100644 --- a/3rdparty/exported/QCBOR/test/float_tests.c +++ b/3rdparty/exported/QCBOR/test/float_tests.c @@ -1,32 +1,33 @@ -/*============================================================================== - float_tests.c -- tests for float and conversion to/from half-precision - - Copyright (c) 2018-2020, Laurence Lundblade. All rights reserved. - Copyright (c) 2021, Arm Limited. All rights reserved. - - SPDX-License-Identifier: BSD-3-Clause - - See BSD-3-Clause license in README.md - - Created on 9/19/18 - =============================================================================*/ +/* ========================================================================== + * float_tests.c -- tests for float and conversion to/from half-precision + * + * Copyright (c) 2018-2024, Laurence Lundblade. All rights reserved. + * Copyright (c) 2021, Arm Limited. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + * + * See BSD-3-Clause license in file named "LICENSE" + * + * Created on 9/19/18 + * ========================================================================= */ #include "float_tests.h" #include "qcbor/qcbor_encode.h" #include "qcbor/qcbor_decode.h" #include "qcbor/qcbor_spiffy_decode.h" -#include // For INFINITY and NAN and isnan() +#include /* For INFINITY and NAN and isnan() */ -/* Make a test results code that includes three components - * Return code is - * xxxyyyzzz where zz is the error code, yy is the test number and zz is - * check being performed + +/* Make a test results code that includes three components. Return code + * is xxxyyyzzz where zz is the error code, yy is the test number and + * zz is check being performed */ -static inline int32_t MakeTestResultCode(uint32_t uTestCase, - uint32_t uTestNumber, - QCBORError uErrorCode) +static inline int32_t +MakeTestResultCode(uint32_t uTestCase, + uint32_t uTestNumber, + QCBORError uErrorCode) { uint32_t uCode = (uTestCase * 1000000) + (uTestNumber * 1000) + @@ -40,205 +41,508 @@ static inline int32_t MakeTestResultCode(uint32_t uTestCase, #include "half_to_double_from_rfc7049.h" -/* - Half-precision values that are input to test half-precision decoding - - As decoded by http://cbor.me - {"zero": 0.0, - "infinitity": Infinity, - "negative infinitity": -Infinity, - "NaN": NaN, - "one": 1.0, - "one third": 0.333251953125, - "largest half-precision": 65504.0, - "too-large half-precision": Infinity, - "smallest subnormal": 5.960464477539063e-8, - "smallest normal": 0.00006097555160522461, - "biggest subnormal": 0.00006103515625, - "subnormal single": 0.0, - 3: -2.0, - 4: NaN, - 5: NaN, - 6: NaN, - 7: NaN} - */ -static const uint8_t spExpectedHalf[] = { - 0xB1, - 0x64, - 0x7A, 0x65, 0x72, 0x6F, - 0xF9, 0x00, 0x00, // half-precision 0.000 - 0x6A, - 0x69, 0x6E, 0x66, 0x69, 0x6E, 0x69, 0x74, 0x69, 0x74, 0x79, - 0xF9, 0x7C, 0x00, // Infinity - 0x73, - 0x6E, 0x65, 0x67, 0x61, 0x74, 0x69, 0x76, 0x65, 0x20, 0x69, 0x6E, - 0x66, 0x69, 0x6E, 0x69, 0x74, 0x69, 0x74, 0x79, - 0xF9, 0xFC, 0x00, // -Inifinity - 0x63, - 0x4E, 0x61, 0x4E, - 0xF9, 0x7E, 0x00, // NaN - 0x63, - 0x6F, 0x6E, 0x65, - 0xF9, 0x3C, 0x00, // 1.0 - 0x69, - 0x6F, 0x6E, 0x65, 0x20, 0x74, 0x68, 0x69, 0x72, 0x64, - 0xF9, 0x35, 0x55, // half-precsion one third 0.333251953125 - 0x76, - 0x6C, 0x61, 0x72, 0x67, 0x65, 0x73, 0x74, 0x20, 0x68, 0x61, 0x6C, - 0x66, 0x2D, 0x70, 0x72, 0x65, 0x63, 0x69, 0x73, 0x69, 0x6F, 0x6E, - 0xF9, 0x7B, 0xFF, // largest half-precision 65504.0 - 0x78, 0x18, - 0x74, 0x6F, 0x6F, 0x2D, 0x6C, 0x61, 0x72, 0x67, 0x65, 0x20, 0x68, - 0x61, 0x6C, 0x66, 0x2D, 0x70, 0x72, 0x65, 0x63, 0x69, 0x73, 0x69, - 0x6F, 0x6E, - 0xF9, 0x7C, 0x00, // Infinity - 0x72, - 0x73, 0x6D, 0x61, 0x6C, 0x6C, 0x65, 0x73, 0x74, 0x20, 0x73, 0x75, - 0x62, 0x6E, 0x6F, 0x72, 0x6D, 0x61, 0x6C, - 0xF9, 0x00, 0x01, // Smallest half-precision subnormal 0.000000059604645 - 0x71, - 0x62, 0x69, 0x67, 0x67, 0x65, 0x73, 0x74, 0x20, 0x73, 0x75, 0x62, - 0x6E, 0x6F, 0x72, 0x6D, 0x61, 0x6C, - 0xF9, 0x03, 0xFF, // Largest half-precision subnormal 0.0000609755516 - 0x6F, - 0x73, 0x6D, 0x61, 0x6C, 0x6C, 0x65, 0x73, 0x74, 0x20, 0x6E, 0x6F, - 0x72, 0x6D, 0x61, 0x6C, - 0xF9, 0x04, 0x00, // Smallest half-precision normal 0.000061988 - 0x70, - 0x73, 0x75, 0x62, 0x6E, 0x6F, 0x72, 0x6D, 0x61, 0x6C, 0x20, 0x73, - 0x69, 0x6E, 0x67, 0x6C, 0x65, - 0xF9, 0x00, 0x00, - 0x03, - 0xF9, 0xC0, 0x00, // -2 - 0x04, - 0xF9, 0x7E, 0x00, // qNaN - 0x05, - 0xF9, 0x7C, 0x01, // sNaN - 0x06, - 0xF9, 0x7E, 0x0F, // qNaN with payload 0x0f - 0x07, - 0xF9, 0x7C, 0x0F, // sNaN with payload 0x0f +struct DoubleTestCase { + double dNumber; + double fNumber; + UsefulBufC Preferred; + UsefulBufC NotPreferred; + UsefulBufC CDE; + UsefulBufC DCBOR; }; +/* Boundaries for all destination conversions to test at. + * + * smallest subnormal single 1.401298464324817e-45 2^^-149 + * largest subnormal single 1.1754942106924411e-38 2^^-126 + * smallest normal single 1.1754943508222875e-38 + * largest single 3.4028234663852886E+38 + * + * smallest subnormal half 5.9604644775390625E-8 + * largest subnormal half 6.097555160522461E-5 + * smallest normal half 6.103515625E-5 + * largest half 65504.0 + * + * Boundaries for origin conversions + * smallest subnormal double 5.0e-324 2^^-1074 + * largest subnormal double + * smallest normal double 2.2250738585072014e-308 2^^-1022 + * largest normal double 1.7976931348623157e308 2^^-1023 + */ -inline static bool CheckDouble(double d, uint64_t u) -{ - return UsefulBufUtil_CopyDoubleToUint64(d) != u; -} - - -int32_t HalfPrecisionDecodeBasicTests(void) -{ - UsefulBufC HalfPrecision = UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spExpectedHalf); - - QCBORDecodeContext DC; - QCBORDecode_Init(&DC, HalfPrecision, 0); - - QCBORItem Item; - - QCBORDecode_GetNext(&DC, &Item); - if(Item.uDataType != QCBOR_TYPE_MAP) { - return -1; - } - - QCBORDecode_GetNext(&DC, &Item); - if(Item.uDataType != QCBOR_TYPE_DOUBLE || Item.val.dfnum != 0.0) { - return -2; - } - - QCBORDecode_GetNext(&DC, &Item); - if(Item.uDataType != QCBOR_TYPE_DOUBLE || Item.val.dfnum != INFINITY) { - return -3; - } +/* Always four lines per test case so shell scripts can process into + * other formats. CDE and DCBOR standards are not complete yet, + * encodings are a guess. C string literals are used because they + * are the shortest notation. They are used __with a length__ . Null + * termination doesn't work because there are zero bytes. + */ +static const struct DoubleTestCase DoubleTestCases[] = { + /* Zero */ + {0.0, 0.0f, + {"\xF9\x00\x00", 3}, {"\xFB\x00\x00\x00\x00\x00\x00\x00\x00", 9}, + {"\xF9\x00\x00", 3}, {"\xF9\x00\x00", 3}}, + + /* Negative Zero */ + {-0.0, -0.0f, + {"\xF9\x80\x00", 3}, {"\xFB\x80\x00\x00\x00\x00\x00\x00\x00", 9}, + {"\xF9\x80\x00", 3}, {"\xF9\x80\x00", 3}}, + + /* NaN */ + {NAN, NAN, + {"\xF9\x7E\x00", 3}, {"\xFB\x7F\xF8\x00\x00\x00\x00\x00\x00", 9}, + {"\xF9\x7E\x00", 3}, {"\xF9\x7E\x00", 3}}, + + /* Infinity */ + {INFINITY, INFINITY, + {"\xF9\x7C\x00", 3}, {"\xFB\x7F\xF0\x00\x00\x00\x00\x00\x00", 9}, + {"\xF9\x7C\x00", 3}, {"\xF9\x7C\x00", 3}}, + + /* Negative Infinity */ + {-INFINITY, -INFINITY, + {"\xF9\xFC\x00", 3}, {"\xFB\xFF\xF0\x00\x00\x00\x00\x00\x00", 9}, + {"\xF9\xFC\x00", 3}, {"\xF9\xFC\x00", 3}}, + + /* 1.0 */ + {1.0, 1.0f, + {"\xF9\x3C\x00", 3}, {"\xFB\x3F\xF0\x00\x00\x00\x00\x00\x00", 9}, + {"\xF9\x3C\x00", 3}, {"\xF9\x3C\x00", 3}}, + + /* -2.0 -- a negative number that is not zero */ + {-2.0, -2.0f, + {"\xF9\xC0\x00", 3}, {"\xFB\xC0\x00\x00\x00\x00\x00\x00\x00", 9}, + {"\xF9\xC0\x00", 3}, {"\xF9\x3C\x00", 3}}, + + /* 1/3 */ + {0.333251953125, 0.333251953125f, + {"\xF9\x35\x55", 3}, {"\xFB\x3F\xD5\x54\x00\x00\x00\x00\x00", 9}, + {"\xF9\x35\x55", 3}, {"\xF9\x35\x55", 3}}, + + /* 5.9604644775390625E-8 -- smallest half-precision subnormal */ + {5.9604644775390625E-8, 0.0f, + {"\xF9\x00\x01", 3}, {"\xFB\x3E\x70\x00\x00\x00\x00\x00\x00", 9}, + {"\xF9\x00\x01", 3}, {"\xF9\x00\x01", 3}}, + + /* 3.0517578125E-5 -- a half-precision subnormal */ + {3.0517578125E-5, 0.0f, + {"\xF9\x02\x00", 3}, {"\xFB\x3F\x00\x00\x00\x00\x00\x00\x00", 9}, + {"\xF9\x02\x00", 3}, {"\xF9\x02\x00", 3}}, + + /* 6.097555160522461E-5 -- largest half-precision subnormal */ + {6.097555160522461E-5, 0.0f, + {"\xF9\x03\xFF", 3}, {"\xFB\x3F\x0F\xF8\x00\x00\x00\x00\x00", 9}, + {"\xF9\x03\xFF", 3}, {"\xF9\04\00", 3}}, + + /* 6.103515625E-5 -- smallest possible half-precision normal */ + {6.103515625E-5, 0.0f, + {"\xF9\04\00", 3}, {"\xFB\x3F\x10\x00\x00\x00\x00\x00\x00", 9}, + {"\xF9\04\00", 3}, {"\xF9\04\00", 3}}, + + /* 6.1035156250000014E-5 -- slightly larger than smallest half-precision normal */ + {6.1035156250000014E-5, 6.1035156250000014E-5f, + {"\xFB\x3F\x10\x00\x00\x00\x00\x00\x01", 9}, {"\xFB\x3F\x10\x00\x00\x00\x00\x00\x01", 9}, + {"\xFB\x3F\x10\x00\x00\x00\x00\x00\x01", 9}, {"\xFB\x3F\x10\x00\x00\x00\x00\x00\x01", 9}}, + + /* 6.1035156249999993E-5 -- slightly smaller than smallest half-precision normal */ + {6.1035156249999993E-5, 0.0f, + {"\xFB\x3F\x0F\xFF\xFF\xFF\xFF\xFF\xFF", 9}, {"\xFB\x3F\x0F\xFF\xFF\xFF\xFF\xFF\xFF", 9}, + {"\xFB\x3F\x0F\xFF\xFF\xFF\xFF\xFF\xFF", 9}, {"\xFB\x3F\x0F\xFF\xFF\xFF\xFF\xFF\xFF", 9}}, + + /* 65504.0 -- largest possible half-precision */ + {65504.0, 0.0f, + {"\xF9\x7B\xFF", 3}, {"\xFB\x40\xEF\xFC\x00\x00\x00\x00\x00", 9}, + {"\xF9\x7B\xFF", 3}, {"\xF9\x7B\xFF", 3}}, + + /* 65504.1 -- exponent too large and too much precision to convert */ + {65504.1, 0.0f, + {"\xFB\x40\xEF\xFC\x03\x33\x33\x33\x33", 9}, {"\xFB\x40\xEF\xFC\x03\x33\x33\x33\x33", 9}, + {"\xFB\x40\xEF\xFC\x03\x33\x33\x33\x33", 9}, {"\xFB\x40\xEF\xFC\x03\x33\x33\x33\x33", 9}}, + + /* 65536.0 -- exponent too large but not too much precision for single */ + {65536.0, 65536.0f, + {"\xFA\x47\x80\x00\x00", 5}, {"\xFB\x40\xF0\x00\x00\x00\x00\x00\x00", 9}, + {"\xFA\x47\x80\x00\x00", 5}, {"\xFA\x47\x80\x00\x00", 5}}, + + /* 1.401298464324817e-45 -- smallest single subnormal */ + {1.401298464324817e-45, 1.40129846E-45f, + {"\xFA\x00\x00\x00\x01", 5}, {"\xFB\x36\xA0\x00\x00\x00\x00\x00\x00", 9}, + {"\xFA\x00\x00\x00\x01", 5}, {"\xFA\x00\x00\x00\x01", 5}}, + + /* 5.8774717541114375E-39 -- slightly smaller than the smallest + // single normal */ + {5.8774717541114375E-39, 5.87747175E-39f, + {"\xFA\x00\x40\x00\x00", 5}, {"\xFB\x38\x00\x00\x00\x00\x00\x00\x00", 9}, + {"\xFA\x00\x40\x00\x00", 5}, {"\xFA\x00\x40\x00\x00", 5}}, + + /* 1.1754942106924411e-38 -- largest single subnormal */ + {1.1754942106924411E-38, 1.17549421E-38f, + {"\xFA\x00\x7f\xff\xff", 5}, {"\xFB\x38\x0f\xff\xff\xC0\x00\x00\x00", 9}, + {"\xFA\x00\x7f\xff\xff", 5}, {"\xFA\x00\x7f\xff\xff", 5} }, + + /* 1.1754943508222874E-38 -- slightly bigger than smallest single normal */ + {1.1754943508222874E-38, 0.0f, + {"\xFB\x38\x0f\xff\xff\xff\xff\xff\xff", 9}, {"\xFB\x38\x0f\xff\xff\xff\xff\xff\xff", 9}, + {"\xFB\x38\x0f\xff\xff\xff\xff\xff\xff", 9}, {"\xFB\x38\x0f\xff\xff\xff\xff\xff\xff", 9}}, + + /* 1.1754943508222875e-38 -- smallest single normal */ + {1.1754943508222875e-38, 1.17549435E-38f, + {"\xFA\x00\x80\x00\x00", 5}, {"\xFB\x38\x10\x00\x00\x00\x00\x00\x00", 9}, + {"\xFA\x00\x80\x00\x00", 5}, {"\xFA\x00\x80\x00\x00", 5}}, + + /* 1.1754943508222875e-38 -- slightly bigger than smallest single normal */ + {1.1754943508222878e-38, 0.0f, + {"\xFB\x38\x10\x00\x00\x00\x00\x00\x01", 9}, {"\xFB\x38\x10\x00\x00\x00\x00\x00\x01", 9}, + {"\xFB\x38\x10\x00\x00\x00\x00\x00\x01", 9}, {"\xFB\x38\x10\x00\x00\x00\x00\x00\x01", 9}}, + + /* 16777216 -- converts to single without loss */ + {16777216, 16777216, + {"\xFA\x4B\x80\x00\x00", 5}, {"\xFB\x41\x70\x00\x00\x00\x00\x00\x00", 9}, + {"\xFA\x4B\x80\x00\x00", 5}, {"\xFA\x4B\x80\x00\x00", 5}}, + + /* 16777217 -- one more than above and fails conversion to single */ + {16777217, 16777216, + {"\xFB\x41\x70\x00\x00\x10\x00\x00\x00", 9}, {"\xFB\x41\x70\x00\x00\x10\x00\x00\x00", 9}, + {"\xFB\x41\x70\x00\x00\x10\x00\x00\x00", 9}, {"\xFB\x41\x70\x00\x00\x10\x00\x00\x00", 9}}, + + /* 3.4028234663852886E+38 -- largest possible single normal */ + {3.4028234663852886E+38, 3.40282347E+38f, + {"\xFA\x7F\x7F\xFF\xFF", 5}, {"\xFB\x47\xEF\xFF\xFF\xE0\x00\x00\x00", 9}, + {"\xFA\x7F\x7F\xFF\xFF", 5}, {"\xFA\x7F\x7F\xFF\xFF", 5}}, + + /* 3.402823466385289E+38 -- slightly larger than largest possible single */ + {3.402823466385289E+38, 0.0f, + {"\xFB\x47\xEF\xFF\xFF\xE0\x00\x00\x01", 9}, {"\xFB\x47\xEF\xFF\xFF\xE0\x00\x00\x01", 9}, + {"\xFB\x47\xEF\xFF\xFF\xE0\x00\x00\x01", 9}, {"\xFB\x47\xEF\xFF\xFF\xE0\x00\x00\x01", 9}}, + + /* 3.402823669209385e+38 -- exponent larger by one than largest possible single */ + {3.402823669209385e+38, 0.0f, + {"\xFB\x47\xF0\x00\x00\x00\x00\x00\x00", 9}, {"\xFB\x47\xF0\x00\x00\x00\x00\x00\x00", 9}, + {"\xFB\x47\xF0\x00\x00\x00\x00\x00\x00", 9}, {"\xFB\x47\xF0\x00\x00\x00\x00\x00\x00", 9}}, + + /* 5.0e-324 -- smallest double subnormal normal */ + {5.0e-324, 0.0f, + {"\xFB\x00\x00\x00\x00\x00\x00\x00\x01", 9}, {"\xFB\x00\x00\x00\x00\x00\x00\x00\x01", 9}, + {"\xFB\x00\x00\x00\x00\x00\x00\x00\x01", 9}, {"\xFB\x00\x00\x00\x00\x00\x00\x00\x01", 9}}, + + /* 2.2250738585072009E−308 -- largest double subnormal */ + {2.2250738585072009e-308, 0.0f, + {"\xFB\x00\x0F\xFF\xFF\xFF\xFF\xFF\xFF", 9}, {"\xFB\x00\x0F\xFF\xFF\xFF\xFF\xFF\xFF", 9}, + {"\xFB\x00\x0F\xFF\xFF\xFF\xFF\xFF\xFF", 9}, {"\xFB\x00\x0F\xFF\xFF\xFF\xFF\xFF\xFF", 9}}, + + /* 2.2250738585072014e-308 -- smallest double normal */ + {2.2250738585072014e-308, 0.0f, + {"\xFB\x00\x10\x00\x00\x00\x00\x00\x00", 9}, {"\xFB\x00\x10\x00\x00\x00\x00\x00\x00", 9}, + {"\xFB\x00\x10\x00\x00\x00\x00\x00\x00", 9}, {"\xFB\x00\x10\x00\x00\x00\x00\x00\x00", 9}}, + + /* 1.7976931348623157E308 -- largest double normal */ + {1.7976931348623157e308, 0.0f, + {"\xFB\x7F\xEF\xFF\xFF\xFF\xFF\xFF\xFF", 9}, {"\xFB\x7F\xEF\xFF\xFF\xFF\xFF\xFF\xFF", 9}, + {"\xFB\x7F\xEF\xFF\xFF\xFF\xFF\xFF\xFF", 9}, {"\xFB\x7F\xEF\xFF\xFF\xFF\xFF\xFF\xFF", 9}}, + + /* List terminator */ + {0.0, 0.0f, {NULL, 0}, {NULL, 0}, {NULL, 0}, {NULL, 0} } +}; - QCBORDecode_GetNext(&DC, &Item); - if(Item.uDataType != QCBOR_TYPE_DOUBLE || Item.val.dfnum != -INFINITY) { - return -4; - } - // TODO: NAN-related is this really converting right? It is carrying - // payload, but this confuses things. - QCBORDecode_GetNext(&DC, &Item); - if(Item.uDataType != QCBOR_TYPE_DOUBLE || !isnan(Item.val.dfnum)) { - return -5; - } +struct NaNTestCase { + uint64_t uDouble; + uint32_t uSingle; + UsefulBufC Preferred; + UsefulBufC NotPreferred; + UsefulBufC CDE; + UsefulBufC DCBOR; +}; - QCBORDecode_GetNext(&DC, &Item); - if(Item.uDataType != QCBOR_TYPE_DOUBLE || Item.val.dfnum != 1.0) { - return -6; - } +/* Always four lines per test case so shell scripts can process into + * other formats. CDE and DCBOR standards are not complete yet, + * encodings are a guess. C string literals are used because they + * are the shortest notation. They are used __with a length__ . Null + * termination doesn't work because there are zero bytes. + */ +static const struct NaNTestCase NaNTestCases[] = { + + /* Payload with most significant bit set, a qNaN by most implementations */ + {0x7ff8000000000000, 0x00000000, + {"\xF9\x7E\x00", 3}, {"\xFB\x7F\xF8\x00\x00\x00\x00\x00\x00", 9}, + {"\xF9\x7E\x00", 3}, {"\xF9\x7E\x00", 3}}, + + /* Payload with single rightmost set */ + {0x7ff8000000000001, 0x00000000, + {"\xFB\x7F\xF8\x00\x00\x00\x00\x00\x01", 9}, {"\xFB\x7F\xF8\x00\x00\x00\x00\x00\x01", 9}, + {"\xF9\x7E\x00", 3}, {"\xF9\x7E\x00", 3}}, + + /* Payload with 10 leftmost bits set -- converts to half */ + {0x7ffffc0000000000, 0x00000000, + {"\xF9\x7F\xFF", 3}, {"\xFB\x7F\xFF\xFC\x00\x00\x00\x00\x00", 9}, + {"\xF9\x7E\x00", 3}, {"\xF9\x7E\x00", 3}}, + + /* Payload with 10 rightmost bits set -- cannot convert to half */ + {0x7ff80000000003ff, 0x00000000, + {"\xFB\x7F\xF8\x00\x00\x00\x00\x03\xFF", 9}, {"\xFB\x7F\xF8\x00\x00\x00\x00\x03\xFF", 9}, + {"\xF9\x7E\x00", 3}, {"\xF9\x7E\x00", 3}}, + + /* Payload with 23 leftmost bits set -- converts to a single */ + {0x7ffFFFFFE0000000, 0x7fffffff, + {"\xFA\x7F\xFF\xFF\xFF", 5}, {"\xFB\x7F\xFF\xFF\xFF\xE0\x00\x00\x00", 9}, + {"\xF9\x7E\x00", 3}, {"\xF9\x7E\x00", 3}}, + + /* Payload with 24 leftmost bits set -- fails to convert to a single */ + {0x7ffFFFFFF0000000, 0x00000000, + {"\xFB\x7F\xFF\xFF\xFF\xF0\x00\x00\x00", 9}, {"\xFB\x7F\xFF\xFF\xFF\xF0\x00\x00\x00", 9}, + {"\xF9\x7E\x00", 3}, {"\xF9\x7E\x00", 3}}, + + /* Payload with all bits set */ + {0x7fffffffffffffff, 0x00000000, + {"\xFB\x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF", 9}, {"\xFB\x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF", 9}, + {"\xF9\x7E\x00", 3}, {"\xFB\x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF", 9}}, + + /* List terminator */ + {0, 0, {NULL, 0}, {NULL, 0}, {NULL, 0}, {NULL, 0} } +}; - // Approximately 1/3 - QCBORDecode_GetNext(&DC, &Item); - if(Item.uDataType != QCBOR_TYPE_DOUBLE || Item.val.dfnum != 0.333251953125) { - return -7; - } - // Largest half-precision - QCBORDecode_GetNext(&DC, &Item); - if(Item.uDataType != QCBOR_TYPE_DOUBLE || Item.val.dfnum != 65504.0) { - return -8; - } - QCBORDecode_GetNext(&DC, &Item); - if(Item.uDataType != QCBOR_TYPE_DOUBLE || Item.val.dfnum != INFINITY) { - return -9; - } +/* Public function. See float_tests.h + * + * This is the main test of floating-point encoding / decoding. It is + * data-driven by the above tables. It works better than tests below that + * it mostly replaces because it tests one number at a time, rather than + * putting them all in a map. It is much easier to debug test failures + * and to add new tests. */ +int32_t +FloatValuesTests(void) +{ + unsigned int uTestIndex; + const struct DoubleTestCase *pTestCase; + const struct NaNTestCase *pNaNTestCase; + MakeUsefulBufOnStack( TestOutBuffer, 20); + UsefulBufC TestOutput; + QCBOREncodeContext EnCtx; + QCBORError uErr; + QCBORDecodeContext DCtx; + QCBORItem Item; + uint64_t uDecoded; +#ifdef QCBOR_DISABLE_FLOAT_HW_USE + uint32_t uDecoded2; +#endif - // Smallest half-precision subnormal - QCBORDecode_GetNext(&DC, &Item); - if(Item.uDataType != QCBOR_TYPE_DOUBLE || Item.val.dfnum != 0.00000005960464477539063) { - return -10; - } + /* Test a variety of doubles */ + for(uTestIndex = 0; DoubleTestCases[uTestIndex].Preferred.len != 0; uTestIndex++) { + pTestCase = &DoubleTestCases[uTestIndex]; + + // if(pTestCase->dNumber == 1.1754943508222874E-38) { + if(uTestIndex == 19) { + uErr = 99; /* For setting break points for particular tests */ + } + + /* Number Encode of Preferred */ + QCBOREncode_Init(&EnCtx, TestOutBuffer); + QCBOREncode_AddDouble(&EnCtx, pTestCase->dNumber); + uErr = QCBOREncode_Finish(&EnCtx, &TestOutput); + + if(uErr != QCBOR_SUCCESS) { + return MakeTestResultCode(uTestIndex, 1, uErr);; + } + if(UsefulBuf_Compare(TestOutput, pTestCase->Preferred)) { + return MakeTestResultCode(uTestIndex, 1, 200); + } + + /* Number Encode of Not Preferred */ + QCBOREncode_Init(&EnCtx, TestOutBuffer); + QCBOREncode_AddDoubleNoPreferred(&EnCtx, pTestCase->dNumber); + uErr = QCBOREncode_Finish(&EnCtx, &TestOutput); + + if(uErr != QCBOR_SUCCESS) { + return MakeTestResultCode(uTestIndex, 2, uErr);; + } + if(UsefulBuf_Compare(TestOutput, pTestCase->NotPreferred)) { + return MakeTestResultCode(uTestIndex, 2, 200); + } + + /* Number Decode of Preferred */ + QCBORDecode_Init(&DCtx, pTestCase->Preferred, 0); + uErr = QCBORDecode_GetNext(&DCtx, &Item); + if(uErr != QCBOR_SUCCESS) { + return MakeTestResultCode(uTestIndex, 3, uErr);; + } +#ifndef QCBOR_DISABLE_FLOAT_HW_USE + if(Item.uDataType != QCBOR_TYPE_DOUBLE) { + return MakeTestResultCode(uTestIndex, 4, 0); + } + if(isnan(pTestCase->dNumber)) { + if(!isnan(Item.val.dfnum)) { + return MakeTestResultCode(uTestIndex, 5, 0); + } + } else { + if(Item.val.dfnum != pTestCase->dNumber) { + return MakeTestResultCode(uTestIndex, 6, 0); + } + } +#else /* QCBOR_DISABLE_FLOAT_HW_USE */ + /* When QCBOR_DISABLE_FLOAT_HW_USE is set, single-precision is not + * converted to double when decoding, so test differently. len == 5 + * indicates single-precision in the encoded CBOR. */ + if(pTestCase->Preferred.len == 5) { + if(Item.uDataType != QCBOR_TYPE_FLOAT) { + return MakeTestResultCode(uTestIndex, 4, 0); + } + if(isnan(pTestCase->dNumber)) { + if(!isnan(Item.val.fnum)) { + return MakeTestResultCode(uTestIndex, 5, 0); + } + } else { + if(Item.val.fnum != pTestCase->fNumber) { + return MakeTestResultCode(uTestIndex, 6, 0); + } + } + } else { + if(Item.uDataType != QCBOR_TYPE_DOUBLE) { + return MakeTestResultCode(uTestIndex, 4, 0); + } + if(isnan(pTestCase->dNumber)) { + if(!isnan(Item.val.dfnum)) { + return MakeTestResultCode(uTestIndex, 5, 0); + } + } else { + if(Item.val.dfnum != pTestCase->dNumber) { + return MakeTestResultCode(uTestIndex, 6, 0); + } + } + } +#endif /* QCBOR_DISABLE_FLOAT_HW_USE */ - // Largest half-precision subnormal - QCBORDecode_GetNext(&DC, &Item); - if(Item.uDataType != QCBOR_TYPE_DOUBLE || Item.val.dfnum != 0.00006097555160522461) { - return -11; - } + /* Number Decode of Not Preferred */ + QCBORDecode_Init(&DCtx, pTestCase->NotPreferred, 0); + uErr = QCBORDecode_GetNext(&DCtx, &Item); + if(uErr != QCBOR_SUCCESS) { + return MakeTestResultCode(uTestIndex, 7, uErr);; + } + if(Item.uDataType != QCBOR_TYPE_DOUBLE) { + return MakeTestResultCode(uTestIndex, 8, 0); + } + if(isnan(pTestCase->dNumber)) { + if(!isnan(Item.val.dfnum)) { + return MakeTestResultCode(uTestIndex, 9, 0); + } + } else { + if(Item.val.dfnum != pTestCase->dNumber) { + return MakeTestResultCode(uTestIndex, 10, 0); + } + } - // Smallest half-precision normal - QCBORDecode_GetNext(&DC, &Item); - if(Item.uDataType != QCBOR_TYPE_DOUBLE || Item.val.dfnum != 0.00006103515625) { - return -12; } - // half-precision zero - QCBORDecode_GetNext(&DC, &Item); - if(Item.uDataType != QCBOR_TYPE_DOUBLE || Item.val.dfnum != 0.0) { - return -13; - } + /* Test a variety of NaNs with payloads */ + for(uTestIndex = 0; NaNTestCases[uTestIndex].Preferred.len != 0; uTestIndex++) { + pNaNTestCase = &NaNTestCases[uTestIndex]; + + + if(uTestIndex == 4) { + uErr = 99; /* For setting break points for particular tests */ + } + + /* NaN Encode of Preferred */ + QCBOREncode_Init(&EnCtx, TestOutBuffer); + QCBOREncode_AddDouble(&EnCtx, UsefulBufUtil_CopyUint64ToDouble(pNaNTestCase->uDouble)); + uErr = QCBOREncode_Finish(&EnCtx, &TestOutput); + if(uErr != QCBOR_SUCCESS) { + return MakeTestResultCode(uTestIndex+100, 10, uErr);; + } + if(UsefulBuf_Compare(TestOutput, pNaNTestCase->Preferred)) { + return MakeTestResultCode(uTestIndex+100, 10, 200); + } + +#ifdef QCBOR_COMPARE_TO_HW_NAN_CONVERSION + { + /* This test is off by default. It's purpose is to check + * QCBOR's mask-n-shift implementation against the HW/CPU + * instructions that do conversion between double and single. + * It is off because it is only used on occasion to verify + * QCBOR and because it is suspected that some HW/CPU does + * implement this correctly. NaN payloads are an obscure + * feature. */ + float f; + double d, d2; + + d = UsefulBufUtil_CopyUint64ToDouble(pNaNTestCase->uNumber); + + /* Cast the double to a single and then back to a double and + * see if they are equal. If so, then the NaN payload doesn't + * have any bits that are lost when converting to single and + * it can be safely converted. + * + * This test can't be done for half-precision because it is + * not widely supported. + */ + f = (float)d; + d2 = (double)f; + + /* The length of encoded doubles is 9, singles 5 and halves + * 3. If there are NaN payload bits that can't be converted, + * then the length must be 9. + */ + if((uint64_t)d != (uint64_t)d2 && pNaNTestCase->Preferred.len != 9) { + /* QCBOR conversion not the same as HW conversion */ + return MakeTestResultCode(uTestIndex, 9, 200); + } + } +#endif /* QCBOR_COMPARE_TO_HW_NAN_CONVERSION */ + + + /* NaN Encode of Not Preferred */ + QCBOREncode_Init(&EnCtx, TestOutBuffer); + QCBOREncode_AddDoubleNoPreferred(&EnCtx, UsefulBufUtil_CopyUint64ToDouble(pNaNTestCase->uDouble)); + uErr = QCBOREncode_Finish(&EnCtx, &TestOutput); + if(uErr != QCBOR_SUCCESS) { + return MakeTestResultCode(uTestIndex+100, 11, uErr);; + } + if(UsefulBuf_Compare(TestOutput, pNaNTestCase->NotPreferred)) { + return MakeTestResultCode(uTestIndex+100, 11, 200); + } + + /* NaN Decode of Preferred */ + QCBORDecode_Init(&DCtx, pNaNTestCase->Preferred, 0); + uErr = QCBORDecode_GetNext(&DCtx, &Item); + if(uErr != QCBOR_SUCCESS) { + return MakeTestResultCode(uTestIndex+100, 12, uErr); + } - // negative 2 - QCBORDecode_GetNext(&DC, &Item); - if(Item.uDataType != QCBOR_TYPE_DOUBLE || Item.val.dfnum != -2.0) { - return -14; - } +#ifndef QCBOR_DISABLE_FLOAT_HW_USE - // TODO: NAN-related double check these four tests - QCBORDecode_GetNext(&DC, &Item); // qNaN - if(Item.uDataType != QCBOR_TYPE_DOUBLE || - CheckDouble(Item.val.dfnum, 0x7ff8000000000000ULL)) { - return -15; - } - QCBORDecode_GetNext(&DC, &Item); // sNaN - if(Item.uDataType != QCBOR_TYPE_DOUBLE || - CheckDouble(Item.val.dfnum, 0x7ff0000000000001ULL)) { - return -16; - } - QCBORDecode_GetNext(&DC, &Item); // qNaN with payload 0x0f - if(Item.uDataType != QCBOR_TYPE_DOUBLE || - CheckDouble(Item.val.dfnum, 0x7ff800000000000fULL)) { - return -17; - } - QCBORDecode_GetNext(&DC, &Item); // sNaN with payload 0x0f - if(Item.uDataType != QCBOR_TYPE_DOUBLE || - CheckDouble(Item.val.dfnum, 0x7ff000000000000fULL)) { - return -18; - } + uDecoded = UsefulBufUtil_CopyDoubleToUint64(Item.val.dfnum); + if(uDecoded != pNaNTestCase->uDouble) { + return MakeTestResultCode(uTestIndex+100, 12, 200); + } +#else /* QCBOR_DISABLE_FLOAT_HW_USE */ + if(pNaNTestCase->Preferred.len == 5) { + if(Item.uDataType != QCBOR_TYPE_FLOAT) { + return MakeTestResultCode(uTestIndex, 4, 0); + } + + uDecoded2 = UsefulBufUtil_CopyFloatToUint32(Item.val.fnum); + + if(uDecoded2 != pNaNTestCase->uSingle) { + return MakeTestResultCode(uTestIndex, 4, 0); + } + } else { + if(Item.uDataType != QCBOR_TYPE_DOUBLE) { + return MakeTestResultCode(uTestIndex, 4, 0); + } + uDecoded = UsefulBufUtil_CopyDoubleToUint64(Item.val.dfnum); + if(uDecoded != pNaNTestCase->uDouble) { + return MakeTestResultCode(uTestIndex+100, 12, 200); + } + } +#endif /* QCBOR_DISABLE_FLOAT_HW_USE */ - if(QCBORDecode_Finish(&DC)) { - return -19; + /* NaN Decode of Not Preferred */ + QCBORDecode_Init(&DCtx, pNaNTestCase->NotPreferred, 0); + uErr = QCBORDecode_GetNext(&DCtx, &Item); + if(uErr != QCBOR_SUCCESS) { + return MakeTestResultCode(uTestIndex+100, 13, uErr); + } + uDecoded = UsefulBufUtil_CopyDoubleToUint64(Item.val.dfnum); + if(uDecoded != pNaNTestCase->uDouble) { + return MakeTestResultCode(uTestIndex+100, 13, 200); + } } return 0; @@ -246,379 +550,58 @@ int32_t HalfPrecisionDecodeBasicTests(void) - -int32_t HalfPrecisionAgainstRFCCodeTest(void) +/* Public function. See float_tests.h */ +int32_t +HalfPrecisionAgainstRFCCodeTest(void) { - for(uint32_t uHalfP = 0; uHalfP < 0xffff; uHalfP += 60) { - unsigned char x[2]; - x[1] = (uint8_t)(uHalfP & 0xff); - x[0] = (uint8_t)(uHalfP >> 8); // uHalfP is always less than 0xffff - double d = decode_half(x); - - // Contruct the CBOR for the half-precision float by hand - UsefulBuf_MAKE_STACK_UB(__xx, 3); - UsefulOutBuf UOB; - UsefulOutBuf_Init(&UOB, __xx); - - const uint8_t uHalfPrecInitialByte = (uint8_t)(HALF_PREC_FLOAT + (CBOR_MAJOR_TYPE_SIMPLE << 5)); // 0xf9 - UsefulOutBuf_AppendByte(&UOB, uHalfPrecInitialByte); // The initial byte for a half-precision float - UsefulOutBuf_AppendUint16(&UOB, (uint16_t)uHalfP); - - // Now parse the hand-constructed CBOR. This will invoke the - // conversion to a float - QCBORDecodeContext DC; - QCBORDecode_Init(&DC, UsefulOutBuf_OutUBuf(&UOB), 0); - - QCBORItem Item; - - QCBORDecode_GetNext(&DC, &Item); - if(Item.uDataType != QCBOR_TYPE_DOUBLE) { - return -1; - } - - //printf("%04x QCBOR:%15.15f RFC: %15.15f (%8x)\n", - // uHalfP, Item.val.fnum, d , UsefulBufUtil_CopyFloatToUint32(d)); - - if(isnan(d)) { - // The RFC code uses the native instructions which may or may not - // handle sNaN, qNaN and NaN payloads correctly. This test just - // makes sure it is a NaN and doesn't worry about the type of NaN - if(!isnan(Item.val.dfnum)) { - return -3; - } - } else { - if(Item.val.dfnum != d) { - return -2; - } - } - } - return 0; -} - - -/* - Expected output from preferred serialization of some of floating-point numbers -{"zero": 0.0, - "negative zero": -0.0, - "infinitity": Infinity, - "negative infinitity": -Infinity, - "NaN": NaN, - "one": 1.0, - "one third": 0.333251953125, - "largest half-precision": 65504.0, - "largest half-precision point one": 65504.1, - "too-large half-precision": 65536.0, - "smallest half subnormal": 5.960464477539063e-8, - "smallest half normal": 0.00006103515625, - "smallest half normal plus": 0.00006103515625000001, - "smallest normal minus": 0.000030517578125, - "largest single": 3.4028234663852886e+38, - "largest single plus": 6.805646932770577e+38, - "smallest single": 1.1754943508222875e-38, - "smallest single plus": 1.1754943508222878e-38, - "smallest single minus": 1.1754943508222874e-38, - "smallest single minus more": 5.877471754111438e-39, - 3: -2.0, "single precision": 16777216.0, - "single with precision loss": 16777217.0, - 1: "fin"} - */ -static const uint8_t spExpectedSmallest[] = { - 0xB8, 0x1A, - 0x64, 0x7A, 0x65, 0x72, 0x6F, - 0xF9, 0x00, 0x00, - - 0x6D, 0x6E, 0x65, 0x67, 0x61, 0x74, 0x69, 0x76, 0x65, 0x20, 0x7A, - 0x65, 0x72, 0x6F, - 0xF9, 0x80, 0x00, - - 0x6A, 0x69, 0x6E, 0x66, 0x69, 0x6E, 0x69, 0x74, 0x69, 0x74, 0x79, - 0xF9, 0x7C, 0x00, - - 0x73, 0x6E, 0x65, 0x67, 0x61, 0x74, 0x69, 0x76, 0x65, 0x20, 0x69, - 0x6E, 0x66, 0x69, 0x6E, 0x69, 0x74, 0x69, 0x74, 0x79, - 0xF9, 0xFC, 0x00, - - 0x63, 0x4E, 0x61, 0x4E, - 0xF9, 0x7E, 0x00, - - 0x63, 0x6F, 0x6E, 0x65, - 0xF9, 0x3C, 0x00, - - 0x69, 0x6F, 0x6E, 0x65, 0x20, 0x74, 0x68, 0x69, 0x72, 0x64, - 0xF9, 0x35, 0x55, - - 0x76, 0x6C, 0x61, 0x72, 0x67, 0x65, 0x73, 0x74, 0x20, 0x68, 0x61, - 0x6C, 0x66, 0x2D, 0x70, 0x72, 0x65, 0x63, 0x69, 0x73, 0x69, - 0x6F, 0x6E, - 0xF9, 0x7B, 0xFF, - - 0x78, 0x20, 0x6C, 0x61, 0x72, 0x67, 0x65, 0x73, 0x74, 0x20, 0x68, - 0x61, 0x6C, 0x66, 0x2D, 0x70, 0x72, 0x65, 0x63, 0x69, 0x73, - 0x69, 0x6F, 0x6E, 0x20, 0x70, 0x6F, 0x69, 0x6E, 0x74, 0x20, - 0x6F, 0x6E, 0x65, - 0xFB, 0x40, 0xEF, 0xFC, 0x03, 0x33, 0x33, 0x33, 0x33, - - 0x78, 0x18, 0x74, 0x6F, 0x6F, 0x2D, 0x6C, 0x61, 0x72, 0x67, 0x65, - 0x20, 0x68, 0x61, 0x6C, 0x66, 0x2D, 0x70, 0x72, 0x65, 0x63, - 0x69, 0x73, 0x69, 0x6F, 0x6E, - 0xFA, 0x47, 0x80, 0x00, 0x00, - - 0x77, 0x73, 0x6D, 0x61, 0x6C, 0x6C, 0x65, 0x73, 0x74, - 0x20, 0x68, 0x61, 0x6C, 0x66, 0x20, 0x73, 0x75, 0x62, 0x6E, - 0x6F, 0x72, 0x6D, 0x61, 0x6C, - 0xFA, 0x33, 0x80, 0x00, 0x00, - - 0x74, 0x73, 0x6D, 0x61, 0x6C, 0x6C, 0x65, 0x73, 0x74, 0x20, 0x68, - 0x61, 0x6C, 0x66, 0x20, 0x6E, 0x6F, 0x72, 0x6D, 0x61, 0x6C, - 0xF9, 0x04, 0x00, - - 0x78, 0x19, 0x73, 0x6D, 0x61, 0x6C, 0x6C, 0x65, 0x73, 0x74, 0x20, - 0x68, 0x61, 0x6C, 0x66, 0x20, 0x6E, 0x6F, 0x72, 0x6D, 0x61, - 0x6C, 0x20, 0x70, 0x6C, 0x75, 0x73, - 0xFB, 0x3F, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, - - 0x75, 0x73, 0x6D, 0x61, 0x6C, 0x6C, 0x65, 0x73, 0x74, 0x20, 0x6E, - 0x6F, 0x72, 0x6D, 0x61, 0x6C, 0x20, 0x6D, 0x69, 0x6E, - 0x75, 0x73, - 0xFB, 0x3F, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - - 0x75, 0x73, 0x6D, 0x61, 0x6C, 0x6C, 0x65, 0x73, 0x74, 0x20, 0x6E, - 0x6F, 0x72, 0x6D, 0x61, 0x6C, 0x20, 0x6D, 0x69, 0x6E, 0x75, - 0x73, - 0xFA, 0x38, 0x00, 0x00, 0x00, - - 0x6E, 0x6C, 0x61, 0x72, 0x67, 0x65, 0x73, 0x74, 0x20, 0x73, 0x69, - 0x6E, 0x67, 0x6C, 0x65, - 0xFA, 0x7F, 0x7F, 0xFF, 0xFF, - - 0x73, 0x6C, 0x61, 0x72, 0x67, 0x65, 0x73, 0x74, 0x20, 0x73, 0x69, - 0x6E,0x67, 0x6C, 0x65, 0x20, 0x70, 0x6C, 0x75, 0x73, - 0xFB, 0x47, 0xEF, 0xFF, 0xFF, 0xE0, 0x00, 0x00, 0x01, - - 0x73, 0x6C, 0x61, 0x72, 0x67, 0x65, 0x73, 0x74, 0x20, 0x73, 0x69, - 0x6E, 0x67, 0x6C, 0x65, 0x20, 0x70, 0x6C, 0x75, 0x73, - 0xFB, 0x47, 0xFF, 0xFF, 0xFF, 0xE0, 0x00, 0x00, 0x00, - - 0x6F, 0x73, 0x6D, 0x61, 0x6C, 0x6C, 0x65, 0x73, 0x74, 0x20, 0x73, - 0x69, 0x6E, 0x67, 0x6C, 0x65, - 0xFA, 0x00, 0x80, 0x00, 0x00, - - 0x74, 0x73, 0x6D, 0x61, 0x6C, 0x6C, 0x65, 0x73, 0x74, 0x20, 0x73, - 0x69, 0x6E, 0x67, 0x6C, 0x65, 0x20, 0x70, 0x6C, 0x75, 0x73, - 0xFB, 0x38, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, - - 0x75, 0x73, 0x6D, 0x61, 0x6C, 0x6C, 0x65, 0x73, 0x74, 0x20, 0x73, - 0x69, 0x6E, 0x67, 0x6C, 0x65, 0x20, 0x6D, 0x69, 0x6E, 0x75, - 0x73, - 0xFB, 0x38, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - - 0x78, 0x1A, 0x73, 0x6D, 0x61, 0x6C, 0x6C, 0x65, 0x73, 0x74, 0x20, - 0x73, 0x69, 0x6E, 0x67, 0x6C, 0x65, 0x20, 0x6D, 0x69, 0x6E, - 0x75, 0x73, 0x20, 0x6D, 0x6F, 0x72, 0x65, - 0xFB, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - - 0x03, - 0xF9, 0xC0, 0x00, - - 0x70, 0x73, 0x69, 0x6E, 0x67, 0x6C, 0x65, 0x20, 0x70, 0x72, 0x65, - 0x63, 0x69, 0x73, 0x69, 0x6F, 0x6E, - 0xFA, 0x4B, 0x80, 0x00, 0x00, - - 0x78, 0x1A, 0x73, 0x69, 0x6E, 0x67, 0x6C, 0x65, 0x20, 0x77, 0x69, - 0x74, 0x68, 0x20, 0x70, 0x72, 0x65, 0x63, 0x69, 0x73, 0x69, - 0x6F, 0x6E, 0x20, 0x6C, 0x6F, 0x73, 0x73, - 0xFB, 0x41, 0x70, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, - - 0x01, - 0x63, 0x66, 0x69, 0x6E -}; - - -/* - Makes a double from a uint64_t by copying the bits, not - by converting the value. - */ -#define MAKE_DOUBLE(x) UsefulBufUtil_CopyUint64ToDouble(x) - - -int32_t DoubleAsSmallestTest(void) -{ - UsefulBuf_MAKE_STACK_UB(EncodedHalfsMem, sizeof(spExpectedSmallest)); - - QCBOREncodeContext EC; - QCBOREncode_Init(&EC, EncodedHalfsMem); - QCBOREncode_OpenMap(&EC); - - // Many of these are from - // https://en.wikipedia.org/wiki/Half-precision_floating-point_format - // and - // https://en.wikipedia.org/wiki/Single-precision_floating-point_format - - // F9 0000 # primitive(0) - QCBOREncode_AddDoubleToMap(&EC, "zero", 0.00); - - // F9 8000 # primitive(0) - QCBOREncode_AddDoubleToMap(&EC, "negative zero", -0.00); - - // F9 7C00 # primitive(31744) - QCBOREncode_AddDoubleToMap(&EC, "infinitity", INFINITY); - - // F9 FC00 # primitive(64512) - QCBOREncode_AddDoubleToMap(&EC, "negative infinitity", -INFINITY); - - // F9 7E00 # primitive(32256) - QCBOREncode_AddDoubleToMap(&EC, "NaN", NAN); - - // TODO: test a few NaN variants - - // F9 3C00 # primitive(15360) - QCBOREncode_AddDoubleToMap(&EC, "one", 1.0); - - // F9 3555 # primitive(13653) - QCBOREncode_AddDoubleToMap(&EC, "one third", 0.333251953125); - - // 65504.0, converts to the large possible half-precision. - // 0xF9, 0x7B, 0xFF, - QCBOREncode_AddDoubleToMap(&EC, "largest half-precision", 65504.0); - - // 65504.1, the double that has both to large an exponent and too - // much precision, so no conversion. - // 0xFB, 0x40, 0xEF, 0xFC, 0x03, 0x33, 0x33, 0x33, 0x33, - QCBOREncode_AddDoubleToMap(&EC, "largest half-precision point one", 65504.1); - - // 65536.0 has an exponent of 16, which is larger than 15, the - // largest half-precision exponent. It is the exponent, not - // precision loss that prevents conversion to half. It does convert - // to single precision. - // 0xFA, 0x47, 0x80, 0x00, 0x00, - QCBOREncode_AddDoubleToMap(&EC, "too-large half-precision", 65536.0); - - // 5.9604644775390625E-8, the smallest possible half-precision - // subnormal, digitis are lost converting to half, but not - // when converting to a single - // 0xFA, 0x33, 0x80, 0x00, 0x00, - QCBOREncode_AddDoubleToMap(&EC, - "smallest half subnormal", - MAKE_DOUBLE(0x3e70000000000000)); - - // 0.00006103515625, the double value that converts to the smallest - // possible half-precision normal. which is what should appear in - // the output. - // 0xF9, 0x04, 0x00, - QCBOREncode_AddDoubleToMap(&EC, - "smallest half normal", - MAKE_DOUBLE(0x3f10000000000000)); - - // 0.000061035156250000014 ,the double value that is a tiny bit - // greater than smallest possible half-precision normal. It will be - // output as a double because converting it will reduce precision. - // 0xFB, 0x3F, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, - QCBOREncode_AddDoubleToMap(&EC, - "smallest half normal plus", - MAKE_DOUBLE(0x3f10000000000001)); - - // 0.000061035156249999993, the double value that is a tiny bit - // smaller than the smallest half-precision normal. This will fail - // to convert to a half-precision because both the exponent is too - // small and the precision is too large for a half-precision. - // 0xFB, 0x3F, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - QCBOREncode_AddDoubleToMap(&EC, - "smallest normal minus", - MAKE_DOUBLE(0x3f0fffffffffffff)); - - // 0.000030517578125, the double value that is too small to fit - // into a half-precision because the exponent won't fit, not - // because precision would be lost. (This would fit into a - // half-precision subnormal, but there is no converstion to - // that). This ends up encoded as a single-precision. - // 0xFA, 0x38, 0x00, 0x00, 0x00, - QCBOREncode_AddDoubleToMap(&EC, - "smallest normal minus", - MAKE_DOUBLE(0x3f00000000000000)); - - // 3.4028234664e38, the value that converts to the largest possible - // single-precision. - // 0xFA, 0x7F, 0x7F, 0xFF, 0xFF, - QCBOREncode_AddDoubleToMap(&EC, - "largest single", - MAKE_DOUBLE(0x47efffffe0000000)); - - // 3.402823466385289E38, sightly larger than the largest possible - // possible precision. Conversion fails because precision would be - // lost. - // 0xFB, 0x47, 0xEF, 0xFF, 0xFF, 0xE0, 0x00, 0x00, 0x01, - QCBOREncode_AddDoubleToMap(&EC, - "largest single plus", - MAKE_DOUBLE(0x47efffffe0000001)); - - // 6.8056469327705772E38, slightly more larger than the largers - // possible single precision. Conversion fails because exponent is - // too large. - // 0xFB, 0x47, 0xFF, 0xFF, 0xFF, 0xE0, 0x00, 0x00, 0x00, - QCBOREncode_AddDoubleToMap(&EC, - "largest single plus", - MAKE_DOUBLE(0x47ffffffe0000000)); - - // 1.1754943508222875E-38, The double value that converts to the - // smallest possible single-precision normal - // 0xFA, 0x00, 0x80, 0x00, 0x00, - QCBOREncode_AddDoubleToMap(&EC, - "smallest single", - MAKE_DOUBLE(0x3810000000000000)); - - // 1.1754943508222878E-38, double value that is slightly larger - // than the smallest single-precision normal. Conversion fails - // because of precision - // 0xFB, 0x38, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, - QCBOREncode_AddDoubleToMap(&EC, - "smallest single plus", - MAKE_DOUBLE(0x3810000000000001)); - - // 1.1754943508222874E-38, slightly smaller than the smallest - // single-precision normal. Conversion fails because of precision - // 0xFB, 0x38, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - QCBOREncode_AddDoubleToMap(&EC, - "smallest single minus", - MAKE_DOUBLE(0x380fffffffffffff)); - - // 5.8774717541114375E-39, slightly smaller than the smallest - // single-precision normal. Conversion fails because the exponent - // is too small. - // 0xFB, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - QCBOREncode_AddDoubleToMap(&EC, - "smallest single minus more", - MAKE_DOUBLE(0x3800000000000000)); - - // Just -2, which converts to a negative half-precision - // F9 C000 # primitive(49152) - QCBOREncode_AddDoubleToMapN(&EC, 3, -2.0); - - // 16777216, No precision loss converting to single - // FA 4B800000 # primitive(1266679808) - QCBOREncode_AddDoubleToMap(&EC, "single precision", 16777216); - - // 16777217, One more than above. Too much precision for a single - // so no conversion. - // 0xFB, 0x41, 0x70, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, - QCBOREncode_AddDoubleToMap(&EC, "single with precision loss", 16777217); - - // Just a convenient marker when cutting and pasting encoded CBOR - QCBOREncode_AddSZStringToMapN(&EC, 1, "fin"); - - QCBOREncode_CloseMap(&EC); - - UsefulBufC EncodedHalfs; - QCBORError uErr = QCBOREncode_Finish(&EC, &EncodedHalfs); - if(uErr) { - return -1; - } - - if(UsefulBuf_Compare(EncodedHalfs, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spExpectedSmallest))) { - return -3; + QCBORItem Item; + QCBORDecodeContext DC; + unsigned char pbHalfBytes[2]; + uint8_t uHalfPrecInitialByte; + double d; + UsefulBuf_MAKE_STACK_UB(EncodedBytes, 3); + UsefulOutBuf UOB; + uint32_t uHalfP; + + + for(uHalfP = 0; uHalfP < 0xffff; uHalfP += 60) { + pbHalfBytes[1] = (uint8_t)(uHalfP & 0xff); + pbHalfBytes[0] = (uint8_t)(uHalfP >> 8); /* uHalfP is always less than 0xffff */ + d = decode_half(pbHalfBytes); + + /* Construct the CBOR for the half-precision float by hand */ + UsefulOutBuf_Init(&UOB, EncodedBytes); + + uHalfPrecInitialByte = (uint8_t)(HALF_PREC_FLOAT + (CBOR_MAJOR_TYPE_SIMPLE << 5)); /* 0xf9 */ + UsefulOutBuf_AppendByte(&UOB, uHalfPrecInitialByte); /* initial byte */ + UsefulOutBuf_AppendUint16(&UOB, (uint16_t)uHalfP); /* argument */ + + /* Now parse the hand-constructed CBOR. This will invoke the + * conversion to a float + */ + QCBORDecode_Init(&DC, UsefulOutBuf_OutUBuf(&UOB), 0); + QCBORDecode_GetNext(&DC, &Item); + if(Item.uDataType != QCBOR_TYPE_DOUBLE) { + return -1; + } + + if(isnan(d)) { + /* The RFC code uses the native instructions which may or may not + * handle sNaN, qNaN and NaN payloads correctly. This test just + * makes sure it is a NaN and doesn't worry about the type of NaN + */ + if(!isnan(Item.val.dfnum)) { + return -3; + } + } else { + if(Item.val.dfnum != d) { + return -2; + } + } } - return 0; } + #endif /* QCBOR_DISABLE_PREFERRED_FLOAT */ @@ -700,17 +683,27 @@ static const uint8_t spExpectedFloatsNoHalf[] = { 0x18, 0x6A, 0xFA, 0x00, 0x00, 0x00, 0x00}; -int32_t GeneralFloatEncodeTests(void) + +/* Public function. See float_tests.h */ +int32_t +GeneralFloatEncodeTests(void) { + /* See FloatNumberTests() for tests that really cover lots of float values. + * Add new tests for new values or decode modes there. + * This test is primarily to cover all the float encode methods. */ + + UsefulBufC Encoded; UsefulBufC ExpectedFloats; + QCBORError uErr; + #ifndef QCBOR_DISABLE_PREFERRED_FLOAT UsefulBuf_MAKE_STACK_UB(OutBuffer, sizeof(spExpectedFloats)); ExpectedFloats = UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spExpectedFloats); - (void)spExpectedFloatsNoHalf; // Avoid unused variable error + (void)spExpectedFloatsNoHalf; /* Avoid unused variable error */ #else UsefulBuf_MAKE_STACK_UB(OutBuffer, sizeof(spExpectedFloatsNoHalf)); ExpectedFloats = UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spExpectedFloatsNoHalf); - (void)spExpectedFloats; // Avoid unused variable error + (void)spExpectedFloats; /* Avoid unused variable error */ #endif /* QCBOR_DISABLE_PREFERRED_FLOAT */ QCBOREncodeContext EC; @@ -744,8 +737,7 @@ int32_t GeneralFloatEncodeTests(void) QCBOREncode_CloseMap(&EC); QCBOREncode_CloseArray(&EC); - UsefulBufC Encoded; - QCBORError uErr = QCBOREncode_Finish(&EC, &Encoded); + uErr = QCBOREncode_Finish(&EC, &Encoded); if(uErr) { return -1; } @@ -757,25 +749,15 @@ int32_t GeneralFloatEncodeTests(void) return 0; } - -/* returns 0 if equivalent, non-zero if not equivalent */ -static int CHECK_EXPECTED_DOUBLE(double val, double expected) -{ - double diff = val - expected; - - diff = fabs(diff); - - if(diff > 0.000001) { - return 1; - } else { - return 0; - } -} #endif /* USEFULBUF_DISABLE_ALL_FLOAT */ -int32_t GeneralFloatDecodeTests(void) +/* Public function. See float_tests.h */ +int32_t +GeneralFloatDecodeTests(void) { + /* See FloatNumberTests() for tests that really cover lots of float values */ + QCBORItem Item; QCBORError uErr; QCBORDecodeContext DC; @@ -872,10 +854,10 @@ int32_t GeneralFloatDecodeTests(void) #ifndef USEFULBUF_DISABLE_ALL_FLOAT #ifndef QCBOR_DISABLE_FLOAT_HW_USE || Item.uDataType != QCBOR_TYPE_DOUBLE - || CHECK_EXPECTED_DOUBLE(3.14, Item.val.dfnum) + || 3.1400001049041748 != Item.val.dfnum #else /* QCBOR_DISABLE_FLOAT_HW_USE */ || Item.uDataType != QCBOR_TYPE_FLOAT - || CHECK_EXPECTED_DOUBLE(3.14, Item.val.fnum) + || 3.140000f != Item.val.fnum #endif /* QCBOR_DISABLE_FLOAT_HW_USE */ #else /* USEFULBUF_DISABLE_ALL_FLOAT */ || Item.uDataType != QCBOR_TYPE_NONE @@ -893,7 +875,7 @@ int32_t GeneralFloatDecodeTests(void) || Item.val.dfnum != 0.0 #else /* QCBOR_DISABLE_FLOAT_HW_USE */ || Item.uDataType != QCBOR_TYPE_FLOAT - || Item.val.fnum != 0.0 + || Item.val.fnum != 0.0f #endif /* QCBOR_DISABLE_FLOAT_HW_USE */ #else /* USEFULBUF_DISABLE_ALL_FLOAT */ || Item.uDataType != QCBOR_TYPE_NONE diff --git a/3rdparty/exported/QCBOR/test/float_tests.h b/3rdparty/exported/QCBOR/test/float_tests.h index 54daa3fdd3a9..cfc2e6ecd6ab 100644 --- a/3rdparty/exported/QCBOR/test/float_tests.h +++ b/3rdparty/exported/QCBOR/test/float_tests.h @@ -1,11 +1,11 @@ /*============================================================================== - float_tests.h -- tests for float and conversion to/from half-precision + float_tests.h -- tests for floats and conversion to/from half-precision - Copyright (c) 2018-2020, Laurence Lundblade. All rights reserved. + Copyright (c) 2018-2024, Laurence Lundblade. All rights reserved. SPDX-License-Identifier: BSD-3-Clause - See BSD-3-Clause license in README.md + See BSD-3-Clause license in file named "LICENSE" Created on 9/19/18 =============================================================================*/ @@ -17,22 +17,35 @@ #ifndef QCBOR_DISABLE_PREFERRED_FLOAT -int32_t HalfPrecisionDecodeBasicTests(void); - -int32_t DoubleAsSmallestTest(void); - +/* This tests a large number half-precision values + * in the conversion to/from half/double against + * the sample code in the CBOR RFC. */ int32_t HalfPrecisionAgainstRFCCodeTest(void); #endif /* QCBOR_DISABLE_PREFERRED_FLOAT */ + +/* + * This tests floating point encoding, decoding + * and conversion for lots of different values. + * It covers Preferred Serialization processing + * of floating point. It's focus is on the numbers + * not the encode/decode functions. + */ +int32_t FloatValuesTests(void); + + /* - This calls each and every method for encoding - floating-point numbers. + * This calls each and every method for encoding + * floating-point numbers. */ int32_t GeneralFloatEncodeTests(void); + /* - Tests basic float decoding. + * Tests float decoding, including error codes in scenarios + * where various float features are disabled. This also + * tests decoding using spiffy decode methods. */ int32_t GeneralFloatDecodeTests(void); diff --git a/3rdparty/exported/QCBOR/test/half_to_double_from_rfc7049.c b/3rdparty/exported/QCBOR/test/half_to_double_from_rfc7049.c index d4fded63c440..9b7aeaabf832 100644 --- a/3rdparty/exported/QCBOR/test/half_to_double_from_rfc7049.c +++ b/3rdparty/exported/QCBOR/test/half_to_double_from_rfc7049.c @@ -36,7 +36,7 @@ #include #ifndef USEFULBUF_DISABLE_ALL_FLOAT -double decode_half(unsigned char *halfp) { +double decode_half(const unsigned char *halfp) { int half = (halfp[0] << 8) + halfp[1]; int exp = (half >> 10) & 0x1f; int mant = half & 0x3ff; diff --git a/3rdparty/exported/QCBOR/test/half_to_double_from_rfc7049.h b/3rdparty/exported/QCBOR/test/half_to_double_from_rfc7049.h index 6318f8027c6a..aa3b4c35b0ca 100644 --- a/3rdparty/exported/QCBOR/test/half_to_double_from_rfc7049.h +++ b/3rdparty/exported/QCBOR/test/half_to_double_from_rfc7049.h @@ -6,7 +6,7 @@ SPDX-License-Identifier: BSD-3-Clause - See BSD-3-Clause license in README.md + See BSD-3-Clause license in file named "LICENSE" Created on 9/23/18 ============================================================================*/ @@ -15,7 +15,7 @@ #define half_to_double_from_rfc7049_h #ifndef USEFULBUF_DISABLE_ALL_FLOAT -double decode_half(unsigned char *halfp); +double decode_half(const unsigned char *halfp); #endif /* USEFULBUF_DISABLE_ALL_FLOAT */ #endif /* half_to_double_from_rfc7049_h */ diff --git a/3rdparty/exported/QCBOR/test/not_well_formed_cbor.h b/3rdparty/exported/QCBOR/test/not_well_formed_cbor.h index e50588716720..c3257686854f 100644 --- a/3rdparty/exported/QCBOR/test/not_well_formed_cbor.h +++ b/3rdparty/exported/QCBOR/test/not_well_formed_cbor.h @@ -7,7 +7,7 @@ SPDX-License-Identifier: BSD-3-Clause - See BSD-3-Clause license in README.md + See BSD-3-Clause license in file named "LICENSE" Created on 7/27/19 ==============================================================================*/ @@ -159,9 +159,10 @@ static const struct someBinaryBytes paNotWellFormedCBOR[] = { {(uint8_t[]){0xa1, 0xff, 0x00}, 3}, // Array of length 1 with 2nd member value replaced by a break {(uint8_t[]){0xa1, 0x00, 0xff}, 3}, - // Map of length 2 with 2nd member replaced by a break - {(uint8_t[]){0xa2, 0x00, 0x00, 0xff}, 4}, - + // Map of length 2 with 2nd entry label replaced by a break + {(uint8_t[]){0xa2, 0x00, 0x00, 0xff, 0x00}, 5}, + // Map of length 2 with 2nd entry value replaced by a break + {(uint8_t[]){0xa2, 0x00, 0x00, 0x00, 0xff}, 5}, // Breaks must not occur on their own out of an indefinite length // data item diff --git a/3rdparty/exported/QCBOR/test/qcbor_decode_tests.c b/3rdparty/exported/QCBOR/test/qcbor_decode_tests.c index e913854d7a3d..910d43af7efc 100644 --- a/3rdparty/exported/QCBOR/test/qcbor_decode_tests.c +++ b/3rdparty/exported/QCBOR/test/qcbor_decode_tests.c @@ -1,12 +1,12 @@ /*============================================================================== - Copyright (c) 2016-2018, The Linux Foundation. - Copyright (c) 2018-2022, Laurence Lundblade. - Copyright (c) 2021, Arm Limited. - All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: + * Copyright (c) 2016-2018, The Linux Foundation. + * Copyright (c) 2018-2024, Laurence Lundblade. + * Copyright (c) 2021, Arm Limited. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above @@ -63,6 +63,22 @@ static void PrintUsefulBufC(const char *szLabel, UsefulBufC Buf) } #endif /* PRINT_FUNCTIONS_FOR_DEBUGGING */ + +/* Make a test results code that includes three components. Return code + * is xxxyyyzzz where zz is the error code, yy is the test number and + * zz is check being performed + */ +static int32_t +MakeTestResultCode(uint32_t uTestCase, + uint32_t uTestNumber, + QCBORError uErrorCode) +{ + uint32_t uCode = (uTestCase * 1000000) + + (uTestNumber * 1000) + + (uint32_t)uErrorCode; + return (int32_t)uCode; +} + /* [ -9223372036854775808, @@ -1011,7 +1027,7 @@ int32_t ParseTooDeepArrayTest(void) UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spTooDeepArrays), QCBOR_DECODE_MODE_NORMAL); - for(i = 0; i < QCBOR_MAX_ARRAY_NESTING1; i++) { + for(i = 0; i < QCBOR_MAX_ARRAY_NESTING; i++) { if(QCBORDecode_GetNext(&DCtx, &Item) != 0 || Item.uDataType != QCBOR_TYPE_ARRAY || @@ -1081,6 +1097,49 @@ int32_t ShortBufferParseTest2(void) return(nReturn); } + +/* This test requires indef strings, HW float and preferred float,... */ +#if !defined(QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS) && \ + !defined(QCBOR_DISABLE_FLOAT_HW_USE) && \ + !defined(QCBOR_DISABLE_PREFERRED_FLOAT) && \ + !defined(QCBOR_DISABLE_TAGS) && \ + !defined(QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS) + +static const uint8_t pPerverseLabels[] = { + 0xae, + + 0xf5, 0x61, 0x61, + + 0xf6, 0x61, 0x62, + + 0xf8, 0xff, 0x61, 0x63, + + 0xf9, 0x7e, 0x00, 0x61, 0x64, + + 0xfa, 0x7f, 0x7f, 0xff, 0xff, 0x61, 0x65, + + 0xfb, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x61, 0x66, + + 0xa1, 0x19, 0x03, 0xe8, 0x10, 0x61, 0x67, + + 0x81, 0x81, 0x81, 0x80, 0x61, 0x68, + + 0xc1, 0x09, 0x61, 0x69, + + 0x82, 0x05, 0xa2, 0x01, 0x02, 0x03, 0x04, 0x61, 0x6a, + + 0xbf, 0xff, 0x61, 0x6b, + + 0x9f, 0x11, 0x12, 0x13, 0xff, 0x61, 0x6c, + + 0x7f, 0x62, 0x41, 0x42, 0x62, 0x43, 0x44, 0xff, 0x61, 0x6d, + + 0xd9, 0x01, 0x02, 0xbf, 0x7f, 0x61, 0x4a, 0x61, 0x4b, 0xff, 0x00, 0xf4, 0xd7, 0x80 ,0xff, 0x61, 0x6e +}; +#endif + + +#ifndef QCBOR_DISABLE_NON_INTEGER_LABELS /* Decode and thoroughly check a moderately complex set of maps. Can be run in QCBOR_DECODE_MODE_NORMAL or in @@ -1208,6 +1267,39 @@ static int32_t ParseMapTest1(QCBORDecodeMode nMode) return 0; } +#endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */ + +/* This test requires indef strings, HW float and preferred float,... */ +#if !defined(QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS) && \ + !defined(QCBOR_DISABLE_FLOAT_HW_USE) && \ + !defined(QCBOR_DISABLE_PREFERRED_FLOAT) && \ + !defined(QCBOR_DISABLE_TAGS) && \ + !defined(QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS) + +/* Utility to decode a one byte string and match to letter. */ +static QCBORError +CheckOneLetterString(QCBORDecodeContext *pDecode, uint8_t letter) +{ + UsefulBufC Text; + QCBORError uErr; + + QCBORDecode_GetTextString(pDecode, &Text); + uErr = QCBORDecode_GetError(pDecode); + if(uErr) { + return uErr; + } + + if(Text.len != 1) { + return QCBOR_ERR_FIRST_USER_DEFINED; + } + + if(*(const uint8_t *)Text.ptr != letter) { + return QCBOR_ERR_FIRST_USER_DEFINED; + } + + return QCBOR_SUCCESS; +} +#endif /* @@ -1217,23 +1309,23 @@ static int32_t ParseMapTest1(QCBORDecodeMode nMode) int32_t ParseMapAsArrayTest(void) { QCBORDecodeContext DCtx; - QCBORItem Item; - QCBORError nCBORError; + QCBORItem Item; + QCBORError uErr; QCBORDecode_Init(&DCtx, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(pValidMapEncoded), QCBOR_DECODE_MODE_MAP_AS_ARRAY); - if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { - return (int32_t)nCBORError; + if((uErr = QCBORDecode_GetNext(&DCtx, &Item))) { + return MakeTestResultCode(1, 1, uErr); } if(Item.uDataType != QCBOR_TYPE_MAP_AS_ARRAY || Item.val.uCount != 6) { return -1; } - if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { - return (int32_t)nCBORError; + if((uErr = QCBORDecode_GetNext(&DCtx, &Item))) { + return (int32_t)uErr; } if(Item.uDataType != QCBOR_TYPE_TEXT_STRING || Item.uDataAlloc || @@ -1243,8 +1335,8 @@ int32_t ParseMapAsArrayTest(void) return -2; } - if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { - return (int32_t)nCBORError; + if((uErr = QCBORDecode_GetNext(&DCtx, &Item))) { + return (int32_t)uErr; } if(Item.uLabelType != QCBOR_TYPE_NONE || Item.uDataType != QCBOR_TYPE_INT64 || @@ -1254,8 +1346,8 @@ int32_t ParseMapAsArrayTest(void) return -3; } - if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { - return (int32_t)nCBORError; + if((uErr = QCBORDecode_GetNext(&DCtx, &Item))) { + return (int32_t)uErr; } if(Item.uLabelType != QCBOR_TYPE_NONE || Item.uDataAlloc || @@ -1265,8 +1357,8 @@ int32_t ParseMapAsArrayTest(void) return -4; } - if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { - return (int32_t)nCBORError; + if((uErr = QCBORDecode_GetNext(&DCtx, &Item))) { + return (int32_t)uErr; } if(Item.uLabelType != QCBOR_TYPE_NONE || Item.uDataAlloc || @@ -1276,8 +1368,8 @@ int32_t ParseMapAsArrayTest(void) return -5; } - if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { - return (int32_t)nCBORError; + if((uErr = QCBORDecode_GetNext(&DCtx, &Item))) { + return (int32_t)uErr; } if(Item.uDataType != QCBOR_TYPE_TEXT_STRING || Item.val.string.len != 7 || @@ -1287,8 +1379,8 @@ int32_t ParseMapAsArrayTest(void) return -6; } - if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { - return (int32_t)nCBORError; + if((uErr = QCBORDecode_GetNext(&DCtx, &Item))) { + return (int32_t)uErr; } if(Item.uDataType != QCBOR_TYPE_TEXT_STRING || Item.uDataAlloc || @@ -1298,8 +1390,8 @@ int32_t ParseMapAsArrayTest(void) } - if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { - return (int32_t)nCBORError; + if((uErr = QCBORDecode_GetNext(&DCtx, &Item))) { + return (int32_t)uErr; } if(Item.uLabelType != QCBOR_TYPE_NONE || Item.uDataAlloc || @@ -1308,8 +1400,8 @@ int32_t ParseMapAsArrayTest(void) return -8; } - if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { - return (int32_t)nCBORError; + if((uErr = QCBORDecode_GetNext(&DCtx, &Item))) { + return (int32_t)uErr; } if(Item.uLabelType != QCBOR_TYPE_NONE || Item.uDataAlloc || @@ -1319,8 +1411,8 @@ int32_t ParseMapAsArrayTest(void) return -9; } - if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { - return (int32_t)nCBORError; + if((uErr = QCBORDecode_GetNext(&DCtx, &Item))) { + return (int32_t)uErr; } if(Item.uLabelType != QCBOR_TYPE_NONE || UsefulBufCompareToSZ(Item.val.string, "bytes 1") || @@ -1330,8 +1422,8 @@ int32_t ParseMapAsArrayTest(void) return -10; } - if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { - return (int32_t)nCBORError; + if((uErr = QCBORDecode_GetNext(&DCtx, &Item))) { + return (int32_t)uErr; } if(Item.uLabelType != QCBOR_TYPE_NONE || Item.uDataType != QCBOR_TYPE_BYTE_STRING || @@ -1341,8 +1433,8 @@ int32_t ParseMapAsArrayTest(void) return -11; } - if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { - return (int32_t)nCBORError; + if((uErr = QCBORDecode_GetNext(&DCtx, &Item))) { + return (int32_t)uErr; } if(Item.uLabelType != QCBOR_TYPE_NONE || UsefulBufCompareToSZ(Item.val.string, "bytes 2") || @@ -1352,8 +1444,8 @@ int32_t ParseMapAsArrayTest(void) return -12; } - if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { - return (int32_t)nCBORError; + if((uErr = QCBORDecode_GetNext(&DCtx, &Item))) { + return (int32_t)uErr; } if(Item.uLabelType != QCBOR_TYPE_NONE || Item.uDataType != QCBOR_TYPE_BYTE_STRING || @@ -1363,8 +1455,8 @@ int32_t ParseMapAsArrayTest(void) return -13; } - if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { - return (int32_t)nCBORError; + if((uErr = QCBORDecode_GetNext(&DCtx, &Item))) { + return (int32_t)uErr; } if(Item.uLabelType != QCBOR_TYPE_NONE || Item.uDataAlloc || @@ -1374,8 +1466,8 @@ int32_t ParseMapAsArrayTest(void) return -14; } - if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { - return (int32_t)nCBORError; + if((uErr = QCBORDecode_GetNext(&DCtx, &Item))) { + return (int32_t)uErr; } if(Item.uLabelType != QCBOR_TYPE_NONE || Item.uDataAlloc || @@ -1385,8 +1477,8 @@ int32_t ParseMapAsArrayTest(void) return -15; } - if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { - return (int32_t)nCBORError; + if((uErr = QCBORDecode_GetNext(&DCtx, &Item))) { + return (int32_t)uErr; } if(Item.uLabelType != QCBOR_TYPE_NONE || UsefulBufCompareToSZ(Item.val.string, "text 2") || @@ -1396,8 +1488,8 @@ int32_t ParseMapAsArrayTest(void) return -16; } - if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { - return (int32_t)nCBORError; + if((uErr = QCBORDecode_GetNext(&DCtx, &Item))) { + return (int32_t)uErr; } if(Item.uLabelType != QCBOR_TYPE_NONE || Item.uDataType != QCBOR_TYPE_TEXT_STRING || @@ -1423,7088 +1515,9115 @@ int32_t ParseMapAsArrayTest(void) return -50; } - // TODO: test decoding of labels that are arrays or such - // TODO: test spiffy decoding of QCBOR_DECODE_MODE_MAP_AS_ARRAY - - return 0; -} - + /* This test requires indef strings, HW float and preferred float,... */ +#if !defined(QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS) && \ + !defined(QCBOR_DISABLE_FLOAT_HW_USE) && \ + !defined(QCBOR_DISABLE_PREFERRED_FLOAT) && \ + !defined(QCBOR_DISABLE_TAGS) && \ + !defined(QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS) -/* - Fully or partially decode pValidMapEncoded. When - partially decoding check for the right error code. - How much partial decoding depends on nLevel. - - The partial decodes test error conditions of - incomplete encoded input. - - This could be combined with the above test - and made prettier and maybe a little more - thorough. - */ -static int32_t ExtraBytesTest(int nLevel) -{ - QCBORDecodeContext DCtx; - QCBORItem Item; - QCBORError nCBORError; + UsefulBufC Encoded; + /* Big decode of a map with a wide variety or labels */ QCBORDecode_Init(&DCtx, - (UsefulBufC){pValidMapEncoded, sizeof(pValidMapEncoded)}, - QCBOR_DECODE_MODE_NORMAL); + UsefulBuf_FROM_BYTE_ARRAY_LITERAL(pPerverseLabels), + QCBOR_DECODE_MODE_MAP_AS_ARRAY); + UsefulBuf_MAKE_STACK_UB(Pool, 100); + QCBORDecode_SetMemPool(&DCtx, Pool, 0); - if(nLevel < 1) { - if(QCBORDecode_Finish(&DCtx) != QCBOR_ERR_EXTRA_BYTES) { - return -1; - } else { - return 0; - } + uErr = QCBORDecode_GetNext(&DCtx, &Item); + if(uErr) { + return MakeTestResultCode(10, 1, uErr); + } + if(Item.uLabelType != QCBOR_TYPE_NONE || + Item.uDataType != QCBOR_TYPE_MAP_AS_ARRAY) { + return MakeTestResultCode(10, 2, 0); } - - if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { - return (int32_t)nCBORError; + uErr = QCBORDecode_GetNext(&DCtx, &Item); + if(uErr) { + return MakeTestResultCode(10, 3, uErr); + } + if(Item.uLabelType != QCBOR_TYPE_NONE || + Item.uDataType != QCBOR_TYPE_TRUE) { + return MakeTestResultCode(10, 4, 0); } - if(Item.uDataType != QCBOR_TYPE_MAP || - Item.val.uCount != 3) - return -2; - if(nLevel < 2) { - if(QCBORDecode_Finish(&DCtx) != QCBOR_ERR_ARRAY_OR_MAP_UNCONSUMED) { - return -3; - } else { - return 0; - } + uErr = QCBORDecode_GetNext(&DCtx, &Item); + if(uErr) { + return MakeTestResultCode(10, 5, uErr); + } + if(Item.uLabelType != QCBOR_TYPE_NONE || + Item.uDataType != QCBOR_TYPE_TEXT_STRING || + ((const char *)Item.val.string.ptr)[0] != 'a') { + return MakeTestResultCode(10, 6, 0); } + uErr = QCBORDecode_GetNext(&DCtx, &Item); + if(uErr) { + return MakeTestResultCode(10, 7, uErr); + } + if(Item.uLabelType != QCBOR_TYPE_NONE || + Item.uDataType != QCBOR_TYPE_NULL) { + return MakeTestResultCode(10, 8, 0); + } - if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { - return (int32_t)nCBORError; + uErr = QCBORDecode_GetNext(&DCtx, &Item); + if(uErr) { + return MakeTestResultCode(10, 9, uErr); } - if(Item.uLabelType != QCBOR_TYPE_TEXT_STRING || - Item.uDataType != QCBOR_TYPE_INT64 || - Item.val.uCount != 42 || - UsefulBufCompareToSZ(Item.label.string, "first integer")) { - return -4; + if(Item.uLabelType != QCBOR_TYPE_NONE || + Item.uDataType != QCBOR_TYPE_TEXT_STRING || + ((const char *)Item.val.string.ptr)[0] != 'b') { + return MakeTestResultCode(10, 10, 0); } - if(nLevel < 3) { - if(QCBORDecode_Finish(&DCtx) != QCBOR_ERR_ARRAY_OR_MAP_UNCONSUMED) { - return -5; - } else { - return 0; - } + uErr = QCBORDecode_GetNext(&DCtx, &Item); + if(uErr) { + return MakeTestResultCode(10, 11, uErr); + } + if(Item.uLabelType != QCBOR_TYPE_NONE || + Item.uDataType != QCBOR_TYPE_UKNOWN_SIMPLE || + Item.val.int64 != 255) { + return MakeTestResultCode(10, 12, 0); } - if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { - return (int32_t)nCBORError; + uErr = QCBORDecode_GetNext(&DCtx, &Item); + if(uErr) { + return MakeTestResultCode(10, 13, uErr); } - if(Item.uLabelType != QCBOR_TYPE_TEXT_STRING || - UsefulBufCompareToSZ(Item.label.string, "an array of two strings") || - Item.uDataType != QCBOR_TYPE_ARRAY || - Item.val.uCount != 2) { - return -6; + if(Item.uLabelType != QCBOR_TYPE_NONE || + Item.uDataType != QCBOR_TYPE_TEXT_STRING || + ((const char *)Item.val.string.ptr)[0] != 'c') { + return MakeTestResultCode(10, 14, 0); } + uErr = QCBORDecode_GetNext(&DCtx, &Item); + if(uErr) { + return MakeTestResultCode(10, 15, uErr); + } + if(Item.uLabelType != QCBOR_TYPE_NONE || + Item.uDataType != QCBOR_TYPE_DOUBLE || + !isnan(Item.val.dfnum)) { + return MakeTestResultCode(10, 16, 0); + } - if(nLevel < 4) { - if(QCBORDecode_Finish(&DCtx) != QCBOR_ERR_ARRAY_OR_MAP_UNCONSUMED) { - return -7; - } else { - return 0; - } + uErr = QCBORDecode_GetNext(&DCtx, &Item); + if(uErr) { + return MakeTestResultCode(10, 17, uErr); + } + if(Item.uLabelType != QCBOR_TYPE_NONE || + Item.uDataType != QCBOR_TYPE_TEXT_STRING || + ((const char *)Item.val.string.ptr)[0] != 'd') { + return MakeTestResultCode(10, 18, 0); } - if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { - return (int32_t)nCBORError; + uErr = QCBORDecode_GetNext(&DCtx, &Item); + if(uErr) { + return MakeTestResultCode(10, 19, uErr); } - if(Item.uDataType != QCBOR_TYPE_TEXT_STRING || - UsefulBufCompareToSZ(Item.val.string, "string1")) { - return -8; + if(Item.uLabelType != QCBOR_TYPE_NONE || + Item.uDataType != QCBOR_TYPE_DOUBLE || + Item.val.dfnum != 3.4028234663852886E+38) { + return MakeTestResultCode(10, 20, 0); } - if(nLevel < 5) { - if(QCBORDecode_Finish(&DCtx) != QCBOR_ERR_ARRAY_OR_MAP_UNCONSUMED) { - return -9; - } else { - return 0; - } + uErr = QCBORDecode_GetNext(&DCtx, &Item); + if(uErr) { + return MakeTestResultCode(10, 21, uErr); + } + if(Item.uLabelType != QCBOR_TYPE_NONE || + Item.uDataType != QCBOR_TYPE_TEXT_STRING || + ((const char *)Item.val.string.ptr)[0] != 'e') { + return MakeTestResultCode(10, 22, 0); } - if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { - return (int32_t)nCBORError; + uErr = QCBORDecode_GetNext(&DCtx, &Item); + if(uErr) { + return MakeTestResultCode(10, 23, uErr); } - if(Item.uDataType != QCBOR_TYPE_TEXT_STRING || - UsefulBufCompareToSZ(Item.val.string, "string2")) { - return -10; + if(Item.uLabelType != QCBOR_TYPE_NONE || + Item.uDataType != QCBOR_TYPE_DOUBLE || + Item.val.dfnum != -INFINITY) { + return MakeTestResultCode(10, 24, 0); } - if(nLevel < 6) { - if(QCBORDecode_Finish(&DCtx) != QCBOR_ERR_ARRAY_OR_MAP_UNCONSUMED) { - return -11; - } else { - return 0; - } + uErr = QCBORDecode_GetNext(&DCtx, &Item); + if(uErr) { + return MakeTestResultCode(10, 25, uErr); } - - if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { - return (int32_t)nCBORError; + if(Item.uLabelType != QCBOR_TYPE_NONE || + Item.uDataType != QCBOR_TYPE_TEXT_STRING || + ((const char *)Item.val.string.ptr)[0] != 'f') { + return MakeTestResultCode(10, 26, 0); } - if(Item.uLabelType != QCBOR_TYPE_TEXT_STRING || - UsefulBufCompareToSZ(Item.label.string, "map in a map") || - Item.uDataType != QCBOR_TYPE_MAP || - Item.val.uCount != 4) - return -12; - if(nLevel < 7) { - if(QCBORDecode_Finish(&DCtx) != QCBOR_ERR_ARRAY_OR_MAP_UNCONSUMED) { - return -13; - } else { - return 0; - } + uErr = QCBORDecode_GetNext(&DCtx, &Item); + if(uErr) { + return MakeTestResultCode(10, 26, uErr); + } + if(Item.uLabelType != QCBOR_TYPE_NONE || + Item.uDataType != QCBOR_TYPE_MAP_AS_ARRAY || + Item.val.uCount != 2) { + return MakeTestResultCode(10, 27, 0); } - if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { - return (int32_t)nCBORError; + uErr = QCBORDecode_GetNext(&DCtx, &Item); + if(uErr) { + return MakeTestResultCode(10, 28, uErr); } - if(Item.uLabelType != QCBOR_TYPE_TEXT_STRING || - UsefulBufCompareToSZ(Item.label.string, "bytes 1") || - Item.uDataType != QCBOR_TYPE_BYTE_STRING || - UsefulBufCompareToSZ(Item.val.string, "xxxx")) { - return -14; + if(Item.uLabelType != QCBOR_TYPE_NONE || + Item.uDataType != QCBOR_TYPE_INT64 || + Item.val.int64 != 1000) { + return MakeTestResultCode(10, 29, 0); } - if(nLevel < 8) { - if(QCBORDecode_Finish(&DCtx) != QCBOR_ERR_ARRAY_OR_MAP_UNCONSUMED) { - return -15; - } else { - return 0; - } + uErr = QCBORDecode_GetNext(&DCtx, &Item); + if(uErr) { + return MakeTestResultCode(10, 30, uErr); + } + if(Item.uLabelType != QCBOR_TYPE_NONE || + Item.uDataType != QCBOR_TYPE_INT64 || + Item.val.int64 != 16) { + return MakeTestResultCode(10, 31, 0); } - if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { - return (int32_t)nCBORError; + uErr = QCBORDecode_GetNext(&DCtx, &Item); + if(uErr) { + return MakeTestResultCode(10, 32, uErr); } - if(Item.uLabelType != QCBOR_TYPE_TEXT_STRING || - UsefulBufCompareToSZ(Item.label.string, "bytes 2") || - Item.uDataType != QCBOR_TYPE_BYTE_STRING || - UsefulBufCompareToSZ(Item.val.string, "yyyy")) { - return -16; + if(Item.uLabelType != QCBOR_TYPE_NONE || + Item.uDataType != QCBOR_TYPE_TEXT_STRING || + ((const char *)Item.val.string.ptr)[0] != 'g') { + return MakeTestResultCode(10, 33, 0); } - if(nLevel < 9) { - if(QCBORDecode_Finish(&DCtx) != QCBOR_ERR_ARRAY_OR_MAP_UNCONSUMED) { - return -17; - } else { - return 0; + for(int i = 0 ; i < 4; i++) { + uErr = QCBORDecode_GetNext(&DCtx, &Item); + if(uErr) { + return MakeTestResultCode(10, 34, uErr); + } + if(Item.uLabelType != QCBOR_TYPE_NONE || + Item.uDataType != QCBOR_TYPE_ARRAY) { + return MakeTestResultCode(10, 35, 0); + } + if(i != 3) { + if(Item.val.uCount != 1) { + return MakeTestResultCode(10, 35, 0); + } } } - - if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { - return (int32_t)nCBORError; + uErr = QCBORDecode_GetNext(&DCtx, &Item); + if(uErr) { + return MakeTestResultCode(10, 36, uErr); + } + if(Item.uLabelType != QCBOR_TYPE_NONE || + Item.uDataType != QCBOR_TYPE_TEXT_STRING || + ((const char *)Item.val.string.ptr)[0] != 'h') { + return MakeTestResultCode(10, 37, 0); } - if(Item.uLabelType != QCBOR_TYPE_TEXT_STRING || - UsefulBufCompareToSZ(Item.label.string, "another int") || - Item.uDataType != QCBOR_TYPE_INT64 || - Item.val.int64 != 98) - return -18; - if(nLevel < 10) { - if(QCBORDecode_Finish(&DCtx) != QCBOR_ERR_ARRAY_OR_MAP_UNCONSUMED) { - return -19; - } else { - return 0; - } + uErr = QCBORDecode_GetNext(&DCtx, &Item); + if(uErr) { + return MakeTestResultCode(10, 38, uErr); + } + if(Item.uLabelType != QCBOR_TYPE_NONE || + Item.uDataType != QCBOR_TYPE_DATE_EPOCH) { + return MakeTestResultCode(10, 39, 0); } - if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { - return (int32_t)nCBORError; + uErr = QCBORDecode_GetNext(&DCtx, &Item); + if(uErr) { + return MakeTestResultCode(10, 40, uErr); } - if(Item.uLabelType != QCBOR_TYPE_TEXT_STRING || - UsefulBuf_Compare(Item.label.string, UsefulBuf_FromSZ("text 2"))|| + if(Item.uLabelType != QCBOR_TYPE_NONE || Item.uDataType != QCBOR_TYPE_TEXT_STRING || - UsefulBufCompareToSZ(Item.val.string, "lies, damn lies and statistics")) { - return -20; + ((const char *)Item.val.string.ptr)[0] != 'i') { + return MakeTestResultCode(10, 41, 0); } - if(QCBORDecode_Finish(&DCtx)) { - return -21; + uErr = QCBORDecode_GetNext(&DCtx, &Item); + if(uErr) { + return MakeTestResultCode(10, 42, uErr); + } + if(Item.uLabelType != QCBOR_TYPE_NONE || + Item.uDataType != QCBOR_TYPE_ARRAY || + Item.val.uCount != 2) { + return MakeTestResultCode(10, 31, 0); } - return 0; -} + uErr = QCBORDecode_GetNext(&DCtx, &Item); + if(uErr) { + return MakeTestResultCode(10, 43, uErr); + } + if(Item.uLabelType != QCBOR_TYPE_NONE || + Item.uDataType != QCBOR_TYPE_INT64) { + return MakeTestResultCode(10, 31, 0); + } + uErr = QCBORDecode_GetNext(&DCtx, &Item); + if(uErr) { + return MakeTestResultCode(10, 44, uErr); + } + if(Item.uLabelType != QCBOR_TYPE_NONE || + Item.uDataType != QCBOR_TYPE_MAP_AS_ARRAY || + Item.val.uCount != 4) { + return MakeTestResultCode(10, 45, 0); + } + for(int i = 0 ; i < 4; i++) { + uErr = QCBORDecode_GetNext(&DCtx, &Item); + if(uErr) { + return MakeTestResultCode(10, 46, uErr); + } + if(Item.uLabelType != QCBOR_TYPE_NONE || + Item.uDataType != QCBOR_TYPE_INT64) { + return MakeTestResultCode(10, 47, 0); + } + } + uErr = QCBORDecode_GetNext(&DCtx, &Item); + if(uErr) { + return MakeTestResultCode(10, 48, uErr); + } + if(Item.uLabelType != QCBOR_TYPE_NONE || + Item.uDataType != QCBOR_TYPE_TEXT_STRING || + ((const char *)Item.val.string.ptr)[0] != 'j') { + return MakeTestResultCode(10, 49, 0); + } + uErr = QCBORDecode_GetNext(&DCtx, &Item); + if(uErr) { + return MakeTestResultCode(10, 50, uErr); + } + if(Item.uLabelType != QCBOR_TYPE_NONE || + Item.uDataType != QCBOR_TYPE_MAP_AS_ARRAY || + Item.val.uCount != UINT16_MAX) { + return MakeTestResultCode(10, 51, 0); + } -int32_t ParseMapTest(void) -{ - // Parse a moderatly complex map structure very thoroughly - int32_t nResult = ParseMapTest1(QCBOR_DECODE_MODE_NORMAL); - if(nResult) { - return nResult; + uErr = QCBORDecode_GetNext(&DCtx, &Item); + if(uErr) { + return MakeTestResultCode(10, 52, uErr); + } + if(Item.uLabelType != QCBOR_TYPE_NONE || + Item.uDataType != QCBOR_TYPE_TEXT_STRING || + ((const char *)Item.val.string.ptr)[0] != 'k') { + return MakeTestResultCode(10, 53, 0); } - // Again, but in strings-only mode. It should succeed since the input - // map has only string labels. - nResult = ParseMapTest1(QCBOR_DECODE_MODE_MAP_STRINGS_ONLY); - if(nResult) { - return nResult; + uErr = QCBORDecode_GetNext(&DCtx, &Item); + if(uErr) { + return MakeTestResultCode(10, 54, uErr); + } + if(Item.uLabelType != QCBOR_TYPE_NONE || + Item.uDataType != QCBOR_TYPE_ARRAY || + Item.val.uCount != UINT16_MAX) { + return MakeTestResultCode(10, 55, 0); } - // Again, but try to finish the decoding before the end of the - // input at 10 different place and see that the right error code - // is returned. - for(int i = 0; i < 10; i++) { - nResult = ExtraBytesTest(i); - if(nResult) { - break; + for(int i = 0 ; i < 3; i++) { + uErr = QCBORDecode_GetNext(&DCtx, &Item); + if(uErr) { + return MakeTestResultCode(10, 56, uErr); + } + if(Item.uLabelType != QCBOR_TYPE_NONE || + Item.uDataType != QCBOR_TYPE_INT64) { + return MakeTestResultCode(10, 57, 0); } } + uErr = QCBORDecode_GetNext(&DCtx, &Item); + if(uErr) { + return MakeTestResultCode(10, 58, uErr); + } + if(Item.uLabelType != QCBOR_TYPE_NONE || + Item.uDataType != QCBOR_TYPE_TEXT_STRING || + ((const char *)Item.val.string.ptr)[0] != 'l') { + return MakeTestResultCode(10, 59, 0); + } - return nResult; -} - + uErr = QCBORDecode_GetNext(&DCtx, &Item); + if(uErr) { + return MakeTestResultCode(10, 60, uErr); + } + if(Item.uLabelType != QCBOR_TYPE_NONE || + Item.uDataType != QCBOR_TYPE_TEXT_STRING || + Item.val.string.len != 4) { + return MakeTestResultCode(10, 61, 0); + } -/* The simple-values including some not well formed */ -static const uint8_t spSimpleValues[] = { - 0x8a, 0xf4, 0xf5, 0xf6, 0xf7, 0xff, 0xe0, 0xf3, - 0xf8, 0x00, 0xf8, 0x13, 0xf8, 0x1f, 0xf8, 0x20, - 0xf8, 0xff}; + uErr = QCBORDecode_GetNext(&DCtx, &Item); + if(uErr) { + return MakeTestResultCode(10, 62, uErr); + } + if(Item.uLabelType != QCBOR_TYPE_NONE || + Item.uDataType != QCBOR_TYPE_TEXT_STRING || + ((const char *)Item.val.string.ptr)[0] != 'm') { + return MakeTestResultCode(10, 63, 0); + } -int32_t ParseSimpleTest(void) -{ - QCBORDecodeContext DCtx; - QCBORItem Item; - QCBORError nCBORError; + uErr = QCBORDecode_GetNext(&DCtx, &Item); + if(uErr) { + return MakeTestResultCode(10, 64, uErr); + } + if(Item.uLabelType != QCBOR_TYPE_NONE || + Item.uDataType != QCBOR_TYPE_MAP_AS_ARRAY || + !QCBORDecode_IsTagged(&DCtx, &Item, 258) || + Item.val.uCount != UINT16_MAX) { + return MakeTestResultCode(10, 65, 0); + } + uErr = QCBORDecode_GetNext(&DCtx, &Item); + if(uErr) { + return MakeTestResultCode(10, 66, uErr); + } + if(Item.uLabelType != QCBOR_TYPE_NONE || + Item.uDataType != QCBOR_TYPE_TEXT_STRING || + Item.val.string.len != 2) { + return MakeTestResultCode(10, 67, 0); + } - QCBORDecode_Init(&DCtx, - UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spSimpleValues), - QCBOR_DECODE_MODE_NORMAL); + uErr = QCBORDecode_GetNext(&DCtx, &Item); + if(uErr) { + return MakeTestResultCode(10, 68, uErr); + } + if(Item.uLabelType != QCBOR_TYPE_NONE || + Item.uDataType != QCBOR_TYPE_INT64 || + Item.val.int64 != 0) { + return MakeTestResultCode(10, 69, 0); + } + uErr = QCBORDecode_GetNext(&DCtx, &Item); + if(uErr) { + return MakeTestResultCode(10, 70, uErr); + } + if(Item.uLabelType != QCBOR_TYPE_NONE || + Item.uDataType != QCBOR_TYPE_FALSE) { + return MakeTestResultCode(10, 71, 0); + } - if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) - return (int32_t)nCBORError; - if(Item.uDataType != QCBOR_TYPE_ARRAY || - Item.val.uCount != 10) - return -1; + uErr = QCBORDecode_GetNext(&DCtx, &Item); + if(uErr) { + return MakeTestResultCode(10, 72, uErr); + } + if(Item.uLabelType != QCBOR_TYPE_NONE || + Item.uDataType != QCBOR_TYPE_ARRAY || + !QCBORDecode_IsTagged(&DCtx, &Item, 23) || + Item.val.uCount != 0) { + return MakeTestResultCode(10, 73, 0); + } - if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) - return (int32_t)nCBORError; - if(Item.uDataType != QCBOR_TYPE_FALSE) - return -1; + uErr = QCBORDecode_GetNext(&DCtx, &Item); + if(uErr) { + return MakeTestResultCode(10, 74, uErr); + } + if(Item.uLabelType != QCBOR_TYPE_NONE || + Item.uDataType != QCBOR_TYPE_TEXT_STRING || + ((const char *)Item.val.string.ptr)[0] != 'n') { + return MakeTestResultCode(10, 75, 0); + } - if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) - return (int32_t)nCBORError; - if(Item.uDataType != QCBOR_TYPE_TRUE) - return -1; - if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) - return (int32_t)nCBORError; - if(Item.uDataType != QCBOR_TYPE_NULL) - return -1; + /* Big decode of a map with a wide variety or labels */ + QCBORDecode_Init(&DCtx, + UsefulBuf_FROM_BYTE_ARRAY_LITERAL(pPerverseLabels), + QCBOR_DECODE_MODE_MAP_AS_ARRAY); + QCBORDecode_SetMemPool(&DCtx, Pool, 0); - if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) - return (int32_t)nCBORError; - if(Item.uDataType != QCBOR_TYPE_UNDEF) - return -1; + QCBORDecode_EnterArray(&DCtx, &Item); + bool b; + QCBORDecode_GetBool(&DCtx, &b); - // A break - if(QCBORDecode_GetNext(&DCtx, &Item) != QCBOR_ERR_BAD_BREAK) - return -1; + uErr = CheckOneLetterString(&DCtx, 'a'); + if(uErr) { + return MakeTestResultCode(11, 1, uErr); + } - if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) - return (int32_t)nCBORError; - if(Item.uDataType != QCBOR_TYPE_UKNOWN_SIMPLE || Item.val.uSimple != 0) - return -1; + QCBORDecode_GetNull(&DCtx); + uErr = CheckOneLetterString(&DCtx, 'b'); + if(uErr) { + return MakeTestResultCode(11, 2, uErr); + } - if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) - return (int32_t)nCBORError; - if(Item.uDataType != QCBOR_TYPE_UKNOWN_SIMPLE || Item.val.uSimple != 19) - return -1; + QCBORDecode_VGetNext(&DCtx, &Item); + uErr = CheckOneLetterString(&DCtx, 'c'); + if(uErr) { + return MakeTestResultCode(11, 3, uErr); + } - if(QCBORDecode_GetNext(&DCtx, &Item) != QCBOR_ERR_BAD_TYPE_7) - return -1; - - if(QCBORDecode_GetNext(&DCtx, &Item) != QCBOR_ERR_BAD_TYPE_7) - return -1; - - if(QCBORDecode_GetNext(&DCtx, &Item) != QCBOR_ERR_BAD_TYPE_7) - return -1; - - if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) - return (int32_t)nCBORError; - if(Item.uDataType != QCBOR_TYPE_UKNOWN_SIMPLE || Item.val.uSimple != 32) - return -1; + double dNum; + QCBORDecode_GetDouble(&DCtx, &dNum); + if(!isnan(dNum)) { + return MakeTestResultCode(11, 4, 0); + } + uErr = CheckOneLetterString(&DCtx, 'd'); + if(uErr) { + return MakeTestResultCode(11, 5, uErr); + } - if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) - return (int32_t)nCBORError; - if(Item.uDataType != QCBOR_TYPE_UKNOWN_SIMPLE || Item.val.uSimple != 255) - return -1; + QCBORDecode_GetDouble(&DCtx, &dNum); + if( dNum != 3.4028234663852886E+38 ) { + return MakeTestResultCode(11, 6, 0); + } + uErr = CheckOneLetterString(&DCtx, 'e'); + if(uErr) { + return MakeTestResultCode(11, 7, uErr); + } - return 0; + QCBORDecode_GetDouble(&DCtx, &dNum); + if(dNum != -INFINITY) { + return MakeTestResultCode(11, 8, 0); + } + uErr = CheckOneLetterString(&DCtx, 'f'); + if(uErr) { + return MakeTestResultCode(11, 9, uErr); + } -} + int64_t nInt; + QCBORDecode_EnterArray(&DCtx, &Item); + QCBORDecode_GetInt64(&DCtx, &nInt); + QCBORDecode_GetInt64(&DCtx, &nInt); + QCBORDecode_ExitArray(&DCtx); + uErr = CheckOneLetterString(&DCtx, 'g'); + if(uErr) { + return MakeTestResultCode(11, 10, uErr); + } + QCBORDecode_EnterArray(&DCtx, &Item); + QCBORDecode_EnterArray(&DCtx, &Item); + QCBORDecode_EnterArray(&DCtx, &Item); + QCBORDecode_EnterArray(&DCtx, &Item); + QCBORDecode_ExitArray(&DCtx); + QCBORDecode_ExitArray(&DCtx); + QCBORDecode_ExitArray(&DCtx); + QCBORDecode_ExitArray(&DCtx); + uErr = CheckOneLetterString(&DCtx, 'h'); + if(uErr) { + return MakeTestResultCode(11, 11, uErr); + } + QCBORDecode_GetEpochDate(&DCtx, QCBOR_TAG_REQUIREMENT_TAG, &nInt); + uErr = CheckOneLetterString(&DCtx, 'i'); + if(uErr) { + return MakeTestResultCode(11, 12, uErr); + } -int32_t NotWellFormedTests(void) -{ - // Loop over all the not-well-formed instance of CBOR - // that are test vectors in not_well_formed_cbor.h - const uint16_t nArraySize = C_ARRAY_COUNT(paNotWellFormedCBOR, - struct someBinaryBytes); - for(uint16_t nIterate = 0; nIterate < nArraySize; nIterate++) { - const struct someBinaryBytes *pBytes = &paNotWellFormedCBOR[nIterate]; - const UsefulBufC Input = (UsefulBufC){pBytes->p, pBytes->n}; + QCBORDecode_EnterArray(&DCtx, &Item); + QCBORDecode_GetInt64(&DCtx, &nInt); + QCBORDecode_EnterArray(&DCtx, &Item); + QCBORDecode_GetInt64(&DCtx, &nInt); + QCBORDecode_GetInt64(&DCtx, &nInt); + QCBORDecode_GetInt64(&DCtx, &nInt); + QCBORDecode_GetInt64(&DCtx, &nInt); + QCBORDecode_ExitArray(&DCtx); + QCBORDecode_ExitArray(&DCtx); + uErr = CheckOneLetterString(&DCtx, 'j'); + if(uErr) { + return MakeTestResultCode(11, 13, uErr); + } - if(nIterate == 86) { - nIterate = 86; - } + QCBORDecode_GetArray(&DCtx, &Item, &Encoded); + uErr = CheckOneLetterString(&DCtx, 'k'); + if(uErr) { + return MakeTestResultCode(11, 14, uErr); + } - // Set up decoder context. String allocator needed for indefinite - // string test cases - QCBORDecodeContext DCtx; - QCBORDecode_Init(&DCtx, Input, QCBOR_DECODE_MODE_NORMAL); -#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS - UsefulBuf_MAKE_STACK_UB(Pool, 100); - QCBORDecode_SetMemPool(&DCtx, Pool, 0); -#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS */ + QCBORDecode_EnterArray(&DCtx, &Item); + QCBORDecode_GetInt64(&DCtx, &nInt); + QCBORDecode_GetInt64(&DCtx, &nInt); + QCBORDecode_GetInt64(&DCtx, &nInt); + QCBORDecode_ExitArray(&DCtx); + uErr = CheckOneLetterString(&DCtx, 'l'); + if(uErr) { + return MakeTestResultCode(11, 15, uErr); + } - // Loop getting items until no more to get - QCBORError uCBORError; - do { - QCBORItem Item; + QCBORDecode_GetTextString(&DCtx, &Encoded); + uErr = CheckOneLetterString(&DCtx, 'm'); + if(uErr) { + return MakeTestResultCode(11, 16, uErr); + } - uCBORError = QCBORDecode_GetNext(&DCtx, &Item); - } while(uCBORError == QCBOR_SUCCESS); + QCBORDecode_EnterArray(&DCtx, &Item); + if(!QCBORDecode_IsTagged(&DCtx, &Item, 258)) { + return MakeTestResultCode(11, 17, 0); + } + if(Item.uDataType != QCBOR_TYPE_MAP_AS_ARRAY) { + return MakeTestResultCode(11, 18, 0); + } + if(Item.val.uCount != UINT16_MAX) { + return MakeTestResultCode(11, 19, 0); + } + QCBORDecode_GetTextString(&DCtx, &Encoded); + if(Encoded.len != 2) { + return MakeTestResultCode(11, 20, 0); + } QCBORDecode_GetInt64(&DCtx, &nInt); + QCBORDecode_GetBool(&DCtx, &b); + if(b != false) { + return MakeTestResultCode(11, 21, 0); + } + QCBORDecode_EnterArray(&DCtx, &Item); + if(!QCBORDecode_IsTagged(&DCtx, &Item, 23)) { + return MakeTestResultCode(11, 22, 0); + } + if(Item.uDataType != QCBOR_TYPE_ARRAY) { + return MakeTestResultCode(11, 23, 0); + } + if(Item.val.uCount != 0) { + return MakeTestResultCode(11, 24, 0); + } + QCBORDecode_ExitArray(&DCtx); + QCBORDecode_ExitArray(&DCtx); + uErr = CheckOneLetterString(&DCtx, 'n'); + if(uErr) { + return MakeTestResultCode(11, 25, uErr); + } - // Every test vector must fail with - // a not-well-formed error. If not - // this test fails. - if(!QCBORDecode_IsNotWellFormedError(uCBORError) && - uCBORError != QCBOR_ERR_NO_MORE_ITEMS) { - /* Return index of failure and QCBOR error in the result */ - return (int32_t)(nIterate * 100 + uCBORError); - } + QCBORDecode_ExitArray(&DCtx); + uErr = QCBORDecode_Finish(&DCtx); + if(uErr) { + return MakeTestResultCode(11, 26, uErr); } +#endif /* QCBOR_DISABLE_... */ + return 0; } -// TODO: add a test index and report it so it is eaier to figure out which test failed. -struct FailInput { - UsefulBufC Input; - QCBORError nError; -}; +#ifndef QCBOR_DISABLE_NON_INTEGER_LABELS -static int32_t ProcessFailures(const struct FailInput *pFailInputs, size_t nNumFails) -{ - for(const struct FailInput *pF = pFailInputs; pF < pFailInputs + nNumFails; pF++) { - QCBORDecodeContext DCtx; - QCBORError uCBORError; +/* + Fully or partially decode pValidMapEncoded. When + partially decoding check for the right error code. + How much partial decoding depends on nLevel. - QCBORDecode_Init(&DCtx, pF->Input, QCBOR_DECODE_MODE_NORMAL); + The partial decodes test error conditions of + incomplete encoded input. -#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS - // Set up the decoding context including a memory pool so that - // indefinite length items can be checked - UsefulBuf_MAKE_STACK_UB(Pool, 100); + This could be combined with the above test + and made prettier and maybe a little more + thorough. + */ +static int32_t ExtraBytesTest(int nLevel) +{ + QCBORDecodeContext DCtx; + QCBORItem Item; + QCBORError nCBORError; - uCBORError = QCBORDecode_SetMemPool(&DCtx, Pool, 0); - if(uCBORError) { - return -9; - } -#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS */ + QCBORDecode_Init(&DCtx, + (UsefulBufC){pValidMapEncoded, sizeof(pValidMapEncoded)}, + QCBOR_DECODE_MODE_NORMAL); - const size_t nIndexx = (size_t)(pF - pFailInputs); - if(nIndexx == 8) { - uCBORError = 9; + if(nLevel < 1) { + if(QCBORDecode_Finish(&DCtx) != QCBOR_ERR_EXTRA_BYTES) { + return -1; + } else { + return 0; } + } - // Iterate until there is an error of some sort error - QCBORItem Item; - do { - // Set to something none-zero, something other than QCBOR_TYPE_NONE - memset(&Item, 0x33, sizeof(Item)); - - uCBORError = QCBORDecode_GetNext(&DCtx, &Item); - } while(uCBORError == QCBOR_SUCCESS); - - + if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { + return (int32_t)nCBORError; + } + if(Item.uDataType != QCBOR_TYPE_MAP || + Item.val.uCount != 3) + return -2; - // Must get the expected error or the this test fails - // The data and label type must also be QCBOR_TYPE_NONE - if(uCBORError != pF->nError || - Item.uDataType != QCBOR_TYPE_NONE || - Item.uLabelType != QCBOR_TYPE_NONE) { - // return index of CBOR + 100 - const size_t nIndex = (size_t)(pF - pFailInputs); - return (int32_t)(nIndex * 100 + uCBORError); + if(nLevel < 2) { + if(QCBORDecode_Finish(&DCtx) != QCBOR_ERR_ARRAY_OR_MAP_UNCONSUMED) { + return -3; + } else { + return 0; } } - return 0; -} + if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { + return (int32_t)nCBORError; + } + if(Item.uLabelType != QCBOR_TYPE_TEXT_STRING || + Item.uDataType != QCBOR_TYPE_INT64 || + Item.val.uCount != 42 || + UsefulBufCompareToSZ(Item.label.string, "first integer")) { + return -4; + } -static const struct FailInput Failures[] = { - // Most of this is copied from not_well_formed.h. Here the error code - // returned is also checked. + if(nLevel < 3) { + if(QCBORDecode_Finish(&DCtx) != QCBOR_ERR_ARRAY_OR_MAP_UNCONSUMED) { + return -5; + } else { + return 0; + } + } -#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS - // Indefinite length strings must be closed off - // An indefinite length byte string not closed off - { {(uint8_t[]){0x5f, 0x41, 0x00}, 3}, QCBOR_ERR_HIT_END }, - // An indefinite length text string not closed off - { {(uint8_t[]){0x7f, 0x61, 0x00}, 3}, QCBOR_ERR_HIT_END }, - - - // All the chunks in an indefinite length string must be of the type of - // indefinite length string - // indefinite length byte string with text string chunk - { {(uint8_t[]){0x5f, 0x61, 0x00, 0xff}, 4}, QCBOR_ERR_INDEFINITE_STRING_CHUNK }, - // indefinite length text string with a byte string chunk - { {(uint8_t[]){0x7f, 0x41, 0x00, 0xff}, 4}, QCBOR_ERR_INDEFINITE_STRING_CHUNK }, - // indefinite length byte string with an positive integer chunk - { {(uint8_t[]){0x5f, 0x00, 0xff}, 3}, QCBOR_ERR_INDEFINITE_STRING_CHUNK }, - // indefinite length byte string with an negative integer chunk - { {(uint8_t[]){0x5f, 0x21, 0xff}, 3}, QCBOR_ERR_INDEFINITE_STRING_CHUNK }, - // indefinite length byte string with an array chunk - { {(uint8_t[]){0x5f, 0x80, 0xff}, 3}, QCBOR_ERR_INDEFINITE_STRING_CHUNK }, - // indefinite length byte string with an map chunk - { {(uint8_t[]){0x5f, 0xa0, 0xff}, 3}, QCBOR_ERR_INDEFINITE_STRING_CHUNK }, -#ifndef QCBOR_DISABLE_TAGS - // indefinite length byte string with tagged integer chunk - { {(uint8_t[]){0x5f, 0xc0, 0x00, 0xff}, 4}, QCBOR_ERR_INDEFINITE_STRING_CHUNK }, -#else - // indefinite length byte string with tagged integer chunk - { {(uint8_t[]){0x5f, 0xc0, 0x00, 0xff}, 4}, QCBOR_ERR_TAGS_DISABLED }, -#endif /* QCBOR_DISABLE_TAGS */ - // indefinite length byte string with an simple type chunk - { {(uint8_t[]){0x5f, 0xe0, 0xff}, 3}, QCBOR_ERR_INDEFINITE_STRING_CHUNK }, - { {(uint8_t[]){0x5f, 0x5f, 0x41, 0x00, 0xff, 0xff}, 6}, QCBOR_ERR_INDEFINITE_STRING_CHUNK}, - // indefinite length text string with indefinite string inside - { {(uint8_t[]){0x7f, 0x7f, 0x61, 0x00, 0xff, 0xff}, 6}, QCBOR_ERR_INDEFINITE_STRING_CHUNK}, + if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { + return (int32_t)nCBORError; + } + if(Item.uLabelType != QCBOR_TYPE_TEXT_STRING || + UsefulBufCompareToSZ(Item.label.string, "an array of two strings") || + Item.uDataType != QCBOR_TYPE_ARRAY || + Item.val.uCount != 2) { + return -6; + } -#else /* QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS */ - { {(uint8_t[]){0x5f, 0x41, 0x00}, 3}, QCBOR_ERR_INDEF_LEN_STRINGS_DISABLED }, - // An indefinite length text string not closed off - { {(uint8_t[]){0x7f, 0x61, 0x00}, 3}, QCBOR_ERR_INDEF_LEN_STRINGS_DISABLED }, - - - // All the chunks in an indefinite length string must be of the type of - // indefinite length string - // indefinite length byte string with text string chunk - { {(uint8_t[]){0x5f, 0x61, 0x00, 0xff}, 4}, QCBOR_ERR_INDEF_LEN_STRINGS_DISABLED }, - // indefinite length text string with a byte string chunk - { {(uint8_t[]){0x7f, 0x41, 0x00, 0xff}, 4}, QCBOR_ERR_INDEF_LEN_STRINGS_DISABLED }, - // indefinite length byte string with an positive integer chunk - { {(uint8_t[]){0x5f, 0x00, 0xff}, 3}, QCBOR_ERR_INDEF_LEN_STRINGS_DISABLED }, - // indefinite length byte string with an negative integer chunk - { {(uint8_t[]){0x5f, 0x21, 0xff}, 3}, QCBOR_ERR_INDEF_LEN_STRINGS_DISABLED }, - // indefinite length byte string with an array chunk - { {(uint8_t[]){0x5f, 0x80, 0xff}, 3}, QCBOR_ERR_INDEF_LEN_STRINGS_DISABLED }, - // indefinite length byte string with an map chunk - { {(uint8_t[]){0x5f, 0xa0, 0xff}, 3}, QCBOR_ERR_INDEF_LEN_STRINGS_DISABLED }, - // indefinite length byte string with tagged integer chunk - { {(uint8_t[]){0x5f, 0xc0, 0x00, 0xff}, 4}, QCBOR_ERR_INDEF_LEN_STRINGS_DISABLED }, - // indefinite length byte string with an simple type chunk - { {(uint8_t[]){0x5f, 0xe0, 0xff}, 3}, QCBOR_ERR_INDEF_LEN_STRINGS_DISABLED }, - { {(uint8_t[]){0x5f, 0x5f, 0x41, 0x00, 0xff, 0xff}, 6}, QCBOR_ERR_INDEF_LEN_STRINGS_DISABLED}, - // indefinite length text string with indefinite string inside - { {(uint8_t[]){0x7f, 0x7f, 0x61, 0x00, 0xff, 0xff}, 6}, QCBOR_ERR_INDEF_LEN_STRINGS_DISABLED}, -#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS */ + if(nLevel < 4) { + if(QCBORDecode_Finish(&DCtx) != QCBOR_ERR_ARRAY_OR_MAP_UNCONSUMED) { + return -7; + } else { + return 0; + } + } - // Definte length maps and arrays must be closed by having the right number of items - // A definte length array that is supposed to have 1 item, but has none - { {(uint8_t[]){0x81}, 1}, QCBOR_ERR_NO_MORE_ITEMS }, - // A definte length array that is supposed to have 2 items, but has only 1 - { {(uint8_t[]){0x82, 0x00}, 2}, QCBOR_ERR_NO_MORE_ITEMS }, - // A definte length array that is supposed to have 511 items, but has only 1 - { {(uint8_t[]){0x9a, 0x01, 0xff, 0x00}, 4}, QCBOR_ERR_HIT_END }, - // A definte length map that is supposed to have 1 item, but has none - { {(uint8_t[]){0xa1}, 1}, QCBOR_ERR_NO_MORE_ITEMS }, - // A definte length map that is supposed to have s item, but has only 1 - { {(uint8_t[]){0xa2, 0x01, 0x02}, 3}, QCBOR_ERR_NO_MORE_ITEMS }, + if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { + return (int32_t)nCBORError; + } + if(Item.uDataType != QCBOR_TYPE_TEXT_STRING || + UsefulBufCompareToSZ(Item.val.string, "string1")) { + return -8; + } -#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS - // Indefinte length maps and arrays must be ended by a break - // Indefinite length array with zero items and no break - { {(uint8_t[]){0x9f}, 1}, QCBOR_ERR_NO_MORE_ITEMS }, - // Indefinite length array with two items and no break - { {(uint8_t[]){0x9f, 0x01, 0x02}, 3}, QCBOR_ERR_NO_MORE_ITEMS }, - // Indefinite length map with zero items and no break - { {(uint8_t[]){0xbf}, 1}, QCBOR_ERR_NO_MORE_ITEMS }, - // Indefinite length map with two items and no break - { {(uint8_t[]){0xbf, 0x01, 0x02, 0x01, 0x02}, 5}, QCBOR_ERR_NO_MORE_ITEMS }, - - - // Nested maps and arrays must be closed off (some extra nested test vectors) - // Unclosed indefinite array containing a closed definite length array - { {(uint8_t[]){0x9f, 0x80, 0x00}, 3}, QCBOR_ERR_NO_MORE_ITEMS }, - // Definite length array containing an unclosed indefinite length array - { {(uint8_t[]){0x81, 0x9f}, 2}, QCBOR_ERR_NO_MORE_ITEMS }, - // Unclosed indefinite map containing a closed definite length array - { {(uint8_t[]){0xbf, 0x01, 0x80, 0x00, 0xa0}, 5}, QCBOR_ERR_NO_MORE_ITEMS }, - // Definite length map containing an unclosed indefinite length array - { {(uint8_t[]){0xa1, 0x02, 0x9f}, 3}, QCBOR_ERR_NO_MORE_ITEMS }, - // Deeply nested definite length arrays with deepest one unclosed - { {(uint8_t[]){0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81}, 9}, QCBOR_ERR_NO_MORE_ITEMS }, - // Deeply nested indefinite length arrays with deepest one unclosed - { {(uint8_t[]){0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0xff, 0xff, 0xff, 0xff}, 9}, QCBOR_ERR_NO_MORE_ITEMS }, - // Mixed nesting with indefinite unclosed - { {(uint8_t[]){0x9f, 0x81, 0x9f, 0x81, 0x9f, 0x9f, 0xff, 0xff, 0xff}, 9}, QCBOR_ERR_NO_MORE_ITEMS }, - // Mixed nesting with definite unclosed - { {(uint8_t[]){0x9f, 0x82, 0x9f, 0x81, 0x9f, 0x9f, 0xff, 0xff, 0xff, 0xff}, 10}, QCBOR_ERR_BAD_BREAK }, - // Unclosed indefinite length map in definite length maps - { {(uint8_t[]){0xa1, 0x01, 0xa2, 0x02, 0xbf, 0xff, 0x02, 0xbf}, 8}, - QCBOR_ERR_NO_MORE_ITEMS}, - // Unclosed definite length map in indefinite length maps - { {(uint8_t[]){0xbf, 0x01, 0xbf, 0x02, 0xa1}, 5}, QCBOR_ERR_NO_MORE_ITEMS}, - // Unclosed indefinite length array in definite length maps - { {(uint8_t[]){0xa1, 0x01, 0xa2, 0x02, 0x9f, 0xff, 0x02, 0x9f}, 8}, - QCBOR_ERR_NO_MORE_ITEMS}, - // Unclosed definite length array in indefinite length maps - { {(uint8_t[]){0xbf, 0x01, 0xbf, 0x02, 0x81}, 5}, QCBOR_ERR_NO_MORE_ITEMS}, - // Unclosed indefinite length map in definite length arrays - { {(uint8_t[]){0x81, 0x82, 0xbf, 0xff, 0xbf}, 5}, QCBOR_ERR_NO_MORE_ITEMS}, - // Unclosed definite length map in indefinite length arrays - { {(uint8_t[]){0x9f, 0x9f, 0xa1}, 3}, QCBOR_ERR_NO_MORE_ITEMS}, -#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS */ + if(nLevel < 5) { + if(QCBORDecode_Finish(&DCtx) != QCBOR_ERR_ARRAY_OR_MAP_UNCONSUMED) { + return -9; + } else { + return 0; + } + } - // The "argument" for the data item is incomplete - // Positive integer missing 1 byte argument - { {(uint8_t[]){0x18}, 1}, QCBOR_ERR_HIT_END }, - // Positive integer missing 2 byte argument - { {(uint8_t[]){0x19}, 1}, QCBOR_ERR_HIT_END }, - // Positive integer missing 4 byte argument - { {(uint8_t[]){0x1a}, 1}, QCBOR_ERR_HIT_END }, - // Positive integer missing 8 byte argument - { {(uint8_t[]){0x1b}, 1}, QCBOR_ERR_HIT_END }, - // Positive integer missing 1 byte of 2 byte argument - { {(uint8_t[]){0x19, 0x01}, 2}, QCBOR_ERR_HIT_END }, - // Positive integer missing 2 bytes of 4 byte argument - { {(uint8_t[]){0x1a, 0x01, 0x02}, 3}, QCBOR_ERR_HIT_END }, - // Positive integer missing 1 bytes of 7 byte argument - { {(uint8_t[]){0x1b, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07}, 8}, QCBOR_ERR_HIT_END }, - // Negative integer missing 1 byte argument - { {(uint8_t[]){0x38}, 1}, QCBOR_ERR_HIT_END }, - // Binary string missing 1 byte argument - { {(uint8_t[]){0x58}, 1}, QCBOR_ERR_HIT_END }, - // Text string missing 1 byte argument - { {(uint8_t[]){0x78}, 1}, QCBOR_ERR_HIT_END }, - // Array missing 1 byte argument - { {(uint8_t[]){0x98}, 1}, QCBOR_ERR_HIT_END }, - // Map missing 1 byte argument - { {(uint8_t[]){0xb8}, 1}, QCBOR_ERR_HIT_END }, - // Tag missing 1 byte argument - { {(uint8_t[]){0xd8}, 1}, QCBOR_ERR_HIT_END }, - // Simple missing 1 byte argument - { {(uint8_t[]){0xf8}, 1}, QCBOR_ERR_HIT_END }, - // half-precision with 1 byte argument - { {(uint8_t[]){0xf9, 0x00}, 2}, QCBOR_ERR_HIT_END }, - // single-precision with 2 byte argument - { {(uint8_t[]){0xfa, 0x00, 0x00}, 3}, QCBOR_ERR_HIT_END }, - // double-precision with 3 byte argument - { {(uint8_t[]){0xfb, 0x00, 0x00, 0x00}, 4}, QCBOR_ERR_HIT_END }, + if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { + return (int32_t)nCBORError; + } + if(Item.uDataType != QCBOR_TYPE_TEXT_STRING || + UsefulBufCompareToSZ(Item.val.string, "string2")) { + return -10; + } -#ifndef QCBOR_DISABLE_TAGS - // Tag with no content - { {(uint8_t[]){0xc0}, 1}, QCBOR_ERR_HIT_END }, -#else /* QCBOR_DISABLE_TAGS */ - { {(uint8_t[]){0xc0}, 1}, QCBOR_ERR_TAGS_DISABLED }, -#endif /* QCBOR_DISABLE_TAGS */ + if(nLevel < 6) { + if(QCBORDecode_Finish(&DCtx) != QCBOR_ERR_ARRAY_OR_MAP_UNCONSUMED) { + return -11; + } else { + return 0; + } + } - // Breaks must not occur in definite length arrays and maps - // Array of length 1 with sole member replaced by a break - { {(uint8_t[]){0x81, 0xff}, 2}, QCBOR_ERR_BAD_BREAK }, - // Array of length 2 with 2nd member replaced by a break - { {(uint8_t[]){0x82, 0x00, 0xff}, 3}, QCBOR_ERR_BAD_BREAK }, - // Map of length 1 with sole member label replaced by a break - { {(uint8_t[]){0xa1, 0xff}, 2}, QCBOR_ERR_BAD_BREAK }, - // Map of length 1 with sole member label replaced by break - // Alternate representation that some decoders handle differently - { {(uint8_t[]){0xa1, 0xff, 0x00}, 3}, QCBOR_ERR_BAD_BREAK }, - // Array of length 1 with 2nd member value replaced by a break - { {(uint8_t[]){0xa1, 0x00, 0xff}, 3}, QCBOR_ERR_BAD_BREAK }, - // Map of length 2 with 2nd member replaced by a break - { {(uint8_t[]){0xa2, 0x00, 0x00, 0xff}, 4}, QCBOR_ERR_BAD_BREAK }, - - - // Breaks must not occur on their own out of an indefinite length data item - // A bare break is not well formed - { {(uint8_t[]){0xff}, 1}, QCBOR_ERR_BAD_BREAK }, - // A bare break after a zero length definite length array - { {(uint8_t[]){0x80, 0xff}, 2}, QCBOR_ERR_BAD_BREAK }, -#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS - // A bare break after a zero length indefinite length map - { {(uint8_t[]){0x9f, 0xff, 0xff}, 3}, QCBOR_ERR_BAD_BREAK }, - // A break inside a definite length array inside an indefenite length array - { {(uint8_t[]){0x9f, 0x81, 0xff}, 3}, QCBOR_ERR_BAD_BREAK }, - // Complicated mixed nesting with break outside indefinite length array - { {(uint8_t[]){0x9f, 0x82, 0x9f, 0x81, 0x9f, 0x9f, 0xff, 0xff, 0xff, 0xff}, 10}, QCBOR_ERR_BAD_BREAK }, -#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS */ + if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { + return (int32_t)nCBORError; + } + if(Item.uLabelType != QCBOR_TYPE_TEXT_STRING || + UsefulBufCompareToSZ(Item.label.string, "map in a map") || + Item.uDataType != QCBOR_TYPE_MAP || + Item.val.uCount != 4) + return -12; + if(nLevel < 7) { + if(QCBORDecode_Finish(&DCtx) != QCBOR_ERR_ARRAY_OR_MAP_UNCONSUMED) { + return -13; + } else { + return 0; + } + } - // Forbidden two byte encodings of simple types - // Must use 0xe0 instead - { {(uint8_t[]){0xf8, 0x00}, 2}, QCBOR_ERR_BAD_TYPE_7 }, - // Should use 0xe1 instead - { {(uint8_t[]){0xf8, 0x01}, 2}, QCBOR_ERR_BAD_TYPE_7 }, - // Should use 0xe2 instead - { {(uint8_t[]){0xf8, 0x02}, 2}, QCBOR_ERR_BAD_TYPE_7 }, - // Should use 0xe3 instead - { {(uint8_t[]){0xf8, 0x03}, 2}, QCBOR_ERR_BAD_TYPE_7 }, - // Should use 0xe4 instead - { {(uint8_t[]){0xf8, 0x04}, 2}, QCBOR_ERR_BAD_TYPE_7 }, - // Should use 0xe5 instead - { {(uint8_t[]){0xf8, 0x05}, 2}, QCBOR_ERR_BAD_TYPE_7 }, - // Should use 0xe6 instead - { {(uint8_t[]){0xf8, 0x06}, 2}, QCBOR_ERR_BAD_TYPE_7 }, - // Should use 0xe7 instead - { {(uint8_t[]){0xf8, 0x07}, 2}, QCBOR_ERR_BAD_TYPE_7 }, - // Should use 0xe8 instead - { {(uint8_t[]){0xf8, 0x08}, 2}, QCBOR_ERR_BAD_TYPE_7 }, - // Should use 0xe9 instead - { {(uint8_t[]){0xf8, 0x09}, 2}, QCBOR_ERR_BAD_TYPE_7 }, - // Should use 0xea instead - { {(uint8_t[]){0xf8, 0x0a}, 2}, QCBOR_ERR_BAD_TYPE_7 }, - // Should use 0xeb instead - { {(uint8_t[]){0xf8, 0x0b}, 2}, QCBOR_ERR_BAD_TYPE_7 }, - // Should use 0xec instead - { {(uint8_t[]){0xf8, 0x0c}, 2}, QCBOR_ERR_BAD_TYPE_7 }, - // Should use 0xed instead - { {(uint8_t[]){0xf8, 0x0d}, 2}, QCBOR_ERR_BAD_TYPE_7 }, - // Should use 0xee instead - { {(uint8_t[]){0xf8, 0x0e}, 2}, QCBOR_ERR_BAD_TYPE_7 }, - // Should use 0xef instead - { {(uint8_t[]){0xf8, 0x0f}, 2}, QCBOR_ERR_BAD_TYPE_7 }, - // Should use 0xf0 instead - { {(uint8_t[]){0xf8, 0x10}, 2}, QCBOR_ERR_BAD_TYPE_7 }, - // Should use 0xf1 instead - { {(uint8_t[]){0xf8, 0x11}, 2}, QCBOR_ERR_BAD_TYPE_7 }, - // Should use 0xf2 instead - { {(uint8_t[]){0xf8, 0x12}, 2}, QCBOR_ERR_BAD_TYPE_7 }, - // Must use 0xf3 instead - { {(uint8_t[]){0xf8, 0x13}, 2}, QCBOR_ERR_BAD_TYPE_7 }, - // Must use 0xf4 instead - { {(uint8_t[]){0xf8, 0x14}, 2}, QCBOR_ERR_BAD_TYPE_7 }, - // Must use 0xf5 instead - { {(uint8_t[]){0xf8, 0x15}, 2}, QCBOR_ERR_BAD_TYPE_7 }, - // Must use 0xf6 instead - { {(uint8_t[]){0xf8, 0x16}, 2}, QCBOR_ERR_BAD_TYPE_7 }, - // Must use 0xf7 instead - { {(uint8_t[]){0xf8, 0x17}, 2}, QCBOR_ERR_BAD_TYPE_7 }, - // Must use 0xf8 instead - { {(uint8_t[]){0xf8, 0x18}, 2}, QCBOR_ERR_BAD_TYPE_7 }, - // Reserved - { {(uint8_t[]){0xf8, 0x1f}, 2}, QCBOR_ERR_BAD_TYPE_7 }, - - // Integers with additional info indefinite length - // Positive integer with additional info indefinite length - { {(uint8_t[]){0x1f}, 1}, QCBOR_ERR_BAD_INT }, - // Negative integer with additional info indefinite length - { {(uint8_t[]){0x3f}, 1}, QCBOR_ERR_BAD_INT }, + if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { + return (int32_t)nCBORError; + } + if(Item.uLabelType != QCBOR_TYPE_TEXT_STRING || + UsefulBufCompareToSZ(Item.label.string, "bytes 1") || + Item.uDataType != QCBOR_TYPE_BYTE_STRING || + UsefulBufCompareToSZ(Item.val.string, "xxxx")) { + return -14; + } -#ifndef QCBOR_DISABLE_TAGS - // CBOR tag with "argument" an indefinite length - { {(uint8_t[]){0xdf, 0x00}, 2}, QCBOR_ERR_BAD_INT }, - // CBOR tag with "argument" an indefinite length alternate vector - { {(uint8_t[]){0xdf}, 1}, QCBOR_ERR_BAD_INT }, -#else /* QCBOR_DISABLE_TAGS */ - { {(uint8_t[]){0xdf, 0x00}, 2}, QCBOR_ERR_TAGS_DISABLED }, - { {(uint8_t[]){0xdf}, 1}, QCBOR_ERR_TAGS_DISABLED }, -#endif /* QCBOR_DISABLE_TAGS */ + if(nLevel < 8) { + if(QCBORDecode_Finish(&DCtx) != QCBOR_ERR_ARRAY_OR_MAP_UNCONSUMED) { + return -15; + } else { + return 0; + } + } - // Missing bytes from a deterministic length string - // A byte string is of length 1 without the 1 byte - { {(uint8_t[]){0x41}, 1}, QCBOR_ERR_HIT_END }, - // A text string is of length 1 without the 1 byte - { {(uint8_t[]){0x61}, 1}, QCBOR_ERR_HIT_END }, - -#if SIZE_MAX > 2147483647 - // Byte string should have 2^32-15 bytes, but has one - { {(uint8_t[]){0x5a, 0xff, 0xff, 0xff, 0xf0, 0x00}, 6}, QCBOR_ERR_HIT_END }, - // Byte string should have 2^32-15 bytes, but has one - { {(uint8_t[]){0x7a, 0xff, 0xff, 0xff, 0xf0, 0x00}, 6}, QCBOR_ERR_HIT_END }, - // Byte string should have 2^64 bytes, but has 3 - { {(uint8_t[]){0x5b, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0x01, 0x02, 0x03}, 6}, QCBOR_ERR_HIT_END }, - // Text string should have 2^64 bytes, but has 3 - { {(uint8_t[]){0x7b, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0x01, 0x02, 0x03}, 6}, QCBOR_ERR_HIT_END }, -#else - // Byte string should have 2^32-15 bytes, but has one - { {(uint8_t[]){0x5a, 0x00, 0x00, 0xff, 0xf0, 0x00}, 6}, QCBOR_ERR_HIT_END }, - // Byte string should have 2^32-15 bytes, but has one - { {(uint8_t[]){0x7a, 0x00, 0x00, 0xff, 0xf0, 0x00}, 6}, QCBOR_ERR_HIT_END }, - // Byte string should have 2^16 bytes, but has 3 - { {(uint8_t[]){0x5b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x01, 0x02, 0x03}, 6}, QCBOR_ERR_HIT_END }, - // Text string should have 2^64 bytes, but has 3 - { {(uint8_t[]){0x7b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x01, 0x02, 0x03}, 6}, QCBOR_ERR_HIT_END }, -#endif + if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { + return (int32_t)nCBORError; + } + if(Item.uLabelType != QCBOR_TYPE_TEXT_STRING || + UsefulBufCompareToSZ(Item.label.string, "bytes 2") || + Item.uDataType != QCBOR_TYPE_BYTE_STRING || + UsefulBufCompareToSZ(Item.val.string, "yyyy")) { + return -16; + } - // Use of unassigned additional information values - // Major type positive integer with reserved value 28 - { {(uint8_t[]){0x1c}, 1}, QCBOR_ERR_UNSUPPORTED }, - // Major type positive integer with reserved value 29 - { {(uint8_t[]){0x1d}, 1}, QCBOR_ERR_UNSUPPORTED }, - // Major type positive integer with reserved value 30 - { {(uint8_t[]){0x1e}, 1}, QCBOR_ERR_UNSUPPORTED }, - // Major type negative integer with reserved value 28 - { {(uint8_t[]){0x3c}, 1}, QCBOR_ERR_UNSUPPORTED }, - // Major type negative integer with reserved value 29 - { {(uint8_t[]){0x3d}, 1}, QCBOR_ERR_UNSUPPORTED }, - // Major type negative integer with reserved value 30 - { {(uint8_t[]){0x3e}, 1}, QCBOR_ERR_UNSUPPORTED }, - // Major type byte string with reserved value 28 length - { {(uint8_t[]){0x5c}, 1}, QCBOR_ERR_UNSUPPORTED }, - // Major type byte string with reserved value 29 length - { {(uint8_t[]){0x5d}, 1}, QCBOR_ERR_UNSUPPORTED }, - // Major type byte string with reserved value 30 length - { {(uint8_t[]){0x5e}, 1}, QCBOR_ERR_UNSUPPORTED }, - // Major type text string with reserved value 28 length - { {(uint8_t[]){0x7c}, 1}, QCBOR_ERR_UNSUPPORTED }, - // Major type text string with reserved value 29 length - { {(uint8_t[]){0x7d}, 1}, QCBOR_ERR_UNSUPPORTED }, - // Major type text string with reserved value 30 length - { {(uint8_t[]){0x7e}, 1}, QCBOR_ERR_UNSUPPORTED }, - // Major type array with reserved value 28 length - { {(uint8_t[]){0x9c}, 1}, QCBOR_ERR_UNSUPPORTED }, - // Major type array with reserved value 29 length - { {(uint8_t[]){0x9d}, 1}, QCBOR_ERR_UNSUPPORTED }, - // Major type array with reserved value 30 length - { {(uint8_t[]){0x9e}, 1}, QCBOR_ERR_UNSUPPORTED }, - // Major type map with reserved value 28 length - { {(uint8_t[]){0xbc}, 1}, QCBOR_ERR_UNSUPPORTED }, - // Major type map with reserved value 29 length - { {(uint8_t[]){0xbd}, 1}, QCBOR_ERR_UNSUPPORTED }, - // Major type map with reserved value 30 length - { {(uint8_t[]){0xbe}, 1}, QCBOR_ERR_UNSUPPORTED }, - // Major type tag with reserved value 28 length - { {(uint8_t[]){0xdc}, 1}, QCBOR_ERR_UNSUPPORTED }, - // Major type tag with reserved value 29 length - { {(uint8_t[]){0xdd}, 1}, QCBOR_ERR_UNSUPPORTED }, - // Major type tag with reserved value 30 length - { {(uint8_t[]){0xde}, 1}, QCBOR_ERR_UNSUPPORTED }, - // Major type simple with reserved value 28 length - { {(uint8_t[]){0xfc}, 1}, QCBOR_ERR_UNSUPPORTED }, - // Major type simple with reserved value 29 length - { {(uint8_t[]){0xfd}, 1}, QCBOR_ERR_UNSUPPORTED }, - // Major type simple with reserved value 30 length - { {(uint8_t[]){0xfe}, 1}, QCBOR_ERR_UNSUPPORTED }, - - - // Maps must have an even number of data items (key & value) - // Map with 1 item when it should have 2 - { {(uint8_t[]){0xa1, 0x00}, 2}, QCBOR_ERR_HIT_END }, - // Map with 3 item when it should have 4 - { {(uint8_t[]){0xa2, 0x00, 0x00, 0x00}, 2}, QCBOR_ERR_HIT_END }, -#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS - // Map with 1 item when it should have 2 - { {(uint8_t[]){0xbf, 0x00, 0xff}, 3}, QCBOR_ERR_BAD_BREAK }, - // Map with 3 item when it should have 4 - { {(uint8_t[]){0xbf, 0x00, 0x00, 0x00, 0xff}, 5}, QCBOR_ERR_BAD_BREAK }, -#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS */ + if(nLevel < 9) { + if(QCBORDecode_Finish(&DCtx) != QCBOR_ERR_ARRAY_OR_MAP_UNCONSUMED) { + return -17; + } else { + return 0; + } + } -#ifndef QCBOR_DISABLE_TAGS - // In addition to not-well-formed, some invalid CBOR - // Text-based date, with an integer - { {(uint8_t[]){0xc0, 0x00}, 2}, QCBOR_ERR_BAD_OPT_TAG }, - // Epoch date, with an byte string - { {(uint8_t[]){0xc1, 0x41, 0x33}, 3}, QCBOR_ERR_BAD_OPT_TAG }, - // tagged as both epoch and string dates - { {(uint8_t[]){0xc1, 0xc0, 0x00}, 3}, QCBOR_ERR_BAD_OPT_TAG }, - // big num tagged an int, not a byte string - { {(uint8_t[]){0xc2, 0x00}, 2}, QCBOR_ERR_BAD_OPT_TAG }, -#else /* QCBOR_DISABLE_TAGS */ - // Text-based date, with an integer - { {(uint8_t[]){0xc0, 0x00}, 2}, QCBOR_ERR_TAGS_DISABLED }, - // Epoch date, with an byte string - { {(uint8_t[]){0xc1, 0x41, 0x33}, 3}, QCBOR_ERR_TAGS_DISABLED }, - // tagged as both epoch and string dates - { {(uint8_t[]){0xc1, 0xc0, 0x00}, 3}, QCBOR_ERR_TAGS_DISABLED }, - // big num tagged an int, not a byte string - { {(uint8_t[]){0xc2, 0x00}, 2}, QCBOR_ERR_TAGS_DISABLED }, -#endif /* QCBOR_DISABLE_TAGS */ + if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { + return (int32_t)nCBORError; + } + if(Item.uLabelType != QCBOR_TYPE_TEXT_STRING || + UsefulBufCompareToSZ(Item.label.string, "another int") || + Item.uDataType != QCBOR_TYPE_INT64 || + Item.val.int64 != 98) + return -18; -}; + if(nLevel < 10) { + if(QCBORDecode_Finish(&DCtx) != QCBOR_ERR_ARRAY_OR_MAP_UNCONSUMED) { + return -19; + } else { + return 0; + } + } -int32_t DecodeFailureTests(void) -{ - int32_t nResult; + if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { + return (int32_t)nCBORError; + } + if(Item.uLabelType != QCBOR_TYPE_TEXT_STRING || + UsefulBuf_Compare(Item.label.string, UsefulBuf_FromSZ("text 2"))|| + Item.uDataType != QCBOR_TYPE_TEXT_STRING || + UsefulBufCompareToSZ(Item.val.string, "lies, damn lies and statistics")) { + return -20; + } - nResult = ProcessFailures(Failures,C_ARRAY_COUNT(Failures,struct FailInput)); - if(nResult) { - return nResult; + if(QCBORDecode_Finish(&DCtx)) { + return -21; } - // Corrupt the UsefulInputBuf and see that - // it reflected correctly for CBOR decoding + return 0; +} + + +/* These are just the item that open large maps and arrays, not + * the items in the array. This is sufficient to test the + * boundary condition. */ +static const uint8_t spLargeArrayFake[] = { + 0x99, 0xff, 0xfe}; + +static const uint8_t spTooLargeArrayFake[] = { + 0x99, 0xff, 0xff}; + +static const uint8_t spLargeMapFake[] = { + 0xb9, 0x7f, 0xff}; + +static const uint8_t spTooLargeMapFake[] = { + 0xba, 0x00, 0x00, 0x80, 0x00}; + + +int32_t ParseMapTest(void) +{ QCBORDecodeContext DCtx; QCBORItem Item; - QCBORError uQCBORError; + QCBORError uErr; QCBORDecode_Init(&DCtx, - UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spSimpleValues), + UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spLargeArrayFake), QCBOR_DECODE_MODE_NORMAL); - - if((uQCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { - return (int32_t)uQCBORError; - } - if(Item.uDataType != QCBOR_TYPE_ARRAY || Item.val.uCount != 10) { - // This wasn't supposed to happen - return -1; + uErr = QCBORDecode_GetNext(&DCtx, &Item); + if(uErr != QCBOR_SUCCESS || Item.val.uCount != QCBOR_MAX_ITEMS_IN_ARRAY) { + return -100; } - DCtx.InBuf.magic = 0; // Reach in and corrupt the UsefulInputBuf - - uQCBORError = QCBORDecode_GetNext(&DCtx, &Item); - if(uQCBORError != QCBOR_ERR_NO_MORE_ITEMS) { - // Did not get back the error expected - return -2; + QCBORDecode_Init(&DCtx, + UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spTooLargeArrayFake), + QCBOR_DECODE_MODE_NORMAL); + uErr = QCBORDecode_GetNext(&DCtx, &Item); + if(uErr != QCBOR_ERR_ARRAY_DECODE_TOO_LONG) { + return -101; } + QCBORDecode_Init(&DCtx, + UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spLargeMapFake), + QCBOR_DECODE_MODE_NORMAL); + uErr = QCBORDecode_GetNext(&DCtx, &Item); + if(uErr != QCBOR_SUCCESS || Item.val.uCount != QCBOR_MAX_ITEMS_IN_MAP) { + return -110; + } - /* - The max size of a string for QCBOR is SIZE_MAX - 4 so this - tests here can be performed to see that the max length - error check works correctly. See DecodeBytes(). If the max - size was SIZE_MAX, it wouldn't be possible to test this. - - This test will automatocally adapt the all CPU sizes - through the use of SIZE_MAX. - */ + QCBORDecode_Init(&DCtx, + UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spTooLargeMapFake), + QCBOR_DECODE_MODE_NORMAL); + uErr = QCBORDecode_GetNext(&DCtx, &Item); + if(uErr != QCBOR_ERR_ARRAY_DECODE_TOO_LONG) { + return -111; + } - UsefulBuf_MAKE_STACK_UB( HeadBuf, QCBOR_HEAD_BUFFER_SIZE); - UsefulBufC EncodedHead; - // This makes a CBOR head with a text string that is very long - // but doesn't fill in the bytes of the text string as that is - // not needed to test this part of QCBOR. - EncodedHead = QCBOREncode_EncodeHead(HeadBuf, CBOR_MAJOR_TYPE_TEXT_STRING, 0, SIZE_MAX); + // Parse a moderatly complex map structure very thoroughly + int32_t nResult = ParseMapTest1(QCBOR_DECODE_MODE_NORMAL); + if(nResult) { + return nResult; + } - QCBORDecode_Init(&DCtx, EncodedHead, QCBOR_DECODE_MODE_NORMAL); + // Again, but in strings-only mode. It should succeed since the input + // map has only string labels. + nResult = ParseMapTest1(QCBOR_DECODE_MODE_MAP_STRINGS_ONLY); + if(nResult) { + return nResult; + } - if(QCBOR_ERR_STRING_TOO_LONG != QCBORDecode_GetNext(&DCtx, &Item)) { - return -4; + // Again, but try to finish the decoding before the end of the + // input at 10 different place and see that the right error code + // is returned. + for(int i = 0; i < 10; i++) { + nResult = ExtraBytesTest(i); + if(nResult) { + break; + } } - return 0; + return nResult; } +#endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */ -/* Try all 256 values of the byte at nLen including recursing for - each of the values to try values at nLen+1 ... up to nLenMax - */ -static void ComprehensiveInputRecurser(uint8_t *pBuf, size_t nLen, size_t nLenMax) +/* The simple-values including some not well formed */ +static const uint8_t spSimpleValues[] = { + 0x8a, 0xf4, 0xf5, 0xf6, 0xf7, 0xff, 0xe0, 0xf3, + 0xf8, 0x00, 0xf8, 0x13, 0xf8, 0x1f, 0xf8, 0x20, + 0xf8, 0xff}; + +/* A map of good simple values, plus one well-formed integer */ +static const uint8_t spGoodSimpleValues[] = { + 0xa9, 0x01, 0xf4, 0x02, 0xf5, 0x03, 0xf6, 0x04, 0xf7, + 0x05, 0xe0, 0x06, 0xf3, 0x07, 0xf8, 0x20, 0x61, 0x40, + 0xf8, 0xff, 0x0f, 0x0f}; + +int32_t SimpleValueDecodeTests(void) { - if(nLen >= nLenMax) { - return; - } + QCBORDecodeContext DCtx; + QCBORItem Item; + QCBORError uErr; - for(int inputByte = 0; inputByte < 256; inputByte++) { - // Set up the input - pBuf[nLen] = (uint8_t)inputByte; - const UsefulBufC Input = {pBuf, nLen+1}; + QCBORDecode_Init(&DCtx, + UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spSimpleValues), + QCBOR_DECODE_MODE_NORMAL); - // Get ready to parse - QCBORDecodeContext DCtx; - QCBORDecode_Init(&DCtx, Input, QCBOR_DECODE_MODE_NORMAL); - // Parse by getting the next item until an error occurs - // Just about every possible decoder error can occur here - // The goal of this test is not to check for the correct - // error since that is not really possible. It is to - // see that there is no crash on hostile input. - while(1) { - QCBORItem Item; - QCBORError nCBORError = QCBORDecode_GetNext(&DCtx, &Item); - if(nCBORError != QCBOR_SUCCESS) { - break; - } - } + if((uErr = QCBORDecode_GetNext(&DCtx, &Item))) + return (int32_t)uErr; + if(Item.uDataType != QCBOR_TYPE_ARRAY || + Item.val.uCount != 10) + return 1; - ComprehensiveInputRecurser(pBuf, nLen+1, nLenMax); - } -} + if((uErr = QCBORDecode_GetNext(&DCtx, &Item))) + return (int32_t)uErr; + if(Item.uDataType != QCBOR_TYPE_FALSE) + return 2; + if((uErr = QCBORDecode_GetNext(&DCtx, &Item))) + return (int32_t)uErr; + if(Item.uDataType != QCBOR_TYPE_TRUE) + return 3; -int32_t ComprehensiveInputTest(void) -{ - // Size 2 tests 64K inputs and runs quickly - uint8_t pBuf[2]; + if((uErr = QCBORDecode_GetNext(&DCtx, &Item))) + return (int32_t)uErr; + if(Item.uDataType != QCBOR_TYPE_NULL) + return 4; - ComprehensiveInputRecurser(pBuf, 0, sizeof(pBuf)); + if((uErr = QCBORDecode_GetNext(&DCtx, &Item))) + return (int32_t)uErr; + if(Item.uDataType != QCBOR_TYPE_UNDEF) + return 5; - return 0; -} + // A break + if(QCBORDecode_GetNext(&DCtx, &Item) != QCBOR_ERR_BAD_BREAK) + return 6; + if((uErr = QCBORDecode_GetNext(&DCtx, &Item))) + return (int32_t)uErr; + if(Item.uDataType != QCBOR_TYPE_UKNOWN_SIMPLE || Item.val.uSimple != 0) + return 7; -int32_t BigComprehensiveInputTest(void) -{ - // size 3 tests 16 million inputs and runs OK - // in seconds on fast machines. Size 4 takes - // 10+ minutes and 5 half a day on fast - // machines. This test is kept separate from - // the others so as to no slow down the use - // of them as a very frequent regression. - uint8_t pBuf[3]; // + if((uErr = QCBORDecode_GetNext(&DCtx, &Item))) + return (int32_t)uErr; + if(Item.uDataType != QCBOR_TYPE_UKNOWN_SIMPLE || Item.val.uSimple != 19) + return 8; - ComprehensiveInputRecurser(pBuf, 0, sizeof(pBuf)); + if(QCBORDecode_GetNext(&DCtx, &Item) != QCBOR_ERR_BAD_TYPE_7) + return 9; - return 0; -} + if(QCBORDecode_GetNext(&DCtx, &Item) != QCBOR_ERR_BAD_TYPE_7) + return 10; + if(QCBORDecode_GetNext(&DCtx, &Item) != QCBOR_ERR_BAD_TYPE_7) + return 11; -static const uint8_t spDateTestInput[] = { - /* 1. The valid date string "1985-04-12" */ - 0xc0, // tag for string date - 0x6a, '1','9','8','5','-','0','4','-','1','2', // Date string + if((uErr = QCBORDecode_GetNext(&DCtx, &Item))) + return (int32_t)uErr; + if(Item.uDataType != QCBOR_TYPE_UKNOWN_SIMPLE || Item.val.uSimple != 32) + return 12; - /* 2. An invalid date string due to wrong tag content type */ - 0xc0, // tag for string date - 0x00, // Wrong type for a string date + if((uErr = QCBORDecode_GetNext(&DCtx, &Item))) + return (int32_t)uErr; + if(Item.uDataType != QCBOR_TYPE_UKNOWN_SIMPLE || Item.val.uSimple != 255) + return 13; - /* 3. A valid epoch date, 1400000000; Tue, 13 May 2014 16:53:20 GMT */ - 0xc1, // tag for epoch date - 0x1a, 0x53, 0x72, 0x4E, 0x00, // Epoch date 1400000000; Tue, 13 May 2014 16:53:20 GMT - /* 4. An invalid epoch date due to wrong tag content type */ - 0xc1, - 0x62, 'h', 'i', // wrong type tagged + QCBORDecode_Init(&DCtx, + UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spGoodSimpleValues), + QCBOR_DECODE_MODE_NORMAL); - /* 5. Valid epoch date tag as content for a two other nested tags */ - // CBOR_TAG_ENC_AS_B64 - 0xcf, 0xd8, 0x16, 0xc1, // Epoch date with extra tags - 0x1a, 0x53, 0x72, 0x4E, 0x01, + uint8_t uSimple; - /* 6. Epoch date with value to large to fit into int64 */ - 0xc1, // tag for epoch date - 0x1b, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, // Too large integer + QCBORDecode_EnterMap(&DCtx, &Item); + QCBORDecode_GetSimple(&DCtx, &uSimple); + if(QCBORDecode_GetError(&DCtx) || uSimple != CBOR_SIMPLEV_FALSE) { + return 20; + } + QCBORDecode_GetSimple(&DCtx, &uSimple); + if(QCBORDecode_GetError(&DCtx) || uSimple != CBOR_SIMPLEV_TRUE) { + return 21; + } + QCBORDecode_GetSimple(&DCtx, &uSimple); + if(QCBORDecode_GetError(&DCtx) || uSimple != CBOR_SIMPLEV_NULL) { + return 22; + } + QCBORDecode_GetSimple(&DCtx, &uSimple); + if(QCBORDecode_GetError(&DCtx) || uSimple != CBOR_SIMPLEV_UNDEF) { + return 23; + } + QCBORDecode_GetSimple(&DCtx, &uSimple); + if(QCBORDecode_GetError(&DCtx) || uSimple != 0) { + return 24; + } + QCBORDecode_GetSimple(&DCtx, &uSimple); + if(QCBORDecode_GetError(&DCtx) || uSimple != 19) { + return 25; + } + QCBORDecode_GetSimple(&DCtx, &uSimple); + if(QCBORDecode_GetError(&DCtx) || uSimple != 32) { + return 26; + } +#ifndef QCBOR_DISABLE_NON_INTEGER_LABELS + QCBORDecode_GetSimple(&DCtx, &uSimple); + if(QCBORDecode_GetError(&DCtx) || uSimple != 255) { + return 27; + } + QCBORDecode_VGetNext(&DCtx, &Item); + QCBORDecode_GetSimple(&DCtx, &uSimple); + if(QCBORDecode_GetError(&DCtx) != QCBOR_ERR_NO_MORE_ITEMS) { + return 28; + } - /* 7. Epoch date with single-precision value of 1.1. */ - 0xc1, // tag for epoch date - 0xfa, 0x3f, 0x8c, 0xcc, 0xcd, // single with value 1.1 + QCBORDecode_Rewind(&DCtx); - /* 8. Epoch date with too-large single precision float */ - 0xc1, // tag for epoch date - 0xfa, 0x7f, 0x7f, 0xff, 0xff, // 3.4028234663852886e+38 too large + QCBORDecode_GetSimpleInMapN(&DCtx, 6, &uSimple); + if(QCBORDecode_GetError(&DCtx) || uSimple != 19) { + return 30; + } - /* 9. Epoch date with slightly too-large double precision value */ - 0xc1, // tag for epoch date - 0xfb, 0x43, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 9223372036854775808.000000 just barely too large - //0xfa, 0x7f, 0x7f, 0xff, 0xff // 3.4028234663852886e+38 too large + QCBORDecode_GetSimpleInMapSZ(&DCtx, "@", &uSimple); + if(QCBORDecode_GetError(&DCtx) || uSimple != 255) { + return 31; + } - /* 10. Epoch date with largest supported double precision value */ - 0xc1, // tag for epoch date - 0xfb, 0x43, 0xdf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, // 9223372036854773760 largest supported + QCBORDecode_GetSimpleInMapN(&DCtx, 99, &uSimple); + if(QCBORDecode_GetAndResetError(&DCtx) != QCBOR_ERR_LABEL_NOT_FOUND) { + return 32; + } - /* 11. Epoch date with single-precision NaN */ - 0xc1, // tag for epoch date - 0xfa, 0x7f, 0xc0, 0x00, 0x00, // Single-precision NaN + QCBORDecode_GetSimpleInMapSZ(&DCtx, "xx", &uSimple); + if(QCBORDecode_GetAndResetError(&DCtx) != QCBOR_ERR_LABEL_NOT_FOUND) { + return 33; + } - /* 12. Epoch date with double precision plus infinity */ - 0xc1, - 0xfb, 0x7f, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // +infinity + QCBORDecode_GetSimpleInMapN(&DCtx, 15, &uSimple); + if(QCBORDecode_GetAndResetError(&DCtx) != QCBOR_ERR_UNEXPECTED_TYPE) { + return 34; + } +#endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */ - /* 13. Epoch date with half-precision negative infinity */ - 0xc1, // tag for epoch date - 0xf9, 0xfc, 0x00, // -Infinity -}; + return 0; +} +int32_t NotWellFormedTests(void) +{ + // Loop over all the not-well-formed instance of CBOR + // that are test vectors in not_well_formed_cbor.h + const uint16_t nArraySize = C_ARRAY_COUNT(paNotWellFormedCBOR, + struct someBinaryBytes); + for(uint16_t nIterate = 0; nIterate < nArraySize; nIterate++) { + const struct someBinaryBytes *pBytes = &paNotWellFormedCBOR[nIterate]; + const UsefulBufC Input = (UsefulBufC){pBytes->p, pBytes->n}; -// have to check float expected only to within an epsilon -#ifndef QCBOR_DISABLE_FLOAT_HW_USE -static int CHECK_EXPECTED_DOUBLE(double val, double expected) { + // Set up decoder context. String allocator needed for indefinite + // string test cases + QCBORDecodeContext DCtx; + QCBORDecode_Init(&DCtx, Input, QCBOR_DECODE_MODE_NORMAL); +#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS + UsefulBuf_MAKE_STACK_UB(Pool, 100); + QCBORDecode_SetMemPool(&DCtx, Pool, 0); +#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS */ - double diff = val - expected; + // Loop getting items until no more to get + QCBORError uCBORError; + do { + QCBORItem Item; - diff = fabs(diff); + uCBORError = QCBORDecode_GetNext(&DCtx, &Item); + } while(uCBORError == QCBOR_SUCCESS); - return diff > 0.0000001; + // Every test vector must fail with + // a not-well-formed error. If not + // this test fails. + if(!QCBORDecode_IsNotWellFormedError(uCBORError) && + uCBORError != QCBOR_ERR_NO_MORE_ITEMS) { + /* Return index of failure and QCBOR error in the result */ + return (int32_t)(nIterate * 100 + uCBORError); + } + } + return 0; } -#endif /* QCBOR_DISABLE_FLOAT_HW_USE */ -/* Test date decoding using GetNext() */ -int32_t DateParseTest(void) +struct DecodeFailTestInput { + const char *szDescription; /* Description of the test */ + QCBORDecodeMode DecoderMode; /* The QCBOR Decoder Mode for test */ + UsefulBufC Input; /* Chunk of CBOR that cases error */ + QCBORError nError; /* The expected error */ +}; + + +static int32_t +ProcessDecodeFailures(const struct DecodeFailTestInput *pFailInputs, const int nNumFails) { + int nIndex; QCBORDecodeContext DCtx; + QCBORError uCBORError; QCBORItem Item; - QCBORError uError; - QCBORDecode_Init(&DCtx, - UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spDateTestInput), - QCBOR_DECODE_MODE_NORMAL); + for(nIndex = 0; nIndex < nNumFails; nIndex++) { + const struct DecodeFailTestInput *pF = &pFailInputs[nIndex]; - /* 1. The valid date string "1985-04-12" */ - if((uError = QCBORDecode_GetNext(&DCtx, &Item))) { - return -1; - } - if(Item.uDataType != QCBOR_TYPE_DATE_STRING || - UsefulBufCompareToSZ(Item.val.dateString, "1985-04-12")){ - return -2; - } + QCBORDecode_Init(&DCtx, pF->Input, pF->DecoderMode); - /* 2. An invalid date string due to wrong tag content type */ - uError = QCBORDecode_GetNext(&DCtx, &Item); - if(uError != QCBOR_ERR_BAD_OPT_TAG) { - return -3; - } +#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS + /* Set up the decoding context including a memory pool so that + * indefinite length items can be checked. + */ + UsefulBuf_MAKE_STACK_UB(Pool, 100); - /* 3. A valid epoch date, 1400000000; Tue, 13 May 2014 16:53:20 GMT */ - uError = QCBORDecode_GetNext(&DCtx, &Item); - if(uError != QCBOR_SUCCESS) { - return -4; - } - if(uError == QCBOR_SUCCESS) { - if(Item.uDataType != QCBOR_TYPE_DATE_EPOCH || - Item.val.epochDate.nSeconds != 1400000000 -#ifndef USEFULBUF_DISABLE_ALL_FLOAT - || Item.val.epochDate.fSecondsFraction != 0 -#endif /* USEFULBUF_DISABLE_ALL_FLOAT */ - ) { - return -5; + uCBORError = QCBORDecode_SetMemPool(&DCtx, Pool, 0); + if(uCBORError != QCBOR_SUCCESS) { + return -1; } - } - - /* 4. An invalid epoch date due to wrong tag content type */ - if(QCBORDecode_GetNext(&DCtx, &Item) != QCBOR_ERR_BAD_OPT_TAG) { - return -6; - } - - /* 5. Valid epoch date tag as content for a two other nested tags */ - // Epoch date wrapped in an CBOR_TAG_ENC_AS_B64 and an unknown tag. - // The date is decoded and the two tags are returned. This is to - // make sure the wrapping of epoch date in another tag works OK. - if((uError = QCBORDecode_GetNext(&DCtx, &Item))) { - return -7; - } - if(Item.uDataType != QCBOR_TYPE_DATE_EPOCH || - Item.val.epochDate.nSeconds != 1400000001 || -#ifndef USEFULBUF_DISABLE_ALL_FLOAT - Item.val.epochDate.fSecondsFraction != 0 || -#endif /* USEFULBUF_DISABLE_ALL_FLOAT */ - !QCBORDecode_IsTagged(&DCtx, &Item, CBOR_TAG_ENC_AS_B64)) { - return -8; - } - - /* 6. Epoch date with value to large to fit into int64 */ - if(QCBORDecode_GetNext(&DCtx, &Item) != QCBOR_ERR_DATE_OVERFLOW) { - return -9; - } +#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS */ - /* 7. Epoch date with single-precision value of 1.1. */ - uError = QCBORDecode_GetNext(&DCtx, &Item); - if(uError != FLOAT_ERR_CODE_NO_FLOAT_HW(QCBOR_SUCCESS)) { - return -10; - } - if(uError == QCBOR_SUCCESS) { - if(Item.uDataType != QCBOR_TYPE_DATE_EPOCH || - Item.val.epochDate.nSeconds != 1 -#ifndef QCBOR_DISABLE_FLOAT_HW_USE - || CHECK_EXPECTED_DOUBLE(Item.val.epochDate.fSecondsFraction, 0.1) -#endif /* USEFULBUF_DISABLE_ALL_FLOAT */ - ) { - return -11; + if(nIndex == 4) { + uCBORError = 9; /* For setting break points */ } - } - /* 8. Epoch date with too-large single-precision float */ - uError = QCBORDecode_GetNext(&DCtx, &Item); - if(uError != FLOAT_ERR_CODE_NO_FLOAT_HW(QCBOR_ERR_DATE_OVERFLOW)) { - return -12; - } + /* Iterate until there is an error of some sort */ + do { + /* Set to something non-zero, something other than QCBOR_TYPE_NONE */ + memset(&Item, 0x33, sizeof(Item)); - /* 9. Epoch date with slightly too-large double-precision value */ - uError = QCBORDecode_GetNext(&DCtx, &Item); - if(uError != FLOAT_ERR_CODE_NO_FLOAT_HW(QCBOR_ERR_DATE_OVERFLOW)) { - return -13; - } + uCBORError = QCBORDecode_GetNext(&DCtx, &Item); + } while(uCBORError == QCBOR_SUCCESS); - /* 10. Epoch date with largest supported double-precision value */ - uError = QCBORDecode_GetNext(&DCtx, &Item); - if(uError != FLOAT_ERR_CODE_NO_FLOAT_HW(QCBOR_SUCCESS)) { - return -14; - } - if(uError == QCBOR_SUCCESS) { - if(Item.uDataType != QCBOR_TYPE_DATE_EPOCH || - Item.val.epochDate.nSeconds != 9223372036854773760 -#ifndef QCBOR_DISABLE_FLOAT_HW_USE - || Item.val.epochDate.fSecondsFraction != 0.0 -#endif /* QCBOR_DISABLE_FLOAT_HW_USE */ - ) { - return -14; + /* Must get the expected error or the this test fails. + * The data and label type must also be QCBOR_TYPE_NONE. + */ + if(uCBORError != pF->nError || + Item.uDataType != QCBOR_TYPE_NONE || + Item.uLabelType != QCBOR_TYPE_NONE) { + return (int32_t)(nIndex * 1000 + (int)uCBORError); } } - /* 11. Epoch date with single-precision NaN */ - if(QCBORDecode_GetNext(&DCtx, &Item) != FLOAT_ERR_CODE_NO_FLOAT_HW(QCBOR_ERR_DATE_OVERFLOW)) { - return -15; - } - - /* 12. Epoch date with double-precision plus infinity */ - if(QCBORDecode_GetNext(&DCtx, &Item) != FLOAT_ERR_CODE_NO_FLOAT_HW(QCBOR_ERR_DATE_OVERFLOW)) { - return -16; - } - - /* 13. Epoch date with half-precision negative infinity */ - uError = QCBORDecode_GetNext(&DCtx, &Item); - if(uError != FLOAT_ERR_CODE_NO_HALF_PREC_NO_FLOAT_HW(QCBOR_ERR_DATE_OVERFLOW)) { - return -17; - } - return 0; } -/* - Test cases covered here. Some items cover more than one of these. - positive integer (zero counts as a positive integer) - negative integer - half-precision float - single-precision float - double-precision float - - float Overflow error - Wrong type error for epoch - Wrong type error for date string - float disabled error - half-precision disabled error - -Infinity - Slightly too large integer - Slightly too far from zero +static const struct DecodeFailTestInput Failures[] = { + /* Most of this is copied from not_well_formed.h. Here the error + * code returned is also checked. + */ - Get epoch by int - Get string by int - Get epoch by string - Get string by string - Fail to get epoch by wrong int label - Fail to get string by wrong string label - Fail to get epoch by string because it is invalid - Fail to get epoch by int because it is invalid +#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS + /* Indefinite length strings must be closed off */ + { "An indefinite length byte string not closed off", + QCBOR_DECODE_MODE_NORMAL, + {"0x5f\x41\x00", 3}, + QCBOR_ERR_HIT_END + }, + { "An indefinite length text string not closed off", + QCBOR_DECODE_MODE_NORMAL, + {"\x7f\x61\x00", 3}, + QCBOR_ERR_HIT_END + }, - Untagged values - */ -static const uint8_t spSpiffyDateTestInput[] = { - 0x87, // array of 7 items + /* All the chunks in an indefinite length string must be of the + * type of indefinite length string + */ + { "Indefinite length byte string with text string chunk", + QCBOR_DECODE_MODE_NORMAL, + {"\x5f\x61\x00\xff", 4}, + QCBOR_ERR_INDEFINITE_STRING_CHUNK + }, + { "Indefinite length text string with a byte string chunk", + QCBOR_DECODE_MODE_NORMAL, + {"\x7f\x41\x00\xff", 4}, + QCBOR_ERR_INDEFINITE_STRING_CHUNK + }, + { "Indefinite length byte string with a positive integer chunk", + QCBOR_DECODE_MODE_NORMAL, + {"\x5f\x00\xff", 3}, + QCBOR_ERR_INDEFINITE_STRING_CHUNK + }, + { "Indefinite length byte string with an negative integer chunk", + QCBOR_DECODE_MODE_NORMAL, + {"\x5f\x21\xff", 3}, + QCBOR_ERR_INDEFINITE_STRING_CHUNK + }, + { "Indefinite length byte string with an array chunk", + QCBOR_DECODE_MODE_NORMAL, + {"\x5f\x80\xff", 3}, + QCBOR_ERR_INDEFINITE_STRING_CHUNK + }, + { "Indefinite length byte string with an map chunk", + QCBOR_DECODE_MODE_NORMAL, + {"\x5f\xa0\xff", 3}, + QCBOR_ERR_INDEFINITE_STRING_CHUNK + }, - 0xa6, // Open a map for tests involving untagged items with labels. +#ifndef QCBOR_DISABLE_TAGS + { "Indefinite length byte string with tagged integer chunk", + QCBOR_DECODE_MODE_NORMAL, + {"\x5f\xc0\x00\xff", 4}, + QCBOR_ERR_INDEFINITE_STRING_CHUNK + }, +#else + { "Indefinite length byte string with tagged integer chunk", + QCBOR_DECODE_MODE_NORMAL, + {"\x5f\xc0\x00\xff", 4}, + QCBOR_ERR_TAGS_DISABLED + }, +#endif /* QCBOR_DISABLE_TAGS */ - // Untagged integer 0 - 0x08, - 0x00, + { "Indefinite length byte string with an simple type chunk", + QCBOR_DECODE_MODE_NORMAL, + {"\x5f\xe0\xff", 3}, + QCBOR_ERR_INDEFINITE_STRING_CHUNK + }, + { "???", + QCBOR_DECODE_MODE_NORMAL, + {"\x5f\x5f\x41\x00\xff\xff", 6}, + QCBOR_ERR_INDEFINITE_STRING_CHUNK + }, + { "indefinite length text string with indefinite string inside", + QCBOR_DECODE_MODE_NORMAL, + {"\x7f\x7f\x61\x00\xff\xff", 6}, + QCBOR_ERR_INDEFINITE_STRING_CHUNK + }, +#else /* QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS */ - // Utagged date string with string label y - 0x61, 0x79, - 0x6a, '2','0','8','5','-','0','4','-','1','2', // Untagged date string +#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS */ - // Untagged single-precision float with value 3.14 with string label x - 0x61, 0x78, - 0xFA, 0x40, 0x48, 0xF5, 0xC3, + /* Definte length maps and arrays must be closed by having the right number of items */ + { "A definte length array that is supposed to have 1 item, but has none", + QCBOR_DECODE_MODE_NORMAL, + {"\x81", 1}, + QCBOR_ERR_NO_MORE_ITEMS + }, + { "A definte length array that is supposed to have 2 items, but has only 1", + QCBOR_DECODE_MODE_NORMAL, + {"\x82\x00", 2}, + QCBOR_ERR_NO_MORE_ITEMS + }, + { "A definte length array that is supposed to have 511 items, but has only 1", + QCBOR_DECODE_MODE_NORMAL, + {"\x9a\x01\xff\x00", 4}, + QCBOR_ERR_HIT_END + }, + { "A definte length map that is supposed to have 1 item, but has none", + QCBOR_DECODE_MODE_NORMAL, + {"\xa1", 1}, + QCBOR_ERR_NO_MORE_ITEMS + }, + { "A definte length map that is supposed to have s item, but has only 1", + QCBOR_DECODE_MODE_NORMAL, + {"\xa2\x01\x02", 3}, + QCBOR_ERR_NO_MORE_ITEMS + }, +#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS + /* Indefinte length maps and arrays must be ended by a break */ + { "Indefinite length array with zero items and no break", + QCBOR_DECODE_MODE_NORMAL, + {"\x9f", 1}, + QCBOR_ERR_NO_MORE_ITEMS }, + + { "Indefinite length array with two items and no break", + QCBOR_DECODE_MODE_NORMAL, + {"\x9\x01\x02", 3}, + QCBOR_ERR_NO_MORE_ITEMS + }, + { "Indefinite length map with zero items and no break", + QCBOR_DECODE_MODE_NORMAL, + {"\xbf", 1}, + QCBOR_ERR_NO_MORE_ITEMS + }, + { "Indefinite length map with two items and no break", + QCBOR_DECODE_MODE_NORMAL, + {"\xbf\x01\x02\x01\x02", 5}, + QCBOR_ERR_NO_MORE_ITEMS + }, - // Untagged half-precision float with value -2 - 0x09, - 0xF9, 0xC0, 0x00, + /* Nested maps and arrays must be closed off (some extra nested test vectors) */ + { "Unclosed indefinite array containing a closed definite length array", + QCBOR_DECODE_MODE_NORMAL, + {"\x9f\x80\x00", 3}, + QCBOR_ERR_NO_MORE_ITEMS + }, - /* Untagged date-only date string */ - 0x18, 0x63, - 0x6A, 0x31, 0x39, 0x38, 0x35, 0x2D, 0x30, 0x34, 0x2D, 0x31, 0x32, /* "1985-04-12" */ + { "Definite length array containing an unclosed indefinite length array", + QCBOR_DECODE_MODE_NORMAL, + {"\x81\x9f", 2}, + QCBOR_ERR_NO_MORE_ITEMS + }, + { "Unclosed indefinite map containing a closed definite length array", + QCBOR_DECODE_MODE_NORMAL, + {"\xbf\x01\x80\x00\xa0", 5}, + QCBOR_ERR_NO_MORE_ITEMS + }, + { "Definite length map containing an unclosed indefinite length array", + QCBOR_DECODE_MODE_NORMAL, + {"\xa1\x02\x9f", 3}, + QCBOR_ERR_NO_MORE_ITEMS + }, + { "Deeply nested definite length arrays with deepest one unclosed", + QCBOR_DECODE_MODE_NORMAL, + {"\x81\x81\x81\x81\x81\x81\x81\x81\x81", 9}, + QCBOR_ERR_NO_MORE_ITEMS + }, + { "Deeply nested indefinite length arrays with deepest one unclosed", + QCBOR_DECODE_MODE_NORMAL, + {"\x9f\x9f\x9f\x9f\x9f\xff\xff\xff\xff", 9}, + QCBOR_ERR_NO_MORE_ITEMS + }, + { "Mixed nesting with indefinite unclosed", + QCBOR_DECODE_MODE_NORMAL, + {"\x9f\x81\x9f\x81\x9f\x9f\xff\xff\xff", 9}, + QCBOR_ERR_NO_MORE_ITEMS }, + { "Mixed nesting with definite unclosed", + QCBOR_DECODE_MODE_NORMAL, + {"\x9f\x82\x9f\x81\x9f\x9f\xff\xff\xff\xff", 10}, + QCBOR_ERR_BAD_BREAK + }, + { "Unclosed indefinite length map in definite length maps", + QCBOR_DECODE_MODE_NORMAL, + {"\xa1\x01\xa2\x02\xbf\xff\x02\xbf", 8}, + QCBOR_ERR_NO_MORE_ITEMS + }, + { "Unclosed definite length map in indefinite length maps", + QCBOR_DECODE_MODE_NORMAL, + {"\xbf\x01\xbf\x02\xa1", 5}, + QCBOR_ERR_NO_MORE_ITEMS + }, + { "Unclosed indefinite length array in definite length maps", + QCBOR_DECODE_MODE_NORMAL, + {"\xa1\x01\xa2\x02\x9f\xff\x02\x9f", 8}, + QCBOR_ERR_NO_MORE_ITEMS + }, + { "Unclosed definite length array in indefinite length maps", + QCBOR_DECODE_MODE_NORMAL, + {"\xbf\x01\xbf\x02\x81", 5}, + QCBOR_ERR_NO_MORE_ITEMS + }, + { "Unclosed indefinite length map in definite length arrays", + QCBOR_DECODE_MODE_NORMAL, + {"\x81\x82\xbf\xff\xbf", 5}, + QCBOR_ERR_NO_MORE_ITEMS + }, + { "Unclosed definite length map in indefinite length arrays", + QCBOR_DECODE_MODE_NORMAL, + {"\x9f\x9f\xa1", 3}, + QCBOR_ERR_NO_MORE_ITEMS + }, - /* Untagged days-count epoch date */ - 0x11, - 0x19, 0x0F, 0x9A, /* 3994 */ +#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS */ - // End of map, back to array + /* The "argument" for the data item is incomplete */ + { "Positive integer missing 1 byte argument", + QCBOR_DECODE_MODE_NORMAL, + {"\x18", 1}, + QCBOR_ERR_HIT_END + }, + { "Positive integer missing 2 byte argument", + QCBOR_DECODE_MODE_NORMAL, + {"\x19", 1}, + QCBOR_ERR_HIT_END + }, + { "Positive integer missing 4 byte argument", + QCBOR_DECODE_MODE_NORMAL, + {"\x1a", 1}, + QCBOR_ERR_HIT_END + }, + { "Positive integer missing 8 byte argument", + QCBOR_DECODE_MODE_NORMAL, + {"\x1b", 1}, + QCBOR_ERR_HIT_END + }, + { "Positive integer missing 1 byte of 2 byte argument", + QCBOR_DECODE_MODE_NORMAL, + {"\x19\x01", 2}, + QCBOR_ERR_HIT_END + }, + { "Positive integer missing 2 bytes of 4 byte argument", + QCBOR_DECODE_MODE_NORMAL, + {"\x1a\x01\x02", 3}, + QCBOR_ERR_HIT_END + }, + { "Positive integer missing 1 bytes of 7 byte argument", + QCBOR_DECODE_MODE_NORMAL, + {"\x1b\x01\x02\x03\x04\x05\x06\x07", 8}, + QCBOR_ERR_HIT_END + }, + { "Negative integer missing 1 byte argument", + QCBOR_DECODE_MODE_NORMAL, + {"\x38", 1}, + QCBOR_ERR_HIT_END + }, + { "Binary string missing 1 byte argument", + QCBOR_DECODE_MODE_NORMAL, + {"\x58", 1}, + QCBOR_ERR_HIT_END + }, + { "Text string missing 1 byte argument", + QCBOR_DECODE_MODE_NORMAL, + {"\x78", 1}, + QCBOR_ERR_HIT_END + }, + { "Array missing 1 byte argument", + QCBOR_DECODE_MODE_NORMAL, + {"\x98", 1}, + QCBOR_ERR_HIT_END + }, + { "Map missing 1 byte argument", + QCBOR_DECODE_MODE_NORMAL, + {"\xb8", 1}, + QCBOR_ERR_HIT_END + }, + { "Tag missing 1 byte argument", + QCBOR_DECODE_MODE_NORMAL, + {"\xd8", 1}, + QCBOR_ERR_HIT_END + }, + { "Simple missing 1 byte argument", + QCBOR_DECODE_MODE_NORMAL, + {"\xf8", 1}, + QCBOR_ERR_HIT_END + }, + { "half-precision with 1 byte argument", + QCBOR_DECODE_MODE_NORMAL, + {"\xf9\x00", 2}, + QCBOR_ERR_HIT_END + }, + { "single-precision with 2 byte argument", + QCBOR_DECODE_MODE_NORMAL, + {"\0xfa\x00\x00", 3}, + QCBOR_ERR_HIT_END + }, + { "double-precision with 3 byte argument", + QCBOR_DECODE_MODE_NORMAL, + {"\xfb\x00\x00\x00", 4}, + QCBOR_ERR_HIT_END + }, - 0xa7, // Open map of tagged items with labels +#ifndef QCBOR_DISABLE_TAGS + { "Tag with no content", + QCBOR_DECODE_MODE_NORMAL, + {"\xc0", 1}, + QCBOR_ERR_HIT_END + }, +#else /* QCBOR_DISABLE_TAGS */ + { "Tag with no content", + QCBOR_DECODE_MODE_NORMAL, + {"\xc0", 1}, + QCBOR_ERR_TAGS_DISABLED + }, +#endif /* QCBOR_DISABLE_TAGS */ - 0x00, - 0xc0, // tag for string date - 0x6a, '1','9','8','5','-','0','4','-','1','2', // Tagged date string + /* Breaks must not occur in definite length arrays and maps */ + { "Array of length 1 with sole member replaced by a break", + QCBOR_DECODE_MODE_NORMAL, + {"\x81\xff", 2}, + QCBOR_ERR_BAD_BREAK + }, + { "Array of length 2 with 2nd member replaced by a break", + QCBOR_DECODE_MODE_NORMAL, + {"\x82\x00\xff", 3}, + QCBOR_ERR_BAD_BREAK + }, + { "Map of length 1 with sole member label replaced by a break", + QCBOR_DECODE_MODE_NORMAL, + {"\xa1\xff", 2}, + QCBOR_ERR_BAD_BREAK + }, + /* Map of length 1 with sole member label replaced by break */ + { "Alternate representation that some decoders handle differently", + QCBOR_DECODE_MODE_NORMAL, + {"\xa1\xff\x00", 3}, + QCBOR_ERR_BAD_BREAK + }, + { "Array of length 1 with 2nd member value replaced by a break", + QCBOR_DECODE_MODE_NORMAL, + {"\xa1\x00\xff", 3}, + QCBOR_ERR_BAD_BREAK + }, + { "Map of length 2 with 2nd entry label replaced by a break", + QCBOR_DECODE_MODE_NORMAL, + {"\xa2\x00\x00\xff\x00", 5}, + QCBOR_ERR_BAD_BREAK + }, + { "Map of length 2 with 2nd entry value replaced by a break", + QCBOR_DECODE_MODE_NORMAL, + {"\xa2\x00\x00\x01\xff", 5}, + QCBOR_ERR_BAD_BREAK + }, - 0x01, - 0xda, 0x03, 0x03, 0x03, 0x03, // An additional tag - 0xc1, // tag for epoch date - 0x1a, 0x53, 0x72, 0x4E, 0x00, // Epoch date 1400000000; Tue, 13 May 2014 16:53:20 GMT + /* Breaks must not occur on their own out of an indefinite length data item */ + { "A bare break is not well formed", + QCBOR_DECODE_MODE_NORMAL, + {"\xff", 1}, + QCBOR_ERR_BAD_BREAK + }, + { "A bare break after a zero length definite length array", + QCBOR_DECODE_MODE_NORMAL, + {"\x80\xff", 2}, + QCBOR_ERR_BAD_BREAK + }, +#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS + { "A bare break after a zero length indefinite length map", + QCBOR_DECODE_MODE_NORMAL, + {"\x9f\xff\xff", 3}, + QCBOR_ERR_BAD_BREAK + }, + { "A break inside a definite length array inside an indefenite length array", + QCBOR_DECODE_MODE_NORMAL, + {"\x9f\x81\xff", 3}, + QCBOR_ERR_BAD_BREAK + }, + { "Complicated mixed nesting with break outside indefinite length array", + QCBOR_DECODE_MODE_NORMAL, + {"\x9f\x82\x9f\x81\x9f\x9f\xff\xff\xff\xff", 10}, + QCBOR_ERR_BAD_BREAK }, +#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS */ - 0x05, - 0xc1, - 0xfb, 0xc3, 0xdf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, // -9223372036854773760 largest negative + /* Forbidden two byte encodings of simple types */ + { "Must use 0xe0 instead", + QCBOR_DECODE_MODE_NORMAL, + {"\xf8\x00", 2}, + QCBOR_ERR_BAD_TYPE_7 + }, + { "Should use 0xe1 instead", + QCBOR_DECODE_MODE_NORMAL, + {"\xf8\x01", 2}, + QCBOR_ERR_BAD_TYPE_7 + }, + { "Should use 0xe2 instead", + QCBOR_DECODE_MODE_NORMAL, + {"\xf8\x02", 2}, + QCBOR_ERR_BAD_TYPE_7 + }, { "Should use 0xe3 instead", + QCBOR_DECODE_MODE_NORMAL, + {"\xf8\x03", 2}, + QCBOR_ERR_BAD_TYPE_7 + }, + { "Should use 0xe4 instead", + QCBOR_DECODE_MODE_NORMAL, + {"\xf8\x04", 2}, + QCBOR_ERR_BAD_TYPE_7 + }, + { "Should use 0xe5 instead", + QCBOR_DECODE_MODE_NORMAL, + {"\xf8\x05", 2}, + QCBOR_ERR_BAD_TYPE_7 + }, + { "Should use 0xe6 instead", + QCBOR_DECODE_MODE_NORMAL, + {"\xf8\x06", 2}, + QCBOR_ERR_BAD_TYPE_7 + }, + { "Should use 0xe7 instead", + QCBOR_DECODE_MODE_NORMAL, + {"\xf8\x07", 2}, + QCBOR_ERR_BAD_TYPE_7 + }, + { "Should use 0xe8 instead", + QCBOR_DECODE_MODE_NORMAL, + {"\xf8\x08", 2}, + QCBOR_ERR_BAD_TYPE_7 + }, + { "Should use 0xe9 instead", + QCBOR_DECODE_MODE_NORMAL, + {"\xf8\x09", 2}, + QCBOR_ERR_BAD_TYPE_7 + }, + { "Should use 0xea instead", + QCBOR_DECODE_MODE_NORMAL, + {"\xf8\x0a", 2}, + QCBOR_ERR_BAD_TYPE_7 + }, + { "Should use 0xeb instead", + QCBOR_DECODE_MODE_NORMAL, + {"\xf8\x0b", 2}, + QCBOR_ERR_BAD_TYPE_7 + }, + { "Should use 0xec instead", + QCBOR_DECODE_MODE_NORMAL, + {"\xf8\x0c", 2}, + QCBOR_ERR_BAD_TYPE_7 + }, + { "Should use 0xed instead", + QCBOR_DECODE_MODE_NORMAL, + {"\xf8\x0d", 2}, + QCBOR_ERR_BAD_TYPE_7 + }, + { "Should use 0xee instead", + QCBOR_DECODE_MODE_NORMAL, + {"\xf8\x0e", 2}, + QCBOR_ERR_BAD_TYPE_7 + }, + { "Should use 0xef instead", + QCBOR_DECODE_MODE_NORMAL, + {"\xf8\x0f", 2}, + QCBOR_ERR_BAD_TYPE_7 + }, + { "Should use 0xf0 instead", + QCBOR_DECODE_MODE_NORMAL, + {"\xf8\x10", 2}, + QCBOR_ERR_BAD_TYPE_7 + }, + { "Should use 0xf1 instead", + QCBOR_DECODE_MODE_NORMAL, + {"\xf8\x11", 2}, + QCBOR_ERR_BAD_TYPE_7 + }, + { "Should use 0xf2 instead", + QCBOR_DECODE_MODE_NORMAL, + {"\xf8\x12", 2}, + QCBOR_ERR_BAD_TYPE_7 + }, + { "Should use 0xf3 instead", + QCBOR_DECODE_MODE_NORMAL, + {"\xf8\x13", 2}, + QCBOR_ERR_BAD_TYPE_7 + }, + { "Should use 0xf4 instead", + QCBOR_DECODE_MODE_NORMAL, + {"\xf8\x14", 2}, + QCBOR_ERR_BAD_TYPE_7 + }, + { "Should use 0xf5 instead", + QCBOR_DECODE_MODE_NORMAL, + {"\xf8\x15", 2}, + QCBOR_ERR_BAD_TYPE_7 + }, + { "Should use 0xf6 instead", + QCBOR_DECODE_MODE_NORMAL, + {"\xf8\x16", 2}, + QCBOR_ERR_BAD_TYPE_7 + }, + { "Should use 0xef7 instead", + QCBOR_DECODE_MODE_NORMAL, + {"\xf8\x17", 2}, + QCBOR_ERR_BAD_TYPE_7 + }, + { "Should use 0xef8 instead", + QCBOR_DECODE_MODE_NORMAL, + {"\xf8\x18", 2}, + QCBOR_ERR_BAD_TYPE_7 + }, + { "Reserved", + QCBOR_DECODE_MODE_NORMAL, + {"\xf8\x18", 2}, + QCBOR_ERR_BAD_TYPE_7 + }, + /* Maps must have an even number of data items (key & value) */ + { "Map with 1 item when it should have 2", + QCBOR_DECODE_MODE_NORMAL, + {"\xa1\x00", 2}, + QCBOR_ERR_HIT_END + }, + { "Map with 3 item when it should have 4", + QCBOR_DECODE_MODE_NORMAL, + {"\xa2\x00\x00\x00", 2}, + QCBOR_ERR_HIT_END + }, +#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS + { "Map with 1 item when it should have 2", + QCBOR_DECODE_MODE_NORMAL, + {"\xbf\x00\xff", 3}, + QCBOR_ERR_BAD_BREAK + }, + { "Map with 3 item when it should have 4", + QCBOR_DECODE_MODE_NORMAL, + {"\xbf\x00\x00\x00\xff", 5}, + QCBOR_ERR_BAD_BREAK + }, +#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS */ - 0x07, - 0xc1, // tag for epoch date - 0xfb, 0x43, 0xdf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, // 9223372036854773760 largest supported - /* Tagged days-count epoch date */ - 0x63, 0x53, 0x44, 0x45, - 0xD8, 0x64, /* tag(100) */ - 0x39, 0x29, 0xB3, /* -10676 */ +#ifndef QCBOR_DISABLE_TAGS + /* In addition to not-well-formed, some invalid CBOR */ + { "Text-based date, with an integer", + QCBOR_DECODE_MODE_NORMAL, + {"\xc0\x00", 2}, + QCBOR_ERR_BAD_OPT_TAG + }, + { "Epoch date, with an byte string", + QCBOR_DECODE_MODE_NORMAL, + {"\xc1\x41\x33", 3}, + QCBOR_ERR_BAD_OPT_TAG + }, + { "tagged as both epoch and string dates", + QCBOR_DECODE_MODE_NORMAL, + {"\xc1\xc0\x00", 3}, + QCBOR_ERR_BAD_OPT_TAG + }, + { "big num tagged an int, not a byte string", + QCBOR_DECODE_MODE_NORMAL, + {"\xc2\x00", 2}, + QCBOR_ERR_BAD_OPT_TAG + }, +#else /* QCBOR_DISABLE_TAGS */ + /* In addition to not-well-formed, some invalid CBOR */ + { "Text-based date, with an integer", + QCBOR_DECODE_MODE_NORMAL, + {"\xc0\x00", 2}, + QCBOR_ERR_TAGS_DISABLED + }, + { "Epoch date, with an byte string", + QCBOR_DECODE_MODE_NORMAL, + {"\xc1\x41\x33", 3}, + QCBOR_ERR_TAGS_DISABLED + }, + { "tagged as both epoch and string dates", + QCBOR_DECODE_MODE_NORMAL, + {"\xc1\xc0\x00", 3}, + QCBOR_ERR_TAGS_DISABLED + }, + { "big num tagged an int, not a byte string", + QCBOR_DECODE_MODE_NORMAL, + {"\xc2\x00", 2}, + QCBOR_ERR_TAGS_DISABLED + }, +#endif /* QCBOR_DISABLE_TAGS */ +}; - // Untagged -1000 with label z - 0x61, 0x7a, - 0xda, 0x01, 0x01, 0x01, 0x01, // An additional tag - 0x39, 0x03, 0xe7, - /* Tagged date-only date string */ - 0x63, 0x53, 0x44, 0x53, - 0xD9, 0x03, 0xEC, - 0x6A, 0x31, 0x39, 0x38, 0x35, 0x2D, 0x30, 0x34, 0x2D, 0x31, 0x32, /* "1985-04-12" */ - // End of map of tagged items +int32_t +DecodeFailureTests(void) +{ + int32_t nResult; - 0xc1, - 0xfb, 0xc3, 0xdf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, // -9.2233720368547748E+18, too negative + nResult = ProcessDecodeFailures(Failures ,C_ARRAY_COUNT(Failures, struct DecodeFailTestInput)); + if(nResult) { + return nResult; + } - 0xc1, // tag for epoch date - 0x1b, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, // Too-large integer + // Corrupt the UsefulInputBuf and see that + // it reflected correctly for CBOR decoding + QCBORDecodeContext DCtx; + QCBORItem Item; + QCBORError uQCBORError; - 0xc1, // tag for epoch date - 0xf9, 0xfc, 0x00, // Half-precision -Infinity + QCBORDecode_Init(&DCtx, + UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spSimpleValues), + QCBOR_DECODE_MODE_NORMAL); - // These two at the end because they are unrecoverable errors - 0xc1, // tag for epoch date - 0x80, // Erroneous empty array as content for date + if((uQCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { + return (int32_t)uQCBORError; + } + if(Item.uDataType != QCBOR_TYPE_ARRAY || Item.val.uCount != 10) { + // This wasn't supposed to happen + return -1; + } - 0xc0, // tag for string date - 0xa0 // Erroneous empty map as content for date -}; + DCtx.InBuf.magic = 0; // Reach in and corrupt the UsefulInputBuf -int32_t SpiffyDateDecodeTest(void) -{ - QCBORDecodeContext DC; - QCBORError uError; - int64_t nEpochDate3, nEpochDate5, - nEpochDate4, nEpochDate6, - nEpochDays2; - UsefulBufC StringDate1, StringDate2, StringDays2; + uQCBORError = QCBORDecode_GetNext(&DCtx, &Item); + if(uQCBORError != QCBOR_ERR_NO_MORE_ITEMS) { + // Did not get back the error expected + return -2; + } - QCBORDecode_Init(&DC, - UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spSpiffyDateTestInput), - QCBOR_DECODE_MODE_NORMAL); - /* Items are in an array or map to test look up by label and other - * that might not occur in isolated items. But it does make the - * test a bit messy. */ - QCBORDecode_EnterArray(&DC, NULL); + /* + The max size of a string for QCBOR is SIZE_MAX - 4 so this + tests here can be performed to see that the max length + error check works correctly. See DecodeBytes(). If the max + size was SIZE_MAX, it wouldn't be possible to test this. - QCBORDecode_EnterMap(&DC, NULL); + This test will automatocally adapt the all CPU sizes + through the use of SIZE_MAX. + */ - // A single-precision date - QCBORDecode_GetEpochDateInMapSZ(&DC, "x", QCBOR_TAG_REQUIREMENT_OPTIONAL_TAG, - &nEpochDate5); - uError = QCBORDecode_GetAndResetError(&DC); - if(uError != FLOAT_ERR_CODE_NO_FLOAT_HW(QCBOR_SUCCESS)) { - return 104; - } - if(uError == QCBOR_SUCCESS) { - if(nEpochDate5 != 3) { - return 103; - } - } + UsefulBuf_MAKE_STACK_UB( HeadBuf, QCBOR_HEAD_BUFFER_SIZE); + UsefulBufC EncodedHead; - // A half-precision date with value -2 FFF - QCBORDecode_GetEpochDateInMapN(&DC, 9, QCBOR_TAG_REQUIREMENT_OPTIONAL_TAG, - &nEpochDate4); - uError = QCBORDecode_GetAndResetError(&DC); - if(uError != FLOAT_ERR_CODE_NO_HALF_PREC_NO_FLOAT_HW(QCBOR_SUCCESS)) { - return 106; - } - if(uError == QCBOR_SUCCESS) { - if(nEpochDate4 != -2) { - return 105; - } - } + // This makes a CBOR head with a text string that is very long + // but doesn't fill in the bytes of the text string as that is + // not needed to test this part of QCBOR. + EncodedHead = QCBOREncode_EncodeHead(HeadBuf, CBOR_MAJOR_TYPE_TEXT_STRING, 0, SIZE_MAX); - // Fail to get an epoch date by string label - QCBORDecode_GetEpochDateInMapSZ(&DC, "no-label", - QCBOR_TAG_REQUIREMENT_NOT_A_TAG, - &nEpochDate6); - uError = QCBORDecode_GetAndResetError(&DC); - if(uError != QCBOR_ERR_LABEL_NOT_FOUND) { - return 107; - } + QCBORDecode_Init(&DCtx, EncodedHead, QCBOR_DECODE_MODE_NORMAL); - // Fail to get an epoch date by integer label - QCBORDecode_GetEpochDateInMapN(&DC, 99999, QCBOR_TAG_REQUIREMENT_NOT_A_TAG, - &nEpochDate6); - uError = QCBORDecode_GetAndResetError(&DC); - if(uError != QCBOR_ERR_LABEL_NOT_FOUND) { - return 108; + if(QCBOR_ERR_STRING_TOO_LONG != QCBORDecode_GetNext(&DCtx, &Item)) { + return -4; } - // Fail to get a string date by string label - QCBORDecode_GetDateStringInMapSZ(&DC, "no-label", - QCBOR_TAG_REQUIREMENT_NOT_A_TAG, - &StringDate1); - uError = QCBORDecode_GetAndResetError(&DC); - if(uError != QCBOR_ERR_LABEL_NOT_FOUND) { - return 109; + return 0; +} + + +/* Try all 256 values of the byte at nLen including recursing for + each of the values to try values at nLen+1 ... up to nLenMax + */ +static void ComprehensiveInputRecurser(uint8_t *pBuf, size_t nLen, size_t nLenMax) +{ + if(nLen >= nLenMax) { + return; } - // Fail to get a string date by integer label - QCBORDecode_GetDateStringInMapN(&DC, 99999, QCBOR_TAG_REQUIREMENT_NOT_A_TAG, - &StringDate1); - uError = QCBORDecode_GetAndResetError(&DC); - if(uError != QCBOR_ERR_LABEL_NOT_FOUND) { - return 110; + for(int inputByte = 0; inputByte < 256; inputByte++) { + // Set up the input + pBuf[nLen] = (uint8_t)inputByte; + const UsefulBufC Input = {pBuf, nLen+1}; + + // Get ready to parse + QCBORDecodeContext DCtx; + QCBORDecode_Init(&DCtx, Input, QCBOR_DECODE_MODE_NORMAL); + + // Parse by getting the next item until an error occurs + // Just about every possible decoder error can occur here + // The goal of this test is not to check for the correct + // error since that is not really possible. It is to + // see that there is no crash on hostile input. + while(1) { + QCBORItem Item; + QCBORError nCBORError = QCBORDecode_GetNext(&DCtx, &Item); + if(nCBORError != QCBOR_SUCCESS) { + break; + } + } + + ComprehensiveInputRecurser(pBuf, nLen+1, nLenMax); } +} - // The rest of these succeed even if float features are disabled +int32_t ComprehensiveInputTest(void) +{ + // Size 2 tests 64K inputs and runs quickly + uint8_t pBuf[2]; - // Untagged integer 0 - QCBORDecode_GetEpochDateInMapN(&DC, 8, QCBOR_TAG_REQUIREMENT_NOT_A_TAG, - &nEpochDate3); - // Untagged date string - QCBORDecode_GetDateStringInMapSZ(&DC, "y", QCBOR_TAG_REQUIREMENT_NOT_A_TAG, - &StringDate2); + ComprehensiveInputRecurser(pBuf, 0, sizeof(pBuf)); - QCBORDecode_GetDaysStringInMapN(&DC, 99, QCBOR_TAG_REQUIREMENT_NOT_A_TAG, - &StringDays2); + return 0; +} - QCBORDecode_GetEpochDaysInMapN(&DC, 17, QCBOR_TAG_REQUIREMENT_NOT_A_TAG, - &nEpochDays2); - QCBORDecode_ExitMap(&DC); - if(QCBORDecode_GetError(&DC) != QCBOR_SUCCESS) { - return 3001; - } +int32_t BigComprehensiveInputTest(void) +{ + // size 3 tests 16 million inputs and runs OK + // in seconds on fast machines. Size 4 takes + // 10+ minutes and 5 half a day on fast + // machines. This test is kept separate from + // the others so as to no slow down the use + // of them as a very frequent regression. + uint8_t pBuf[3]; // - // The map of tagged items - QCBORDecode_EnterMap(&DC, NULL); + ComprehensiveInputRecurser(pBuf, 0, sizeof(pBuf)); -#ifndef QCBOR_DISABLE_TAGS - int64_t nEpochDate2, - nEpochDateFail, - nEpochDate1400000000, nEpochDays1; - UsefulBufC StringDays1; - uint64_t uTag1, uTag2; + return 0; +} - // Tagged date string - QCBORDecode_GetDateStringInMapN(&DC, 0, QCBOR_TAG_REQUIREMENT_OPTIONAL_TAG, - &StringDate1); - // Epoch date 1400000000; Tue, 13 May 2014 16:53:20 GMT - QCBORDecode_GetEpochDateInMapN(&DC, - 1, - QCBOR_TAG_REQUIREMENT_TAG | - QCBOR_TAG_REQUIREMENT_ALLOW_ADDITIONAL_TAGS, - &nEpochDate1400000000); - uTag1 = QCBORDecode_GetNthTagOfLast(&DC, 0); +static const uint8_t spDateTestInput[] = { + /* 1. The valid date string "1985-04-12" */ + 0xc0, // tag for string date + 0x6a, '1','9','8','5','-','0','4','-','1','2', // Date string - // Get largest negative double precision epoch date allowed - QCBORDecode_GetEpochDateInMapN(&DC, - 5, - QCBOR_TAG_REQUIREMENT_OPTIONAL_TAG | - QCBOR_TAG_REQUIREMENT_ALLOW_ADDITIONAL_TAGS, - &nEpochDate2); - uError = QCBORDecode_GetAndResetError(&DC); - if(uError != FLOAT_ERR_CODE_NO_FLOAT_HW(QCBOR_SUCCESS)) { - return 102; - } - if(uError == QCBOR_SUCCESS) { - if(nEpochDate2 != -9223372036854773760LL) { - return 101; - } - } + /* 2. An invalid date string due to wrong tag content type */ + 0xc0, // tag for string date + 0x00, // Wrong type for a string date - // Untagged -1000 with label z - QCBORDecode_GetEpochDateInMapSZ(&DC, - "z", - QCBOR_TAG_REQUIREMENT_NOT_A_TAG | - QCBOR_TAG_REQUIREMENT_ALLOW_ADDITIONAL_TAGS, - &nEpochDate6); - uTag2 = QCBORDecode_GetNthTagOfLast(&DC, 0); + /* 3. A valid epoch date, 1400000000; Tue, 13 May 2014 16:53:20 GMT */ + 0xc1, // tag for epoch date + 0x1a, 0x53, 0x72, 0x4E, 0x00, // Epoch date 1400000000; Tue, 13 May 2014 16:53:20 GMT + /* 4. An invalid epoch date due to wrong tag content type */ + 0xc1, + 0x62, 'h', 'i', // wrong type tagged - // Get largest double precision epoch date allowed - QCBORDecode_GetEpochDateInMapN(&DC, 7, QCBOR_TAG_REQUIREMENT_OPTIONAL_TAG, - &nEpochDate2); - uError = QCBORDecode_GetAndResetError(&DC); - if(uError != FLOAT_ERR_CODE_NO_FLOAT_HW(QCBOR_SUCCESS)) { - return 112; - } - if(uError == QCBOR_SUCCESS) { - if(nEpochDate2 != 9223372036854773760ULL) { - return 111; - } - } + /* 5. Valid epoch date tag as content for a two other nested tags */ + // CBOR_TAG_ENC_AS_B64 + 0xcf, 0xd8, 0x16, 0xc1, // Epoch date with extra tags + 0x1a, 0x53, 0x72, 0x4E, 0x01, - /* The days format is much simpler than the date format - * because it can't be a floating point value. The test - * of the spiffy decode functions sufficiently covers - * the test of the non-spiffy decode days date decoding. - * There is no full fan out of the error conditions - * and decode options as that is implemented by code - * that is tested well by the date testing above. - */ - QCBORDecode_GetDaysStringInMapSZ(&DC, "SDS", QCBOR_TAG_REQUIREMENT_TAG, - &StringDays1); + /* 6. Epoch date with value to large to fit into int64 */ + 0xc1, // tag for epoch date + 0x1b, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, // Too large integer - QCBORDecode_GetEpochDaysInMapSZ(&DC, "SDE", QCBOR_TAG_REQUIREMENT_TAG, - &nEpochDays1); + /* 7. Epoch date with single-precision value of 1.1. */ + 0xc1, // tag for epoch date + 0xfa, 0x3f, 0x8c, 0xcc, 0xcd, // single with value 1.1 - QCBORDecode_ExitMap(&DC); - if(QCBORDecode_GetError(&DC) != QCBOR_SUCCESS) { - return 3001; - } + /* 8. Epoch date with too-large single precision float */ + 0xc1, // tag for epoch date + 0xfa, 0x7f, 0x7f, 0xff, 0xff, // 3.4028234663852886e+38 too large - // Too-negative float, -9.2233720368547748E+18 - QCBORDecode_GetEpochDate(&DC, QCBOR_TAG_REQUIREMENT_TAG, &nEpochDateFail); - uError = QCBORDecode_GetAndResetError(&DC); - if(uError != FLOAT_ERR_CODE_NO_FLOAT_HW(QCBOR_ERR_DATE_OVERFLOW)) { - return 1111; - } + /* 9. Epoch date with slightly too-large double precision value */ + 0xc1, // tag for epoch date + 0xfb, 0x43, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 9223372036854775808.000000 just barely too large + //0xfa, 0x7f, 0x7f, 0xff, 0xff // 3.4028234663852886e+38 too large - // Too-large integer - QCBORDecode_GetEpochDate(&DC, QCBOR_TAG_REQUIREMENT_TAG, &nEpochDateFail); - uError = QCBORDecode_GetAndResetError(&DC); - if(uError != QCBOR_ERR_DATE_OVERFLOW) { - return 1; - } + /* 10. Epoch date with largest supported double precision value */ + 0xc1, // tag for epoch date + 0xfb, 0x43, 0xdf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, // 9223372036854773760 largest supported - // Half-precision minus infinity - QCBORDecode_GetEpochDate(&DC, QCBOR_TAG_REQUIREMENT_TAG, &nEpochDateFail); - uError = QCBORDecode_GetAndResetError(&DC); - if(uError != FLOAT_ERR_CODE_NO_HALF_PREC_NO_FLOAT_HW(QCBOR_ERR_DATE_OVERFLOW)) { - return 2; - } + /* 11. Epoch date with single-precision NaN */ + 0xc1, // tag for epoch date + 0xfa, 0x7f, 0xc0, 0x00, 0x00, // Single-precision NaN + /* 12. Epoch date with double precision plus infinity */ + 0xc1, + 0xfb, 0x7f, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // +infinity - // Bad content for epoch date - QCBORDecode_GetEpochDate(&DC, QCBOR_TAG_REQUIREMENT_TAG, &nEpochDateFail); - uError = QCBORDecode_GetAndResetError(&DC); - if(uError != QCBOR_ERR_UNRECOVERABLE_TAG_CONTENT) { - return 3; - } + /* 13. Epoch date with half-precision negative infinity */ + 0xc1, // tag for epoch date + 0xf9, 0xfc, 0x00, // -Infinity +}; - // Bad content for string date - QCBORDecode_GetDateString(&DC, QCBOR_TAG_REQUIREMENT_TAG, &StringDate1); - uError = QCBORDecode_GetAndResetError(&DC); - if(uError != QCBOR_ERR_UNRECOVERABLE_TAG_CONTENT) { - return 4; - } - QCBORDecode_ExitArray(&DC); - uError = QCBORDecode_Finish(&DC); - if(uError != QCBOR_ERR_UNRECOVERABLE_TAG_CONTENT) { - return 1000 + (int32_t)uError; - } -#else /* QCBOR_DISABLE_TAGS */ - QCBORDecode_GetDateStringInMapN(&DC, 0, QCBOR_TAG_REQUIREMENT_OPTIONAL_TAG, - &StringDate1); - uError = QCBORDecode_GetAndResetError(&DC); - if(uError != QCBOR_ERR_TAGS_DISABLED) { - return 4; - } -#endif /* QCBOR_DISABLE_TAGS */ +// have to check float expected only to within an epsilon +#ifndef QCBOR_DISABLE_FLOAT_HW_USE +static int CHECK_EXPECTED_DOUBLE(double val, double expected) { + + double diff = val - expected; -#ifndef QCBOR_DISABLE_TAGS + diff = fabs(diff); - if(nEpochDate1400000000 != 1400000000) { - return 200; + return diff > 0.0000001; +} +#endif /* QCBOR_DISABLE_FLOAT_HW_USE */ + + +/* Test date decoding using GetNext() */ +int32_t DateParseTest(void) +{ + QCBORDecodeContext DCtx; + QCBORItem Item; + QCBORError uError; + + QCBORDecode_Init(&DCtx, + UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spDateTestInput), + QCBOR_DECODE_MODE_NORMAL); + + /* 1. The valid date string "1985-04-12" */ + if((uError = QCBORDecode_GetNext(&DCtx, &Item))) { + return -1; + } + if(Item.uDataType != QCBOR_TYPE_DATE_STRING || + UsefulBufCompareToSZ(Item.val.string, "1985-04-12")){ + return -2; } - if(uTag1 != 0x03030303) { - return 201; + /* 2. An invalid date string due to wrong tag content type */ + uError = QCBORDecode_GetNext(&DCtx, &Item); + if(uError != QCBOR_ERR_BAD_OPT_TAG) { + return -3; } - if(nEpochDays1 != -10676) { - return 205; + /* 3. A valid epoch date, 1400000000; Tue, 13 May 2014 16:53:20 GMT */ + uError = QCBORDecode_GetNext(&DCtx, &Item); + if(uError != QCBOR_SUCCESS) { + return -4; + } + if(uError == QCBOR_SUCCESS) { + if(Item.uDataType != QCBOR_TYPE_DATE_EPOCH || + Item.val.epochDate.nSeconds != 1400000000 +#ifndef USEFULBUF_DISABLE_ALL_FLOAT + || Item.val.epochDate.fSecondsFraction != 0 +#endif /* USEFULBUF_DISABLE_ALL_FLOAT */ + ) { + return -5; + } } - if(UsefulBuf_Compare(StringDays1, UsefulBuf_FromSZ("1985-04-12"))) { - return 207; + /* 4. An invalid epoch date due to wrong tag content type */ + if(QCBORDecode_GetNext(&DCtx, &Item) != QCBOR_ERR_BAD_OPT_TAG) { + return -6; } - if(uTag2 != 0x01010101) { - return 204; + /* 5. Valid epoch date tag as content for a two other nested tags */ + // Epoch date wrapped in an CBOR_TAG_ENC_AS_B64 and an unknown tag. + // The date is decoded and the two tags are returned. This is to + // make sure the wrapping of epoch date in another tag works OK. + if((uError = QCBORDecode_GetNext(&DCtx, &Item))) { + return -7; + } + if(Item.uDataType != QCBOR_TYPE_DATE_EPOCH || + Item.val.epochDate.nSeconds != 1400000001 || +#ifndef USEFULBUF_DISABLE_ALL_FLOAT + Item.val.epochDate.fSecondsFraction != 0 || +#endif /* USEFULBUF_DISABLE_ALL_FLOAT */ + !QCBORDecode_IsTagged(&DCtx, &Item, CBOR_TAG_ENC_AS_B64)) { + return -8; } - if(nEpochDate6 != -1000) { - return 203; + /* 6. Epoch date with value to large to fit into int64 */ + if(QCBORDecode_GetNext(&DCtx, &Item) != QCBOR_ERR_DATE_OVERFLOW) { + return -9; } - if(UsefulBuf_Compare(StringDate1, UsefulBuf_FromSZ("1985-04-12"))) { - return 205; + /* 7. Epoch date with single-precision value of 1.1. */ + uError = QCBORDecode_GetNext(&DCtx, &Item); + if(uError != FLOAT_ERR_CODE_NO_FLOAT_HW(QCBOR_SUCCESS)) { + return -10; + } + if(uError == QCBOR_SUCCESS) { + if(Item.uDataType != QCBOR_TYPE_DATE_EPOCH || + Item.val.epochDate.nSeconds != 1 +#ifndef QCBOR_DISABLE_FLOAT_HW_USE + || CHECK_EXPECTED_DOUBLE(Item.val.epochDate.fSecondsFraction, 0.1) +#endif /* USEFULBUF_DISABLE_ALL_FLOAT */ + ) { + return -11; + } } -#endif /* QCBOR_DISABLE_TAGS */ + /* 8. Epoch date with too-large single-precision float */ + uError = QCBORDecode_GetNext(&DCtx, &Item); + if(uError != FLOAT_ERR_CODE_NO_FLOAT_HW(QCBOR_ERR_DATE_OVERFLOW)) { + return -12; + } - if(nEpochDate3 != 0) { - return 202; + /* 9. Epoch date with slightly too-large double-precision value */ + uError = QCBORDecode_GetNext(&DCtx, &Item); + if(uError != FLOAT_ERR_CODE_NO_FLOAT_HW(QCBOR_ERR_DATE_OVERFLOW)) { + return -13; } - if(nEpochDays2 != 3994) { - return 206; + /* 10. Epoch date with largest supported double-precision value */ + uError = QCBORDecode_GetNext(&DCtx, &Item); + if(uError != FLOAT_ERR_CODE_NO_FLOAT_HW(QCBOR_SUCCESS)) { + return -14; + } + if(uError == QCBOR_SUCCESS) { + if(Item.uDataType != QCBOR_TYPE_DATE_EPOCH || + Item.val.epochDate.nSeconds != 9223372036854773760 +#ifndef QCBOR_DISABLE_FLOAT_HW_USE + || Item.val.epochDate.fSecondsFraction != 0.0 +#endif /* QCBOR_DISABLE_FLOAT_HW_USE */ + ) { + return -14; + } } - if(UsefulBuf_Compare(StringDate2, UsefulBuf_FromSZ("2085-04-12"))) { - return 206; + /* 11. Epoch date with single-precision NaN */ + if(QCBORDecode_GetNext(&DCtx, &Item) != FLOAT_ERR_CODE_NO_FLOAT_HW(QCBOR_ERR_DATE_OVERFLOW)) { + return -15; } - if(UsefulBuf_Compare(StringDays2, UsefulBuf_FromSZ("1985-04-12"))) { - return 208; + /* 12. Epoch date with double-precision plus infinity */ + if(QCBORDecode_GetNext(&DCtx, &Item) != FLOAT_ERR_CODE_NO_FLOAT_HW(QCBOR_ERR_DATE_OVERFLOW)) { + return -16; + } + + /* 13. Epoch date with half-precision negative infinity */ + uError = QCBORDecode_GetNext(&DCtx, &Item); + if(uError != FLOAT_ERR_CODE_NO_HALF_PREC_NO_FLOAT_HW(QCBOR_ERR_DATE_OVERFLOW)) { + return -17; } return 0; } -// Input for one of the tagging tests -static const uint8_t spTagInput[] = { - 0xd9, 0xd9, 0xf7, // CBOR magic number - 0x81, // Array of one - 0xd8, 0x04, // non-preferred serialization of tag 4, decimal fraction - 0x82, // Array of two that is the faction 1/3 - 0x01, - 0x03, - - /* - More than 4 tags on an item 225(226(227(228(229([]))))) - */ - 0xd8, 0xe1, - 0xd8, 0xe2, - 0xd8, 0xe3, - 0xd8, 0xe4, - 0xd8, 0xe5, - 0x80, +/* + Test cases covered here. Some items cover more than one of these. + positive integer (zero counts as a positive integer) + negative integer + half-precision float + single-precision float + double-precision float - /* tag 10489608748473423768( - 2442302356( - 21590( - 240( - [])))) - */ - 0xdb, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, - 0xda, 0x91, 0x92, 0x93, 0x94, - 0xd9, 0x54, 0x56, - 0xd8, 0xf0, - 0x80, + float Overflow error + Wrong type error for epoch + Wrong type error for date string + float disabled error + half-precision disabled error + -Infinity + Slightly too large integer + Slightly too far from zero - /* tag 21590( - 10489608748473423768( - 2442302357( - 65534( - [])))) - */ - 0xdb, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x54, 0x56, - 0xdb, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, - 0xda, 0x91, 0x92, 0x93, 0x95, - 0xd9, 0xff, 0xfe, - 0x80, + Get epoch by int + Get string by int + Get epoch by string + Get string by string + Fail to get epoch by wrong int label + Fail to get string by wrong string label + Fail to get epoch by string because it is invalid + Fail to get epoch by int because it is invalid - /* Make sure to blow past the limit of tags that must be mapped. - works in conjuntion with entries above. - 269488144(269488145(269488146(269488147([])))) - */ - 0xda, 0x10, 0x10, 0x10, 0x10, - 0xda, 0x10, 0x10, 0x10, 0x11, - 0xda, 0x10, 0x10, 0x10, 0x12, - 0xda, 0x10, 0x10, 0x10, 0x13, - 0x80, + Untagged values + */ +static const uint8_t spSpiffyDateTestInput[] = { + 0x87, // array of 7 items - /* An invalid decimal fraction with an additional tag */ - 0xd9, 0xff, 0xfa, - 0xd8, 0x02, // non-preferred serialization of tag 2, a big num - 0x00, // the integer 0; should be a byte string -}; + 0xa6, // Open a map for tests involving untagged items with labels. -/* - DB 9192939495969798 # tag(10489608748473423768) - 80 # array(0) - */ -static const uint8_t spEncodedLargeTag[] = {0xdb, 0x91, 0x92, 0x93, 0x94, 0x95, - 0x96, 0x97, 0x98, 0x80}; + // Untagged integer 0 + 0x08, + 0x00, -/* -DB 9192939495969798 # tag(10489608748473423768) - D8 88 # tag(136) - C6 # tag(6) - C7 # tag(7) - 80 # array(0) -*/ -static const uint8_t spLotsOfTags[] = {0xdb, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, - 0x97, 0x98, 0xd8, 0x88, 0xc6, 0xc7, 0x80}; + // Utagged date string with string label y + 0x61, 0x79, + 0x6a, '2','0','8','5','-','0','4','-','1','2', // Untagged date string -/* - 55799(55799(55799({ - 6(7(-23)): 5859837686836516696(7({ - 7(-20): 11({ - 17(-18): 17(17(17("Organization"))), - 9(-17): 773("SSG"), - -15: 16(17(6(7("Confusion")))), - 17(-16): 17("San Diego"), - 17(-14): 17("US") - }), - 23(-19): 19({ - -11: 9({ - -9: -7 - }), - 90599561(90599561(90599561(-10))): 12(h'0102030405060708090A') - }) - })), - 16(-22): 23({ - 11(8(7(-5))): 8(-3) - }) - }))) - */ -static const uint8_t spCSRWithTags[] = { - 0xd9, 0xd9, 0xf7, 0xd9, 0xd9, 0xf7, 0xd9, 0xd9, 0xf7, 0xa2, - 0xc6, 0xc7, 0x36, - 0xdb, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0xc7, 0xa2, - 0xda, 0x00, 0x00, 0x00, 0x07, 0x33, - 0xcb, 0xa5, - 0xd1, 0x31, - 0xd1, 0xd1, 0xd1, 0x6c, - 0x4f, 0x72, 0x67, 0x61, 0x6e, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, - 0xc9, 0x30, - 0xd9, 0x03, 0x05, 0x63, - 0x53, 0x53, 0x47, - 0x2e, - 0xd0, 0xd1, 0xc6, 0xc7, - 0x69, - 0x43, 0x6f, 0x6e, 0x66, 0x75, 0x73, 0x69, 0x6f, 0x6e, - 0xd1, 0x2f, - 0xd1, 0x69, - 0x53, 0x61, 0x6e, 0x20, 0x44, 0x69, 0x65, 0x67, 0x6f, - 0xd1, 0x2d, - 0xd1, 0x62, - 0x55, 0x53, - 0xd7, 0x32, - 0xd3, 0xa2, - 0x2a, - 0xc9, 0xa1, - 0x28, - 0x26, - 0xda, 0x05, 0x66, 0x70, 0x89, 0xda, 0x05, 0x66, 0x70, 0x89, 0xda, 0x05, 0x66, 0x70, 0x89, 0x29, - 0xcc, 0x4a, - 0x01, 0x02, 0x03, 0x04, 0x05, 0x06,0x07, 0x08, 0x09, 0x0a, - 0xd0, 0x35, - 0xd7, 0xa1, - 0xcb, 0xc8, 0xc7, 0x24, - 0xc8, 0x22}; + // Untagged single-precision float with value 3.14 with string label x + 0x61, 0x78, + 0xFA, 0x40, 0x48, 0xF5, 0xC3, + // Untagged half-precision float with value -2 + 0x09, + 0xF9, 0xC0, 0x00, -static const uint8_t spSpiffyTagInput[] = { - 0x85, // Open array + /* Untagged date-only date string */ + 0x18, 0x63, + 0x6A, 0x31, 0x39, 0x38, 0x35, 0x2D, 0x30, 0x34, 0x2D, 0x31, 0x32, /* "1985-04-12" */ + + /* Untagged days-count epoch date */ + 0x11, + 0x19, 0x0F, 0x9A, /* 3994 */ + + // End of map, back to array + + 0xa7, // Open map of tagged items with labels + 0x00, 0xc0, // tag for string date - 0x6a, '1','9','8','5','-','0','4','-','1','2', // Date string + 0x6a, '1','9','8','5','-','0','4','-','1','2', // Tagged date string - 0x6a, '1','9','8','5','-','0','4','-','1','2', // Date string - 0x4a, '1','9','8','5','-','0','4','-','1','2', // Date string in byte string + 0x01, + 0xda, 0x03, 0x03, 0x03, 0x03, // An additional tag + 0xc1, // tag for epoch date + 0x1a, 0x53, 0x72, 0x4E, 0x00, // Epoch date 1400000000; Tue, 13 May 2014 16:53:20 GMT - 0xd8, 0x23, // tag for regex - 0x6a, '1','9','8','5','-','0','4','-','1','2', // Date string + 0x05, + 0xc1, + 0xfb, 0xc3, 0xdf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, // -9223372036854773760 largest negative - 0xc0, // tag for string date - 0x4a, '1','9','8','5','-','0','4','-','1','2', // Date string in byte string - // This last case makes the array untraversable because it is - // an uncrecoverable error. Make sure it stays last and is the only - // instance so the other tests can work. -}; + 0x07, + 0xc1, // tag for epoch date + 0xfb, 0x43, 0xdf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, // 9223372036854773760 largest supported + /* Tagged days-count epoch date */ + 0x63, 0x53, 0x44, 0x45, + 0xD8, 0x64, /* tag(100) */ + 0x39, 0x29, 0xB3, /* -10676 */ -static int32_t CheckCSRMaps(QCBORDecodeContext *pDC); + // Untagged -1000 with label z + 0x61, 0x7a, + 0xda, 0x01, 0x01, 0x01, 0x01, // An additional tag + 0x39, 0x03, 0xe7, + /* Tagged date-only date string */ + 0x63, 0x53, 0x44, 0x53, + 0xD9, 0x03, 0xEC, + 0x6A, 0x31, 0x39, 0x38, 0x35, 0x2D, 0x30, 0x34, 0x2D, 0x31, 0x32, /* "1985-04-12" */ -int32_t OptTagParseTest(void) + // End of map of tagged items + + 0xc1, + 0xfb, 0xc3, 0xdf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, // -9.2233720368547748E+18, too negative + + 0xc1, // tag for epoch date + 0x1b, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, // Too-large integer + + 0xc1, // tag for epoch date + 0xf9, 0xfc, 0x00, // Half-precision -Infinity + + // These two at the end because they are unrecoverable errors + 0xc1, // tag for epoch date + 0x80, // Erroneous empty array as content for date + + 0xc0, // tag for string date + 0xa0 // Erroneous empty map as content for date +}; + +int32_t SpiffyDateDecodeTest(void) { - QCBORDecodeContext DCtx; - QCBORItem Item; + QCBORDecodeContext DC; QCBORError uError; + int64_t nEpochDate3, nEpochDate5, + nEpochDate4, nEpochDate6, + nEpochDays2; + UsefulBufC StringDate1, StringDate2, StringDays2; - QCBORDecode_Init(&DCtx, - UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spTagInput), + QCBORDecode_Init(&DC, + UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spSpiffyDateTestInput), QCBOR_DECODE_MODE_NORMAL); - /* - This test matches the magic number tag and the fraction tag - 55799([...]) - */ - uError = QCBORDecode_GetNext(&DCtx, &Item); - if(uError != QCBOR_SUCCESS) { - return -2; + /* Items are in an array or map to test look up by label and other + * that might not occur in isolated items. But it does make the + * test a bit messy. */ + QCBORDecode_EnterArray(&DC, NULL); + + QCBORDecode_EnterMap(&DC, NULL); + + // A single-precision date + QCBORDecode_GetEpochDateInMapSZ(&DC, "x", QCBOR_TAG_REQUIREMENT_OPTIONAL_TAG, + &nEpochDate5); + uError = QCBORDecode_GetAndResetError(&DC); + if(uError != FLOAT_ERR_CODE_NO_FLOAT_HW(QCBOR_SUCCESS)) { + return 104; } - if(Item.uDataType != QCBOR_TYPE_ARRAY || - !QCBORDecode_IsTagged(&DCtx, &Item, CBOR_TAG_CBOR_MAGIC)) { - return -3; + if(uError == QCBOR_SUCCESS) { + if(nEpochDate5 != 3) { + return 103; + } } - /* - 4([1,3]) - */ - uError = QCBORDecode_GetNext(&DCtx, &Item); -#ifdef QCBOR_DISABLE_EXP_AND_MANTISSA - if(uError != QCBOR_SUCCESS || - Item.uDataType != QCBOR_TYPE_ARRAY || - !QCBORDecode_IsTagged(&DCtx, &Item, CBOR_TAG_DECIMAL_FRACTION) || - QCBORDecode_GetNthTag(&DCtx, &Item, 0) != CBOR_TAG_DECIMAL_FRACTION || - QCBORDecode_GetNthTag(&DCtx, &Item, 1) != CBOR_TAG_INVALID64 || - QCBORDecode_GetNthTag(&DCtx, &Item, 2) != CBOR_TAG_INVALID64 || - QCBORDecode_GetNthTag(&DCtx, &Item, 3) != CBOR_TAG_INVALID64 || - QCBORDecode_GetNthTag(&DCtx, &Item, 4) != CBOR_TAG_INVALID64 || - Item.val.uCount != 2) { - return -4; + // A half-precision date with value -2 FFF + QCBORDecode_GetEpochDateInMapN(&DC, 9, QCBOR_TAG_REQUIREMENT_OPTIONAL_TAG, + &nEpochDate4); + uError = QCBORDecode_GetAndResetError(&DC); + if(uError != FLOAT_ERR_CODE_NO_HALF_PREC_NO_FLOAT_HW(QCBOR_SUCCESS)) { + return 106; } - // consume the items in the array - uError = QCBORDecode_GetNext(&DCtx, &Item); - uError = QCBORDecode_GetNext(&DCtx, &Item); - -#else /* QCBOR_DISABLE_EXP_AND_MANTISSA */ - if(uError != QCBOR_SUCCESS || - Item.uDataType != QCBOR_TYPE_DECIMAL_FRACTION || - QCBORDecode_GetNthTag(&DCtx, &Item, 0) != CBOR_TAG_INVALID64 || - QCBORDecode_GetNthTag(&DCtx, &Item, 1) != CBOR_TAG_INVALID64 || - QCBORDecode_GetNthTag(&DCtx, &Item, 2) != CBOR_TAG_INVALID64 || - QCBORDecode_GetNthTag(&DCtx, &Item, 3) != CBOR_TAG_INVALID64 || - QCBORDecode_GetNthTag(&DCtx, &Item, 4) != CBOR_TAG_INVALID64 ) { - return -5; + if(uError == QCBOR_SUCCESS) { + if(nEpochDate4 != -2) { + return 105; + } } -#endif /* QCBOR_DISABLE_EXP_AND_MANTISSA */ - /* - More than 4 tags on an item 225(226(227(228(229([]))))) - */ - uError = QCBORDecode_GetNext(&DCtx, &Item); - if(uError != QCBOR_ERR_TOO_MANY_TAGS) { - return -6; + // Fail to get an epoch date by string label + QCBORDecode_GetEpochDateInMapSZ(&DC, "no-label", + QCBOR_TAG_REQUIREMENT_NOT_A_TAG, + &nEpochDate6); + uError = QCBORDecode_GetAndResetError(&DC); + if(uError != QCBOR_ERR_LABEL_NOT_FOUND) { + return 107; } - if(QCBORDecode_GetNthTag(&DCtx, &Item, 0) != CBOR_TAG_INVALID64) { - return -106; + // Fail to get an epoch date by integer label + QCBORDecode_GetEpochDateInMapN(&DC, 99999, QCBOR_TAG_REQUIREMENT_NOT_A_TAG, + &nEpochDate6); + uError = QCBORDecode_GetAndResetError(&DC); + if(uError != QCBOR_ERR_LABEL_NOT_FOUND) { + return 108; } - - /* tag 10489608748473423768( - 2442302356( - 21590( - 240( - [])))) - */ - uError = QCBORDecode_GetNext(&DCtx, &Item); - if(uError != QCBOR_SUCCESS || - Item.uDataType != QCBOR_TYPE_ARRAY || - QCBORDecode_GetNthTag(&DCtx, &Item, 3) != 10489608748473423768ULL || - QCBORDecode_GetNthTag(&DCtx, &Item, 2) != 2442302356ULL || - QCBORDecode_GetNthTag(&DCtx, &Item, 1) != 21590ULL || - QCBORDecode_GetNthTag(&DCtx, &Item, 0) != 240ULL) { - return -7; + // Fail to get a string date by string label + QCBORDecode_GetDateStringInMapSZ(&DC, "no-label", + QCBOR_TAG_REQUIREMENT_NOT_A_TAG, + &StringDate1); + uError = QCBORDecode_GetAndResetError(&DC); + if(uError != QCBOR_ERR_LABEL_NOT_FOUND) { + return 109; } - /* tag 21590( - 10489608748473423768( - 2442302357( - 21591( - [])))) - */ - uError = QCBORDecode_GetNext(&DCtx, &Item); - if(uError != QCBOR_SUCCESS || - Item.uDataType != QCBOR_TYPE_ARRAY || - QCBORDecode_GetNthTag(&DCtx, &Item, 0) != 65534ULL || - QCBORDecode_GetNthTag(&DCtx, &Item, 1) != 2442302357ULL || - QCBORDecode_GetNthTag(&DCtx, &Item, 2) != 10489608748473423768ULL || - QCBORDecode_GetNthTag(&DCtx, &Item, 3) != 21590ULL) { - return -8; + // Fail to get a string date by integer label + QCBORDecode_GetDateStringInMapN(&DC, 99999, QCBOR_TAG_REQUIREMENT_NOT_A_TAG, + &StringDate1); + uError = QCBORDecode_GetAndResetError(&DC); + if(uError != QCBOR_ERR_LABEL_NOT_FOUND) { + return 110; } - /* Make sure to blow past the limit of tags that must be mapped. - works in conjuntion with entries above. - 269488144(269488145(269488146(269488147([])))) - */ - uError = QCBORDecode_GetNext(&DCtx, &Item); - if(uError != QCBOR_ERR_TOO_MANY_TAGS) { - return -9; + // The rest of these succeed even if float features are disabled + + + // Untagged integer 0 + QCBORDecode_GetEpochDateInMapN(&DC, 8, QCBOR_TAG_REQUIREMENT_NOT_A_TAG, + &nEpochDate3); + // Untagged date string + QCBORDecode_GetDateStringInMapSZ(&DC, "y", QCBOR_TAG_REQUIREMENT_NOT_A_TAG, + &StringDate2); + + QCBORDecode_GetDaysStringInMapN(&DC, 99, QCBOR_TAG_REQUIREMENT_NOT_A_TAG, + &StringDays2); + + QCBORDecode_GetEpochDaysInMapN(&DC, 17, QCBOR_TAG_REQUIREMENT_NOT_A_TAG, + &nEpochDays2); + + QCBORDecode_ExitMap(&DC); + if(QCBORDecode_GetError(&DC) != QCBOR_SUCCESS) { + return 3001; } - uError = QCBORDecode_GetNext(&DCtx, &Item); + // The map of tagged items + QCBORDecode_EnterMap(&DC, NULL); + +#ifndef QCBOR_DISABLE_TAGS + int64_t nEpochDate2, + nEpochDateFail, + nEpochDate1400000000, nEpochDays1; + UsefulBufC StringDays1; + uint64_t uTag1, uTag2; + + // Tagged date string + QCBORDecode_GetDateStringInMapN(&DC, 0, QCBOR_TAG_REQUIREMENT_OPTIONAL_TAG, + &StringDate1); + + // Epoch date 1400000000; Tue, 13 May 2014 16:53:20 GMT + QCBORDecode_GetEpochDateInMapN(&DC, + 1, + QCBOR_TAG_REQUIREMENT_TAG | + QCBOR_TAG_REQUIREMENT_ALLOW_ADDITIONAL_TAGS, + &nEpochDate1400000000); + uTag1 = QCBORDecode_GetNthTagOfLast(&DC, 0); + + // Get largest negative double precision epoch date allowed + QCBORDecode_GetEpochDateInMapN(&DC, + 5, + QCBOR_TAG_REQUIREMENT_OPTIONAL_TAG | + QCBOR_TAG_REQUIREMENT_ALLOW_ADDITIONAL_TAGS, + &nEpochDate2); + uError = QCBORDecode_GetAndResetError(&DC); + if(uError != FLOAT_ERR_CODE_NO_FLOAT_HW(QCBOR_SUCCESS)) { + return 102; + } if(uError == QCBOR_SUCCESS) { - return -10; + if(nEpochDate2 != -9223372036854773760LL) { + return 101; + } } - // ---------------------------------- - // This test sets up a caller-config list that includes the very large - // tage and then matches it. Caller-config lists are no longer - // used or needed. This tests backwards compatibility with them. - QCBORDecode_Init(&DCtx, - UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spEncodedLargeTag), - QCBOR_DECODE_MODE_NORMAL); - const uint64_t puList[] = {0x9192939495969798, 257}; - const QCBORTagListIn TL = {2, puList}; - QCBORDecode_SetCallerConfiguredTagList(&DCtx, &TL); + // Untagged -1000 with label z + QCBORDecode_GetEpochDateInMapSZ(&DC, + "z", + QCBOR_TAG_REQUIREMENT_NOT_A_TAG | + QCBOR_TAG_REQUIREMENT_ALLOW_ADDITIONAL_TAGS, + &nEpochDate6); + uTag2 = QCBORDecode_GetNthTagOfLast(&DC, 0); - if(QCBORDecode_GetNext(&DCtx, &Item)) { - return -8; + + // Get largest double precision epoch date allowed + QCBORDecode_GetEpochDateInMapN(&DC, 7, QCBOR_TAG_REQUIREMENT_OPTIONAL_TAG, + &nEpochDate2); + uError = QCBORDecode_GetAndResetError(&DC); + if(uError != FLOAT_ERR_CODE_NO_FLOAT_HW(QCBOR_SUCCESS)) { + return 112; } - if(Item.uDataType != QCBOR_TYPE_ARRAY || - !QCBORDecode_IsTagged(&DCtx, &Item, 0x9192939495969798) || - QCBORDecode_IsTagged(&DCtx, &Item, 257) || - QCBORDecode_IsTagged(&DCtx, &Item, CBOR_TAG_BIGFLOAT) || - Item.val.uCount != 0) { - return -9; + if(uError == QCBOR_SUCCESS) { + if(nEpochDate2 != 9223372036854773760ULL) { + return 111; + } } - //------------------------ - // Sets up a caller-configured list and look up something not in it - // Another backwards compatibility test. - const uint64_t puLongList[17] = {1,2,1}; - const QCBORTagListIn TLLong = {17, puLongList}; - QCBORDecode_Init(&DCtx, - UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spEncodedLargeTag), - QCBOR_DECODE_MODE_NORMAL); - QCBORDecode_SetCallerConfiguredTagList(&DCtx, &TLLong); - if(QCBORDecode_GetNext(&DCtx, &Item)) { - return -11; - } + /* The days format is much simpler than the date format + * because it can't be a floating point value. The test + * of the spiffy decode functions sufficiently covers + * the test of the non-spiffy decode days date decoding. + * There is no full fan out of the error conditions + * and decode options as that is implemented by code + * that is tested well by the date testing above. + */ + QCBORDecode_GetDaysStringInMapSZ(&DC, "SDS", QCBOR_TAG_REQUIREMENT_TAG, + &StringDays1); - uint64_t puTags[4]; - QCBORTagListOut Out = {0, 4, puTags}; + QCBORDecode_GetEpochDaysInMapSZ(&DC, "SDE", QCBOR_TAG_REQUIREMENT_TAG, + &nEpochDays1); + QCBORDecode_ExitMap(&DC); + if(QCBORDecode_GetError(&DC) != QCBOR_SUCCESS) { + return 3001; + } - // This tests retrievel of the full tag list - QCBORDecode_Init(&DCtx, - UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spLotsOfTags), - QCBOR_DECODE_MODE_NORMAL); - if(QCBORDecode_GetNextWithTags(&DCtx, &Item, &Out)) { - return -12; + // Too-negative float, -9.2233720368547748E+18 + QCBORDecode_GetEpochDate(&DC, QCBOR_TAG_REQUIREMENT_TAG, &nEpochDateFail); + uError = QCBORDecode_GetAndResetError(&DC); + if(uError != FLOAT_ERR_CODE_NO_FLOAT_HW(QCBOR_ERR_DATE_OVERFLOW)) { + return 1111; } - if(puTags[0] != 0x9192939495969798 || - puTags[1] != 0x88 || - puTags[2] != 0x06 || - puTags[3] != 0x07) { - return -13; + + // Too-large integer + QCBORDecode_GetEpochDate(&DC, QCBOR_TAG_REQUIREMENT_TAG, &nEpochDateFail); + uError = QCBORDecode_GetAndResetError(&DC); + if(uError != QCBOR_ERR_DATE_OVERFLOW) { + return 1; } - // ---------------------- - // This tests too small of an out list - QCBORDecode_Init(&DCtx, - UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spLotsOfTags), - QCBOR_DECODE_MODE_NORMAL); - QCBORTagListOut OutSmall = {0, 3, puTags}; - if(QCBORDecode_GetNextWithTags(&DCtx, &Item, &OutSmall) != QCBOR_ERR_TOO_MANY_TAGS) { - return -14; + // Half-precision minus infinity + QCBORDecode_GetEpochDate(&DC, QCBOR_TAG_REQUIREMENT_TAG, &nEpochDateFail); + uError = QCBORDecode_GetAndResetError(&DC); + if(uError != FLOAT_ERR_CODE_NO_HALF_PREC_NO_FLOAT_HW(QCBOR_ERR_DATE_OVERFLOW)) { + return 2; } + // Bad content for epoch date + QCBORDecode_GetEpochDate(&DC, QCBOR_TAG_REQUIREMENT_TAG, &nEpochDateFail); + uError = QCBORDecode_GetAndResetError(&DC); + if(uError != QCBOR_ERR_UNRECOVERABLE_TAG_CONTENT) { + return 3; + } - // --------------- - // Decode a version of the "CSR" that has had a ton of tags randomly inserted - // It is a bit of a messy test and maybe could be improved, but - // it is retained as a backwards compatibility check. - QCBORDecode_Init(&DCtx, - UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spCSRWithTags), - QCBOR_DECODE_MODE_NORMAL); - int n = CheckCSRMaps(&DCtx); - if(n) { - return n-2000; + // Bad content for string date + QCBORDecode_GetDateString(&DC, QCBOR_TAG_REQUIREMENT_TAG, &StringDate1); + uError = QCBORDecode_GetAndResetError(&DC); + if(uError != QCBOR_ERR_UNRECOVERABLE_TAG_CONTENT) { + return 4; } - Out = (QCBORTagListOut){0, 16, puTags}; - QCBORDecode_Init(&DCtx, - UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spCSRWithTags), - QCBOR_DECODE_MODE_NORMAL); + QCBORDecode_ExitArray(&DC); + uError = QCBORDecode_Finish(&DC); + if(uError != QCBOR_ERR_UNRECOVERABLE_TAG_CONTENT) { + return 1000 + (int32_t)uError; + } +#else /* QCBOR_DISABLE_TAGS */ + QCBORDecode_GetDateStringInMapN(&DC, 0, QCBOR_TAG_REQUIREMENT_OPTIONAL_TAG, + &StringDate1); + uError = QCBORDecode_GetAndResetError(&DC); + if(uError != QCBOR_ERR_TAGS_DISABLED) { + return 4; + } +#endif /* QCBOR_DISABLE_TAGS */ - /* With the spiffy decode revision, this tag list is not used. - It doesn't matter if a tag is in this list or not so some - tests that couldn't process a tag because it isn't in this list - now can process these unlisted tags. The tests have been - adjusted for this. */ - const uint64_t puTagList[] = {773, 1, 90599561}; - const QCBORTagListIn TagList = {3, puTagList}; - QCBORDecode_SetCallerConfiguredTagList(&DCtx, &TagList); +#ifndef QCBOR_DISABLE_TAGS - if(QCBORDecode_GetNextWithTags(&DCtx, &Item, &Out)) { - return -100; - } - if(Item.uDataType != QCBOR_TYPE_MAP || - !QCBORDecode_IsTagged(&DCtx, &Item, CBOR_TAG_CBOR_MAGIC) || - QCBORDecode_IsTagged(&DCtx, &Item, 90599561) || - QCBORDecode_IsTagged(&DCtx, &Item, CBOR_TAG_DATE_EPOCH) || - Item.val.uCount != 2 || - puTags[0] != CBOR_TAG_CBOR_MAGIC || - puTags[1] != CBOR_TAG_CBOR_MAGIC || - puTags[2] != CBOR_TAG_CBOR_MAGIC || - Out.uNumUsed != 3) { - return -101; + if(nEpochDate1400000000 != 1400000000) { + return 200; } - if(QCBORDecode_GetNextWithTags(&DCtx, &Item, &Out)) { - return -102; - } - if(Item.uDataType != QCBOR_TYPE_MAP || - QCBORDecode_IsTagged(&DCtx, &Item, CBOR_TAG_CBOR_MAGIC) || - QCBORDecode_IsTagged(&DCtx, &Item, 6) || - !QCBORDecode_IsTagged(&DCtx, &Item, 7) || - Item.val.uCount != 2 || - puTags[0] != 5859837686836516696 || - puTags[1] != 7 || - Out.uNumUsed != 2) { - return -103; + if(uTag1 != 0x03030303) { + return 201; } - if(QCBORDecode_GetNextWithTags(&DCtx, &Item, &Out)) { - return -104; - } - if(Item.uDataType != QCBOR_TYPE_MAP || - Item.val.uCount != 5 || - puTags[0] != 0x0b || - Out.uNumUsed != 1) { - return -105; + if(nEpochDays1 != -10676) { + return 205; } - if(QCBORDecode_GetNextWithTags(&DCtx, &Item, &Out)) { - return -106; - } - if(Item.uDataType != QCBOR_TYPE_TEXT_STRING || - !QCBORDecode_IsTagged(&DCtx, &Item, CBOR_TAG_COSE_MAC0) || - Item.val.string.len != 12 || - puTags[0] != CBOR_TAG_COSE_MAC0 || - puTags[1] != CBOR_TAG_COSE_MAC0 || - puTags[2] != CBOR_TAG_COSE_MAC0 || - Out.uNumUsed != 3) { - return -105; + if(UsefulBuf_Compare(StringDays1, UsefulBuf_FromSZ("1985-04-12"))) { + return 207; } - if(QCBORDecode_GetNextWithTags(&DCtx, &Item, &Out)) { - return -107; - } - if(Item.uDataType != QCBOR_TYPE_TEXT_STRING || - !QCBORDecode_IsTagged(&DCtx, &Item, 773) || - Item.val.string.len != 3 || - puTags[0] != 773 || - Out.uNumUsed != 1) { - return -108; + if(uTag2 != 0x01010101) { + return 204; } - if(QCBORDecode_GetNextWithTags(&DCtx, &Item, &Out)) { - return -109; - } - if(Item.uDataType != QCBOR_TYPE_TEXT_STRING || - !QCBORDecode_IsTagged(&DCtx, &Item, 16) || - Item.val.string.len != 9 || - puTags[0] != 16 || - puTags[3] != 7 || - Out.uNumUsed != 4) { - return -110; + if(nEpochDate6 != -1000) { + return 203; } - if(QCBORDecode_GetNextWithTags(&DCtx, &Item, &Out)) { - return -111; - } - if(Item.uDataType != QCBOR_TYPE_TEXT_STRING || - !QCBORDecode_IsTagged(&DCtx, &Item, 17) || - Item.val.string.len != 9 || - puTags[0] != 17 || - Out.uNumUsed != 1) { - return -112; + if(UsefulBuf_Compare(StringDate1, UsefulBuf_FromSZ("1985-04-12"))) { + return 205; } - if(QCBORDecode_GetNextWithTags(&DCtx, &Item, &Out)) { - return -111; - } - if(Item.uDataType != QCBOR_TYPE_TEXT_STRING || - !QCBORDecode_IsTagged(&DCtx, &Item, 17) || - Item.val.string.len != 2 || - puTags[0] != 17 || - Out.uNumUsed != 1) { - return -112; - } +#endif /* QCBOR_DISABLE_TAGS */ - if(QCBORDecode_GetNextWithTags(&DCtx, &Item, &Out)) { - return -113; - } - if(Item.uDataType != QCBOR_TYPE_MAP || - !QCBORDecode_IsTagged(&DCtx, &Item, 19) || - Item.val.uCount != 2 || - puTags[0] != 19 || - Out.uNumUsed != 1) { - return -114; + if(nEpochDate3 != 0) { + return 202; } - if(QCBORDecode_GetNextWithTags(&DCtx, &Item, &Out)) { - return -115; - } - if(Item.uDataType != QCBOR_TYPE_MAP || - !QCBORDecode_IsTagged(&DCtx, &Item, 9) || - Item.val.uCount != 1 || - puTags[0] != 9 || - Out.uNumUsed != 1) { - return -116; + if(nEpochDays2 != 3994) { + return 206; } - if(QCBORDecode_GetNextWithTags(&DCtx, &Item, &Out)) { - return -116; - } - if(Item.uDataType != QCBOR_TYPE_INT64 || - Item.val.int64 != -7 || - Out.uNumUsed != 0) { - return -117; + if(UsefulBuf_Compare(StringDate2, UsefulBuf_FromSZ("2085-04-12"))) { + return 206; } - if(QCBORDecode_GetNextWithTags(&DCtx, &Item, &Out)) { - return -118; - } - if(Item.uDataType != QCBOR_TYPE_BYTE_STRING || - Item.val.string.len != 10 || - puTags[0] != 12 || - Out.uNumUsed != 1) { - return -119; + if(UsefulBuf_Compare(StringDays2, UsefulBuf_FromSZ("1985-04-12"))) { + return 208; } - if(QCBORDecode_GetNextWithTags(&DCtx, &Item, &Out)) { - return -120; - } - if(Item.uDataType != QCBOR_TYPE_MAP || - !QCBORDecode_IsTagged(&DCtx, &Item, CBOR_TAG_ENC_AS_B16) || - Item.val.uCount != 1 || - puTags[0] != 0x17 || - Out.uNumUsed != 1) { - return -121; - } + return 0; +} - if(QCBORDecode_GetNextWithTags(&DCtx, &Item, &Out)) { - return -122; - } - if(Item.uDataType != QCBOR_TYPE_INT64 || - !QCBORDecode_IsTagged(&DCtx, &Item, 8) || - Item.val.int64 != -3 || - puTags[0] != 8 || - Out.uNumUsed != 1) { - return -123; - } - if(QCBORDecode_Finish(&DCtx)) { - return -124; - } +// Input for one of the tagging tests +static const uint8_t spTagInput[] = { + 0xd9, 0xd9, 0xf7, // CBOR magic number + 0x81, // Array of one + 0xd8, 0x04, // non-preferred serialization of tag 4, decimal fraction + 0x82, // Array of two that is the faction 1/3 + 0x01, + 0x03, - UsefulBufC DateString; - QCBORDecode_Init(&DCtx, - UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spSpiffyTagInput), - QCBOR_DECODE_MODE_NORMAL); + /* + More than 4 tags on an item 225(226(227(228(229([]))))) + */ + 0xd8, 0xe1, + 0xd8, 0xe2, + 0xd8, 0xe3, + 0xd8, 0xe4, + 0xd8, 0xe5, + 0x80, - QCBORDecode_EnterArray(&DCtx, NULL); - // tagged date string - QCBORDecode_GetDateString(&DCtx, QCBOR_TAG_REQUIREMENT_TAG, &DateString); - // untagged date string - QCBORDecode_GetDateString(&DCtx, QCBOR_TAG_REQUIREMENT_NOT_A_TAG, &DateString); - if(QCBORDecode_GetAndResetError(&DCtx) != QCBOR_SUCCESS) { - return 100; - } - // untagged byte string - QCBORDecode_GetDateString(&DCtx, QCBOR_TAG_REQUIREMENT_NOT_A_TAG, &DateString); - if(QCBORDecode_GetAndResetError(&DCtx) != QCBOR_ERR_UNEXPECTED_TYPE) { - return 101; - } - // tagged regex - QCBORDecode_GetDateString(&DCtx, QCBOR_TAG_REQUIREMENT_TAG, &DateString); - if(QCBORDecode_GetAndResetError(&DCtx) != QCBOR_ERR_UNEXPECTED_TYPE) { - return 102; - } - // tagged date string with a byte string - QCBORDecode_GetDateString(&DCtx, QCBOR_TAG_REQUIREMENT_TAG, &DateString); - if(QCBORDecode_GetAndResetError(&DCtx) != QCBOR_ERR_UNRECOVERABLE_TAG_CONTENT) { - return 103; - } - // The exit errors out because the last item, the date string with - // bad content makes the array untraversable (the bad date string - // could have tag content of an array or such that is not consumed - // by the date decoding). - QCBORDecode_ExitArray(&DCtx); - if(QCBORDecode_Finish(&DCtx) != QCBOR_ERR_UNRECOVERABLE_TAG_CONTENT) { - return 104; - } + /* tag 10489608748473423768( + 2442302356( + 21590( + 240( + [])))) + */ + 0xdb, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, + 0xda, 0x91, 0x92, 0x93, 0x94, + 0xd9, 0x54, 0x56, + 0xd8, 0xf0, + 0x80, + /* tag 21590( + 10489608748473423768( + 2442302357( + 65534( + [])))) + */ + 0xdb, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x54, 0x56, + 0xdb, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, + 0xda, 0x91, 0x92, 0x93, 0x95, + 0xd9, 0xff, 0xfe, + 0x80, - QCBORDecode_Init(&DCtx, - UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spSpiffyTagInput), - QCBOR_DECODE_MODE_NORMAL); + /* Make sure to blow past the limit of tags that must be mapped. + works in conjuntion with entries above. + 269488144(269488145(269488146(269488147([])))) + */ + 0xda, 0x10, 0x10, 0x10, 0x10, + 0xda, 0x10, 0x10, 0x10, 0x11, + 0xda, 0x10, 0x10, 0x10, 0x12, + 0xda, 0x10, 0x10, 0x10, 0x13, + 0x80, - QCBORDecode_EnterArray(&DCtx, NULL); - // tagged date string - QCBORDecode_GetDateString(&DCtx, QCBOR_TAG_REQUIREMENT_OPTIONAL_TAG, &DateString); - // untagged date string - QCBORDecode_GetDateString(&DCtx, QCBOR_TAG_REQUIREMENT_OPTIONAL_TAG, &DateString); - if(QCBORDecode_GetAndResetError(&DCtx) != QCBOR_SUCCESS) { - return 200; - } - // untagged byte string - QCBORDecode_GetDateString(&DCtx, QCBOR_TAG_REQUIREMENT_OPTIONAL_TAG, &DateString); - if(QCBORDecode_GetAndResetError(&DCtx) != QCBOR_ERR_UNEXPECTED_TYPE) { - return 201; - } - // tagged regex - QCBORDecode_GetDateString(&DCtx, QCBOR_TAG_REQUIREMENT_OPTIONAL_TAG, &DateString); - if(QCBORDecode_GetAndResetError(&DCtx) != QCBOR_ERR_UNEXPECTED_TYPE) { - return 202; - } - // tagged date string with a byte string - QCBORDecode_GetDateString(&DCtx, QCBOR_TAG_REQUIREMENT_OPTIONAL_TAG, &DateString); - if(QCBORDecode_GetAndResetError(&DCtx) != QCBOR_ERR_UNRECOVERABLE_TAG_CONTENT) { - return 203; - } - // See comments above - QCBORDecode_ExitArray(&DCtx); - if(QCBORDecode_Finish(&DCtx) != QCBOR_ERR_UNRECOVERABLE_TAG_CONTENT) { - return 204; - } + /* An invalid decimal fraction with an additional tag */ + 0xd9, 0xff, 0xfa, + 0xd8, 0x02, // non-preferred serialization of tag 2, a big num + 0x00, // the integer 0; should be a byte string +}; - QCBORDecode_Init(&DCtx, - UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spSpiffyTagInput), - QCBOR_DECODE_MODE_NORMAL); - - QCBORDecode_EnterArray(&DCtx, NULL); - // tagged date string - QCBORDecode_GetDateString(&DCtx, QCBOR_TAG_REQUIREMENT_NOT_A_TAG, &DateString); - if(QCBORDecode_GetAndResetError(&DCtx) != QCBOR_ERR_UNEXPECTED_TYPE) { - return 300; - } - // untagged date string - QCBORDecode_GetDateString(&DCtx, QCBOR_TAG_REQUIREMENT_TAG, &DateString); - if(QCBORDecode_GetAndResetError(&DCtx) != QCBOR_ERR_UNEXPECTED_TYPE) { - return 301; - } - // untagged byte string - QCBORDecode_GetDateString(&DCtx, QCBOR_TAG_REQUIREMENT_TAG, &DateString); - if(QCBORDecode_GetAndResetError(&DCtx) != QCBOR_ERR_UNEXPECTED_TYPE) { - return 302; - } - // tagged regex - QCBORDecode_GetDateString(&DCtx, QCBOR_TAG_REQUIREMENT_NOT_A_TAG, &DateString); - if(QCBORDecode_GetAndResetError(&DCtx) != QCBOR_ERR_UNEXPECTED_TYPE) { - return 303; - } - // tagged date string with a byte string - QCBORDecode_GetDateString(&DCtx, QCBOR_TAG_REQUIREMENT_NOT_A_TAG, &DateString); - if(QCBORDecode_GetAndResetError(&DCtx) != QCBOR_ERR_UNRECOVERABLE_TAG_CONTENT) { - return 304; - } - // See comments above - QCBORDecode_ExitArray(&DCtx); - if(QCBORDecode_Finish(&DCtx) != QCBOR_ERR_UNRECOVERABLE_TAG_CONTENT) { - return 305; - } +/* + DB 9192939495969798 # tag(10489608748473423768) + 80 # array(0) + */ +static const uint8_t spEncodedLargeTag[] = {0xdb, 0x91, 0x92, 0x93, 0x94, 0x95, + 0x96, 0x97, 0x98, 0x80}; - return 0; -} +/* +DB 9192939495969798 # tag(10489608748473423768) + D8 88 # tag(136) + C6 # tag(6) + C7 # tag(7) + 80 # array(0) +*/ +static const uint8_t spLotsOfTags[] = {0xdb, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, + 0x97, 0x98, 0xd8, 0x88, 0xc6, 0xc7, 0x80}; /* - * These are showing the big numbers converted to integers. - * The tag numbers are not shown. - * - * [ 18446744073709551616, - * -18446744073709551617, - * {"BN+": 18446744073709551616, - * 64: 18446744073709551616, - * "BN-": -18446744073709551617, - * -64: -18446744073709551617 - * } - * ] + 55799(55799(55799({ + 6(7(-23)): 5859837686836516696(7({ + 7(-20): 11({ + 17(-18): 17(17(17("Organization"))), + 9(-17): 773("SSG"), + -15: 16(17(6(7("Confusion")))), + 17(-16): 17("San Diego"), + 17(-14): 17("US") + }), + 23(-19): 19({ + -11: 9({ + -9: -7 + }), + 90599561(90599561(90599561(-10))): 12(h'0102030405060708090A') + }) + })), + 16(-22): 23({ + 11(8(7(-5))): 8(-3) + }) + }))) */ +static const uint8_t spCSRWithTags[] = { + 0xd9, 0xd9, 0xf7, 0xd9, 0xd9, 0xf7, 0xd9, 0xd9, 0xf7, 0xa2, + 0xc6, 0xc7, 0x36, + 0xdb, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0xc7, 0xa2, + 0xda, 0x00, 0x00, 0x00, 0x07, 0x33, + 0xcb, 0xa5, + 0xd1, 0x31, + 0xd1, 0xd1, 0xd1, 0x6c, + 0x4f, 0x72, 0x67, 0x61, 0x6e, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0xc9, 0x30, + 0xd9, 0x03, 0x05, 0x63, + 0x53, 0x53, 0x47, + 0x2e, + 0xd0, 0xd1, 0xc6, 0xc7, + 0x69, + 0x43, 0x6f, 0x6e, 0x66, 0x75, 0x73, 0x69, 0x6f, 0x6e, + 0xd1, 0x2f, + 0xd1, 0x69, + 0x53, 0x61, 0x6e, 0x20, 0x44, 0x69, 0x65, 0x67, 0x6f, + 0xd1, 0x2d, + 0xd1, 0x62, + 0x55, 0x53, + 0xd7, 0x32, + 0xd3, 0xa2, + 0x2a, + 0xc9, 0xa1, + 0x28, + 0x26, + 0xda, 0x05, 0x66, 0x70, 0x89, 0xda, 0x05, 0x66, 0x70, 0x89, 0xda, 0x05, 0x66, 0x70, 0x89, 0x29, + 0xcc, 0x4a, + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06,0x07, 0x08, 0x09, 0x0a, + 0xd0, 0x35, + 0xd7, 0xa1, + 0xcb, 0xc8, 0xc7, 0x24, + 0xc8, 0x22}; -static const uint8_t spBigNumInput[] = { - 0x83, - 0xC2, 0x49, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xC3, 0x49, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xA4, - 0x63, 0x42, 0x4E, 0x2B, - 0xC2, 0x49, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x18, 0x40, - 0xC2, 0x49, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x63, 0x42, 0x4E, 0x2D, - 0xC3, 0x49, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x38, 0x3F, - 0xC3, 0x49, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; -#ifndef QCBOR_DISABLE_TAGS -/* The expected big num */ -static const uint8_t spBigNum[] = { - 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00}; -#endif /* QCBOR_DISABLE_TAGS */ +static const uint8_t spSpiffyTagInput[] = { + 0x85, // Open array + + 0xc0, // tag for string date + 0x6a, '1','9','8','5','-','0','4','-','1','2', // Date string + 0x6a, '1','9','8','5','-','0','4','-','1','2', // Date string -int32_t BignumParseTest(void) + 0x4a, '1','9','8','5','-','0','4','-','1','2', // Date string in byte string + + 0xd8, 0x23, // tag for regex + 0x6a, '1','9','8','5','-','0','4','-','1','2', // Date string + + 0xc0, // tag for string date + 0x4a, '1','9','8','5','-','0','4','-','1','2', // Date string in byte string + + // This last case makes the array untraversable because it is + // an uncrecoverable error. Make sure it stays last and is the only + // instance so the other tests can work. +}; + + +static const uint8_t spTaggedString[] = { + 0xd8, 0xf0, 0x61, 0x40, +}; + +static const uint8_t spTaggedInt[] = { + 0xd8, 0xf4, 0x01, +}; + +static int32_t CheckCSRMaps(QCBORDecodeContext *pDC); + + +int32_t OptTagParseTest(void) { QCBORDecodeContext DCtx; - QCBORItem Item; - QCBORError nCBORError; + QCBORItem Item; + QCBORError uError; + UsefulBufC UBC; + int64_t nInt; + QCBORDecode_Init(&DCtx, - UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spBigNumInput), + UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spTagInput), QCBOR_DECODE_MODE_NORMAL); - - // - if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) - return -1; - if(Item.uDataType != QCBOR_TYPE_ARRAY) { + /* + This test matches the magic number tag and the fraction tag + 55799([...]) + */ + uError = QCBORDecode_GetNext(&DCtx, &Item); + if(uError != QCBOR_SUCCESS) { return -2; } - -#ifndef QCBOR_DISABLE_TAGS - // - if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) + if(Item.uDataType != QCBOR_TYPE_ARRAY || + !QCBORDecode_IsTagged(&DCtx, &Item, CBOR_TAG_CBOR_MAGIC)) { return -3; - if(Item.uDataType != QCBOR_TYPE_POSBIGNUM || - UsefulBuf_Compare(Item.val.bigNum, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spBigNum))){ + } + + /* + 4([1,3]) + */ + uError = QCBORDecode_GetNext(&DCtx, &Item); +#ifdef QCBOR_DISABLE_EXP_AND_MANTISSA + if(uError != QCBOR_SUCCESS || + Item.uDataType != QCBOR_TYPE_ARRAY || + !QCBORDecode_IsTagged(&DCtx, &Item, CBOR_TAG_DECIMAL_FRACTION) || + QCBORDecode_GetNthTag(&DCtx, &Item, 0) != CBOR_TAG_DECIMAL_FRACTION || + QCBORDecode_GetNthTag(&DCtx, &Item, 1) != CBOR_TAG_INVALID64 || + QCBORDecode_GetNthTag(&DCtx, &Item, 2) != CBOR_TAG_INVALID64 || + QCBORDecode_GetNthTag(&DCtx, &Item, 3) != CBOR_TAG_INVALID64 || + QCBORDecode_GetNthTag(&DCtx, &Item, 4) != CBOR_TAG_INVALID64 || + Item.val.uCount != 2) { return -4; } + // consume the items in the array + uError = QCBORDecode_GetNext(&DCtx, &Item); + uError = QCBORDecode_GetNext(&DCtx, &Item); - // - if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) +#else /* QCBOR_DISABLE_EXP_AND_MANTISSA */ + if(uError != QCBOR_SUCCESS || + Item.uDataType != QCBOR_TYPE_DECIMAL_FRACTION || + QCBORDecode_GetNthTag(&DCtx, &Item, 0) != CBOR_TAG_INVALID64 || + QCBORDecode_GetNthTag(&DCtx, &Item, 1) != CBOR_TAG_INVALID64 || + QCBORDecode_GetNthTag(&DCtx, &Item, 2) != CBOR_TAG_INVALID64 || + QCBORDecode_GetNthTag(&DCtx, &Item, 3) != CBOR_TAG_INVALID64 || + QCBORDecode_GetNthTag(&DCtx, &Item, 4) != CBOR_TAG_INVALID64 ) { return -5; - if(Item.uDataType != QCBOR_TYPE_NEGBIGNUM || - UsefulBuf_Compare(Item.val.bigNum, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spBigNum))){ - return -6; } +#endif /* QCBOR_DISABLE_EXP_AND_MANTISSA */ - // - if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) - return -7; - if(Item.uDataType != QCBOR_TYPE_MAP) { - return -8; + /* + More than 4 tags on an item 225(226(227(228(229([]))))) + */ + uError = QCBORDecode_GetNext(&DCtx, &Item); + if(uError != QCBOR_ERR_TOO_MANY_TAGS) { + return -6; } - if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) - return -9; - if(Item.uDataType != QCBOR_TYPE_POSBIGNUM || - Item.uLabelType != QCBOR_TYPE_TEXT_STRING || - UsefulBuf_Compare(Item.val.bigNum, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spBigNum))){ - return -10; + if(QCBORDecode_GetNthTag(&DCtx, &Item, 0) != CBOR_TAG_INVALID64) { + return -106; } - if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) - return -11; - if(Item.uDataType != QCBOR_TYPE_POSBIGNUM || - Item.uLabelType != QCBOR_TYPE_INT64 || - Item.label.int64 != 64 || - UsefulBuf_Compare(Item.val.bigNum, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spBigNum))){ - return -12; + + /* tag 10489608748473423768( + 2442302356( + 21590( + 240( + [])))) + */ + uError = QCBORDecode_GetNext(&DCtx, &Item); + if(uError != QCBOR_SUCCESS || + Item.uDataType != QCBOR_TYPE_ARRAY || + QCBORDecode_GetNthTag(&DCtx, &Item, 3) != 10489608748473423768ULL || + QCBORDecode_GetNthTag(&DCtx, &Item, 2) != 2442302356ULL || + QCBORDecode_GetNthTag(&DCtx, &Item, 1) != 21590ULL || + QCBORDecode_GetNthTag(&DCtx, &Item, 0) != 240ULL) { + return -7; } - if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) - return -13; - if(Item.uDataType != QCBOR_TYPE_NEGBIGNUM || - Item.uLabelType != QCBOR_TYPE_TEXT_STRING || - UsefulBuf_Compare(Item.val.bigNum, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spBigNum))){ - return -14; + /* tag 21590( + 10489608748473423768( + 2442302357( + 21591( + [])))) + */ + uError = QCBORDecode_GetNext(&DCtx, &Item); + if(uError != QCBOR_SUCCESS || + Item.uDataType != QCBOR_TYPE_ARRAY || + QCBORDecode_GetNthTag(&DCtx, &Item, 0) != 65534ULL || + QCBORDecode_GetNthTag(&DCtx, &Item, 1) != 2442302357ULL || + QCBORDecode_GetNthTag(&DCtx, &Item, 2) != 10489608748473423768ULL || + QCBORDecode_GetNthTag(&DCtx, &Item, 3) != 21590ULL) { + return -8; } - if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) - return -15; - if(Item.uDataType != QCBOR_TYPE_NEGBIGNUM || - Item.uLabelType != QCBOR_TYPE_INT64 || - Item.label.int64 != -64 || - UsefulBuf_Compare(Item.val.bigNum, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spBigNum))){ - return -16; + /* Make sure to blow past the limit of tags that must be mapped. + works in conjuntion with entries above. + 269488144(269488145(269488146(269488147([])))) + */ + uError = QCBORDecode_GetNext(&DCtx, &Item); + if(uError != QCBOR_ERR_TOO_MANY_TAGS) { + return -9; } -#else - if(QCBORDecode_GetNext(&DCtx, &Item) != QCBOR_ERR_TAGS_DISABLED) { - return -100; + uError = QCBORDecode_GetNext(&DCtx, &Item); + if(uError == QCBOR_SUCCESS) { + return -10; } -#endif /* QCBOR_DISABLE_TAGS */ - - return 0; -} - + // ---------------------------------- + // This test sets up a caller-config list that includes the very large + // tage and then matches it. Caller-config lists are no longer + // used or needed. This tests backwards compatibility with them. + QCBORDecode_Init(&DCtx, + UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spEncodedLargeTag), + QCBOR_DECODE_MODE_NORMAL); + const uint64_t puList[] = {0x9192939495969798, 257}; + const QCBORTagListIn TL = {2, puList}; + QCBORDecode_SetCallerConfiguredTagList(&DCtx, &TL); -static int32_t CheckItemWithIntLabel(QCBORDecodeContext *pCtx, - uint8_t uDataType, - uint8_t uNestingLevel, - uint8_t uNextNest, - int64_t nLabel, - QCBORItem *pItem) -{ - QCBORItem Item; - QCBORError nCBORError; - - if((nCBORError = QCBORDecode_GetNext(pCtx, &Item))) return -1; - if(Item.uDataType != uDataType) return -1; - if(uNestingLevel > 0) { - if(Item.uLabelType != QCBOR_TYPE_INT64 && - Item.uLabelType != QCBOR_TYPE_UINT64) { - return -1; - } - if(Item.uLabelType == QCBOR_TYPE_INT64) { - if(Item.label.int64 != nLabel) return -1; - } else { - if(Item.label.uint64 != (uint64_t)nLabel) return -1; - } + if(QCBORDecode_GetNext(&DCtx, &Item)) { + return -8; } - if(Item.uNestingLevel != uNestingLevel) return -1; - if(Item.uNextNestLevel != uNextNest) return -1; - - if(pItem) { - *pItem = Item; + if(Item.uDataType != QCBOR_TYPE_ARRAY || + !QCBORDecode_IsTagged(&DCtx, &Item, 0x9192939495969798) || + QCBORDecode_IsTagged(&DCtx, &Item, 257) || + QCBORDecode_IsTagged(&DCtx, &Item, CBOR_TAG_BIGFLOAT) || + Item.val.uCount != 0) { + return -9; } - return 0; -} - - -// Same code checks definite and indefinite length versions of the map -static int32_t CheckCSRMaps(QCBORDecodeContext *pDC) -{ - if(CheckItemWithIntLabel(pDC, QCBOR_TYPE_MAP, 0, 1, 0, NULL)) return -1; - - if(CheckItemWithIntLabel(pDC, QCBOR_TYPE_MAP, 1, 2, -23, NULL)) return -2; - - if(CheckItemWithIntLabel(pDC, QCBOR_TYPE_MAP, 2, 3, -20, NULL)) return -3; - - if(CheckItemWithIntLabel(pDC, QCBOR_TYPE_TEXT_STRING, 3, 3, -18, NULL)) return -4; - if(CheckItemWithIntLabel(pDC, QCBOR_TYPE_TEXT_STRING, 3, 3, -17, NULL)) return -5; - if(CheckItemWithIntLabel(pDC, QCBOR_TYPE_TEXT_STRING, 3, 3, -15, NULL)) return -6; - if(CheckItemWithIntLabel(pDC, QCBOR_TYPE_TEXT_STRING, 3, 3, -16, NULL)) return -7; - if(CheckItemWithIntLabel(pDC, QCBOR_TYPE_TEXT_STRING, 3, 2, -14, NULL)) return -8; - - if(CheckItemWithIntLabel(pDC, QCBOR_TYPE_MAP, 2, 3, -19, NULL)) return -9; - if(CheckItemWithIntLabel(pDC, QCBOR_TYPE_MAP, 3, 4, -11, NULL)) return -10; - - if(CheckItemWithIntLabel(pDC, QCBOR_TYPE_INT64, 4, 3, -9, NULL)) return -11; - if(CheckItemWithIntLabel(pDC, QCBOR_TYPE_BYTE_STRING, 3, 1, -10, NULL)) return -12; - - if(CheckItemWithIntLabel(pDC, QCBOR_TYPE_MAP, 1, 2, -22, NULL)) return -13; - if(CheckItemWithIntLabel(pDC, QCBOR_TYPE_INT64, 2, 0, -5, NULL)) return -14; - - if(QCBORDecode_Finish(pDC)) return -20; - - return 0; -} - - -/* -{ - -23: { - -20: { - -18: "Organization", - -17: "SSG", - -15: "Confusion", - -16: "San Diego", - -14: "US" - }, - -19: { - -11: { - -9: -7 - }, - -10: '\u0001\u0002\u0003\u0004\u0005\u0006\a\b\t\n' - } - }, - -22: { - -5: -3 - } -} -*/ -static const uint8_t spCSRInput[] = { - 0xa2, 0x36, 0xa2, 0x33, 0xa5, 0x31, 0x6c, 0x4f, - 0x72, 0x67, 0x61, 0x6e, 0x69, 0x7a, 0x61, 0x74, - 0x69, 0x6f, 0x6e, 0x30, 0x63, 0x53, 0x53, 0x47, - 0x2e, 0x69, 0x43, 0x6f, 0x6e, 0x66, 0x75, 0x73, - 0x69, 0x6f, 0x6e, 0x2f, 0x69, 0x53, 0x61, 0x6e, - 0x20, 0x44, 0x69, 0x65, 0x67, 0x6f, 0x2d, 0x62, - 0x55, 0x53, 0x32, 0xa2, 0x2a, 0xa1, 0x28, 0x26, - 0x29, 0x4a, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, - 0x07, 0x08, 0x09, 0x0a, 0x35, 0xa1, 0x24, 0x22}; - -// Same map as above, but using indefinite lengths -static const uint8_t spCSRInputIndefLen[] = { - 0xbf, 0x36, 0xbf, 0x33, 0xbf, 0x31, 0x6c, 0x4f, - 0x72, 0x67, 0x61, 0x6e, 0x69, 0x7a, 0x61, 0x74, - 0x69, 0x6f, 0x6e, 0x30, 0x63, 0x53, 0x53, 0x47, - 0x2e, 0x69, 0x43, 0x6f, 0x6e, 0x66, 0x75, 0x73, - 0x69, 0x6f, 0x6e, 0x2f, 0x69, 0x53, 0x61, 0x6e, - 0x20, 0x44, 0x69, 0x65, 0x67, 0x6f, 0x2d, 0x62, - 0x55, 0x53, 0xff, 0x32, 0xbf, 0x2a, 0xbf, 0x28, - 0x26, 0xff, 0x29, 0x4a, 0x01, 0x02, 0x03, 0x04, - 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0xff, 0xff, - 0x35, 0xbf, 0x24, 0x22, 0xff, 0xff}; - - -int32_t NestedMapTest(void) -{ - QCBORDecodeContext DCtx; + //------------------------ + // Sets up a caller-configured list and look up something not in it + // Another backwards compatibility test. + const uint64_t puLongList[17] = {1,2,1}; + const QCBORTagListIn TLLong = {17, puLongList}; QCBORDecode_Init(&DCtx, - UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spCSRInput), + UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spEncodedLargeTag), QCBOR_DECODE_MODE_NORMAL); + QCBORDecode_SetCallerConfiguredTagList(&DCtx, &TLLong); + if(QCBORDecode_GetNext(&DCtx, &Item)) { + return -11; + } - return CheckCSRMaps(&DCtx); -} - - + uint64_t puTags[4]; + QCBORTagListOut Out = {0, 4, puTags}; -int32_t StringDecoderModeFailTest(void) -{ - QCBORDecodeContext DCtx; + // This tests retrievel of the full tag list QCBORDecode_Init(&DCtx, - UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spCSRInput), - QCBOR_DECODE_MODE_MAP_STRINGS_ONLY); - - QCBORItem Item; - QCBORError nCBORError; - - if(QCBORDecode_GetNext(&DCtx, &Item)) { - return -1; + UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spLotsOfTags), + QCBOR_DECODE_MODE_NORMAL); + if(QCBORDecode_GetNextWithTags(&DCtx, &Item, &Out)) { + return -12; } - if(Item.uDataType != QCBOR_TYPE_MAP) { - return -2; + if(puTags[0] != 0x9192939495969798 || + puTags[1] != 0x88 || + puTags[2] != 0x06 || + puTags[3] != 0x07) { + return -13; } - nCBORError = QCBORDecode_GetNext(&DCtx, &Item); - if(nCBORError != QCBOR_ERR_MAP_LABEL_TYPE) { - return -3; + // ---------------------- + // This tests too small of an out list + QCBORDecode_Init(&DCtx, + UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spLotsOfTags), + QCBOR_DECODE_MODE_NORMAL); + QCBORTagListOut OutSmall = {0, 3, puTags}; + if(QCBORDecode_GetNextWithTags(&DCtx, &Item, &OutSmall) != QCBOR_ERR_TOO_MANY_TAGS) { + return -14; } - return 0; -} - - -int32_t NestedMapTestIndefLen(void) -{ - QCBORDecodeContext DCtx; + // --------------- + // Decode a version of the "CSR" that has had a ton of tags randomly inserted + // It is a bit of a messy test and maybe could be improved, but + // it is retained as a backwards compatibility check. QCBORDecode_Init(&DCtx, - UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spCSRInputIndefLen), + UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spCSRWithTags), QCBOR_DECODE_MODE_NORMAL); + int n = CheckCSRMaps(&DCtx); + if(n) { + return n-2000; + } - return CheckCSRMaps(&DCtx); -} - + Out = (QCBORTagListOut){0, 16, puTags}; + QCBORDecode_Init(&DCtx, + UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spCSRWithTags), + QCBOR_DECODE_MODE_NORMAL); + /* With the spiffy decode revision, this tag list is not used. + It doesn't matter if a tag is in this list or not so some + tests that couldn't process a tag because it isn't in this list + now can process these unlisted tags. The tests have been + adjusted for this. */ + const uint64_t puTagList[] = {773, 1, 90599561}; + const QCBORTagListIn TagList = {3, puTagList}; + QCBORDecode_SetCallerConfiguredTagList(&DCtx, &TagList); -static UsefulBufC make_nested_indefinite_arrays(int n, UsefulBuf Storage) -{ - UsefulOutBuf UOB; - UsefulOutBuf_Init(&UOB, Storage); - int i; - for(i = 0; i < n; i++) { - UsefulOutBuf_AppendByte(&UOB, 0x9f); - } - - for(i = 0; i < n; i++) { - UsefulOutBuf_AppendByte(&UOB, 0xff); + if(QCBORDecode_GetNextWithTags(&DCtx, &Item, &Out)) { + return -100; + } + if(Item.uDataType != QCBOR_TYPE_MAP || + !QCBORDecode_IsTagged(&DCtx, &Item, CBOR_TAG_CBOR_MAGIC) || + QCBORDecode_IsTagged(&DCtx, &Item, 90599561) || + QCBORDecode_IsTagged(&DCtx, &Item, CBOR_TAG_DATE_EPOCH) || + Item.val.uCount != 2 || + puTags[0] != CBOR_TAG_CBOR_MAGIC || + puTags[1] != CBOR_TAG_CBOR_MAGIC || + puTags[2] != CBOR_TAG_CBOR_MAGIC || + Out.uNumUsed != 3) { + return -101; } - return UsefulOutBuf_OutUBuf(&UOB); -} - - -static int32_t parse_indeflen_nested(UsefulBufC Nested, int nNestLevel) -{ - QCBORDecodeContext DC; - QCBORDecode_Init(&DC, Nested, 0); - int j; - for(j = 0; j < nNestLevel; j++) { - QCBORItem Item; - QCBORError nReturn = QCBORDecode_GetNext(&DC, &Item); - if(j >= QCBOR_MAX_ARRAY_NESTING) { - // Should be in error - if(nReturn != QCBOR_ERR_ARRAY_DECODE_NESTING_TOO_DEEP) { - return -4; - } else { - return 0; // Decoding doesn't recover after an error - } - } else { - // Should be no error - if(nReturn) { - return -9; // Should not have got an error - } - } - if(Item.uDataType != QCBOR_TYPE_ARRAY) { - return -7; - } + if(QCBORDecode_GetNextWithTags(&DCtx, &Item, &Out)) { + return -102; } - QCBORError nReturn = QCBORDecode_Finish(&DC); - if(nReturn) { - return -3; + if(Item.uDataType != QCBOR_TYPE_MAP || + QCBORDecode_IsTagged(&DCtx, &Item, CBOR_TAG_CBOR_MAGIC) || + QCBORDecode_IsTagged(&DCtx, &Item, 6) || + !QCBORDecode_IsTagged(&DCtx, &Item, 7) || + Item.val.uCount != 2 || + puTags[0] != 5859837686836516696 || + puTags[1] != 7 || + Out.uNumUsed != 2) { + return -103; } - return 0; -} - -int32_t IndefiniteLengthNestTest(void) -{ - UsefulBuf_MAKE_STACK_UB(Storage, 50); - int i; - for(i=1; i < QCBOR_MAX_ARRAY_NESTING+4; i++) { - const UsefulBufC Nested = make_nested_indefinite_arrays(i, Storage); - int nReturn = parse_indeflen_nested(Nested, i); - if(nReturn) { - return nReturn; - } + if(QCBORDecode_GetNextWithTags(&DCtx, &Item, &Out)) { + return -104; } - return 0; -} - -// [1, [2, 3]] -static const uint8_t spIndefiniteArray[] = {0x9f, 0x01, 0x82, 0x02, 0x03, 0xff}; -// No closing break -static const uint8_t spIndefiniteArrayBad1[] = {0x9f}; -// Not enough closing breaks -static const uint8_t spIndefiniteArrayBad2[] = {0x9f, 0x9f, 0x02, 0xff}; -// Too many closing breaks -static const uint8_t spIndefiniteArrayBad3[] = {0x9f, 0x02, 0xff, 0xff}; -// Unclosed indeflen inside def len -static const uint8_t spIndefiniteArrayBad4[] = {0x81, 0x9f}; -// confused tag -static const uint8_t spIndefiniteArrayBad5[] = {0x9f, 0xd1, 0xff}; - -int32_t IndefiniteLengthArrayMapTest(void) -{ - QCBORError nResult; - // --- first test ----- - UsefulBufC IndefLen = UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spIndefiniteArray); - - // Decode it and see if it is OK - QCBORDecodeContext DC; - QCBORItem Item; - QCBORDecode_Init(&DC, IndefLen, QCBOR_DECODE_MODE_NORMAL); - - QCBORDecode_GetNext(&DC, &Item); - - if(Item.uDataType != QCBOR_TYPE_ARRAY || - Item.uNestingLevel != 0 || - Item.uNextNestLevel != 1) { - return -111; - } - - QCBORDecode_GetNext(&DC, &Item); - if(Item.uDataType != QCBOR_TYPE_INT64 || - Item.uNestingLevel != 1 || - Item.uNextNestLevel != 1) { - return -2; - } - - QCBORDecode_GetNext(&DC, &Item); - if(Item.uDataType != QCBOR_TYPE_ARRAY || - Item.uNestingLevel != 1 || - Item.uNextNestLevel != 2) { - return -3; - } - - QCBORDecode_GetNext(&DC, &Item); - if(Item.uDataType != QCBOR_TYPE_INT64 || - Item.uNestingLevel != 2 || - Item.uNextNestLevel != 2) { - return -4; - } - - QCBORDecode_GetNext(&DC, &Item); - if(Item.uDataType != QCBOR_TYPE_INT64 || - Item.uNestingLevel != 2 || - Item.uNextNestLevel != 0) { - return -5; - } - - if(QCBORDecode_Finish(&DC)) { - return -6; - } - - // --- next test ----- - IndefLen = UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spIndefiniteArrayBad1); - - QCBORDecode_Init(&DC, IndefLen, QCBOR_DECODE_MODE_NORMAL); - - nResult = QCBORDecode_GetNext(&DC, &Item); - if(nResult || Item.uDataType != QCBOR_TYPE_ARRAY) { - return -7; + if(Item.uDataType != QCBOR_TYPE_MAP || + Item.val.uCount != 5 || + puTags[0] != 0x0b || + Out.uNumUsed != 1) { + return -105; } - nResult = QCBORDecode_Finish(&DC); - if(nResult != QCBOR_ERR_ARRAY_OR_MAP_UNCONSUMED) { - return -8; + if(QCBORDecode_GetNextWithTags(&DCtx, &Item, &Out)) { + return -106; } - - - // --- next test ----- - IndefLen = UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spIndefiniteArrayBad2); - - QCBORDecode_Init(&DC, IndefLen, QCBOR_DECODE_MODE_NORMAL); - - nResult = QCBORDecode_GetNext(&DC, &Item); - if(nResult || Item.uDataType != QCBOR_TYPE_ARRAY) { - return -9; + if(Item.uDataType != QCBOR_TYPE_TEXT_STRING || + !QCBORDecode_IsTagged(&DCtx, &Item, CBOR_TAG_COSE_MAC0) || + Item.val.string.len != 12 || + puTags[0] != CBOR_TAG_COSE_MAC0 || + puTags[1] != CBOR_TAG_COSE_MAC0 || + puTags[2] != CBOR_TAG_COSE_MAC0 || + Out.uNumUsed != 3) { + return -105; } - nResult = QCBORDecode_GetNext(&DC, &Item); - if(nResult || Item.uDataType != QCBOR_TYPE_ARRAY) { - return -10; + if(QCBORDecode_GetNextWithTags(&DCtx, &Item, &Out)) { + return -107; } - - nResult = QCBORDecode_GetNext(&DC, &Item); - if(nResult || Item.uDataType != QCBOR_TYPE_INT64) { - return -11; + if(Item.uDataType != QCBOR_TYPE_TEXT_STRING || + !QCBORDecode_IsTagged(&DCtx, &Item, 773) || + Item.val.string.len != 3 || + puTags[0] != 773 || + Out.uNumUsed != 1) { + return -108; } - nResult = QCBORDecode_Finish(&DC); - if(nResult != QCBOR_ERR_ARRAY_OR_MAP_UNCONSUMED) { - return -12; + if(QCBORDecode_GetNextWithTags(&DCtx, &Item, &Out)) { + return -109; } - - - // --- next test ----- - IndefLen = UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spIndefiniteArrayBad3); - - QCBORDecode_Init(&DC, IndefLen, QCBOR_DECODE_MODE_NORMAL); - - nResult = QCBORDecode_GetNext(&DC, &Item); - if(nResult || Item.uDataType != QCBOR_TYPE_ARRAY) { - return -13; + if(Item.uDataType != QCBOR_TYPE_TEXT_STRING || + !QCBORDecode_IsTagged(&DCtx, &Item, 16) || + Item.val.string.len != 9 || + puTags[0] != 16 || + puTags[3] != 7 || + Out.uNumUsed != 4) { + return -110; } - nResult = QCBORDecode_GetNext(&DC, &Item); - if(nResult != QCBOR_SUCCESS) { - return -14; + if(QCBORDecode_GetNextWithTags(&DCtx, &Item, &Out)) { + return -111; } - - nResult = QCBORDecode_GetNext(&DC, &Item); - if(nResult != QCBOR_ERR_BAD_BREAK) { - return -140; - } - - - // --- next test ----- - IndefLen = UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spIndefiniteArrayBad4); - - QCBORDecode_Init(&DC, IndefLen, QCBOR_DECODE_MODE_NORMAL); - - nResult = QCBORDecode_GetNext(&DC, &Item); - if(nResult || Item.uDataType != QCBOR_TYPE_ARRAY) { - return -15; + if(Item.uDataType != QCBOR_TYPE_TEXT_STRING || + !QCBORDecode_IsTagged(&DCtx, &Item, 17) || + Item.val.string.len != 9 || + puTags[0] != 17 || + Out.uNumUsed != 1) { + return -112; } - nResult = QCBORDecode_GetNext(&DC, &Item); - if(nResult || Item.uDataType != QCBOR_TYPE_ARRAY) { - return -16; + if(QCBORDecode_GetNextWithTags(&DCtx, &Item, &Out)) { + return -111; } - - nResult = QCBORDecode_Finish(&DC); - if(nResult != QCBOR_ERR_ARRAY_OR_MAP_UNCONSUMED) { - return -17; + if(Item.uDataType != QCBOR_TYPE_TEXT_STRING || + !QCBORDecode_IsTagged(&DCtx, &Item, 17) || + Item.val.string.len != 2 || + puTags[0] != 17 || + Out.uNumUsed != 1) { + return -112; } - // --- next test ----- - IndefLen = UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spIndefiniteArrayBad5); - - QCBORDecode_Init(&DC, IndefLen, QCBOR_DECODE_MODE_NORMAL); - - nResult = QCBORDecode_GetNext(&DC, &Item); - -#ifndef QCBOR_DISABLE_TAGS - if(nResult || Item.uDataType != QCBOR_TYPE_ARRAY) { - return -18; + if(QCBORDecode_GetNextWithTags(&DCtx, &Item, &Out)) { + return -113; + } + if(Item.uDataType != QCBOR_TYPE_MAP || + !QCBORDecode_IsTagged(&DCtx, &Item, 19) || + Item.val.uCount != 2 || + puTags[0] != 19 || + Out.uNumUsed != 1) { + return -114; } - nResult = QCBORDecode_GetNext(&DC, &Item); - if(nResult != QCBOR_ERR_BAD_BREAK) { - return -19; + if(QCBORDecode_GetNextWithTags(&DCtx, &Item, &Out)) { + return -115; } -#else /* QCBOR_DISABLE_TAGS */ - if(nResult != QCBOR_ERR_TAGS_DISABLED) { - return -20; + if(Item.uDataType != QCBOR_TYPE_MAP || + !QCBORDecode_IsTagged(&DCtx, &Item, 9) || + Item.val.uCount != 1 || + puTags[0] != 9 || + Out.uNumUsed != 1) { + return -116; } -#endif /* QCBOR_DISABLE_TAGS */ - - return 0; -} - - -#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS - -static const uint8_t spIndefiniteLenString[] = { - 0x81, // Array of length one - 0x7f, // text string marked with indefinite length - 0x65, 0x73, 0x74, 0x72, 0x65, 0x61, // first segment - 0x64, 0x6d, 0x69, 0x6e, 0x67, // second segment - 0xff // ending break -}; - -static const uint8_t spIndefiniteLenStringBad2[] = { - 0x81, // Array of length one - 0x7f, // text string marked with indefinite length - 0x65, 0x73, 0x74, 0x72, 0x65, 0x61, // first segment - 0x44, 0x6d, 0x69, 0x6e, 0x67, // second segment of wrong type - 0xff // ending break -}; - -static const uint8_t spIndefiniteLenStringBad3[] = { - 0x81, // Array of length one - 0x7f, // text string marked with indefinite length - 0x01, 0x02, // Not a string - 0xff // ending break -}; - -static const uint8_t spIndefiniteLenStringBad4[] = { - 0x81, // Array of length one - 0x7f, // text string marked with indefinite length - 0x65, 0x73, 0x74, 0x72, 0x65, 0x61, // first segment - 0x64, 0x6d, 0x69, 0x6e, 0x67, // second segment - // missing end of string -}; - -static const uint8_t spIndefiniteLenStringLabel[] = { - 0xa1, // Array of length one - 0x7f, // text string marked with indefinite length - 0x65, 0x73, 0x74, 0x72, 0x75, 0x75, // first segment - 0x64, 0x6d, 0x69, 0x6e, 0x67, // second segment - 0xff, // ending break - 0x01 // integer being labeled. -}; - -/** - Make an indefinite length string - - @param Storage Storage for string, must be 144 bytes in size - @return The indefinite length string - - This makes an array with one indefinite length string that has 7 chunks - from size of 1 byte up to 64 bytes. - */ -static UsefulBufC MakeIndefiniteBigBstr(UsefulBuf Storage) -{ - UsefulOutBuf UOB; - - UsefulOutBuf_Init(&UOB, Storage); - UsefulOutBuf_AppendByte(&UOB, 0x81); - UsefulOutBuf_AppendByte(&UOB, 0x5f); - uint8_t uStringByte = 0; - // Use of type int is intentional - for(int uChunkSize = 1; uChunkSize <= 128; uChunkSize *= 2) { - // Not using preferred encoding here, but that is OK. - UsefulOutBuf_AppendByte(&UOB, 0x58); - UsefulOutBuf_AppendByte(&UOB, (uint8_t)uChunkSize); - for(int j = 0; j < uChunkSize; j++) { - UsefulOutBuf_AppendByte(&UOB, uStringByte); - uStringByte++; - } + if(QCBORDecode_GetNextWithTags(&DCtx, &Item, &Out)) { + return -116; } - UsefulOutBuf_AppendByte(&UOB, 0xff); - - return UsefulOutBuf_OutUBuf(&UOB); -} - -static int CheckBigString(UsefulBufC BigString) -{ - if(BigString.len != 255) { - return 1; + if(Item.uDataType != QCBOR_TYPE_INT64 || + Item.val.int64 != -7 || + Out.uNumUsed != 0) { + return -117; } - for(uint8_t i = 0; i < 255; i++){ - if(((const uint8_t *)BigString.ptr)[i] != i) { - return 1; - } + if(QCBORDecode_GetNextWithTags(&DCtx, &Item, &Out)) { + return -118; } - return 0; -} - - -int32_t IndefiniteLengthStringTest(void) -{ - QCBORDecodeContext DC; - QCBORItem Item; - // big enough for MakeIndefiniteBigBstr() + MemPool overhead - UsefulBuf_MAKE_STACK_UB(MemPool, 350); - - // --- Simple normal indefinite length string ------ - UsefulBufC IndefLen = UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spIndefiniteLenString); - QCBORDecode_Init(&DC, IndefLen, QCBOR_DECODE_MODE_NORMAL); - - if(QCBORDecode_SetMemPool(&DC, MemPool, false)) { - return -1; + if(Item.uDataType != QCBOR_TYPE_BYTE_STRING || + Item.val.string.len != 10 || + puTags[0] != 12 || + Out.uNumUsed != 1) { + return -119; } - if(QCBORDecode_GetNext(&DC, &Item)) { - return -2; + if(QCBORDecode_GetNextWithTags(&DCtx, &Item, &Out)) { + return -120; } - if(Item.uDataType != QCBOR_TYPE_ARRAY || Item.uDataAlloc) { - return -3; + if(Item.uDataType != QCBOR_TYPE_MAP || + !QCBORDecode_IsTagged(&DCtx, &Item, CBOR_TAG_ENC_AS_B16) || + Item.val.uCount != 1 || + puTags[0] != 0x17 || + Out.uNumUsed != 1) { + return -121; } - if(QCBORDecode_GetNext(&DC, &Item)) { - return -4; + if(QCBORDecode_GetNextWithTags(&DCtx, &Item, &Out)) { + return -122; } - if(Item.uDataType != QCBOR_TYPE_TEXT_STRING || !Item.uDataAlloc) { - return -5; + if(Item.uDataType != QCBOR_TYPE_INT64 || + !QCBORDecode_IsTagged(&DCtx, &Item, 8) || + Item.val.int64 != -3 || + puTags[0] != 8 || + Out.uNumUsed != 1) { + return -123; } - if(QCBORDecode_Finish(&DC)) { - return -6; + + if(QCBORDecode_Finish(&DCtx)) { + return -124; } - // ----- types mismatch --- - QCBORDecode_Init(&DC, - UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spIndefiniteLenStringBad2), + UsefulBufC DateString; + QCBORDecode_Init(&DCtx, + UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spSpiffyTagInput), QCBOR_DECODE_MODE_NORMAL); - if(QCBORDecode_SetMemPool(&DC, MemPool, false)) { - return -7; + QCBORDecode_EnterArray(&DCtx, NULL); + // tagged date string + QCBORDecode_GetDateString(&DCtx, QCBOR_TAG_REQUIREMENT_TAG, &DateString); + // untagged date string + QCBORDecode_GetDateString(&DCtx, QCBOR_TAG_REQUIREMENT_NOT_A_TAG, &DateString); + if(QCBORDecode_GetAndResetError(&DCtx) != QCBOR_SUCCESS) { + return 100; } - - if(QCBORDecode_GetNext(&DC, &Item)) { - return -8; + // untagged byte string + QCBORDecode_GetDateString(&DCtx, QCBOR_TAG_REQUIREMENT_NOT_A_TAG, &DateString); + if(QCBORDecode_GetAndResetError(&DCtx) != QCBOR_ERR_UNEXPECTED_TYPE) { + return 101; } - if(Item.uDataType != QCBOR_TYPE_ARRAY) { - return -9; + // tagged regex + QCBORDecode_GetDateString(&DCtx, QCBOR_TAG_REQUIREMENT_TAG, &DateString); + if(QCBORDecode_GetAndResetError(&DCtx) != QCBOR_ERR_UNEXPECTED_TYPE) { + return 102; } - - if(QCBORDecode_GetNext(&DC, &Item) != QCBOR_ERR_INDEFINITE_STRING_CHUNK) { - return -10; + // tagged date string with a byte string + QCBORDecode_GetDateString(&DCtx, QCBOR_TAG_REQUIREMENT_TAG, &DateString); + if(QCBORDecode_GetAndResetError(&DCtx) != QCBOR_ERR_UNRECOVERABLE_TAG_CONTENT) { + return 103; + } + // The exit errors out because the last item, the date string with + // bad content makes the array untraversable (the bad date string + // could have tag content of an array or such that is not consumed + // by the date decoding). + QCBORDecode_ExitArray(&DCtx); + if(QCBORDecode_Finish(&DCtx) != QCBOR_ERR_UNRECOVERABLE_TAG_CONTENT) { + return 104; } - // ----- not a string --- - QCBORDecode_Init(&DC, - UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spIndefiniteLenStringBad3), - QCBOR_DECODE_MODE_NORMAL); - if(QCBORDecode_SetMemPool(&DC, MemPool, false)) { - return -11; + QCBORDecode_Init(&DCtx, + UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spCSRWithTags), + QCBOR_DECODE_MODE_NORMAL); + QCBORDecode_EnterMap(&DCtx, NULL); + if(QCBORDecode_GetNthTagOfLast(&DCtx, 0) != 55799) { + return 200; } - - if(QCBORDecode_GetNext(&DC, &Item)) { - return -12; + if(QCBORDecode_GetNthTagOfLast(&DCtx, 1) != 55799) { + return 202; } - if(Item.uDataType != QCBOR_TYPE_ARRAY) { - return -13; + if(QCBORDecode_GetNthTagOfLast(&DCtx, 2) != 55799) { + return 203; } - - if(QCBORDecode_GetNext(&DC, &Item) != QCBOR_ERR_INDEFINITE_STRING_CHUNK) { - return -14; + if(QCBORDecode_GetNthTagOfLast(&DCtx, 3) != CBOR_TAG_INVALID64) { + return 204; } - // ----- no end ----- - QCBORDecode_Init(&DC, - UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spIndefiniteLenStringBad4), - QCBOR_DECODE_MODE_NORMAL); - - if(QCBORDecode_SetMemPool(&DC, MemPool, false)) { - return -15; + QCBORDecode_EnterMap(&DCtx, NULL); + if(QCBORDecode_GetNthTagOfLast(&DCtx, 0) != 7) { + return 210; } - - if(QCBORDecode_GetNext(&DC, &Item)) { - return -16; + if(QCBORDecode_GetNthTagOfLast(&DCtx, 1) != 5859837686836516696) { + return 212; } - if(Item.uDataType != QCBOR_TYPE_ARRAY) { - return -17; + if(QCBORDecode_GetNthTagOfLast(&DCtx, 2) != CBOR_TAG_INVALID64) { + return 213; + } + if(QCBORDecode_GetNthTagOfLast(&DCtx, 3) != CBOR_TAG_INVALID64) { + return 214; } - if(QCBORDecode_GetNext(&DC, &Item) != QCBOR_ERR_HIT_END) { - return -18; - } - - // ------ Don't set a string allocator and see an error ----- - QCBORDecode_Init(&DC, IndefLen, QCBOR_DECODE_MODE_NORMAL); - QCBORDecode_GetNext(&DC, &Item); - if(Item.uDataType != QCBOR_TYPE_ARRAY) { - return -19; + QCBORDecode_Init(&DCtx, + UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spCSRWithTags), + QCBOR_DECODE_MODE_NORMAL); + QCBORDecode_EnterMap(&DCtx, NULL); + QCBORDecode_EnterMapFromMapN(&DCtx, -23); + if(QCBORDecode_GetNthTagOfLast(&DCtx, 0) != 7) { + return 220; } - - if(QCBORDecode_GetNext(&DC, &Item) != QCBOR_ERR_NO_STRING_ALLOCATOR) { - return -20; + if(QCBORDecode_GetNthTagOfLast(&DCtx, 1) != 5859837686836516696) { + return 221; + } + if(QCBORDecode_GetNthTagOfLast(&DCtx, 2) != CBOR_TAG_INVALID64) { + return 222; } - // ----- Mempool is way too small ----- - UsefulBuf_MAKE_STACK_UB(MemPoolTooSmall, QCBOR_DECODE_MIN_MEM_POOL_SIZE-1); - - QCBORDecode_Init(&DC, IndefLen, QCBOR_DECODE_MODE_NORMAL); - if(!QCBORDecode_SetMemPool(&DC, MemPoolTooSmall, false)) { - return -21; +#ifndef QCBOR_DISABLE_NON_INTEGER_LABELS + QCBORDecode_Init(&DCtx, + UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spCSRWithTags), + QCBOR_DECODE_MODE_MAP_AS_ARRAY); + QCBORDecode_EnterArray(&DCtx, NULL); + if(QCBORDecode_GetNthTagOfLast(&DCtx, 0) != 55799) { + return 230; + } + if(QCBORDecode_GetNthTagOfLast(&DCtx, 1) != 55799) { + return 231; + } + if(QCBORDecode_GetNthTagOfLast(&DCtx, 2) != 55799) { + return 232; + } + if(QCBORDecode_GetNthTagOfLast(&DCtx, 3) != CBOR_TAG_INVALID64) { + return 234; + } + QCBORDecode_GetInt64(&DCtx, &nInt); + if(QCBORDecode_GetNthTagOfLast(&DCtx, 0) != 7) { + return 240; + } + if(QCBORDecode_GetNthTagOfLast(&DCtx, 1) != 6) { + return 241; } + if(QCBORDecode_GetNthTagOfLast(&DCtx, 2) != CBOR_TAG_INVALID64) { + return 242; + } + if(QCBORDecode_GetNthTagOfLast(&DCtx, 3) != CBOR_TAG_INVALID64) { + return 243; + } +#endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */ - // ----- Mempool is way too small ----- - UsefulBuf_MAKE_STACK_UB(BigIndefBStrStorage, 290); - const UsefulBufC BigIndefBStr = MakeIndefiniteBigBstr(BigIndefBStrStorage); - // 80 is big enough for MemPool overhead, but not BigIndefBStr - UsefulBuf_MAKE_STACK_UB(MemPoolSmall, 80); - QCBORDecode_Init(&DC, BigIndefBStr, QCBOR_DECODE_MODE_NORMAL); - if(QCBORDecode_SetMemPool(&DC, MemPoolSmall, false)) { - return -22; - } + QCBORDecode_Init(&DCtx, + UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spSpiffyTagInput), + QCBOR_DECODE_MODE_NORMAL); - QCBORDecode_GetNext(&DC, &Item); - if(Item.uDataType != QCBOR_TYPE_ARRAY) { - return -23; + QCBORDecode_EnterArray(&DCtx, NULL); + // tagged date string + QCBORDecode_GetDateString(&DCtx, QCBOR_TAG_REQUIREMENT_OPTIONAL_TAG, &DateString); + // untagged date string + QCBORDecode_GetDateString(&DCtx, QCBOR_TAG_REQUIREMENT_OPTIONAL_TAG, &DateString); + if(QCBORDecode_GetAndResetError(&DCtx) != QCBOR_SUCCESS) { + return 250; } - if(QCBORDecode_GetNext(&DC, &Item) != QCBOR_ERR_STRING_ALLOCATE) { - return -24; + // untagged byte string + QCBORDecode_GetDateString(&DCtx, QCBOR_TAG_REQUIREMENT_OPTIONAL_TAG, &DateString); + if(QCBORDecode_GetAndResetError(&DCtx) != QCBOR_ERR_UNEXPECTED_TYPE) { + return 251; } - - // ---- big bstr ----- - QCBORDecode_Init(&DC, BigIndefBStr, QCBOR_DECODE_MODE_NORMAL); - - if(QCBORDecode_SetMemPool(&DC, MemPool, false)) { - return -25; + // tagged regex + QCBORDecode_GetDateString(&DCtx, QCBOR_TAG_REQUIREMENT_OPTIONAL_TAG, &DateString); + if(QCBORDecode_GetAndResetError(&DCtx) != QCBOR_ERR_UNEXPECTED_TYPE) { + return 252; } - - if(QCBORDecode_GetNext(&DC, &Item)) { - return -26; + // tagged date string with a byte string + QCBORDecode_GetDateString(&DCtx, QCBOR_TAG_REQUIREMENT_OPTIONAL_TAG, &DateString); + if(QCBORDecode_GetAndResetError(&DCtx) != QCBOR_ERR_UNRECOVERABLE_TAG_CONTENT) { + return 253; } - if(Item.uDataType != QCBOR_TYPE_ARRAY || Item.uDataAlloc) { - return -26; + // See comments above + QCBORDecode_ExitArray(&DCtx); + if(QCBORDecode_Finish(&DCtx) != QCBOR_ERR_UNRECOVERABLE_TAG_CONTENT) { + return 254; } - if(QCBORDecode_GetNext(&DC, &Item)) { - return -27; + QCBORDecode_Init(&DCtx, + UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spSpiffyTagInput), + QCBOR_DECODE_MODE_NORMAL); + + QCBORDecode_EnterArray(&DCtx, NULL); + // tagged date string + QCBORDecode_GetDateString(&DCtx, QCBOR_TAG_REQUIREMENT_NOT_A_TAG, &DateString); + if(QCBORDecode_GetAndResetError(&DCtx) != QCBOR_ERR_UNEXPECTED_TYPE) { + return 300; } - if(Item.uDataType != QCBOR_TYPE_BYTE_STRING || !Item.uDataAlloc || Item.uNestingLevel != 1) { - return -28; + // untagged date string + QCBORDecode_GetDateString(&DCtx, QCBOR_TAG_REQUIREMENT_TAG, &DateString); + if(QCBORDecode_GetAndResetError(&DCtx) != QCBOR_ERR_UNEXPECTED_TYPE) { + return 301; } - if(CheckBigString(Item.val.string)) { - return -3; + // untagged byte string + QCBORDecode_GetDateString(&DCtx, QCBOR_TAG_REQUIREMENT_TAG, &DateString); + if(QCBORDecode_GetAndResetError(&DCtx) != QCBOR_ERR_UNEXPECTED_TYPE) { + return 302; } - if(QCBORDecode_Finish(&DC)) { - return -29; + // tagged regex + QCBORDecode_GetDateString(&DCtx, QCBOR_TAG_REQUIREMENT_NOT_A_TAG, &DateString); + if(QCBORDecode_GetAndResetError(&DCtx) != QCBOR_ERR_UNEXPECTED_TYPE) { + return 303; + } + // tagged date string with a byte string + QCBORDecode_GetDateString(&DCtx, QCBOR_TAG_REQUIREMENT_NOT_A_TAG, &DateString); + if(QCBORDecode_GetAndResetError(&DCtx) != QCBOR_ERR_UNRECOVERABLE_TAG_CONTENT) { + return 304; + } + // See comments above + QCBORDecode_ExitArray(&DCtx); + if(QCBORDecode_Finish(&DCtx) != QCBOR_ERR_UNRECOVERABLE_TAG_CONTENT) { + return 305; } - // --- label is an indefinite length string ------ - QCBORDecode_Init(&DC, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spIndefiniteLenStringLabel), QCBOR_DECODE_MODE_NORMAL); + QCBORDecode_Init(&DCtx, + UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spTaggedString), + QCBOR_DECODE_MODE_NORMAL); - if(QCBORDecode_SetMemPool(&DC, MemPool, false)) { - return -30; + /* See that QCBORDecode_GetTextString() ignores tags */ + QCBORDecode_GetTextString(&DCtx, &UBC); + if(QCBORDecode_GetError(&DCtx) != QCBOR_SUCCESS) { + return 400; + } + if(UBC.len != 1) { + return 401; } - QCBORDecode_GetNext(&DC, &Item); - if(Item.uDataType != QCBOR_TYPE_MAP) { - return -31; + uint64_t uTagNumber = QCBORDecode_GetNthTagOfLast(&DCtx, 0); + if(uTagNumber != 240) { + return 404; } - if(QCBORDecode_GetNext(&DC, &Item)){ - return -32; + + QCBORDecode_Init(&DCtx, + UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spTaggedInt), + QCBOR_DECODE_MODE_NORMAL); + /* See that QCBORDecode_GetInt64() ignores tags */ + QCBORDecode_GetInt64(&DCtx, &nInt); + if(QCBORDecode_GetError(&DCtx) != QCBOR_SUCCESS) { + return 410; } - if(Item.uLabelType != QCBOR_TYPE_TEXT_STRING || - Item.uDataType != QCBOR_TYPE_INT64 || - Item.uDataAlloc || !Item.uLabelAlloc || - UsefulBuf_Compare(Item.label.string, UsefulBuf_FromSZ("struuming"))) { - return -33; + if(nInt != 1) { + return 411; } - if(QCBORDecode_Finish(&DC)) { - return -34; + uTagNumber = QCBORDecode_GetNthTagOfLast(&DCtx, 0); + if(uTagNumber != 244) { + return 414; } return 0; } +/* + * These are showing the big numbers converted to integers. + * The tag numbers are not shown. + * + * [ + * 18446744073709551616, + * -18446744073709551617, + * { + * -64: -18446744073709551617, + * 64: 18446744073709551616, + * "BN+": 18446744073709551616, + * "BN-": -18446744073709551617 + * } + * ] + */ -int32_t AllocAllStringsTest(void) +static const uint8_t spBigNumInput[] = { + 0x83, + 0xC2, 0x49, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xC3, 0x49, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xA4, + 0x38, 0x3F, + 0xC3, 0x49, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x18, 0x40, + 0xC2, 0x49, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x63, 0x42, 0x4E, 0x2B, + 0xC2, 0x49, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x63, 0x42, 0x4E, 0x2D, + 0xC3, 0x49, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; + +#ifndef QCBOR_DISABLE_TAGS +/* The expected big num */ +static const uint8_t spBigNum[] = { + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00}; +#endif /* QCBOR_DISABLE_TAGS */ + + +int32_t BignumParseTest(void) { - QCBORDecodeContext DC; + QCBORDecodeContext DCtx; + QCBORItem Item; QCBORError nCBORError; - - // First test, use the "CSRMap" as easy input and checking - QCBORDecode_Init(&DC, - UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spCSRInput), + QCBORDecode_Init(&DCtx, + UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spBigNumInput), QCBOR_DECODE_MODE_NORMAL); - UsefulBuf_MAKE_STACK_UB(Pool, sizeof(spCSRInput) + QCBOR_DECODE_MIN_MEM_POOL_SIZE); - nCBORError = QCBORDecode_SetMemPool(&DC, Pool, 1); // Turn on copying. - if(nCBORError) { + // + if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) return -1; - } - - if(CheckCSRMaps(&DC)) { + if(Item.uDataType != QCBOR_TYPE_ARRAY) { return -2; } - // Next parse, save pointers to a few strings, destroy original and - // see all is OK. - UsefulBuf_MAKE_STACK_UB(CopyOfStorage, sizeof(pValidMapEncoded) + QCBOR_DECODE_MIN_MEM_POOL_SIZE); - const UsefulBufC CopyOf = UsefulBuf_Copy(CopyOfStorage, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(pValidMapEncoded)); - - QCBORDecode_Init(&DC, CopyOf, QCBOR_DECODE_MODE_NORMAL); - UsefulBuf_Set(Pool, '/'); - QCBORDecode_SetMemPool(&DC, Pool, 1); // Turn on copying. - - QCBORItem Item1, Item2, Item3, Item4; - if((nCBORError = QCBORDecode_GetNext(&DC, &Item1))) - return (int32_t)nCBORError; - if(Item1.uDataType != QCBOR_TYPE_MAP || - Item1.val.uCount != 3) +#ifndef QCBOR_DISABLE_TAGS + // + if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) return -3; - if((nCBORError = QCBORDecode_GetNext(&DC, &Item1))) - return (int32_t)nCBORError; - if((nCBORError = QCBORDecode_GetNext(&DC, &Item2))) - return (int32_t)nCBORError; - if((nCBORError = QCBORDecode_GetNext(&DC, &Item3))) - return (int32_t)nCBORError; - if((nCBORError = QCBORDecode_GetNext(&DC, &Item4))) - return (int32_t)nCBORError; - - UsefulBuf_Set(CopyOfStorage, '_'); - - if(Item1.uLabelType != QCBOR_TYPE_TEXT_STRING || - Item1.uDataType != QCBOR_TYPE_INT64 || - Item1.val.int64 != 42 || - Item1.uDataAlloc != 0 || - Item1.uLabelAlloc == 0 || - UsefulBufCompareToSZ(Item1.label.string, "first integer")) { + if(Item.uDataType != QCBOR_TYPE_POSBIGNUM || + UsefulBuf_Compare(Item.val.bigNum, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spBigNum))){ return -4; } - - if(Item2.uLabelType != QCBOR_TYPE_TEXT_STRING || - UsefulBufCompareToSZ(Item2.label.string, "an array of two strings") || - Item2.uDataType != QCBOR_TYPE_ARRAY || - Item2.uDataAlloc != 0 || - Item2.uLabelAlloc == 0 || - Item2.val.uCount != 2) + // + if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) return -5; - - if(Item3.uDataType != QCBOR_TYPE_TEXT_STRING || - Item3.uDataAlloc == 0 || - Item3.uLabelAlloc != 0 || - UsefulBufCompareToSZ(Item3.val.string, "string1")) { + if(Item.uDataType != QCBOR_TYPE_NEGBIGNUM || + UsefulBuf_Compare(Item.val.bigNum, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spBigNum))){ return -6; } - if(Item4.uDataType != QCBOR_TYPE_TEXT_STRING || - Item4.uDataAlloc == 0 || - Item4.uLabelAlloc != 0 || - UsefulBufCompareToSZ(Item4.val.string, "string2")) { + // + if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) return -7; + if(Item.uDataType != QCBOR_TYPE_MAP) { + return -8; } - // Next parse with a pool that is too small - UsefulBuf_MAKE_STACK_UB(SmallPool, QCBOR_DECODE_MIN_MEM_POOL_SIZE + 1); - QCBORDecode_Init(&DC, - UsefulBuf_FROM_BYTE_ARRAY_LITERAL(pValidMapEncoded), - QCBOR_DECODE_MODE_NORMAL); - QCBORDecode_SetMemPool(&DC, SmallPool, 1); // Turn on copying. - if((nCBORError = QCBORDecode_GetNext(&DC, &Item1))) - return -8; - if(Item1.uDataType != QCBOR_TYPE_MAP || - Item1.val.uCount != 3) { - return -9; + if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) + return -15; + if(Item.uDataType != QCBOR_TYPE_NEGBIGNUM || + Item.uLabelType != QCBOR_TYPE_INT64 || + Item.label.int64 != -64 || + UsefulBuf_Compare(Item.val.bigNum, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spBigNum))){ + return -16; } - if(!(nCBORError = QCBORDecode_GetNext(&DC, &Item1))){ - if(!(nCBORError = QCBORDecode_GetNext(&DC, &Item2))) { - if(!(nCBORError = QCBORDecode_GetNext(&DC, &Item3))) { - nCBORError = QCBORDecode_GetNext(&DC, &Item4); - } - } + + if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) + return -11; + if(Item.uDataType != QCBOR_TYPE_POSBIGNUM || + Item.uLabelType != QCBOR_TYPE_INT64 || + Item.label.int64 != 64 || + UsefulBuf_Compare(Item.val.bigNum, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spBigNum))){ + return -12; } - if(nCBORError != QCBOR_ERR_STRING_ALLOCATE) { + +#ifndef QCBOR_DISABLE_NON_INTEGER_LABELS + if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) + return -9; + if(Item.uDataType != QCBOR_TYPE_POSBIGNUM || + Item.uLabelType != QCBOR_TYPE_TEXT_STRING || + UsefulBuf_Compare(Item.val.bigNum, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spBigNum))){ return -10; } + if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) + return -13; + if(Item.uDataType != QCBOR_TYPE_NEGBIGNUM || + Item.uLabelType != QCBOR_TYPE_TEXT_STRING || + UsefulBuf_Compare(Item.val.bigNum, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spBigNum))){ + return -14; + } + + +#endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */ + +#else + + if(QCBORDecode_GetNext(&DCtx, &Item) != QCBOR_ERR_TAGS_DISABLED) { + return -100; + } +#endif /* QCBOR_DISABLE_TAGS */ + return 0; } -int32_t MemPoolTest(void) +static int32_t CheckItemWithIntLabel(QCBORDecodeContext *pCtx, + uint8_t uDataType, + uint8_t uNestingLevel, + uint8_t uNextNest, + int64_t nLabel, + QCBORItem *pItem) { - // Set up the decoder with a tiny bit of CBOR to parse because - // nothing can be done with it unless that is set up. - QCBORDecodeContext DC; - const uint8_t pMinimalCBOR[] = {0xa0}; // One empty map - QCBORDecode_Init(&DC, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(pMinimalCBOR),0); + QCBORItem Item; + QCBORError nCBORError; + + if((nCBORError = QCBORDecode_GetNext(pCtx, &Item))) return -1; + if(Item.uDataType != uDataType) return -1; + if(uNestingLevel > 0) { + if(Item.uLabelType != QCBOR_TYPE_INT64) { + return -1; + } + if(Item.label.int64 != nLabel) { + return -1; + } - // Set up an memory pool of 100 bytes - // Then fish into the internals of the decode context - // to get the allocator function so it can be called directly. - // Also figure out how much pool is available for use - // buy subtracting out the overhead. - UsefulBuf_MAKE_STACK_UB(Pool, 100); - QCBORError nError = QCBORDecode_SetMemPool(&DC, Pool, 0); - if(nError) { - return -9; } - QCBORStringAllocate pAlloc = DC.StringAllocator.pfAllocator; - void *pAllocCtx = DC.StringAllocator.pAllocateCxt; - size_t uAvailPool = Pool.len - QCBOR_DECODE_MIN_MEM_POOL_SIZE; + if(Item.uNestingLevel != uNestingLevel) return -1; + if(Item.uNextNestLevel != uNextNest) return -1; - // First test -- ask for one more byte than available and see failure - UsefulBuf Allocated = (*pAlloc)(pAllocCtx, NULL, uAvailPool+1); - if(!UsefulBuf_IsNULL(Allocated)) { - return -1; + if(pItem) { + *pItem = Item; } + return 0; +} - // Re do the set up for the next test that will do a successful alloc, - // a fail, a free and then success - QCBORDecode_SetMemPool(&DC, Pool, 0); - pAlloc = DC.StringAllocator.pfAllocator; - pAllocCtx = DC.StringAllocator.pAllocateCxt; - uAvailPool = Pool.len - QCBOR_DECODE_MIN_MEM_POOL_SIZE; +// Same code checks definite and indefinite length versions of the map +static int32_t CheckCSRMaps(QCBORDecodeContext *pDC) +{ + if(CheckItemWithIntLabel(pDC, QCBOR_TYPE_MAP, 0, 1, 0, NULL)) return -1; - // Allocate one byte less than available and see success - Allocated = (pAlloc)(pAllocCtx, NULL, uAvailPool-1); - if(UsefulBuf_IsNULL(Allocated)) { // expected to succeed - return -2; - } - // Ask for some more and see failure - UsefulBuf Allocated2 = (*pAlloc)(pAllocCtx, NULL, uAvailPool/2); - if(!UsefulBuf_IsNULL(Allocated2)) { // expected to fail - return -3; - } - // Free the first allocate, retry the second and see success - (*pAlloc)(pAllocCtx, Allocated.ptr, 0); // Free - Allocated = (*pAlloc)(pAllocCtx, NULL, uAvailPool/2); - if(UsefulBuf_IsNULL(Allocated)) { // succeed because of the free - return -4; - } + if(CheckItemWithIntLabel(pDC, QCBOR_TYPE_MAP, 1, 2, -23, NULL)) return -2; - // Re do set up for next test that involves a successful alloc, - // and a successful realloc and a failed realloc - QCBORDecode_SetMemPool(&DC, Pool, 0); - pAlloc = DC.StringAllocator.pfAllocator; - pAllocCtx = DC.StringAllocator.pAllocateCxt; + if(CheckItemWithIntLabel(pDC, QCBOR_TYPE_MAP, 2, 3, -20, NULL)) return -3; - // Allocate half the pool and see success - Allocated = (*pAlloc)(pAllocCtx, NULL, uAvailPool/2); - if(UsefulBuf_IsNULL(Allocated)) { // expected to succeed - return -5; - } - // Reallocate to take up the whole pool and see success - Allocated2 = (*pAlloc)(pAllocCtx, Allocated.ptr, uAvailPool); - if(UsefulBuf_IsNULL(Allocated2)) { - return -6; - } - // Make sure its the same pointer and the size is right - if(Allocated2.ptr != Allocated.ptr || Allocated2.len != uAvailPool) { - return -7; - } - // Try to allocate more to be sure there is failure after a realloc - UsefulBuf Allocated3 = (*pAlloc)(pAllocCtx, Allocated.ptr, uAvailPool+1); - if(!UsefulBuf_IsNULL(Allocated3)) { - return -8; - } + if(CheckItemWithIntLabel(pDC, QCBOR_TYPE_TEXT_STRING, 3, 3, -18, NULL)) return -4; + if(CheckItemWithIntLabel(pDC, QCBOR_TYPE_TEXT_STRING, 3, 3, -17, NULL)) return -5; + if(CheckItemWithIntLabel(pDC, QCBOR_TYPE_TEXT_STRING, 3, 3, -15, NULL)) return -6; + if(CheckItemWithIntLabel(pDC, QCBOR_TYPE_TEXT_STRING, 3, 3, -16, NULL)) return -7; + if(CheckItemWithIntLabel(pDC, QCBOR_TYPE_TEXT_STRING, 3, 2, -14, NULL)) return -8; + + if(CheckItemWithIntLabel(pDC, QCBOR_TYPE_MAP, 2, 3, -19, NULL)) return -9; + if(CheckItemWithIntLabel(pDC, QCBOR_TYPE_MAP, 3, 4, -11, NULL)) return -10; + + if(CheckItemWithIntLabel(pDC, QCBOR_TYPE_INT64, 4, 3, -9, NULL)) return -11; + if(CheckItemWithIntLabel(pDC, QCBOR_TYPE_BYTE_STRING, 3, 1, -10, NULL)) return -12; + + if(CheckItemWithIntLabel(pDC, QCBOR_TYPE_MAP, 1, 2, -22, NULL)) return -13; + if(CheckItemWithIntLabel(pDC, QCBOR_TYPE_INT64, 2, 0, -5, NULL)) return -14; + + if(QCBORDecode_Finish(pDC)) return -20; return 0; } -/* Just enough of an allocator to test configuration of one */ -static UsefulBuf AllocateTestFunction(void *pCtx, void *pOldMem, size_t uNewSize) +/* { - (void)pOldMem; // unused variable - - if(uNewSize) { - // Assumes the context pointer is the buffer and - // nothing too big will ever be asked for. - // This is only good for this basic test! - return (UsefulBuf) {pCtx, uNewSize}; - } else { - return NULLUsefulBuf; - } + -23: { + -20: { + -18: "Organization", + -17: "SSG", + -15: "Confusion", + -16: "San Diego", + -14: "US" + }, + -19: { + -11: { + -9: -7 + }, + -10: '\u0001\u0002\u0003\u0004\u0005\u0006\a\b\t\n' + } + }, + -22: { + -5: -3 + } } +*/ +static const uint8_t spCSRInput[] = { + 0xa2, 0x36, 0xa2, 0x33, 0xa5, 0x31, 0x6c, 0x4f, + 0x72, 0x67, 0x61, 0x6e, 0x69, 0x7a, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x30, 0x63, 0x53, 0x53, 0x47, + 0x2e, 0x69, 0x43, 0x6f, 0x6e, 0x66, 0x75, 0x73, + 0x69, 0x6f, 0x6e, 0x2f, 0x69, 0x53, 0x61, 0x6e, + 0x20, 0x44, 0x69, 0x65, 0x67, 0x6f, 0x2d, 0x62, + 0x55, 0x53, 0x32, 0xa2, 0x2a, 0xa1, 0x28, 0x26, + 0x29, 0x4a, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, + 0x07, 0x08, 0x09, 0x0a, 0x35, 0xa1, 0x24, 0x22}; + +// Same map as above, but using indefinite lengths +static const uint8_t spCSRInputIndefLen[] = { + 0xbf, 0x36, 0xbf, 0x33, 0xbf, 0x31, 0x6c, 0x4f, + 0x72, 0x67, 0x61, 0x6e, 0x69, 0x7a, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x30, 0x63, 0x53, 0x53, 0x47, + 0x2e, 0x69, 0x43, 0x6f, 0x6e, 0x66, 0x75, 0x73, + 0x69, 0x6f, 0x6e, 0x2f, 0x69, 0x53, 0x61, 0x6e, + 0x20, 0x44, 0x69, 0x65, 0x67, 0x6f, 0x2d, 0x62, + 0x55, 0x53, 0xff, 0x32, 0xbf, 0x2a, 0xbf, 0x28, + 0x26, 0xff, 0x29, 0x4a, 0x01, 0x02, 0x03, 0x04, + 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0xff, 0xff, + 0x35, 0xbf, 0x24, 0x22, 0xff, 0xff}; -int32_t SetUpAllocatorTest(void) +int32_t NestedMapTest(void) { - // Set up the decoder with a tiny bit of CBOR to parse because - // nothing can be done with it unless that is set up. - QCBORDecodeContext DC; - const uint8_t pMinimalCBOR[] = {0x62, 0x48, 0x69}; // "Hi" - QCBORDecode_Init(&DC, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(pMinimalCBOR),0); + QCBORDecodeContext DCtx; - uint8_t pAllocatorBuffer[50]; + QCBORDecode_Init(&DCtx, + UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spCSRInput), + QCBOR_DECODE_MODE_NORMAL); - // This is really just to test that this call works. - // The full functionality of string allocators is tested - // elsewhere with the MemPool internal allocator. - QCBORDecode_SetUpAllocator(&DC, AllocateTestFunction, pAllocatorBuffer, 1); + return CheckCSRMaps(&DCtx); +} + + + +int32_t StringDecoderModeFailTest(void) +{ + QCBORDecodeContext DCtx; + + QCBORDecode_Init(&DCtx, + UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spCSRInput), + QCBOR_DECODE_MODE_MAP_STRINGS_ONLY); QCBORItem Item; - if(QCBORDecode_GetNext(&DC, &Item) != QCBOR_SUCCESS) { + QCBORError nCBORError; + + if(QCBORDecode_GetNext(&DCtx, &Item)) { return -1; } - - if(Item.uDataAlloc == 0 || - Item.uDataType != QCBOR_TYPE_TEXT_STRING || - Item.val.string.ptr != pAllocatorBuffer) { + if(Item.uDataType != QCBOR_TYPE_MAP) { return -2; } - if(QCBORDecode_Finish(&DC) != QCBOR_SUCCESS) { + nCBORError = QCBORDecode_GetNext(&DCtx, &Item); + if(nCBORError != QCBOR_ERR_MAP_LABEL_TYPE) { return -3; } return 0; } -#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS */ -#ifndef QCBOR_DISABLE_EXP_AND_MANTISSA -struct EaMTest { - const char *szName; - UsefulBufC Input; - uint8_t uTagRequirement; - bool bHasTags; +int32_t NestedMapTestIndefLen(void) +{ + QCBORDecodeContext DCtx; - /* Expected values for GetNext */ - QCBORError uExpectedErrorGN; - uint8_t uQCBORTypeGN; - int64_t nExponentGN; - int64_t nMantissaGN; - UsefulBufC MantissaGN; + QCBORDecode_Init(&DCtx, + UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spCSRInputIndefLen), + QCBOR_DECODE_MODE_NORMAL); - /* Expected values for GetDecimalFraction */ - QCBORError uExpectedErrorGDF; - int64_t nExponentGDF; - int64_t nMantissaGDF; + return CheckCSRMaps(&DCtx); +} - /* Expected values for GetDecimalFractionBig */ - QCBORError uExpectedErrorGDFB; - int64_t nExponentGDFB; - UsefulBufC MantissaGDFB; - bool IsNegativeGDFB; - /* Expected values for GetBigFloat */ - QCBORError uExpectedErrorGBF; - int64_t nExponentGBF; - int64_t nMantissaGBF; - /* Expected values for GetBigFloatBig */ - QCBORError uExpectedErrorGBFB; - int64_t nExponentGBFB; - UsefulBufC MantissaGBFB; - bool IsNegativeGBFB; -}; +static UsefulBufC make_nested_indefinite_arrays(int n, UsefulBuf Storage) +{ + UsefulOutBuf UOB; + UsefulOutBuf_Init(&UOB, Storage); + int i; + for(i = 0; i < n; i++) { + UsefulOutBuf_AppendByte(&UOB, 0x9f); + } + for(i = 0; i < n; i++) { + UsefulOutBuf_AppendByte(&UOB, 0xff); + } + return UsefulOutBuf_OutUBuf(&UOB); +} -static const struct EaMTest pEaMTests[] = { - { - "1. Untagged pair (big float or decimal fraction), no tag required", - {(const uint8_t []){0x82, 0x20, 0x03}, 3}, - QCBOR_TAG_REQUIREMENT_NOT_A_TAG, - false, - QCBOR_SUCCESS, /* for GetNext */ - QCBOR_TYPE_ARRAY, - 0, - 0, - {(const uint8_t []){0x00}, 1}, +static int32_t parse_indeflen_nested(UsefulBufC Nested, int nNestLevel) +{ + QCBORDecodeContext DC; + QCBORDecode_Init(&DC, Nested, 0); - QCBOR_SUCCESS, /* GetDecimalFraction */ - -1, - 3, + int j; + for(j = 0; j < nNestLevel; j++) { + QCBORItem Item; + QCBORError nReturn = QCBORDecode_GetNext(&DC, &Item); + if(j >= QCBOR_MAX_ARRAY_NESTING) { + // Should be in error + if(nReturn != QCBOR_ERR_ARRAY_DECODE_NESTING_TOO_DEEP) { + return -4; + } else { + return 0; // Decoding doesn't recover after an error + } + } else { + // Should be no error + if(nReturn) { + return -9; // Should not have got an error + } + } + if(Item.uDataType != QCBOR_TYPE_ARRAY) { + return -7; + } + } + QCBORError nReturn = QCBORDecode_Finish(&DC); + if(nReturn) { + return -3; + } + return 0; +} - QCBOR_SUCCESS, /* for GetDecimalFractionBig */ - -1, - {(const uint8_t []){0x03}, 1}, - false, - QCBOR_SUCCESS, /* for GetBigFloat */ - -1, - 3, +int32_t IndefiniteLengthNestTest(void) +{ + UsefulBuf_MAKE_STACK_UB(Storage, 50); + int i; + for(i=1; i < QCBOR_MAX_ARRAY_NESTING+4; i++) { + const UsefulBufC Nested = make_nested_indefinite_arrays(i, Storage); + int nReturn = parse_indeflen_nested(Nested, i); + if(nReturn) { + return nReturn; + } + } + return 0; +} - QCBOR_SUCCESS, /* for GetBigFloatBig */ - -1, - {(const uint8_t []){0x03}, 1}, - false - }, +// [1, [2, 3]] +static const uint8_t spIndefiniteArray[] = {0x9f, 0x01, 0x82, 0x02, 0x03, 0xff}; +// No closing break +static const uint8_t spIndefiniteArrayBad1[] = {0x9f}; +// Not enough closing breaks +static const uint8_t spIndefiniteArrayBad2[] = {0x9f, 0x9f, 0x02, 0xff}; +// Too many closing breaks +static const uint8_t spIndefiniteArrayBad3[] = {0x9f, 0x02, 0xff, 0xff}; +// Unclosed indeflen inside def len +static const uint8_t spIndefiniteArrayBad4[] = {0x81, 0x9f}; +// confused tag +static const uint8_t spIndefiniteArrayBad5[] = {0x9f, 0xd1, 0xff}; - { - "2. Untagged pair (big float or decimal fraction), tag required", - {(const uint8_t []){0x82, 0x20, 0x03}, 3}, - QCBOR_TAG_REQUIREMENT_TAG, - false, +int32_t IndefiniteLengthArrayMapTest(void) +{ + QCBORError nResult; + // --- first test ----- + UsefulBufC IndefLen = UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spIndefiniteArray); - QCBOR_SUCCESS, /* for GetNext */ - QCBOR_TYPE_ARRAY, - 0, - 0, - {(const uint8_t []){0x00}, 1}, + // Decode it and see if it is OK + QCBORDecodeContext DC; + QCBORItem Item; + QCBORDecode_Init(&DC, IndefLen, QCBOR_DECODE_MODE_NORMAL); - QCBOR_ERR_UNEXPECTED_TYPE, /* for GetDecimalFraction */ - 0, - 0, + QCBORDecode_GetNext(&DC, &Item); - QCBOR_ERR_UNEXPECTED_TYPE, /* for GetDecimalFractionBig */ - 0, - {(const uint8_t []){0x00}, 1}, - false, + if(Item.uDataType != QCBOR_TYPE_ARRAY || + Item.uNestingLevel != 0 || + Item.uNextNestLevel != 1) { + return -111; + } - QCBOR_ERR_UNEXPECTED_TYPE, /* for GetBigFloat */ - 0, - 0, + QCBORDecode_GetNext(&DC, &Item); + if(Item.uDataType != QCBOR_TYPE_INT64 || + Item.uNestingLevel != 1 || + Item.uNextNestLevel != 1) { + return -2; + } - QCBOR_ERR_UNEXPECTED_TYPE, /* for GetBigFloatBig */ - 0, - {(const uint8_t []){0x00}, 1}, - false + QCBORDecode_GetNext(&DC, &Item); + if(Item.uDataType != QCBOR_TYPE_ARRAY || + Item.uNestingLevel != 1 || + Item.uNextNestLevel != 2) { + return -3; + } - }, + QCBORDecode_GetNext(&DC, &Item); + if(Item.uDataType != QCBOR_TYPE_INT64 || + Item.uNestingLevel != 2 || + Item.uNextNestLevel != 2) { + return -4; + } - { - "3. Tagged 1.5 decimal fraction, tag 4 optional", - {(const uint8_t []){0xC4, 0x82, 0x20, 0x03}, 4}, - QCBOR_TAG_REQUIREMENT_OPTIONAL_TAG, - true, + QCBORDecode_GetNext(&DC, &Item); + if(Item.uDataType != QCBOR_TYPE_INT64 || + Item.uNestingLevel != 2 || + Item.uNextNestLevel != 0) { + return -5; + } - QCBOR_SUCCESS, /* for GetNext */ - QCBOR_TYPE_DECIMAL_FRACTION, - -1, - 3, - {(const uint8_t []){0x00}, 1}, + if(QCBORDecode_Finish(&DC)) { + return -6; + } + // --- next test ----- + IndefLen = UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spIndefiniteArrayBad1); - QCBOR_SUCCESS, /* for GetDecimalFraction */ - -1, - 3, + QCBORDecode_Init(&DC, IndefLen, QCBOR_DECODE_MODE_NORMAL); - QCBOR_SUCCESS, /* for GetDecimalFractionBig */ - -1, - {(const uint8_t []){0x03}, 1}, - false, + nResult = QCBORDecode_GetNext(&DC, &Item); + if(nResult || Item.uDataType != QCBOR_TYPE_ARRAY) { + return -7; + } - QCBOR_ERR_UNEXPECTED_TYPE, /* for GetBigFloat */ - 0, - 0, + nResult = QCBORDecode_Finish(&DC); + if(nResult != QCBOR_ERR_ARRAY_OR_MAP_UNCONSUMED) { + return -8; + } - QCBOR_ERR_UNEXPECTED_TYPE, /* for GetBigFloatBig */ - 0, - {(const uint8_t []){0x00}, 1}, - false - }, - { - "4. Tagged 100 * 2^300 big float, tag 5 optional", - {(const uint8_t []){0xC5, 0x82, 0x19, 0x01, 0x2C, 0x18, 0x64}, 7}, - QCBOR_TAG_REQUIREMENT_OPTIONAL_TAG, - true, - QCBOR_SUCCESS, /* for GetNext */ - QCBOR_TYPE_BIGFLOAT, - 300, - 100, - {(const uint8_t []){0x00}, 1}, + // --- next test ----- + IndefLen = UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spIndefiniteArrayBad2); + QCBORDecode_Init(&DC, IndefLen, QCBOR_DECODE_MODE_NORMAL); - QCBOR_ERR_UNEXPECTED_TYPE, /* for GetDecimalFraction */ - 0, - 0, + nResult = QCBORDecode_GetNext(&DC, &Item); + if(nResult || Item.uDataType != QCBOR_TYPE_ARRAY) { + return -9; + } - QCBOR_ERR_UNEXPECTED_TYPE, /* for GetDecimalFractionBig */ - 0, - {(const uint8_t []){0x03}, 1}, - false, - - QCBOR_SUCCESS, /* for GetBigFloat */ - 300, - 100, - - QCBOR_SUCCESS, /* for GetBigFloatBig */ - 300, - {(const uint8_t []){0x64}, 1}, - false - }, - - { - "5. Tagged 4([-20, 4759477275222530853136]) decimal fraction, tag 4 required", - {(const uint8_t []){0xC4, 0x82, 0x33, - 0xC2, 0x4A, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x10,}, 15}, - QCBOR_TAG_REQUIREMENT_TAG, - true, - - QCBOR_SUCCESS, /* for GetNext */ - QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM, - -20, - 0, - {(const uint8_t []){0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x10}, 10}, + nResult = QCBORDecode_GetNext(&DC, &Item); + if(nResult || Item.uDataType != QCBOR_TYPE_ARRAY) { + return -10; + } - QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW, /* for GetDecimalFraction */ - 0, - 0, + nResult = QCBORDecode_GetNext(&DC, &Item); + if(nResult || Item.uDataType != QCBOR_TYPE_INT64) { + return -11; + } - QCBOR_SUCCESS, /* for GetDecimalFractionBig */ - -20, - {(const uint8_t []){0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x10}, 10}, - false, + nResult = QCBORDecode_Finish(&DC); + if(nResult != QCBOR_ERR_ARRAY_OR_MAP_UNCONSUMED) { + return -12; + } - QCBOR_ERR_UNEXPECTED_TYPE, /* for GetBigFloat */ - 0, - 0, - QCBOR_ERR_UNEXPECTED_TYPE, /* for GetBigFloatBig */ - 0, - {(const uint8_t []){0x00}, 0}, - false - }, + // --- next test ----- + IndefLen = UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spIndefiniteArrayBad3); - { - "6. Error: Mantissa and exponent inside a Mantissa and exponent", - {(const uint8_t []){0xC4, 0x82, 0x33, - 0xC5, 0x82, 0x19, 0x01, 0x2C, 0x18, 0x64}, 10}, - QCBOR_TAG_REQUIREMENT_TAG, - true, + QCBORDecode_Init(&DC, IndefLen, QCBOR_DECODE_MODE_NORMAL); - QCBOR_ERR_BAD_EXP_AND_MANTISSA, /* for GetNext */ - QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM, - 0, - 0, - {(const uint8_t []){0x00}, 0}, + nResult = QCBORDecode_GetNext(&DC, &Item); + if(nResult || Item.uDataType != QCBOR_TYPE_ARRAY) { + return -13; + } - QCBOR_ERR_BAD_EXP_AND_MANTISSA, /* for GetDecimalFraction */ - 0, - 0, + nResult = QCBORDecode_GetNext(&DC, &Item); + if(nResult != QCBOR_SUCCESS) { + return -14; + } - QCBOR_ERR_BAD_EXP_AND_MANTISSA, /* for GetDecimalFractionBig */ - 0, - {(const uint8_t []){0x00}, 0}, - false, + nResult = QCBORDecode_GetNext(&DC, &Item); + if(nResult != QCBOR_ERR_BAD_BREAK) { + return -140; + } - QCBOR_ERR_BAD_EXP_AND_MANTISSA, /* for GetBigFloat */ - 0, - 0, - QCBOR_ERR_BAD_EXP_AND_MANTISSA, /* for GetBigFloatBig */ - 0, - {(const uint8_t []){0x00}, 0}, - false - }, - { - "7. Tagged 5([-20, 4294967295]) big float, big num mantissa, tag 5 required", - {(const uint8_t []){0xC5, 0x82, 0x33, - 0xC2, 0x44, 0xff, 0xff, 0xff, 0xff}, 9}, - QCBOR_TAG_REQUIREMENT_TAG, - true, + // --- next test ----- + IndefLen = UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spIndefiniteArrayBad4); - QCBOR_SUCCESS, /* for GetNext */ - QCBOR_TYPE_BIGFLOAT_POS_BIGNUM, - -20, - 0, - {(const uint8_t []){0xff, 0xff, 0xff, 0xff}, 4}, + QCBORDecode_Init(&DC, IndefLen, QCBOR_DECODE_MODE_NORMAL); - QCBOR_ERR_UNEXPECTED_TYPE, /* for GetDecimalFraction */ - 0, - 0, + nResult = QCBORDecode_GetNext(&DC, &Item); + if(nResult || Item.uDataType != QCBOR_TYPE_ARRAY) { + return -15; + } - QCBOR_ERR_UNEXPECTED_TYPE, /* for GetDecimalFractionBig */ - -20, - {(const uint8_t []){0x00}, 1}, - false, + nResult = QCBORDecode_GetNext(&DC, &Item); + if(nResult || Item.uDataType != QCBOR_TYPE_ARRAY) { + return -16; + } - QCBOR_SUCCESS, /* for GetBigFloat */ - -20, - 4294967295, + nResult = QCBORDecode_Finish(&DC); + if(nResult != QCBOR_ERR_ARRAY_OR_MAP_UNCONSUMED) { + return -17; + } - QCBOR_SUCCESS, /* for GetBigFloatBig */ - -20, - {(const uint8_t []){0xff, 0xff, 0xff, 0xff}, 4}, - false - }, + // --- next test ----- + IndefLen = UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spIndefiniteArrayBad5); - { - /* Special case for test 8. Don't renumber it. */ - "8. Untagged pair with big num (big float or decimal fraction), tag optional", - {(const uint8_t []){0x82, 0x33, 0xC2, 0x4A, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x10}, 14}, - QCBOR_TAG_REQUIREMENT_OPTIONAL_TAG, - true, + QCBORDecode_Init(&DC, IndefLen, QCBOR_DECODE_MODE_NORMAL); - QCBOR_SUCCESS, /* for GetNext */ - QCBOR_TYPE_ARRAY, - 0, - 0, - {(const uint8_t []){0x00}, 1}, + nResult = QCBORDecode_GetNext(&DC, &Item); - QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW, /* GetDecimalFraction */ - 0, - 0, +#ifndef QCBOR_DISABLE_TAGS + if(nResult || Item.uDataType != QCBOR_TYPE_ARRAY) { + return -18; + } - QCBOR_SUCCESS, /* for GetDecimalFractionBig */ - -20, - {(const uint8_t []){0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x10}, 10}, - false, + nResult = QCBORDecode_GetNext(&DC, &Item); + if(nResult != QCBOR_ERR_BAD_BREAK) { + return -19; + } +#else /* QCBOR_DISABLE_TAGS */ + if(nResult != QCBOR_ERR_TAGS_DISABLED) { + return -20; + } +#endif /* QCBOR_DISABLE_TAGS */ - QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW, /* for GetBigFloat */ - 0, - 0, + return 0; +} - QCBOR_SUCCESS, /* for GetBigFloatBig */ - -20, - {(const uint8_t []){0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x10}, 10}, - false - }, - { - "9. decimal fraction with large exponent and negative big num mantissa", - {(const uint8_t []){0xC4, 0x82, 0x1B, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xC3, 0x4A, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x10}, 23}, - QCBOR_TAG_REQUIREMENT_OPTIONAL_TAG, - true, +#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS - QCBOR_SUCCESS, /* for GetNext */ - QCBOR_TYPE_DECIMAL_FRACTION_NEG_BIGNUM, - 9223372036854775807, - 0, - {(const uint8_t []){0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x10}, 10}, +static const uint8_t spIndefiniteLenString[] = { + 0x81, // Array of length one + 0x7f, // text string marked with indefinite length + 0x65, 0x73, 0x74, 0x72, 0x65, 0x61, // first segment + 0x64, 0x6d, 0x69, 0x6e, 0x67, // second segment + 0xff // ending break +}; - QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW, /* GetDecimalFraction */ - 0, - 0, +static const uint8_t spIndefiniteLenStringBad2[] = { + 0x81, // Array of length one + 0x7f, // text string marked with indefinite length + 0x65, 0x73, 0x74, 0x72, 0x65, 0x61, // first segment + 0x44, 0x6d, 0x69, 0x6e, 0x67, // second segment of wrong type + 0xff // ending break +}; - QCBOR_SUCCESS, /* for GetDecimalFractionBig */ - 9223372036854775807, - {(const uint8_t []){0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x10}, 10}, - true, +static const uint8_t spIndefiniteLenStringBad3[] = { + 0x81, // Array of length one + 0x7f, // text string marked with indefinite length + 0x01, 0x02, // Not a string + 0xff // ending break +}; - QCBOR_ERR_UNEXPECTED_TYPE, /* for GetBigFloat */ - 0, - 0, +static const uint8_t spIndefiniteLenStringBad4[] = { + 0x81, // Array of length one + 0x7f, // text string marked with indefinite length + 0x65, 0x73, 0x74, 0x72, 0x65, 0x61, // first segment + 0x64, 0x6d, 0x69, 0x6e, 0x67, // second segment + // missing end of string +}; - QCBOR_ERR_UNEXPECTED_TYPE, /* for GetBigFloatBig */ - 0, - {(const uint8_t []){0x00}, 1}, - false - }, +#ifndef QCBOR_DISABLE_NON_INTEGER_LABELS +static const uint8_t spIndefiniteLenStringLabel[] = { + 0xa1, // Array of length one + 0x7f, // text string marked with indefinite length + 0x65, 0x73, 0x74, 0x72, 0x75, 0x75, // first segment + 0x64, 0x6d, 0x69, 0x6e, 0x67, // second segment + 0xff, // ending break + 0x01 // integer being labeled. }; +#endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */ +/** + Make an indefinite length string + @param Storage Storage for string, must be 144 bytes in size + @return The indefinite length string -int32_t ProcessEaMTests(void) + This makes an array with one indefinite length string that has 7 chunks + from size of 1 byte up to 64 bytes. + */ +static UsefulBufC MakeIndefiniteBigBstr(UsefulBuf Storage) { - size_t uIndex; - QCBORDecodeContext DCtx; - QCBORItem Item; - QCBORError uError; - int64_t nMantissa, nExponent; - MakeUsefulBufOnStack( MantissaBuf, 200); - UsefulBufC Mantissa; - bool bMantissaIsNegative; - - for(uIndex = 0; uIndex < C_ARRAY_COUNT(pEaMTests, struct EaMTest); uIndex++) { - const struct EaMTest *pT = &pEaMTests[uIndex]; - /* Decode with GetNext */ - QCBORDecode_Init(&DCtx, pT->Input, 0); - - if(uIndex + 1 == 9) { - nExponent = 99; // just to set a break point - } + UsefulOutBuf UOB; - uError = QCBORDecode_GetNext(&DCtx, &Item); -#ifdef QCBOR_DISABLE_TAGS - /* Test 8 is a special case when tags are disabled */ - if(pT->bHasTags && uIndex + 1 != 8) { - if(uError != QCBOR_ERR_TAGS_DISABLED) { - return (int32_t)(1+uIndex) * 1000 + 9; - } - } else { -#endif - /* Now check return code, data type, mantissa and exponent */ - if(pT->uExpectedErrorGN != uError) { - return (int32_t)(1+uIndex) * 1000 + 1; - } - if(uError == QCBOR_SUCCESS && pT->uQCBORTypeGN != QCBOR_TYPE_ARRAY) { - if(pT->uQCBORTypeGN != Item.uDataType) { - return (int32_t)(1+uIndex) * 1000 + 2; - } - if(pT->nExponentGN != Item.val.expAndMantissa.nExponent) { - return (int32_t)(1+uIndex) * 1000 + 3; - } - if(Item.uDataType == QCBOR_TYPE_DECIMAL_FRACTION || Item.uDataType == QCBOR_TYPE_BIGFLOAT ) { - if(pT->nMantissaGN != Item.val.expAndMantissa.Mantissa.nInt) { - return (int32_t)(1+uIndex) * 1000 + 4; - } - } else { - if(UsefulBuf_Compare(Item.val.expAndMantissa.Mantissa.bigNum, pT->MantissaGN)) { - return (int32_t)(1+uIndex) * 1000 + 5; - } - } - } -#ifdef QCBOR_DISABLE_TAGS - } -#endif + UsefulOutBuf_Init(&UOB, Storage); + UsefulOutBuf_AppendByte(&UOB, 0x81); + UsefulOutBuf_AppendByte(&UOB, 0x5f); - /* Decode with GetDecimalFraction */ - QCBORDecode_Init(&DCtx, pT->Input, 0); - QCBORDecode_GetDecimalFraction(&DCtx, - pT->uTagRequirement, - &nMantissa, - &nExponent); - uError = QCBORDecode_GetAndResetError(&DCtx); -#ifdef QCBOR_DISABLE_TAGS - if(pT->bHasTags) { - if(uError != QCBOR_ERR_TAGS_DISABLED) { - return (int32_t)(1+uIndex) * 1000 + 39; - } - } else { -#endif - /* Now check return code, mantissa and exponent */ - if(pT->uExpectedErrorGDF != uError) { - return (int32_t)(1+uIndex) * 1000 + 31; - } - if(uError == QCBOR_SUCCESS) { - if(pT->nExponentGDF != nExponent) { - return (int32_t)(1+uIndex) * 1000 + 32; - } - if(pT->nMantissaGDF != nMantissa) { - return (int32_t)(1+uIndex) * 1000 + 33; - } - } -#ifdef QCBOR_DISABLE_TAGS + uint8_t uStringByte = 0; + // Use of type int is intentional + for(int uChunkSize = 1; uChunkSize <= 128; uChunkSize *= 2) { + // Not using preferred encoding here, but that is OK. + UsefulOutBuf_AppendByte(&UOB, 0x58); + UsefulOutBuf_AppendByte(&UOB, (uint8_t)uChunkSize); + for(int j = 0; j < uChunkSize; j++) { + UsefulOutBuf_AppendByte(&UOB, uStringByte); + uStringByte++; } -#endif + } + UsefulOutBuf_AppendByte(&UOB, 0xff); - /* Decode with GetDecimalFractionBig */ - QCBORDecode_Init(&DCtx, pT->Input, 0); - QCBORDecode_GetDecimalFractionBig(&DCtx, - pT->uTagRequirement, - MantissaBuf, - &Mantissa, - &bMantissaIsNegative, - &nExponent); - uError = QCBORDecode_GetAndResetError(&DCtx); -#ifdef QCBOR_DISABLE_TAGS - if(pT->bHasTags) { - if(uError != QCBOR_ERR_TAGS_DISABLED) { - return (int32_t)(1+uIndex) * 1000 + 49; - } - } else { -#endif - /* Now check return code, mantissa (bytes and sign) and exponent */ - if(pT->uExpectedErrorGDFB != uError) { - return (int32_t)(1+uIndex) * 1000 + 41; - } - if(uError == QCBOR_SUCCESS) { - if(pT->nExponentGDFB != nExponent) { - return (int32_t)(1+uIndex) * 1000 + 42; - } - if(pT->IsNegativeGDFB != bMantissaIsNegative) { - return (int32_t)(1+uIndex) * 1000 + 43; - } - if(UsefulBuf_Compare(Mantissa, pT->MantissaGDFB)) { - return (int32_t)(1+uIndex) * 1000 + 44; - } - } -#ifdef QCBOR_DISABLE_TAGS - } -#endif + return UsefulOutBuf_OutUBuf(&UOB); +} - /* Decode with GetBigFloat */ - QCBORDecode_Init(&DCtx, pT->Input, 0); - QCBORDecode_GetBigFloat(&DCtx, - pT->uTagRequirement, - &nMantissa, - &nExponent); - uError = QCBORDecode_GetAndResetError(&DCtx); -#ifdef QCBOR_DISABLE_TAGS - if(pT->bHasTags) { - if(uError != QCBOR_ERR_TAGS_DISABLED) { - return (int32_t)(1+uIndex) * 1000 + 19; - } - } else { -#endif - /* Now check return code, mantissa and exponent */ - if(pT->uExpectedErrorGBF != uError) { - return (int32_t)(1+uIndex) * 1000 + 11; - } - if(uError == QCBOR_SUCCESS) { - if(pT->nExponentGBF != nExponent) { - return (int32_t)(1+uIndex) * 1000 + 12; - } - if(pT->nMantissaGBF != nMantissa) { - return (int32_t)(1+uIndex) * 1000 + 13; - } - } -#ifdef QCBOR_DISABLE_TAGS - } -#endif +static int CheckBigString(UsefulBufC BigString) +{ + if(BigString.len != 255) { + return 1; + } - /* Decode with GetBigFloatBig */ - QCBORDecode_Init(&DCtx, pT->Input, 0); - QCBORDecode_GetBigFloatBig(&DCtx, - pT->uTagRequirement, - MantissaBuf, - &Mantissa, - &bMantissaIsNegative, - &nExponent); - uError = QCBORDecode_GetAndResetError(&DCtx); -#ifdef QCBOR_DISABLE_TAGS - if(pT->bHasTags) { - if(uError != QCBOR_ERR_TAGS_DISABLED) { - return (int32_t)(1+uIndex) * 1000 + 29; - } - } else { -#endif - /* Now check return code, mantissa (bytes and sign) and exponent */ - if(pT->uExpectedErrorGBFB != uError) { - return (int32_t)(1+uIndex) * 1000 + 21; - } - if(uError == QCBOR_SUCCESS) { - if(pT->nExponentGBFB != nExponent) { - return (int32_t)(1+uIndex) * 1000 + 22; - } - if(pT->IsNegativeGBFB != bMantissaIsNegative) { - return (int32_t)(1+uIndex) * 1000 + 23; - } - if(UsefulBuf_Compare(Mantissa, pT->MantissaGBFB)) { - return (int32_t)(1+uIndex) * 1000 + 24; - } - } -#ifdef QCBOR_DISABLE_TAGS + for(uint8_t i = 0; i < 255; i++){ + if(((const uint8_t *)BigString.ptr)[i] != i) { + return 1; } -#endif } - return 0; } -int32_t ExponentAndMantissaDecodeTestsSecondary(void) +int32_t IndefiniteLengthStringTest(void) { -#ifndef QCBOR_DISABLE_TAGS QCBORDecodeContext DC; - QCBORError uErr; - QCBORItem item; - - static const uint8_t spBigNumMantissa[] = {0x01, 0x02, 0x03, 0x04, 0x05, - 0x06, 0x07, 0x08, 0x09, 0x010}; - UsefulBufC BN = UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spBigNumMantissa); - - - - /* Now encode some stuff and then decode it */ - uint8_t pBuf[40]; - QCBOREncodeContext EC; - UsefulBufC Encoded; - - QCBOREncode_Init(&EC, UsefulBuf_FROM_BYTE_ARRAY(pBuf)); - QCBOREncode_OpenArray(&EC); - QCBOREncode_AddDecimalFraction(&EC, 999, 1000); // 999 * (10 ^ 1000) - QCBOREncode_AddBigFloat(&EC, 100, INT32_MIN); - QCBOREncode_AddDecimalFractionBigNum(&EC, BN, false, INT32_MAX); - QCBOREncode_CloseArray(&EC); - QCBOREncode_Finish(&EC, &Encoded); + QCBORItem Item; + // big enough for MakeIndefiniteBigBstr() + MemPool overhead + UsefulBuf_MAKE_STACK_UB(MemPool, 350); + // --- Simple normal indefinite length string ------ + UsefulBufC IndefLen = UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spIndefiniteLenString); + QCBORDecode_Init(&DC, IndefLen, QCBOR_DECODE_MODE_NORMAL); - QCBORDecode_Init(&DC, Encoded, QCBOR_DECODE_MODE_NORMAL); - uErr = QCBORDecode_GetNext(&DC, &item); - if(uErr != QCBOR_SUCCESS) { - return 100; + if(QCBORDecode_SetMemPool(&DC, MemPool, false)) { + return -1; } - uErr = QCBORDecode_GetNext(&DC, &item); - if(uErr != QCBOR_SUCCESS) { - return 101; + if(QCBORDecode_GetNext(&DC, &Item)) { + return -2; } - - if(item.uDataType != QCBOR_TYPE_DECIMAL_FRACTION || - item.val.expAndMantissa.nExponent != 1000 || - item.val.expAndMantissa.Mantissa.nInt != 999) { - return 102; + if(Item.uDataType != QCBOR_TYPE_ARRAY || Item.uDataAlloc) { + return -3; } - uErr = QCBORDecode_GetNext(&DC, &item); - if(uErr != QCBOR_SUCCESS) { - return 103; + if(QCBORDecode_GetNext(&DC, &Item)) { + return -4; } - - if(item.uDataType != QCBOR_TYPE_BIGFLOAT || - item.val.expAndMantissa.nExponent != INT32_MIN || - item.val.expAndMantissa.Mantissa.nInt != 100) { - return 104; + if(Item.uDataType != QCBOR_TYPE_TEXT_STRING || !Item.uDataAlloc) { + return -5; } - - uErr = QCBORDecode_GetNext(&DC, &item); - if(uErr != QCBOR_SUCCESS) { - return 105; + if(QCBORDecode_Finish(&DC)) { + return -6; } - if(item.uDataType != QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM || - item.val.expAndMantissa.nExponent != INT32_MAX || - UsefulBuf_Compare(item.val.expAndMantissa.Mantissa.bigNum, BN)) { - return 106; + // ----- types mismatch --- + QCBORDecode_Init(&DC, + UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spIndefiniteLenStringBad2), + QCBOR_DECODE_MODE_NORMAL); + + if(QCBORDecode_SetMemPool(&DC, MemPool, false)) { + return -7; } -#endif /* QCBOR_TAGS_DISABLED */ + if(QCBORDecode_GetNext(&DC, &Item)) { + return -8; + } + if(Item.uDataType != QCBOR_TYPE_ARRAY) { + return -9; + } - return 0; -} + if(QCBORDecode_GetNext(&DC, &Item) != QCBOR_ERR_INDEFINITE_STRING_CHUNK) { + return -10; + } + // ----- not a string --- + QCBORDecode_Init(&DC, + UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spIndefiniteLenStringBad3), + QCBOR_DECODE_MODE_NORMAL); -int32_t ExponentAndMantissaDecodeTests(void) -{ - int32_t rv = ProcessEaMTests(); - if(rv) { - return rv; + if(QCBORDecode_SetMemPool(&DC, MemPool, false)) { + return -11; } - return ExponentAndMantissaDecodeTestsSecondary(); -} + if(QCBORDecode_GetNext(&DC, &Item)) { + return -12; + } + if(Item.uDataType != QCBOR_TYPE_ARRAY) { + return -13; + } + if(QCBORDecode_GetNext(&DC, &Item) != QCBOR_ERR_INDEFINITE_STRING_CHUNK) { + return -14; + } -static const struct FailInput ExponentAndMantissaFailures[] = { - // Exponent > INT64_MAX - { {(uint8_t[]){0xC4, 0x82, 0x1B, 0x7f, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0x1B, 0x80, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF,}, 20}, QCBOR_ERR_BAD_EXP_AND_MANTISSA}, - // Mantissa > INT64_MAX - { {(uint8_t[]){0xC4, 0x82, 0x1B, 0x80, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xC3, 0x4A, 0x01, 0x02, 0x03, 0x04, 0x05, - 0x06, 0x07, 0x08, 0x09, 0x10}, 23}, QCBOR_ERR_BAD_EXP_AND_MANTISSA}, - // End of input - { {(uint8_t[]){0xC4, 0x82}, 2}, QCBOR_ERR_NO_MORE_ITEMS}, - // End of input - { {(uint8_t[]){0xC4, 0x82, 0x01}, 3}, QCBOR_ERR_NO_MORE_ITEMS}, - // bad content for big num - { {(uint8_t[]){0xC4, 0x82, 0x01, 0xc3, 0x01}, 5}, QCBOR_ERR_BAD_OPT_TAG}, - // bad content for big num - { {(uint8_t[]){0xC4, 0x82, 0xc2, 0x01, 0x1f}, 5}, QCBOR_ERR_BAD_INT}, - // Bad integer for exponent - { {(uint8_t[]){0xC4, 0x82, 0x01, 0x1f}, 4}, QCBOR_ERR_BAD_INT}, - // Bad integer for mantissa - { {(uint8_t[]){0xC4, 0x82, 0x1f, 0x01}, 4}, QCBOR_ERR_BAD_INT}, - // 3 items in array - { {(uint8_t[]){0xC4, 0x83, 0x03, 0x01, 02}, 5}, QCBOR_ERR_BAD_EXP_AND_MANTISSA}, -#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS - // unterminated indefinite length array - { {(uint8_t[]){0xC4, 0x9f, 0x03, 0x01, 0x02}, 5}, QCBOR_ERR_BAD_EXP_AND_MANTISSA}, -#else /* QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS */ - // unterminated indefinite length array - { {(uint8_t[]){0xC4, 0x9f, 0x03, 0x01, 0x02}, 5}, QCBOR_ERR_INDEF_LEN_ARRAYS_DISABLED}, -#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS */ - // Empty array - { {(uint8_t[]){0xC4, 0x80}, 2}, QCBOR_ERR_NO_MORE_ITEMS}, - // Second is not an integer - { {(uint8_t[]){0xC4, 0x82, 0x03, 0x40}, 4}, QCBOR_ERR_BAD_EXP_AND_MANTISSA}, - // First is not an integer - { {(uint8_t[]){0xC4, 0x82, 0x40}, 3}, QCBOR_ERR_BAD_EXP_AND_MANTISSA}, - // Not an array - { {(uint8_t[]){0xC4, 0xa2}, 2}, QCBOR_ERR_BAD_EXP_AND_MANTISSA} -}; + // ----- no end ----- + QCBORDecode_Init(&DC, + UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spIndefiniteLenStringBad4), + QCBOR_DECODE_MODE_NORMAL); + if(QCBORDecode_SetMemPool(&DC, MemPool, false)) { + return -15; + } -int32_t ExponentAndMantissaDecodeFailTests(void) -{ - return ProcessFailures(ExponentAndMantissaFailures, - C_ARRAY_COUNT(ExponentAndMantissaFailures, - struct FailInput)); -} + if(QCBORDecode_GetNext(&DC, &Item)) { + return -16; + } + if(Item.uDataType != QCBOR_TYPE_ARRAY) { + return -17; + } -#endif /* QCBOR_DISABLE_EXP_AND_MANTISSA */ + if(QCBORDecode_GetNext(&DC, &Item) != QCBOR_ERR_HIT_END) { + return -18; + } + // ------ Don't set a string allocator and see an error ----- + QCBORDecode_Init(&DC, IndefLen, QCBOR_DECODE_MODE_NORMAL); + QCBORDecode_GetNext(&DC, &Item); + if(Item.uDataType != QCBOR_TYPE_ARRAY) { + return -19; + } -/* - Some basic CBOR with map and array used in a lot of tests. - The map labels are all strings + if(QCBORDecode_GetNext(&DC, &Item) != QCBOR_ERR_NO_STRING_ALLOCATOR) { + return -20; + } - { - "first integer": 42, - "an array of two strings": [ - "string1", "string2" - ], - "map in a map": { - "bytes 1": h'78787878', - "bytes 2": h'79797979', - "another int": 98, - "text 2": "lies, damn lies and statistics" + // ----- Mempool is way too small ----- + UsefulBuf_MAKE_STACK_UB(MemPoolTooSmall, QCBOR_DECODE_MIN_MEM_POOL_SIZE-1); + + QCBORDecode_Init(&DC, IndefLen, QCBOR_DECODE_MODE_NORMAL); + if(!QCBORDecode_SetMemPool(&DC, MemPoolTooSmall, false)) { + return -21; } - } - */ -int32_t SpiffyDecodeBasicMap(UsefulBufC input) -{ - QCBORItem Item1, Item2, Item3; - int64_t nDecodedInt1, nDecodedInt2; - UsefulBufC B1, B2, S1, S2, S3; + // ----- Mempool is way too small ----- + UsefulBuf_MAKE_STACK_UB(BigIndefBStrStorage, 290); + const UsefulBufC BigIndefBStr = MakeIndefiniteBigBstr(BigIndefBStrStorage); - QCBORDecodeContext DCtx; - QCBORError nCBORError; + // 80 is big enough for MemPool overhead, but not BigIndefBStr + UsefulBuf_MAKE_STACK_UB(MemPoolSmall, 80); - QCBORDecode_Init(&DCtx, input, 0); + QCBORDecode_Init(&DC, BigIndefBStr, QCBOR_DECODE_MODE_NORMAL); + if(QCBORDecode_SetMemPool(&DC, MemPoolSmall, false)) { + return -22; + } - QCBORDecode_EnterMap(&DCtx, NULL); + QCBORDecode_GetNext(&DC, &Item); + if(Item.uDataType != QCBOR_TYPE_ARRAY) { + return -23; + } + if(QCBORDecode_GetNext(&DC, &Item) != QCBOR_ERR_STRING_ALLOCATE) { + return -24; + } - QCBORDecode_GetInt64InMapSZ(&DCtx, "first integer", &nDecodedInt1); + // ---- big bstr ----- + QCBORDecode_Init(&DC, BigIndefBStr, QCBOR_DECODE_MODE_NORMAL); - QCBORDecode_EnterMapFromMapSZ(&DCtx, "map in a map"); - QCBORDecode_GetInt64InMapSZ(&DCtx, "another int", &nDecodedInt2); - QCBORDecode_GetByteStringInMapSZ(&DCtx, "bytes 1", &B1); - QCBORDecode_GetByteStringInMapSZ(&DCtx, "bytes 2", &B2); - QCBORDecode_GetTextStringInMapSZ(&DCtx, "text 2", &S1); - QCBORDecode_ExitMap(&DCtx); + if(QCBORDecode_SetMemPool(&DC, MemPool, false)) { + return -25; + } - QCBORDecode_EnterArrayFromMapSZ(&DCtx, "an array of two strings"); - QCBORDecode_GetNext(&DCtx, &Item1); - QCBORDecode_GetNext(&DCtx, &Item2); - if(QCBORDecode_GetNext(&DCtx, &Item3) != QCBOR_ERR_NO_MORE_ITEMS) { - return -400; - } - QCBORDecode_ExitArray(&DCtx); + if(QCBORDecode_GetNext(&DC, &Item)) { + return -26; + } + if(Item.uDataType != QCBOR_TYPE_ARRAY || Item.uDataAlloc) { + return -26; + } - // Parse the same array again using GetText() instead of GetItem() - QCBORDecode_EnterArrayFromMapSZ(&DCtx, "an array of two strings"); - QCBORDecode_GetTextString(&DCtx, &S2); - QCBORDecode_GetTextString(&DCtx, &S3); - if(QCBORDecode_GetError(&DCtx) != QCBOR_SUCCESS) { - return 5000; - } - /* QCBORDecode_GetText(&DCtx, &S3); - if(QCBORDecode_GetAndResetError(&DCtx) != QCBOR_ERR_NO_MORE_ITEMS) { - return 5001; - } */ + if(QCBORDecode_GetNext(&DC, &Item)) { + return -27; + } + if(Item.uDataType != QCBOR_TYPE_BYTE_STRING || !Item.uDataAlloc || Item.uNestingLevel != 1) { + return -28; + } + if(CheckBigString(Item.val.string)) { + return -3; + } + if(QCBORDecode_Finish(&DC)) { + return -29; + } - QCBORDecode_ExitArray(&DCtx); +#ifndef QCBOR_DISABLE_NON_INTEGER_LABELS + // --- label is an indefinite length string ------ + QCBORDecode_Init(&DC, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spIndefiniteLenStringLabel), QCBOR_DECODE_MODE_NORMAL); - QCBORDecode_ExitMap(&DCtx); + if(QCBORDecode_SetMemPool(&DC, MemPool, false)) { + return -30; + } - nCBORError = QCBORDecode_Finish(&DCtx); + QCBORDecode_GetNext(&DC, &Item); + if(Item.uDataType != QCBOR_TYPE_MAP) { + return -31; + } - if(nCBORError) { - return (int32_t)nCBORError; - } + if(QCBORDecode_GetNext(&DC, &Item)){ + return -32; + } + if(Item.uLabelType != QCBOR_TYPE_TEXT_STRING || + Item.uDataType != QCBOR_TYPE_INT64 || + Item.uDataAlloc || !Item.uLabelAlloc || + UsefulBuf_Compare(Item.label.string, UsefulBuf_FromSZ("struuming"))) { + return -33; + } - if(nDecodedInt1 != 42) { - return 1001; - } + if(QCBORDecode_Finish(&DC)) { + return -34; + } +#endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */ - if(nDecodedInt2 != 98) { - return 1002; - } + return 0; +} - if(Item1.uDataType != QCBOR_TYPE_TEXT_STRING || - UsefulBufCompareToSZ(Item1.val.string, "string1")) { - return 1003; - } - if(Item1.uDataType != QCBOR_TYPE_TEXT_STRING || - UsefulBufCompareToSZ(Item2.val.string, "string2")) { - return 1004; - } +int32_t AllocAllStringsTest(void) +{ + QCBORDecodeContext DC; + QCBORError nCBORError; - if(UsefulBufCompareToSZ(S1, "lies, damn lies and statistics")) { - return 1005; - } - if(UsefulBuf_Compare(B1, UsefulBuf_FromSZ("xxxx"))){ - return 1006; - } + // First test, use the "CSRMap" as easy input and checking + QCBORDecode_Init(&DC, + UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spCSRInput), + QCBOR_DECODE_MODE_NORMAL); - if(UsefulBuf_Compare(B2, UsefulBuf_FromSZ("yyyy"))){ - return 1007; - } + UsefulBuf_MAKE_STACK_UB(Pool, sizeof(spCSRInput) + QCBOR_DECODE_MIN_MEM_POOL_SIZE); - if(UsefulBuf_Compare(S2, UsefulBuf_FromSZ("string1"))){ - return 1008; - } + nCBORError = QCBORDecode_SetMemPool(&DC, Pool, 1); // Turn on copying. + if(nCBORError) { + return -1; + } - if(UsefulBuf_Compare(S3, UsefulBuf_FromSZ("string2"))){ - return 1009; - } + if(CheckCSRMaps(&DC)) { + return -2; + } - return 0; -} +#ifndef QCBOR_DISABLE_NON_INTEGER_LABELS + // Next parse, save pointers to a few strings, destroy original and + // see all is OK. + UsefulBuf_MAKE_STACK_UB(CopyOfStorage, sizeof(pValidMapEncoded) + QCBOR_DECODE_MIN_MEM_POOL_SIZE); + const UsefulBufC CopyOf = UsefulBuf_Copy(CopyOfStorage, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(pValidMapEncoded)); -/* - { - -75008: h'05083399', - 88: [], - 100100: { - "sub1": { - 10: [ - 0 - ], - -75009: h'A46823990001', - 100100: { - "json": "{ \"ueid\", \"xyz\"}", - "subsub": { - 100002: h'141813191001' - } - } - } - } - } - */ - -static const uint8_t spNestedCBOR[] = { - 0xa3, 0x3a, 0x00, 0x01, 0x24, 0xff, 0x44, 0x05, - 0x08, 0x33, 0x99, 0x18, 0x58, 0x80, 0x1a, 0x00, - 0x01, 0x87, 0x04, 0xa1, 0x64, 0x73, 0x75, 0x62, - 0x31, 0xa3, 0x0a, 0x81, 0x00, 0x3a, 0x00, 0x01, - 0x25, 0x00, 0x46, 0xa4, 0x68, 0x23, 0x99, 0x00, - 0x01, 0x1a, 0x00, 0x01, 0x87, 0x04, 0xa2, 0x64, - 0x6a, 0x73, 0x6f, 0x6e, 0x70, 0x7b, 0x20, 0x22, - 0x75, 0x65, 0x69, 0x64, 0x22, 0x2c, 0x20, 0x22, - 0x78, 0x79, 0x7a, 0x22, 0x7d, 0x66, 0x73, 0x75, - 0x62, 0x73, 0x75, 0x62, 0xa1, 0x1a, 0x00, 0x01, - 0x86, 0xa2, 0x46, 0x14, 0x18, 0x13, 0x19, 0x10, - 0x01 -}; + QCBORDecode_Init(&DC, CopyOf, QCBOR_DECODE_MODE_NORMAL); + UsefulBuf_Set(Pool, '/'); + QCBORDecode_SetMemPool(&DC, Pool, 1); // Turn on copying. -/* Get item in multi-level nesting in spNestedCBOR */ -static int32_t DecodeNestedGetSubSub(QCBORDecodeContext *pDCtx) -{ - UsefulBufC String; + QCBORItem Item1, Item2, Item3, Item4; + if((nCBORError = QCBORDecode_GetNext(&DC, &Item1))) + return (int32_t)nCBORError; + if(Item1.uDataType != QCBOR_TYPE_MAP || + Item1.val.uCount != 3) + return -3; + if((nCBORError = QCBORDecode_GetNext(&DC, &Item1))) + return (int32_t)nCBORError; + if((nCBORError = QCBORDecode_GetNext(&DC, &Item2))) + return (int32_t)nCBORError; + if((nCBORError = QCBORDecode_GetNext(&DC, &Item3))) + return (int32_t)nCBORError; + if((nCBORError = QCBORDecode_GetNext(&DC, &Item4))) + return (int32_t)nCBORError; - uint8_t test_oemid_bytes[] = {0x14, 0x18, 0x13, 0x19, 0x10, 0x01}; - const struct q_useful_buf_c test_oemid = UsefulBuf_FROM_BYTE_ARRAY_LITERAL(test_oemid_bytes); + UsefulBuf_Set(CopyOfStorage, '_'); - QCBORDecode_EnterMapFromMapN(pDCtx, 100100); - QCBORDecode_EnterMap(pDCtx, NULL); - QCBORDecode_EnterMapFromMapN(pDCtx, 100100); - QCBORDecode_EnterMapFromMapSZ(pDCtx, "subsub"); - QCBORDecode_GetByteStringInMapN(pDCtx, 100002, &String); - if(QCBORDecode_GetError(pDCtx)) { - return 4001; - } - if(UsefulBuf_Compare(String, test_oemid)) { - return 4002; + if(Item1.uLabelType != QCBOR_TYPE_TEXT_STRING || + Item1.uDataType != QCBOR_TYPE_INT64 || + Item1.val.int64 != 42 || + Item1.uDataAlloc != 0 || + Item1.uLabelAlloc == 0 || + UsefulBufCompareToSZ(Item1.label.string, "first integer") || + Item1.label.string.ptr < Pool.ptr || + Item1.label.string.ptr > (const void *)((const uint8_t *)Pool.ptr + Pool.len)) { + return -4; } - QCBORDecode_ExitMap(pDCtx); - QCBORDecode_ExitMap(pDCtx); - QCBORDecode_ExitMap(pDCtx); - QCBORDecode_ExitMap(pDCtx); - return 0; -} -/* Iterations on the zero-length array in spNestedCBOR */ -static int32_t DecodeNestedGetEmpty(QCBORDecodeContext *pDCtx) -{ - QCBORItem Item; - QCBORError uErr; + if(Item2.uLabelType != QCBOR_TYPE_TEXT_STRING || + UsefulBufCompareToSZ(Item2.label.string, "an array of two strings") || + Item2.uDataType != QCBOR_TYPE_ARRAY || + Item2.uDataAlloc != 0 || + Item2.uLabelAlloc == 0 || + Item2.val.uCount != 2) + return -5; - QCBORDecode_EnterArrayFromMapN(pDCtx, 88); - for(int x = 0; x < 20; x++) { - uErr = QCBORDecode_GetNext(pDCtx, &Item); - if(uErr != QCBOR_ERR_NO_MORE_ITEMS) { - return 4100; + if(Item3.uDataType != QCBOR_TYPE_TEXT_STRING || + Item3.uDataAlloc == 0 || + Item3.uLabelAlloc != 0 || + UsefulBufCompareToSZ(Item3.val.string, "string1")) { + return -6; + } + + if(Item4.uDataType != QCBOR_TYPE_TEXT_STRING || + Item4.uDataAlloc == 0 || + Item4.uLabelAlloc != 0 || + UsefulBufCompareToSZ(Item4.val.string, "string2")) { + return -7; + } + // Next parse with a pool that is too small + UsefulBuf_MAKE_STACK_UB(SmallPool, QCBOR_DECODE_MIN_MEM_POOL_SIZE + 1); + QCBORDecode_Init(&DC, + UsefulBuf_FROM_BYTE_ARRAY_LITERAL(pValidMapEncoded), + QCBOR_DECODE_MODE_NORMAL); + QCBORDecode_SetMemPool(&DC, SmallPool, 1); // Turn on copying. + if((nCBORError = QCBORDecode_GetNext(&DC, &Item1))) + return -8; + if(Item1.uDataType != QCBOR_TYPE_MAP || + Item1.val.uCount != 3) { + return -9; + } + if(!(nCBORError = QCBORDecode_GetNext(&DC, &Item1))){ + if(!(nCBORError = QCBORDecode_GetNext(&DC, &Item2))) { + if(!(nCBORError = QCBORDecode_GetNext(&DC, &Item3))) { + nCBORError = QCBORDecode_GetNext(&DC, &Item4); + } } } - QCBORDecode_ExitArray(pDCtx); - if(QCBORDecode_GetError(pDCtx)) { - return 4101; + if(nCBORError != QCBOR_ERR_STRING_ALLOCATE) { + return -10; } +#endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */ return 0; } -/* Various iterations on the array that contains a zero in spNestedCBOR */ -static int32_t DecodeNestedGetZero(QCBORDecodeContext *pDCtx) + +int32_t MemPoolTest(void) { - QCBORError uErr; + // Set up the decoder with a tiny bit of CBOR to parse because + // nothing can be done with it unless that is set up. + QCBORDecodeContext DC; + const uint8_t pMinimalCBOR[] = {0xa0}; // One empty map + QCBORDecode_Init(&DC, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(pMinimalCBOR),0); - QCBORDecode_EnterMapFromMapN(pDCtx, 100100); - QCBORDecode_EnterMapFromMapSZ(pDCtx, "sub1"); - QCBORDecode_EnterArrayFromMapN(pDCtx, 10); - int64_t nInt = 99; - QCBORDecode_GetInt64(pDCtx, &nInt); - if(nInt != 0) { - return 4200; + // Set up an memory pool of 100 bytes + // Then fish into the internals of the decode context + // to get the allocator function so it can be called directly. + // Also figure out how much pool is available for use + // buy subtracting out the overhead. + UsefulBuf_MAKE_STACK_UB(Pool, 100); + QCBORError nError = QCBORDecode_SetMemPool(&DC, Pool, 0); + if(nError) { + return -9; } - for(int x = 0; x < 20; x++) { - QCBORItem Item; - uErr = QCBORDecode_GetNext(pDCtx, &Item); - if(uErr != QCBOR_ERR_NO_MORE_ITEMS) { - return 4201; + QCBORStringAllocate pAlloc = DC.StringAllocator.pfAllocator; + void *pAllocCtx = DC.StringAllocator.pAllocateCxt; + size_t uAvailPool = Pool.len - QCBOR_DECODE_MIN_MEM_POOL_SIZE; - } + // First test -- ask for one more byte than available and see failure + UsefulBuf Allocated = (*pAlloc)(pAllocCtx, NULL, uAvailPool+1); + if(!UsefulBuf_IsNULL(Allocated)) { + return -1; } - QCBORDecode_ExitArray(pDCtx); - if(QCBORDecode_GetAndResetError(pDCtx)) { - return 4202; + + // Re do the set up for the next test that will do a successful alloc, + // a fail, a free and then success + QCBORDecode_SetMemPool(&DC, Pool, 0); + pAlloc = DC.StringAllocator.pfAllocator; + pAllocCtx = DC.StringAllocator.pAllocateCxt; + uAvailPool = Pool.len - QCBOR_DECODE_MIN_MEM_POOL_SIZE; + + // Allocate one byte less than available and see success + Allocated = (pAlloc)(pAllocCtx, NULL, uAvailPool-1); + if(UsefulBuf_IsNULL(Allocated)) { // expected to succeed + return -2; } - QCBORDecode_EnterArrayFromMapN(pDCtx, 10); - UsefulBufC dD; - QCBORDecode_GetByteString(pDCtx, &dD); - if(QCBORDecode_GetAndResetError(pDCtx) != QCBOR_ERR_UNEXPECTED_TYPE) { - return 4203; + // Ask for some more and see failure + UsefulBuf Allocated2 = (*pAlloc)(pAllocCtx, NULL, uAvailPool/2); + if(!UsefulBuf_IsNULL(Allocated2)) { // expected to fail + return -3; } - for(int x = 0; x < 20; x++) { - QCBORDecode_GetByteString(pDCtx, &dD); - uErr = QCBORDecode_GetAndResetError(pDCtx); - if(uErr != QCBOR_ERR_NO_MORE_ITEMS) { - return 4204; - } + // Free the first allocate, retry the second and see success + (*pAlloc)(pAllocCtx, Allocated.ptr, 0); // Free + Allocated = (*pAlloc)(pAllocCtx, NULL, uAvailPool/2); + if(UsefulBuf_IsNULL(Allocated)) { // succeed because of the free + return -4; + } + + // Re do set up for next test that involves a successful alloc, + // and a successful realloc and a failed realloc + QCBORDecode_SetMemPool(&DC, Pool, 0); + pAlloc = DC.StringAllocator.pfAllocator; + pAllocCtx = DC.StringAllocator.pAllocateCxt; + + // Allocate half the pool and see success + Allocated = (*pAlloc)(pAllocCtx, NULL, uAvailPool/2); + if(UsefulBuf_IsNULL(Allocated)) { // expected to succeed + return -5; + } + // Reallocate to take up the whole pool and see success + Allocated2 = (*pAlloc)(pAllocCtx, Allocated.ptr, uAvailPool); + if(UsefulBuf_IsNULL(Allocated2)) { + return -6; + } + // Make sure its the same pointer and the size is right + if(Allocated2.ptr != Allocated.ptr || Allocated2.len != uAvailPool) { + return -7; + } + // Try to allocate more to be sure there is failure after a realloc + UsefulBuf Allocated3 = (*pAlloc)(pAllocCtx, Allocated.ptr, uAvailPool+1); + if(!UsefulBuf_IsNULL(Allocated3)) { + return -8; } - QCBORDecode_ExitArray(pDCtx); - QCBORDecode_ExitMap(pDCtx); - QCBORDecode_ExitMap(pDCtx); return 0; } -/* Repeatedly enter and exit maps and arrays, go off the end of maps - and arrays and such. */ -static int32_t DecodeNestedIterate(void) + +/* Just enough of an allocator to test configuration of one */ +static UsefulBuf AllocateTestFunction(void *pCtx, void *pOldMem, size_t uNewSize) { - QCBORDecodeContext DCtx; - int32_t nReturn; - QCBORError uErr; + (void)pOldMem; // unused variable - QCBORDecode_Init(&DCtx, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spNestedCBOR), 0); - QCBORDecode_EnterMap(&DCtx, NULL); + if(uNewSize) { + // Assumes the context pointer is the buffer and + // nothing too big will ever be asked for. + // This is only good for this basic test! + return (UsefulBuf) {pCtx, uNewSize}; + } else { + return NULLUsefulBuf; + } +} - for(int j = 0; j < 5; j++) { - for(int i = 0; i < 20; i++) { - nReturn = DecodeNestedGetSubSub(&DCtx); - if(nReturn) { - return nReturn; - } - } - for(int i = 0; i < 20; i++) { - nReturn = DecodeNestedGetEmpty(&DCtx); - if(nReturn ) { - return nReturn; - } - } +int32_t SetUpAllocatorTest(void) +{ + // Set up the decoder with a tiny bit of CBOR to parse because + // nothing can be done with it unless that is set up. + QCBORDecodeContext DC; + const uint8_t pMinimalCBOR[] = {0x62, 0x48, 0x69}; // "Hi" + QCBORDecode_Init(&DC, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(pMinimalCBOR),0); - for(int i = 0; i < 20; i++) { - nReturn = DecodeNestedGetZero(&DCtx); - if(nReturn ) { - return nReturn; - } - } + uint8_t pAllocatorBuffer[50]; + + // This is really just to test that this call works. + // The full functionality of string allocators is tested + // elsewhere with the MemPool internal allocator. + QCBORDecode_SetUpAllocator(&DC, AllocateTestFunction, pAllocatorBuffer, 1); + + QCBORItem Item; + if(QCBORDecode_GetNext(&DC, &Item) != QCBOR_SUCCESS) { + return -1; } - QCBORDecode_ExitMap(&DCtx); - uErr = QCBORDecode_Finish(&DCtx); - if(uErr) { - return (int32_t)uErr + 4100; + if(Item.uDataAlloc == 0 || + Item.uDataType != QCBOR_TYPE_TEXT_STRING || + Item.val.string.ptr != pAllocatorBuffer) { + return -2; + } + + if(QCBORDecode_Finish(&DC) != QCBOR_SUCCESS) { + return -3; } return 0; } +#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS */ -/* - [ - 23, - 6000, - h'67616C6163746963', - h'686176656E20746F6B656E' - ] - */ -static const uint8_t spSimpleArray[] = { - 0x84, - 0x17, - 0x19, 0x17, 0x70, - 0x48, 0x67, 0x61, 0x6C, 0x61, 0x63, 0x74, 0x69, 0x63, - 0x4B, 0x68, 0x61, 0x76, 0x65, 0x6E, 0x20, 0x74, 0x6F, 0x6B, 0x65, 0x6E}; +#ifndef QCBOR_DISABLE_EXP_AND_MANTISSA -/* [h'', {}, [], 0] */ -static const uint8_t spArrayOfEmpty[] = {0x84, 0x40, 0xa0, 0x80, 0x00}; +struct EaMTest { + const char *szName; + UsefulBufC Input; + uint8_t uTagRequirement; + bool bHasTags; -/* {} */ -static const uint8_t spEmptyMap[] = {0xa0}; + /* Expected values for GetNext */ + QCBORError uExpectedErrorGN; + uint8_t uQCBORTypeGN; + int64_t nExponentGN; + int64_t nMantissaGN; + UsefulBufC MantissaGN; -#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS -/* {} */ -static const uint8_t spEmptyInDefinteLengthMap[] = {0xbf, 0xff}; + /* Expected values for GetDecimalFraction */ + QCBORError uExpectedErrorGDF; + int64_t nExponentGDF; + int64_t nMantissaGDF; + /* Expected values for GetDecimalFractionBig */ + QCBORError uExpectedErrorGDFB; + int64_t nExponentGDFB; + UsefulBufC MantissaGDFB; + bool IsNegativeGDFB; -/* - { - 0: [], - 9: [ - [], - [] - ], - 8: { - 1: [], - 2: {}, - 3: [] - }, - 4: {}, - 5: [], - 6: [ - [], - [] - ] - } - */ -static const uint8_t spMapOfEmpty[] = { - 0xa6, 0x00, 0x80, 0x09, 0x82, 0x80, 0x80, 0x08, - 0xa3, 0x01, 0x80, 0x02, 0xa0, 0x03, 0x80, 0x04, - 0xa0, 0x05, 0x9f, 0xff, 0x06, 0x9f, 0x80, 0x9f, - 0xff, 0xff}; + /* Expected values for GetBigFloat */ + QCBORError uExpectedErrorGBF; + int64_t nExponentGBF; + int64_t nMantissaGBF; -#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS */ + /* Expected values for GetBigFloatBig */ + QCBORError uExpectedErrorGBFB; + int64_t nExponentGBFB; + UsefulBufC MantissaGBFB; + bool IsNegativeGBFB; +}; -/* - Too many tags - Duplicate label - Integer overflow - Date overflow +static const struct EaMTest pEaMTests[] = { { - 1: 224(225(226(227(4(0))))), - 3: -18446744073709551616, - 4: 1(1.0e+300), - 5: 0, - 8: 8 - } - */ -static const uint8_t spRecoverableMapErrors[] = { -#ifndef QCBOR_DISABLE_TAGS - 0xa6, - 0x04, 0xc1, 0xfb, 0x7e, 0x37, 0xe4, 0x3c, 0x88, 0x00, 0x75, 0x9c, - 0x01, 0xd8, 0xe0, 0xd8, 0xe1, 0xd8, 0xe2, 0xd8, 0xe3, 0xd8, 0x04, 0x00, -#else - 0xa4, -#endif - 0x03, 0x3b, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0x05, 0x00, - 0x05, 0x00, - 0x08, 0x08, -}; - -/* Bad break */ -static const uint8_t spUnRecoverableMapError1[] = { - 0xa2, 0xff, 0x01, 0x00, 0x02, 0x00 -}; + "1. Untagged pair (big float or decimal fraction), no tag required", + {(const uint8_t []){0x82, 0x20, 0x03}, 3}, + QCBOR_TAG_REQUIREMENT_NOT_A_TAG, + false, -#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS -/* No more items */ -static const uint8_t spUnRecoverableMapError2[] = { - 0xbf, 0x02, 0xbf, 0xff, 0x01, 0x00, 0x02, 0x00 -}; + QCBOR_SUCCESS, /* for GetNext */ + QCBOR_TYPE_ARRAY, + 0, + 0, + {(const uint8_t []){0x00}, 1}, -/* Hit end because string is too long */ -static const uint8_t spUnRecoverableMapError3[] = { - 0xbf, 0x02, 0x69, 0x64, 0x64, 0xff -}; + QCBOR_SUCCESS, /* GetDecimalFraction */ + -1, + 3, -/* Hit end because string is too long */ -static const uint8_t spUnRecoverableMapError4[] = { - 0xbf, - 0x02, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, - 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff -}; -#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS */ + QCBOR_SUCCESS, /* for GetDecimalFractionBig */ + -1, + {(const uint8_t []){0x02}, 1}, + false, -const unsigned char not_well_formed_submod_section[] = { - 0xa1, 0x14, 0x1f, -}; + QCBOR_SUCCESS, /* for GetBigFloat */ + -1, + 3, + QCBOR_SUCCESS, /* for GetBigFloatBig */ + -1, + {(const uint8_t []){0x02}, 1}, + false + }, -/* Array of length 3, but only two items. */ -const unsigned char spBadConsumeInput[] = { - 0x83, 0x00, 0x00 -}; + { + "2. Untagged pair (big float or decimal fraction), tag required", + {(const uint8_t []){0x82, 0x20, 0x03}, 3}, + QCBOR_TAG_REQUIREMENT_TAG, + false, -/* Tag nesting too deep. */ -const unsigned char spBadConsumeInput2[] = { - 0x81, - 0xD8, 0x37, - 0xD8, 0x2C, - 0xD8, 0x21, - 0xD6, - 0xCB, - 00 -}; + QCBOR_SUCCESS, /* for GetNext */ + QCBOR_TYPE_ARRAY, + 0, + 0, + {(const uint8_t []){0x00}, 1}, -const unsigned char spBadConsumeInput3[] = { - 0x81, 0xc0, 0x81, 0x00 -}; + QCBOR_ERR_UNEXPECTED_TYPE, /* for GetDecimalFraction */ + 0, + 0, -const unsigned char spBadConsumeInput4[] = { - 0x81, 0x9f, 0x00, 0xff -}; + QCBOR_ERR_UNEXPECTED_TYPE, /* for GetDecimalFractionBig */ + 0, + {(const uint8_t []){0x00}, 1}, + false, -const unsigned char spBadConsumeInput5[] = { - 0xa1, 0x80, 0x00 -}; + QCBOR_ERR_UNEXPECTED_TYPE, /* for GetBigFloat */ + 0, + 0, + QCBOR_ERR_UNEXPECTED_TYPE, /* for GetBigFloatBig */ + 0, + {(const uint8_t []){0x00}, 1}, + false + }, -int32_t EnterMapTest(void) -{ - QCBORItem Item1; - QCBORItem ArrayItem; - QCBORDecodeContext DCtx; - int32_t nReturn; - QCBORError uErr; + { + "3. Tagged 1.5 decimal fraction, tag 4 optional", + {(const uint8_t []){0xC4, 0x82, 0x20, 0x03}, 4}, + QCBOR_TAG_REQUIREMENT_OPTIONAL_TAG, + true, -#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS - QCBORDecode_Init(&DCtx, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spMapOfEmpty), 0); - QCBORDecode_EnterMap(&DCtx, NULL); + QCBOR_SUCCESS, /* for GetNext */ + QCBOR_TYPE_DECIMAL_FRACTION, + -1, + 3, + {(const uint8_t []){0x00}, 1}, - QCBORDecode_EnterArray(&DCtx, NULL); // Label 0 - QCBORDecode_ExitArray(&DCtx); + QCBOR_SUCCESS, /* for GetDecimalFraction */ + -1, + 3, - QCBORDecode_EnterArray(&DCtx, NULL); // Label 9 - QCBORDecode_EnterArray(&DCtx, NULL); - QCBORDecode_ExitArray(&DCtx); - QCBORDecode_EnterArray(&DCtx, NULL); - QCBORDecode_ExitArray(&DCtx); - QCBORDecode_ExitArray(&DCtx); + QCBOR_SUCCESS, /* for GetDecimalFractionBig */ + -1, + {(const uint8_t []){0x02}, 1}, + false, - QCBORDecode_EnterMap(&DCtx, NULL); // Label 8 - QCBORDecode_EnterArray(&DCtx, NULL); - QCBORDecode_ExitArray(&DCtx); - QCBORDecode_EnterMap(&DCtx, NULL); - QCBORDecode_ExitMap(&DCtx); - QCBORDecode_EnterArray(&DCtx, NULL); - QCBORDecode_ExitArray(&DCtx); - QCBORDecode_ExitMap(&DCtx); + QCBOR_ERR_UNEXPECTED_TYPE, /* for GetBigFloat */ + 0, + 0, - QCBORDecode_EnterMap(&DCtx, NULL); // Label4 - QCBORDecode_ExitMap(&DCtx); + QCBOR_ERR_UNEXPECTED_TYPE, /* for GetBigFloatBig */ + 0, + {(const uint8_t []){0x00}, 1}, + false + }, + { + "4. Tagged 100 * 2^300 big float, tag 5 optional", + {(const uint8_t []){0xC5, 0x82, 0x19, 0x01, 0x2C, 0x18, 0x64}, 7}, + QCBOR_TAG_REQUIREMENT_OPTIONAL_TAG, + true, - QCBORDecode_EnterArray(&DCtx, NULL); // Label 5 - QCBORDecode_ExitArray(&DCtx); + QCBOR_SUCCESS, /* for GetNext */ + QCBOR_TYPE_BIGFLOAT, + 300, + 100, + {(const uint8_t []){0x00}, 1}, - QCBORDecode_EnterArray(&DCtx, NULL); // Label 6 - QCBORDecode_EnterArray(&DCtx, NULL); - QCBORDecode_ExitArray(&DCtx); - QCBORDecode_EnterArray(&DCtx, NULL); - QCBORDecode_ExitArray(&DCtx); - QCBORDecode_ExitArray(&DCtx); - QCBORDecode_ExitMap(&DCtx); + QCBOR_ERR_UNEXPECTED_TYPE, /* for GetDecimalFraction */ + 0, + 0, - uErr = QCBORDecode_Finish(&DCtx); - if(uErr != QCBOR_SUCCESS){ - return 3011; - } + QCBOR_ERR_UNEXPECTED_TYPE, /* for GetDecimalFractionBig */ + 0, + {(const uint8_t []){0x02}, 1}, + false, - (void)pValidMapIndefEncoded; - nReturn = SpiffyDecodeBasicMap(UsefulBuf_FROM_BYTE_ARRAY_LITERAL(pValidMapIndefEncoded)); - if(nReturn) { - return nReturn + 20000; - } -#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS */ + QCBOR_SUCCESS, /* for GetBigFloat */ + 300, + 100, + QCBOR_SUCCESS, /* for GetBigFloatBig */ + 300, + {(const uint8_t []){0x63}, 1}, + false + }, - nReturn = SpiffyDecodeBasicMap(UsefulBuf_FROM_BYTE_ARRAY_LITERAL(pValidMapEncoded)); - if(nReturn) { - return nReturn; - } + { + "5. Tagged 4([-20, 4759477275222530853136]) decimal fraction, tag 4 required", + {(const uint8_t []){0xC4, 0x82, 0x33, + 0xC2, 0x4A, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x10,}, 15}, + QCBOR_TAG_REQUIREMENT_TAG, + true, + QCBOR_SUCCESS, /* for GetNext */ + QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM, + -20, + 0, + {(const uint8_t []){0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x10}, 10}, + QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW, /* for GetDecimalFraction */ + 0, + 0, - // These tests confirm the cursor is at the right place after entering - // a map or array - const UsefulBufC ValidEncodedMap = UsefulBuf_FROM_BYTE_ARRAY_LITERAL(pValidMapEncoded); + QCBOR_SUCCESS, /* for GetDecimalFractionBig */ + -20, + {(const uint8_t []){0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x10}, 10}, + false, - // Confirm cursor is at right place - QCBORDecode_Init(&DCtx, ValidEncodedMap, 0); - QCBORDecode_EnterMap(&DCtx, NULL); - QCBORDecode_GetNext(&DCtx, &Item1); - if(Item1.uDataType != QCBOR_TYPE_INT64) { - return 2001; - } + QCBOR_ERR_UNEXPECTED_TYPE, /* for GetBigFloat */ + 0, + 0, + QCBOR_ERR_UNEXPECTED_TYPE, /* for GetBigFloatBig */ + 0, + {(const uint8_t []){0x00}, 0}, + false + }, - QCBORDecode_Init(&DCtx, ValidEncodedMap, 0); - QCBORDecode_VGetNext(&DCtx, &Item1); - QCBORDecode_VGetNext(&DCtx, &Item1); - QCBORDecode_EnterArray(&DCtx, &ArrayItem); - if(ArrayItem.uLabelType != QCBOR_TYPE_TEXT_STRING || - UsefulBuf_Compare(ArrayItem.label.string, - UsefulBuf_FROM_SZ_LITERAL("an array of two strings"))) { - return 2051; - } - QCBORDecode_GetNext(&DCtx, &Item1); - if(Item1.uDataType != QCBOR_TYPE_TEXT_STRING) { - return 2002; - } - QCBORDecode_ExitArray(&DCtx); - QCBORDecode_EnterMap(&DCtx, &ArrayItem); - if(ArrayItem.uLabelType != QCBOR_TYPE_TEXT_STRING || - UsefulBuf_Compare(ArrayItem.label.string, - UsefulBuf_FROM_SZ_LITERAL("map in a map"))) { - return 2052; - } + { + "6. Error: Mantissa and exponent inside a Mantissa and exponent", + {(const uint8_t []){0xC4, 0x82, 0x33, + 0xC5, 0x82, 0x19, 0x01, 0x2C, 0x18, 0x64}, 10}, + QCBOR_TAG_REQUIREMENT_TAG, + true, + QCBOR_ERR_BAD_EXP_AND_MANTISSA, /* for GetNext */ + QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM, + 0, + 0, + {(const uint8_t []){0x00}, 0}, - QCBORDecode_Init(&DCtx, ValidEncodedMap, 0); - QCBORDecode_EnterMap(&DCtx, NULL); - QCBORDecode_GetNext(&DCtx, &Item1); - QCBORDecode_GetNext(&DCtx, &Item1); - QCBORDecode_GetNext(&DCtx, &Item1); - QCBORDecode_EnterMapFromMapSZ(&DCtx, "map in a map"); - QCBORDecode_GetNext(&DCtx, &Item1); - if(Item1.uDataType != QCBOR_TYPE_BYTE_STRING) { - return 2003; - } + QCBOR_ERR_BAD_EXP_AND_MANTISSA, /* for GetDecimalFraction */ + 0, + 0, - QCBORDecode_Init(&DCtx, ValidEncodedMap, 0); - QCBORDecode_EnterMap(&DCtx, NULL); - QCBORDecode_GetNext(&DCtx, &Item1); - QCBORDecode_GetNext(&DCtx, &Item1); - QCBORDecode_GetNext(&DCtx, &Item1); - QCBORDecode_GetNext(&DCtx, &Item1); - QCBORDecode_GetNext(&DCtx, &Item1); - QCBORDecode_GetNext(&DCtx, &Item1); - QCBORDecode_GetNext(&DCtx, &Item1); - QCBORDecode_EnterArrayFromMapSZ(&DCtx, "an array of two strings"); - QCBORDecode_GetNext(&DCtx, &Item1); - if(Item1.uDataType != QCBOR_TYPE_TEXT_STRING) { - return 2004; - } + QCBOR_ERR_BAD_EXP_AND_MANTISSA, /* for GetDecimalFractionBig */ + 0, + {(const uint8_t []){0x00}, 0}, + false, - QCBORDecode_Init(&DCtx, ValidEncodedMap, 0); - QCBORDecode_EnterMap(&DCtx, NULL); - QCBORDecode_EnterArrayFromMapSZ(&DCtx, "an array of two strings"); - QCBORDecode_ExitArray(&DCtx); - QCBORDecode_GetNext(&DCtx, &Item1); - if(Item1.uDataType != QCBOR_TYPE_MAP && Item1.uLabelAlloc != QCBOR_TYPE_TEXT_STRING) { - return 2006; - } - QCBORDecode_ExitMap(&DCtx); - if(QCBORDecode_GetNext(&DCtx, &Item1) != QCBOR_ERR_NO_MORE_ITEMS) { - return 2007; - } + QCBOR_ERR_BAD_EXP_AND_MANTISSA, /* for GetBigFloat */ + 0, + 0, - QCBORDecode_Init(&DCtx, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spSimpleArray), 0); - QCBORDecode_EnterArray(&DCtx, NULL); - int64_t nDecodedInt2; - QCBORDecode_GetInt64InMapSZ(&DCtx, "another int", &nDecodedInt2); - uErr = QCBORDecode_GetAndResetError(&DCtx); - if(uErr != QCBOR_ERR_MAP_NOT_ENTERED){ - return 2008; - } - UsefulBufC String; - QCBORDecode_GetTextStringInMapN(&DCtx, 88, &String); - if(uErr != QCBOR_ERR_MAP_NOT_ENTERED){ - return 2009; - } + QCBOR_ERR_BAD_EXP_AND_MANTISSA, /* for GetBigFloatBig */ + 0, + {(const uint8_t []){0x00}, 0}, + false + }, + { + "7. Tagged 5([-20, 4294967295]) big float, big num mantissa, tag 5 required", + {(const uint8_t []){0xC5, 0x82, 0x33, + 0xC2, 0x44, 0xff, 0xff, 0xff, 0xff}, 9}, + QCBOR_TAG_REQUIREMENT_TAG, + true, + QCBOR_SUCCESS, /* for GetNext */ + QCBOR_TYPE_BIGFLOAT_POS_BIGNUM, + -20, + 0, + {(const uint8_t []){0xff, 0xff, 0xff, 0xff}, 4}, - QCBORDecode_Init(&DCtx, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spEmptyMap), 0); - QCBORDecode_EnterMap(&DCtx, NULL); - // This will fail because the map is empty. - QCBORDecode_GetInt64InMapSZ(&DCtx, "another int", &nDecodedInt2); - uErr = QCBORDecode_GetAndResetError(&DCtx); - if(uErr != QCBOR_ERR_LABEL_NOT_FOUND){ - return 2010; - } - QCBORDecode_ExitMap(&DCtx); - uErr = QCBORDecode_Finish(&DCtx); - if(uErr != QCBOR_SUCCESS){ - return 2011; - } + QCBOR_ERR_UNEXPECTED_TYPE, /* for GetDecimalFraction */ + 0, + 0, + QCBOR_ERR_UNEXPECTED_TYPE, /* for GetDecimalFractionBig */ + -20, + {(const uint8_t []){0x00}, 1}, + false, -#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS - QCBORDecode_Init(&DCtx, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spEmptyInDefinteLengthMap), 0); - QCBORDecode_EnterMap(&DCtx, NULL); - // This will fail because the map is empty. - QCBORDecode_GetInt64InMapSZ(&DCtx, "another int", &nDecodedInt2); - uErr = QCBORDecode_GetAndResetError(&DCtx); - if(uErr != QCBOR_ERR_LABEL_NOT_FOUND){ - return 2012; - } - QCBORDecode_ExitMap(&DCtx); - uErr = QCBORDecode_Finish(&DCtx); - if(uErr != QCBOR_SUCCESS){ - return 2013; - } -#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS */ - - - QCBORDecode_Init(&DCtx, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spArrayOfEmpty), 0); - QCBORDecode_EnterArray(&DCtx, NULL); - QCBORDecode_GetByteString(&DCtx, &String); - QCBORDecode_EnterMap(&DCtx, NULL); - QCBORDecode_ExitMap(&DCtx); - QCBORDecode_EnterArray(&DCtx, NULL); - QCBORDecode_ExitArray(&DCtx); - QCBORDecode_GetInt64(&DCtx, &nDecodedInt2); - QCBORDecode_ExitArray(&DCtx); - uErr = QCBORDecode_Finish(&DCtx); - if(uErr != QCBOR_SUCCESS) { - return 2014; - } - - int64_t nInt; - QCBORDecode_Init(&DCtx, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spRecoverableMapErrors), 0); - QCBORDecode_EnterMap(&DCtx, NULL); -#ifndef QCBOR_DISABLE_TAGS - QCBORDecode_GetInt64InMapN(&DCtx, 0x01, &nInt); - uErr = QCBORDecode_GetError(&DCtx); - if(uErr != QCBOR_ERR_TOO_MANY_TAGS) { - return 2021; - } - if(QCBORDecode_GetNthTagOfLast(&DCtx, 0) != CBOR_TAG_INVALID64) { - return 2121; - } - (void)QCBORDecode_GetAndResetError(&DCtx); -#endif - + QCBOR_SUCCESS, /* for GetBigFloat */ + -20, + 4294967295, - QCBORDecode_GetInt64InMapN(&DCtx, 0x03, &nInt); - uErr = QCBORDecode_GetAndResetError(&DCtx); - if(uErr != QCBOR_ERR_INT_OVERFLOW) { - return 2023; - } + QCBOR_SUCCESS, /* for GetBigFloatBig */ + -20, + {(const uint8_t []){0xff, 0xff, 0xff, 0xff}, 4}, + false + }, -#ifndef QCBOR_DISABLE_TAGS - QCBORDecode_GetEpochDateInMapN(&DCtx, 0x04, QCBOR_TAG_REQUIREMENT_TAG, &nInt); - uErr = QCBORDecode_GetAndResetError(&DCtx); - if(uErr != FLOAT_ERR_CODE_NO_FLOAT_HW(QCBOR_ERR_DATE_OVERFLOW)) { - return 2024; - } -#endif + { + /* Special case for test 8. Don't renumber it. */ + "8. Untagged pair with big num (big float or decimal fraction), tag optional", + {(const uint8_t []){0x82, 0x33, 0xC2, 0x4A, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x10}, 14}, + QCBOR_TAG_REQUIREMENT_OPTIONAL_TAG, + true, - QCBORDecode_GetInt64InMapN(&DCtx, 0x05, &nInt); - uErr = QCBORDecode_GetAndResetError(&DCtx); - if(uErr != QCBOR_ERR_DUPLICATE_LABEL) { - return 2025; - } + QCBOR_SUCCESS, /* for GetNext */ + QCBOR_TYPE_ARRAY, + 0, + 0, + {(const uint8_t []){0x00}, 1}, - QCBORDecode_GetInt64InMapN(&DCtx, 0x08, &nInt); + QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW, /* GetDecimalFraction */ + 0, + 0, - QCBORDecode_ExitMap(&DCtx); - uErr = QCBORDecode_Finish(&DCtx); - if(uErr != QCBOR_SUCCESS) { - return 2026; - } + QCBOR_SUCCESS, /* for GetDecimalFractionBig */ + -20, + {(const uint8_t []){0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x10}, 10}, + false, - QCBORDecode_Init(&DCtx, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spUnRecoverableMapError1), 0); - QCBORDecode_EnterMap(&DCtx, NULL); - QCBORDecode_GetInt64InMapN(&DCtx, 0x01, &nInt); - uErr = QCBORDecode_GetAndResetError(&DCtx); - if(uErr != QCBOR_ERR_BAD_BREAK) { - return 2030; - } + QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW, /* for GetBigFloat */ + 0, + 0, -#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS - QCBORDecode_Init(&DCtx, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spUnRecoverableMapError2), 0); - QCBORDecode_EnterMap(&DCtx, NULL); - QCBORDecode_GetInt64InMapN(&DCtx, 0x01, &nInt); - uErr = QCBORDecode_GetAndResetError(&DCtx); - if(uErr != QCBOR_ERR_NO_MORE_ITEMS) { - return 2031; - } + QCBOR_SUCCESS, /* for GetBigFloatBig */ + -20, + {(const uint8_t []){0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x10}, 10}, + false + }, - QCBORDecode_Init(&DCtx, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spUnRecoverableMapError3), 0); - QCBORDecode_EnterMap(&DCtx, NULL); - QCBORDecode_GetInt64InMapN(&DCtx, 0x01, &nInt); - uErr = QCBORDecode_GetAndResetError(&DCtx); - if(uErr != QCBOR_ERR_HIT_END) { - return 2032; - } + { + "9. decimal fraction with large exponent and negative big num mantissa", + {(const uint8_t []){0xC4, 0x82, 0x1B, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xC3, 0x4A, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x10}, 23}, + QCBOR_TAG_REQUIREMENT_OPTIONAL_TAG, + true, - QCBORDecode_Init(&DCtx, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spUnRecoverableMapError4), 0); - QCBORDecode_EnterMap(&DCtx, NULL); - QCBORDecode_GetInt64InMapN(&DCtx, 0x01, &nInt); - uErr = QCBORDecode_GetAndResetError(&DCtx); - if(uErr != QCBOR_ERR_ARRAY_DECODE_NESTING_TOO_DEEP) { - return 2033; - } -#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS */ + QCBOR_SUCCESS, /* for GetNext */ + QCBOR_TYPE_DECIMAL_FRACTION_NEG_BIGNUM, + 9223372036854775807, + 0, + {(const uint8_t []){0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x10}, 10}, - QCBORDecode_Init(&DCtx, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(pValidMapEncoded), 0); - QCBORDecode_VGetNextConsume(&DCtx, &Item1); - if(Item1.uDataType != QCBOR_TYPE_MAP) { - return 2401; - } - if(QCBORDecode_GetError(&DCtx)) { - return 2402; - } + QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW, /* GetDecimalFraction */ + 0, + 0, - QCBORDecode_Init(&DCtx, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(pValidMapEncoded), 0); - QCBORDecode_VGetNext(&DCtx, &Item1); - if(Item1.uDataType != QCBOR_TYPE_MAP || - Item1.val.uCount != 3 || - Item1.uNextNestLevel != 1) { - return 2403; - } - if(QCBORDecode_GetError(&DCtx)) { - return 2404; - } - QCBORDecode_VGetNextConsume(&DCtx, &Item1); - if(Item1.uDataType != QCBOR_TYPE_INT64 || - Item1.uNextNestLevel != 1 || - Item1.val.int64 != 42) { - return 2405; - } - if(QCBORDecode_GetError(&DCtx)) { - return 2406; - } - QCBORDecode_VGetNextConsume(&DCtx, &Item1); - if(Item1.uDataType != QCBOR_TYPE_ARRAY || - Item1.uNestingLevel != 1 || - Item1.uNextNestLevel != 1 || - Item1.val.uCount != 2) { - return 2407; - } - if(QCBORDecode_GetError(&DCtx)) { - return 2408; - } - QCBORDecode_VGetNextConsume(&DCtx, &Item1); - if(Item1.uDataType != QCBOR_TYPE_MAP || - Item1.uNestingLevel != 1 || - Item1.uNextNestLevel != 0 || - Item1.val.uCount != 4) { - return 2409; - } - if(QCBORDecode_GetError(&DCtx)) { - return 2410; - } + QCBOR_SUCCESS, /* for GetDecimalFractionBig */ + 9223372036854775807, + {(const uint8_t []){0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x10}, 10}, + true, - nReturn = DecodeNestedIterate(); + QCBOR_ERR_UNEXPECTED_TYPE, /* for GetBigFloat */ + 0, + 0, + QCBOR_ERR_UNEXPECTED_TYPE, /* for GetBigFloatBig */ + 0, + {(const uint8_t []){0x00}, 1}, + false + }, +}; - QCBORDecode_Init(&DCtx, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(not_well_formed_submod_section), 0); - QCBORDecode_EnterMap(&DCtx, NULL); - QCBORDecode_EnterMapFromMapN(&DCtx, 20); - if(QCBORDecode_GetError(&DCtx) != QCBOR_ERR_BAD_INT) { - return 2500; - } - QCBORDecode_Init(&DCtx, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spBadConsumeInput), 0); - QCBORDecode_VGetNextConsume(&DCtx, &Item1); - if(QCBORDecode_GetError(&DCtx) != QCBOR_ERR_NO_MORE_ITEMS) { - return 2600; - } -#ifndef QCBOR_DISABLE_TAGS - QCBORDecode_Init(&DCtx, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spBadConsumeInput2), 0); - QCBORDecode_VGetNextConsume(&DCtx, &Item1); - if(QCBORDecode_GetError(&DCtx) != QCBOR_SUCCESS) { - return 2700; - } +int32_t ProcessEaMTests(void) +{ + size_t uIndex; + QCBORDecodeContext DCtx; + QCBORItem Item; + QCBORError uError; + int64_t nMantissa, nExponent; + MakeUsefulBufOnStack( MantissaBuf, 200); + UsefulBufC Mantissa; + bool bMantissaIsNegative; - QCBORDecode_Init(&DCtx, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spBadConsumeInput3), 0); - QCBORDecode_VGetNextConsume(&DCtx, &Item1); - if(QCBORDecode_GetError(&DCtx) != QCBOR_ERR_UNRECOVERABLE_TAG_CONTENT) { - return 2800; - } -#endif + for(uIndex = 0; uIndex < C_ARRAY_COUNT(pEaMTests, struct EaMTest); uIndex++) { + const struct EaMTest *pT = &pEaMTests[uIndex]; + /* Decode with GetNext */ + QCBORDecode_Init(&DCtx, pT->Input, 0); + if(uIndex + 1 == 9) { + nExponent = 99; // just to set a break point + } - QCBORDecode_Init(&DCtx, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spBadConsumeInput4), 0); - QCBORDecode_VGetNextConsume(&DCtx, &Item1); -#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS - if(QCBORDecode_GetError(&DCtx) != QCBOR_SUCCESS) { - return 2900; - } -#else - if(QCBORDecode_GetError(&DCtx) != QCBOR_ERR_INDEF_LEN_ARRAYS_DISABLED) { - return 2901; - } + uError = QCBORDecode_GetNext(&DCtx, &Item); +#ifdef QCBOR_DISABLE_TAGS + /* Test 8 is a special case when tags are disabled */ + if(pT->bHasTags && uIndex + 1 != 8) { + if(uError != QCBOR_ERR_TAGS_DISABLED) { + return (int32_t)(1+uIndex) * 1000 + 9; + } + } else { +#endif + /* Now check return code, data type, mantissa and exponent */ + if(pT->uExpectedErrorGN != uError) { + return (int32_t)(1+uIndex) * 1000 + 1; + } + if(uError == QCBOR_SUCCESS && pT->uQCBORTypeGN != QCBOR_TYPE_ARRAY) { + if(pT->uQCBORTypeGN != Item.uDataType) { + return (int32_t)(1+uIndex) * 1000 + 2; + } + if(pT->nExponentGN != Item.val.expAndMantissa.nExponent) { + return (int32_t)(1+uIndex) * 1000 + 3; + } + if(Item.uDataType == QCBOR_TYPE_DECIMAL_FRACTION || Item.uDataType == QCBOR_TYPE_BIGFLOAT ) { + if(pT->nMantissaGN != Item.val.expAndMantissa.Mantissa.nInt) { + return (int32_t)(1+uIndex) * 1000 + 4; + } + } else { + if(UsefulBuf_Compare(Item.val.expAndMantissa.Mantissa.bigNum, pT->MantissaGN)) { + return (int32_t)(1+uIndex) * 1000 + 5; + } + } + } +#ifdef QCBOR_DISABLE_TAGS + } #endif - QCBORDecode_Init(&DCtx, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spBadConsumeInput5), 0); - QCBORDecode_VGetNextConsume(&DCtx, &Item1); - if(QCBORDecode_GetError(&DCtx) != QCBOR_ERR_MAP_LABEL_TYPE) { - return 3000; - } - - return nReturn; -} + /* Decode with GetDecimalFraction */ + QCBORDecode_Init(&DCtx, pT->Input, 0); + QCBORDecode_GetDecimalFraction(&DCtx, + pT->uTagRequirement, + &nMantissa, + &nExponent); + uError = QCBORDecode_GetAndResetError(&DCtx); +#ifdef QCBOR_DISABLE_TAGS + if(pT->bHasTags) { + if(uError != QCBOR_ERR_TAGS_DISABLED) { + return (int32_t)(1+uIndex) * 1000 + 39; + } + } else { +#endif + /* Now check return code, mantissa and exponent */ + if(pT->uExpectedErrorGDF != uError) { + return (int32_t)(1+uIndex) * 1000 + 31; + } + if(uError == QCBOR_SUCCESS) { + if(pT->nExponentGDF != nExponent) { + return (int32_t)(1+uIndex) * 1000 + 32; + } + if(pT->nMantissaGDF != nMantissa) { + return (int32_t)(1+uIndex) * 1000 + 33; + } + } +#ifdef QCBOR_DISABLE_TAGS + } +#endif + /* Decode with GetDecimalFractionBig */ + QCBORDecode_Init(&DCtx, pT->Input, 0); + QCBORDecode_GetDecimalFractionBig(&DCtx, + pT->uTagRequirement, + MantissaBuf, + &Mantissa, + &bMantissaIsNegative, + &nExponent); + uError = QCBORDecode_GetAndResetError(&DCtx); +#ifdef QCBOR_DISABLE_TAGS + if(pT->bHasTags) { + if(uError != QCBOR_ERR_TAGS_DISABLED) { + return (int32_t)(1+uIndex) * 1000 + 49; + } + } else { +#endif + /* Now check return code, mantissa (bytes and sign) and exponent */ + if(pT->uExpectedErrorGDFB != uError) { + return (int32_t)(1+uIndex) * 1000 + 41; + } + if(uError == QCBOR_SUCCESS) { + if(pT->nExponentGDFB != nExponent) { + return (int32_t)(1+uIndex) * 1000 + 42; + } + if(pT->IsNegativeGDFB != bMantissaIsNegative) { + return (int32_t)(1+uIndex) * 1000 + 43; + } + if(UsefulBuf_Compare(Mantissa, pT->MantissaGDFB)) { + return (int32_t)(1+uIndex) * 1000 + 44; + } + } +#ifdef QCBOR_DISABLE_TAGS + } +#endif -struct NumberConversion { - char *szDescription; - UsefulBufC CBOR; - int64_t nConvertedToInt64; - QCBORError uErrorInt64; - uint64_t uConvertToUInt64; - QCBORError uErrorUint64; - double dConvertToDouble; - QCBORError uErrorDouble; -}; + /* Decode with GetBigFloat */ + QCBORDecode_Init(&DCtx, pT->Input, 0); + QCBORDecode_GetBigFloat(&DCtx, + pT->uTagRequirement, + &nMantissa, + &nExponent); + uError = QCBORDecode_GetAndResetError(&DCtx); +#ifdef QCBOR_DISABLE_TAGS + if(pT->bHasTags) { + if(uError != QCBOR_ERR_TAGS_DISABLED) { + return (int32_t)(1+uIndex) * 1000 + 19; + } + } else { +#endif + /* Now check return code, mantissa and exponent */ + if(pT->uExpectedErrorGBF != uError) { + return (int32_t)(1+uIndex) * 1000 + 11; + } + if(uError == QCBOR_SUCCESS) { + if(pT->nExponentGBF != nExponent) { + return (int32_t)(1+uIndex) * 1000 + 12; + } + if(pT->nMantissaGBF != nMantissa) { + return (int32_t)(1+uIndex) * 1000 + 13; + } + } +#ifdef QCBOR_DISABLE_TAGS + } +#endif -#ifndef QCBOR_DISABLE_EXP_AND_MANTISSA -#define EXP_AND_MANTISSA_ERROR(x) x -#else -#define EXP_AND_MANTISSA_ERROR(x) QCBOR_ERR_UNEXPECTED_TYPE + /* Decode with GetBigFloatBig */ + QCBORDecode_Init(&DCtx, pT->Input, 0); + QCBORDecode_GetBigFloatBig(&DCtx, + pT->uTagRequirement, + MantissaBuf, + &Mantissa, + &bMantissaIsNegative, + &nExponent); + uError = QCBORDecode_GetAndResetError(&DCtx); +#ifdef QCBOR_DISABLE_TAGS + if(pT->bHasTags) { + if(uError != QCBOR_ERR_TAGS_DISABLED) { + return (int32_t)(1+uIndex) * 1000 + 29; + } + } else { +#endif + /* Now check return code, mantissa (bytes and sign) and exponent */ + if(pT->uExpectedErrorGBFB != uError) { + return (int32_t)(1+uIndex) * 1000 + 21; + } + if(uError == QCBOR_SUCCESS) { + if(pT->nExponentGBFB != nExponent) { + return (int32_t)(1+uIndex) * 1000 + 22; + } + if(pT->IsNegativeGBFB != bMantissaIsNegative) { + return (int32_t)(1+uIndex) * 1000 + 23; + } + if(UsefulBuf_Compare(Mantissa, pT->MantissaGBFB)) { + return (int32_t)(1+uIndex) * 1000 + 24; + } + } +#ifdef QCBOR_DISABLE_TAGS + } #endif + } + + return 0; +} -static const struct NumberConversion NumberConversions[] = { +int32_t ExponentAndMantissaDecodeTestsSecondary(void) +{ #ifndef QCBOR_DISABLE_TAGS - { - "Big float: INT64_MIN * 2e-1 to test handling of INT64_MIN", - {(uint8_t[]){0xC5, 0x82, 0x20, - 0x3B, 0x7f, 0xff, 0xff, 0xff, 0xff, 0x0ff, 0xff, 0xff, - }, 15}, - -4611686018427387904, /* INT64_MIN / 2 */ - EXP_AND_MANTISSA_ERROR(QCBOR_SUCCESS), - 0, - EXP_AND_MANTISSA_ERROR(QCBOR_ERR_NUMBER_SIGN_CONVERSION), - -4.6116860184273879E+18, - FLOAT_ERR_CODE_NO_FLOAT_HW(EXP_AND_MANTISSA_ERROR(QCBOR_SUCCESS)) - }, - { - "too large to fit into int64_t", - {(uint8_t[]){0xc3, 0x48, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, 10}, - 0, - QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW, - 0, - QCBOR_ERR_NUMBER_SIGN_CONVERSION, - ((double)INT64_MIN) + 1 , - FLOAT_ERR_CODE_NO_FLOAT_HW(QCBOR_SUCCESS) - }, - { - "largest negative int that fits in int64_t", - {(uint8_t[]){0xc3, 0x48, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}, 10}, - INT64_MIN, - QCBOR_SUCCESS, - 0, - QCBOR_ERR_NUMBER_SIGN_CONVERSION, - (double)INT64_MIN, - FLOAT_ERR_CODE_NO_FLOAT_HW(QCBOR_SUCCESS) - }, - { - "negative bignum -1", - {(uint8_t[]){0xc3, 0x41, 0x00}, 3}, - -1, - QCBOR_SUCCESS, - 0, - QCBOR_ERR_NUMBER_SIGN_CONVERSION, - -1.0, - FLOAT_ERR_CODE_NO_FLOAT_HW(QCBOR_SUCCESS) - }, - { - "Decimal Fraction with positive bignum 257 * 10e3", - {(uint8_t[]){0xC4, 0x82, 0x1B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, - 0xC2, 0x42, 0x01, 0x01}, 15}, - 257000, - EXP_AND_MANTISSA_ERROR(QCBOR_SUCCESS), - 257000, - EXP_AND_MANTISSA_ERROR(QCBOR_SUCCESS), - 257000.0, - FLOAT_ERR_CODE_NO_FLOAT_HW(EXP_AND_MANTISSA_ERROR(QCBOR_SUCCESS)) - }, - { - "bigfloat with negative bignum -258 * 2e3", - {(uint8_t[]){0xC5, 0x82, 0x1B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, - 0xC3, 0x42, 0x01, 0x01}, 15}, - -2064, - EXP_AND_MANTISSA_ERROR(QCBOR_SUCCESS), - 0, - EXP_AND_MANTISSA_ERROR(QCBOR_ERR_NUMBER_SIGN_CONVERSION), - -2064.0, - FLOAT_ERR_CODE_NO_FLOAT_HW(EXP_AND_MANTISSA_ERROR(QCBOR_SUCCESS)) - }, - { - "bigfloat with positive bignum 257 * 2e3", - {(uint8_t[]){0xC5, 0x82, 0x1B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, - 0xC2, 0x42, 0x01, 0x01}, 15}, - 2056, - EXP_AND_MANTISSA_ERROR(QCBOR_SUCCESS), - 2056, - EXP_AND_MANTISSA_ERROR(QCBOR_SUCCESS), - 2056.0, - FLOAT_ERR_CODE_NO_FLOAT_HW(EXP_AND_MANTISSA_ERROR(QCBOR_SUCCESS)) - }, - { - "negative bignum 0xc349010000000000000000 -18446744073709551617", - {(uint8_t[]){0xc3, 0x49, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, 11}, - 0, - QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW, - 0, - QCBOR_ERR_NUMBER_SIGN_CONVERSION, - -18446744073709551617.0, - FLOAT_ERR_CODE_NO_FLOAT_HW(QCBOR_SUCCESS) + QCBORDecodeContext DC; + QCBORError uErr; + QCBORItem item; + + static const uint8_t spBigNumMantissa[] = {0x01, 0x02, 0x03, 0x04, 0x05, + 0x06, 0x07, 0x08, 0x09, 0x010}; + UsefulBufC BN = UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spBigNumMantissa); + + + + /* Now encode some stuff and then decode it */ + uint8_t pBuf[40]; + QCBOREncodeContext EC; + UsefulBufC Encoded; + + QCBOREncode_Init(&EC, UsefulBuf_FROM_BYTE_ARRAY(pBuf)); + QCBOREncode_OpenArray(&EC); + QCBOREncode_AddDecimalFraction(&EC, 999, 1000); // 999 * (10 ^ 1000) + QCBOREncode_AddTBigFloat(&EC, QCBOR_ENCODE_AS_TAG, 100, INT32_MIN); + QCBOREncode_AddTDecimalFractionBigNum(&EC, QCBOR_ENCODE_AS_TAG, BN, false, INT32_MAX); + QCBOREncode_CloseArray(&EC); + QCBOREncode_Finish(&EC, &Encoded); + + + QCBORDecode_Init(&DC, Encoded, QCBOR_DECODE_MODE_NORMAL); + uErr = QCBORDecode_GetNext(&DC, &item); + if(uErr != QCBOR_SUCCESS) { + return 100; + } + + uErr = QCBORDecode_GetNext(&DC, &item); + if(uErr != QCBOR_SUCCESS) { + return 101; + } + + if(item.uDataType != QCBOR_TYPE_DECIMAL_FRACTION || + item.val.expAndMantissa.nExponent != 1000 || + item.val.expAndMantissa.Mantissa.nInt != 999) { + return 102; + } + + uErr = QCBORDecode_GetNext(&DC, &item); + if(uErr != QCBOR_SUCCESS) { + return 103; + } + + if(item.uDataType != QCBOR_TYPE_BIGFLOAT || + item.val.expAndMantissa.nExponent != INT32_MIN || + item.val.expAndMantissa.Mantissa.nInt != 100) { + return 104; + } + + uErr = QCBORDecode_GetNext(&DC, &item); + if(uErr != QCBOR_SUCCESS) { + return 105; + } + + if(item.uDataType != QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM || + item.val.expAndMantissa.nExponent != INT32_MAX || + UsefulBuf_Compare(item.val.expAndMantissa.Mantissa.bigNum, BN)) { + return 106; + } + +#endif /* QCBOR_TAGS_DISABLED */ + + return 0; +} + + +int32_t ExponentAndMantissaDecodeTests(void) +{ + int32_t rv = ProcessEaMTests(); + if(rv) { + return rv; + } + + return ExponentAndMantissaDecodeTestsSecondary(); +} + + +static const struct DecodeFailTestInput ExponentAndMantissaFailures[] = { + { "Exponent > INT64_MAX", + QCBOR_DECODE_MODE_NORMAL, + {"\xC4\x82\x1B\x7f\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x1B\x80\xFF\xFF\xFF\xFF\xFF\xFF\xFF", 20}, + QCBOR_ERR_BAD_EXP_AND_MANTISSA }, -#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS - { - "Positive bignum 0x01020304 indefinite length string", - {(uint8_t[]){0xC2, 0x5f, 0x42, 0x01, 0x02, 0x41, 0x03, 0x41, 0x04, 0xff}, 10}, - 0x01020304, - QCBOR_SUCCESS, - 0x01020304, - QCBOR_SUCCESS, - 16909060.0, - FLOAT_ERR_CODE_NO_FLOAT_HW(QCBOR_SUCCESS) + { "Mantissa > INT64_MAX", + QCBOR_DECODE_MODE_NORMAL, + {"\xC4\x82\x1B\x80\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xC3\x4A\x01\x02\x03\x04\x05\x06\x07\x08\x09\x10", 23}, + QCBOR_ERR_BAD_EXP_AND_MANTISSA }, -#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS */ { - "Decimal Fraction with neg bignum [9223372036854775807, -4759477275222530853137]", - {(uint8_t[]){0xC4, 0x82, 0x1B, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xC3, 0x4A, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x10,}, 23}, - 0, - EXP_AND_MANTISSA_ERROR(QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW), - 0, - EXP_AND_MANTISSA_ERROR(QCBOR_ERR_NUMBER_SIGN_CONVERSION), - -INFINITY, - FLOAT_ERR_CODE_NO_FLOAT_HW(EXP_AND_MANTISSA_ERROR(QCBOR_SUCCESS)) + "End of input", + QCBOR_DECODE_MODE_NORMAL, + {"\xC4\x82", 2}, + QCBOR_ERR_NO_MORE_ITEMS }, - { - "big float [9223372036854775806, 9223372036854775806]", - {(uint8_t[]){0xC5, 0x82, 0x1B, 0x7f, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, - 0x1B, 0x7f, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE}, 20}, - 0, - EXP_AND_MANTISSA_ERROR(QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW), - 0, - EXP_AND_MANTISSA_ERROR(QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW), - INFINITY, - FLOAT_ERR_CODE_NO_FLOAT_HW(EXP_AND_MANTISSA_ERROR(QCBOR_SUCCESS)) + {"bad content for big num", + QCBOR_DECODE_MODE_NORMAL, + {"\xC4\x82\x01\xc3\x01", 5}, + QCBOR_ERR_BAD_OPT_TAG }, - { - "Big float 3 * 2^^2", - {(uint8_t[]){0xC5, 0x82, 0x02, 0x03}, 4}, - 12, - EXP_AND_MANTISSA_ERROR(QCBOR_SUCCESS), - 12, - EXP_AND_MANTISSA_ERROR(QCBOR_SUCCESS), - 12.0, - FLOAT_ERR_CODE_NO_FLOAT_HW(EXP_AND_MANTISSA_ERROR(QCBOR_SUCCESS)) + {"bad content for big num", + QCBOR_DECODE_MODE_NORMAL, + {"\xC4\x82\xC2\x01\x1F", 5}, + QCBOR_ERR_UNRECOVERABLE_TAG_CONTENT }, - { - "Decimal fraction 3/10", - {(uint8_t[]){0xC4, 0x82, 0x20, 0x03}, 4}, - 0, - EXP_AND_MANTISSA_ERROR(QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW), - 0, - EXP_AND_MANTISSA_ERROR(QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW), - 0.30000000000000004, - FLOAT_ERR_CODE_NO_FLOAT_HW(EXP_AND_MANTISSA_ERROR(QCBOR_SUCCESS)) + {"Bad integer for exponent", + QCBOR_DECODE_MODE_NORMAL, + {"\xC4\x82\x01\x1f", 4}, + QCBOR_ERR_BAD_INT }, - { - "extreme pos bignum", - {(uint8_t[]){0xc2, 0x59, 0x01, 0x90, - // 50 rows of 8 is 400 digits. - 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, - 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, - 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, - 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, - 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, - 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, - 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, - 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, - 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, - 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, - 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, - 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, - 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, - 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, - 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, - 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, - 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, - 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, - 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, - 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, - 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, - 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, - 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, - 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, - 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, - 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, - 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, - 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, - 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, - 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, - 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, - 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, - 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, - 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, - 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, - 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, - 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, - 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, - 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, - 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, - 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, - 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, - 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, - 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, - 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, - 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, - 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, - 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, - 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, - 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0}, - 404}, - 0, - QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW, - 0, - QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW, - INFINITY, - FLOAT_ERR_CODE_NO_FLOAT_HW(QCBOR_SUCCESS), + {"Bad integer for mantissa", + QCBOR_DECODE_MODE_NORMAL, + {"\xC4\x82\x1f\x01", 4}, + QCBOR_ERR_BAD_INT }, - - { - "extreme neg bignum", - {(uint8_t[]){0xc3, 0x59, 0x01, 0x90, - // 50 rows of 8 is 400 digits. - 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, - 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, - 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, - 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, - 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, - 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, - 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, - 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, - 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, - 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, - 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, - 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, - 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, - 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, - 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, - 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, - 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, - 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, - 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, - 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, - 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, - 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, - 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, - 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, - 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, - 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, - 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, - 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, - 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, - 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, - 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, - 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, - 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, - 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, - 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, - 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, - 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, - 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, - 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, - 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, - 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, - 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, - 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, - 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, - 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, - 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, - 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, - 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, - 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, - 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0}, - 404}, - 0, - QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW, - 0, - QCBOR_ERR_NUMBER_SIGN_CONVERSION, - -INFINITY, - FLOAT_ERR_CODE_NO_FLOAT_HW(QCBOR_SUCCESS) + {"3 items in array", + QCBOR_DECODE_MODE_NORMAL, + {"\xC4\x83\x03\x01\x02", 5}, + QCBOR_ERR_BAD_EXP_AND_MANTISSA}, +#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS + {"unterminated indefinite length array", + QCBOR_DECODE_MODE_NORMAL, + {"\xC4\x9f\x03\x01\x02", 5}, + QCBOR_ERR_BAD_EXP_AND_MANTISSA }, - - { - "big float underflow [9223372036854775806, -9223372036854775806]", - {(uint8_t[]){ - 0xC5, 0x82, - 0x3B, 0x7f, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, - 0x1B, 0x7f, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE}, 20}, - 0, - EXP_AND_MANTISSA_ERROR(QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW), - 0, - EXP_AND_MANTISSA_ERROR(QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW), - 0, - FLOAT_ERR_CODE_NO_FLOAT_HW(EXP_AND_MANTISSA_ERROR(QCBOR_SUCCESS)) +#else /* QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS */ + {"unterminated indefinite length array", + QCBOR_DECODE_MODE_NORMAL, + {"\xC4\x9f\x03\x01\x02", 5}, + QCBOR_ERR_INDEF_LEN_ARRAYS_DISABLED }, - - { - "bigfloat that evaluates to -INFINITY", - {(uint8_t[]){ - 0xC5, 0x82, - 0x1B, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, - 0xC3, 0x42, 0x01, 0x01}, 15}, - 0, - EXP_AND_MANTISSA_ERROR(QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW), - 0, - EXP_AND_MANTISSA_ERROR(QCBOR_ERR_NUMBER_SIGN_CONVERSION), - -INFINITY, - FLOAT_ERR_CODE_NO_FLOAT_HW(EXP_AND_MANTISSA_ERROR(QCBOR_SUCCESS)) +#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS */ + {"Empty array", + QCBOR_DECODE_MODE_NORMAL, + {"\xC4\x80", 2}, + QCBOR_ERR_NO_MORE_ITEMS }, - { - "Positive bignum 0xffff", - {(uint8_t[]){0xC2, 0x42, 0xff, 0xff}, 4}, - 65536-1, - QCBOR_SUCCESS, - 0xffff, - QCBOR_SUCCESS, - 65535.0, - FLOAT_ERR_CODE_NO_FLOAT_HW(QCBOR_SUCCESS) + {"Second is not an integer", + QCBOR_DECODE_MODE_NORMAL, + {"\xC4\x82\x03\x40", 4}, + QCBOR_ERR_BAD_EXP_AND_MANTISSA }, -#endif /* QCBOR_DISABLE_TAGS */ - { - "Positive integer 18446744073709551615", - {(uint8_t[]){0x1b, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}, 9}, - 0, - QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW, - 18446744073709551615ULL, - QCBOR_SUCCESS, - 18446744073709551615.0, - FLOAT_ERR_CODE_NO_FLOAT_HW(QCBOR_SUCCESS) + {"First is not an integer", + QCBOR_DECODE_MODE_NORMAL, + {"\xC4\x82\x40", 3}, + QCBOR_ERR_BAD_EXP_AND_MANTISSA }, + {"Not an array", + QCBOR_DECODE_MODE_NORMAL, + {"\xC4\xA2", 2}, + QCBOR_ERR_BAD_EXP_AND_MANTISSA + } +}; + +int32_t +ExponentAndMantissaDecodeFailTests(void) +{ + return ProcessDecodeFailures(ExponentAndMantissaFailures, + C_ARRAY_COUNT(ExponentAndMantissaFailures, + struct DecodeFailTestInput)); +} + +#endif /* QCBOR_DISABLE_EXP_AND_MANTISSA */ + + + +/* + Some basic CBOR with map and array used in a lot of tests. + The map labels are all strings + + { + "first integer": 42, + "an array of two strings": [ + "string1", "string2" + ], + "map in a map": { + "bytes 1": h'78787878', + "bytes 2": h'79797979', + "another int": 98, + "text 2": "lies, damn lies and statistics" + } + } + */ + +int32_t SpiffyDecodeBasicMap(UsefulBufC input) +{ + QCBORItem Item1, Item2, Item3; + int64_t nDecodedInt1, nDecodedInt2; + UsefulBufC B1, B2, S1, S2, S3; + + QCBORDecodeContext DCtx; + QCBORError nCBORError; + + QCBORDecode_Init(&DCtx, input, 0); + + QCBORDecode_EnterMap(&DCtx, NULL); + + QCBORDecode_GetInt64InMapSZ(&DCtx, "first integer", &nDecodedInt1); + + QCBORDecode_EnterMapFromMapSZ(&DCtx, "map in a map"); + QCBORDecode_GetInt64InMapSZ(&DCtx, "another int", &nDecodedInt2); + QCBORDecode_GetByteStringInMapSZ(&DCtx, "bytes 1", &B1); + QCBORDecode_GetByteStringInMapSZ(&DCtx, "bytes 2", &B2); + QCBORDecode_GetTextStringInMapSZ(&DCtx, "text 2", &S1); + QCBORDecode_ExitMap(&DCtx); + + QCBORDecode_EnterArrayFromMapSZ(&DCtx, "an array of two strings"); + QCBORDecode_GetNext(&DCtx, &Item1); + QCBORDecode_GetNext(&DCtx, &Item2); + if(QCBORDecode_GetNext(&DCtx, &Item3) != QCBOR_ERR_NO_MORE_ITEMS) { + return -400; + } + QCBORDecode_ExitArray(&DCtx); + + // Parse the same array again using GetText() instead of GetItem() + QCBORDecode_EnterArrayFromMapSZ(&DCtx, "an array of two strings"); + QCBORDecode_GetTextString(&DCtx, &S2); + QCBORDecode_GetTextString(&DCtx, &S3); + if(QCBORDecode_GetError(&DCtx) != QCBOR_SUCCESS) { + return 5000; + } + /* QCBORDecode_GetText(&DCtx, &S3); + if(QCBORDecode_GetAndResetError(&DCtx) != QCBOR_ERR_NO_MORE_ITEMS) { + return 5001; + } */ + + QCBORDecode_ExitArray(&DCtx); + + QCBORDecode_ExitMap(&DCtx); + + nCBORError = QCBORDecode_Finish(&DCtx); + + if(nCBORError) { + return (int32_t)nCBORError; + } + + if(nDecodedInt1 != 42) { + return 1001; + } + + if(nDecodedInt2 != 98) { + return 1002; + } + + if(Item1.uDataType != QCBOR_TYPE_TEXT_STRING || + UsefulBufCompareToSZ(Item1.val.string, "string1")) { + return 1003; + } + + if(Item1.uDataType != QCBOR_TYPE_TEXT_STRING || + UsefulBufCompareToSZ(Item2.val.string, "string2")) { + return 1004; + } + + if(UsefulBufCompareToSZ(S1, "lies, damn lies and statistics")) { + return 1005; + } + + if(UsefulBuf_Compare(B1, UsefulBuf_FromSZ("xxxx"))){ + return 1006; + } + + if(UsefulBuf_Compare(B2, UsefulBuf_FromSZ("yyyy"))){ + return 1007; + } + + if(UsefulBuf_Compare(S2, UsefulBuf_FromSZ("string1"))){ + return 1008; + } + + if(UsefulBuf_Compare(S3, UsefulBuf_FromSZ("string2"))){ + return 1009; + } + + return 0; +} + +/* { - "Postive integer 0", - {(uint8_t[]){0x0}, 1}, - 0LL, - QCBOR_SUCCESS, - 0ULL, - QCBOR_SUCCESS, - 0.0, - FLOAT_ERR_CODE_NO_FLOAT_HW(QCBOR_SUCCESS) - }, - { - "Negative integer -18446744073709551616", - {(uint8_t[]){0x3b, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }, 9}, - -9223372036854775807-1, // INT64_MIN - QCBOR_SUCCESS, - 0ULL, - QCBOR_ERR_NUMBER_SIGN_CONVERSION, - -9223372036854775808.0, - FLOAT_ERR_CODE_NO_FLOAT_HW(QCBOR_SUCCESS) - }, - { - "Double Floating point value 100.3", - {(uint8_t[]){0xfb, 0x40, 0x59, 0x13, 0x33, 0x33, 0x33, 0x33, 0x33}, 9}, - 100L, - FLOAT_ERR_CODE_NO_FLOAT_HW(QCBOR_SUCCESS), - 100ULL, - FLOAT_ERR_CODE_NO_FLOAT_HW(QCBOR_SUCCESS), - 100.3, - FLOAT_ERR_CODE_NO_FLOAT(QCBOR_SUCCESS), - }, - { - "Floating point value NaN 0xfa7fc00000", - {(uint8_t[]){0xfa, 0x7f, 0xc0, 0x00, 0x00}, 5}, - 0, - FLOAT_ERR_CODE_NO_FLOAT_HW(QCBOR_ERR_FLOAT_EXCEPTION), - 0, - FLOAT_ERR_CODE_NO_FLOAT_HW(QCBOR_ERR_FLOAT_EXCEPTION), - NAN, - FLOAT_ERR_CODE_NO_FLOAT_HW(QCBOR_SUCCESS), - }, - { - "half-precision Floating point value -4", - {(uint8_t[]){0xf9, 0xc4, 0x00}, 3}, - // Normal case with all enabled. - -4, - FLOAT_ERR_CODE_NO_HALF_PREC_NO_FLOAT_HW(QCBOR_SUCCESS), - 0, - FLOAT_ERR_CODE_NO_HALF_PREC_NO_FLOAT_HW(QCBOR_ERR_NUMBER_SIGN_CONVERSION), - -4.0, - FLOAT_ERR_CODE_NO_HALF_PREC(QCBOR_SUCCESS) - }, - { - "+inifinity single precision", - {(uint8_t[]){0xfa, 0x7f, 0x80, 0x00, 0x00}, 5}, - 0, - FLOAT_ERR_CODE_NO_FLOAT_HW(QCBOR_ERR_FLOAT_EXCEPTION), - 0, - FLOAT_ERR_CODE_NO_FLOAT_HW(QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW), - INFINITY, - FLOAT_ERR_CODE_NO_FLOAT_HW(QCBOR_SUCCESS) - }, + -75008: h'05083399', + 88: [], + 100100: { + "sub1": { + 10: [ + 0 + ], + -75009: h'A46823990001', + 100100: { + "json": "{ \"ueid\", \"xyz\"}", + "subsub": { + 100002: h'141813191001' + } + } + } + } + } + */ + +static const uint8_t spNestedCBOR[] = { + 0xa3, 0x3a, 0x00, 0x01, 0x24, 0xff, 0x44, 0x05, + 0x08, 0x33, 0x99, 0x18, 0x58, 0x80, 0x1a, 0x00, + 0x01, 0x87, 0x04, 0xa1, 0x64, 0x73, 0x75, 0x62, + 0x31, 0xa3, 0x0a, 0x81, 0x00, 0x3a, 0x00, 0x01, + 0x25, 0x00, 0x46, 0xa4, 0x68, 0x23, 0x99, 0x00, + 0x01, 0x1a, 0x00, 0x01, 0x87, 0x04, 0xa2, 0x64, + 0x6a, 0x73, 0x6f, 0x6e, 0x70, 0x7b, 0x20, 0x22, + 0x75, 0x65, 0x69, 0x64, 0x22, 0x2c, 0x20, 0x22, + 0x78, 0x79, 0x7a, 0x22, 0x7d, 0x66, 0x73, 0x75, + 0x62, 0x73, 0x75, 0x62, 0xa1, 0x1a, 0x00, 0x01, + 0x86, 0xa2, 0x46, 0x14, 0x18, 0x13, 0x19, 0x10, + 0x01 +}; + +/* Get item in multi-level nesting in spNestedCBOR */ +static int32_t DecodeNestedGetSubSub(QCBORDecodeContext *pDCtx) +{ + UsefulBufC String; + + uint8_t test_oemid_bytes[] = {0x14, 0x18, 0x13, 0x19, 0x10, 0x01}; + const struct q_useful_buf_c test_oemid = UsefulBuf_FROM_BYTE_ARRAY_LITERAL(test_oemid_bytes); + + QCBORDecode_EnterMapFromMapN(pDCtx, 100100); + QCBORDecode_EnterMap(pDCtx, NULL); + QCBORDecode_EnterMapFromMapN(pDCtx, 100100); + QCBORDecode_EnterMapFromMapSZ(pDCtx, "subsub"); + QCBORDecode_GetByteStringInMapN(pDCtx, 100002, &String); + if(QCBORDecode_GetError(pDCtx)) { + return 4001; + } + if(UsefulBuf_Compare(String, test_oemid)) { + return 4002; + } + QCBORDecode_ExitMap(pDCtx); + QCBORDecode_ExitMap(pDCtx); + QCBORDecode_ExitMap(pDCtx); + QCBORDecode_ExitMap(pDCtx); + + return 0; +} + +/* Iterations on the zero-length array in spNestedCBOR */ +static int32_t DecodeNestedGetEmpty(QCBORDecodeContext *pDCtx) +{ + QCBORItem Item; + QCBORError uErr; + + QCBORDecode_EnterArrayFromMapN(pDCtx, 88); + for(int x = 0; x < 20; x++) { + uErr = QCBORDecode_GetNext(pDCtx, &Item); + if(uErr != QCBOR_ERR_NO_MORE_ITEMS) { + return 4100; + + } + } + QCBORDecode_ExitArray(pDCtx); + if(QCBORDecode_GetError(pDCtx)) { + return 4101; + } + + return 0; +} + +/* Various iterations on the array that contains a zero in spNestedCBOR */ +static int32_t DecodeNestedGetZero(QCBORDecodeContext *pDCtx) +{ + QCBORError uErr; + + QCBORDecode_EnterMapFromMapN(pDCtx, 100100); + QCBORDecode_EnterMapFromMapSZ(pDCtx, "sub1"); + QCBORDecode_EnterArrayFromMapN(pDCtx, 10); + int64_t nInt = 99; + QCBORDecode_GetInt64(pDCtx, &nInt); + if(nInt != 0) { + return 4200; + } + for(int x = 0; x < 20; x++) { + QCBORItem Item; + uErr = QCBORDecode_GetNext(pDCtx, &Item); + if(uErr != QCBOR_ERR_NO_MORE_ITEMS) { + return 4201; + + } + } + QCBORDecode_ExitArray(pDCtx); + if(QCBORDecode_GetAndResetError(pDCtx)) { + return 4202; + } + QCBORDecode_EnterArrayFromMapN(pDCtx, 10); + UsefulBufC dD; + QCBORDecode_GetByteString(pDCtx, &dD); + if(QCBORDecode_GetAndResetError(pDCtx) != QCBOR_ERR_UNEXPECTED_TYPE) { + return 4203; + } + for(int x = 0; x < 20; x++) { + QCBORDecode_GetByteString(pDCtx, &dD); + uErr = QCBORDecode_GetAndResetError(pDCtx); + if(uErr != QCBOR_ERR_NO_MORE_ITEMS) { + return 4204; + } + } + QCBORDecode_ExitArray(pDCtx); + QCBORDecode_ExitMap(pDCtx); + QCBORDecode_ExitMap(pDCtx); + + return 0; +} + +/* Repeatedly enter and exit maps and arrays, go off the end of maps + and arrays and such. */ +static int32_t DecodeNestedIterate(void) +{ + QCBORDecodeContext DCtx; + int32_t nReturn; + QCBORError uErr; + + QCBORDecode_Init(&DCtx, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spNestedCBOR), 0); + QCBORDecode_EnterMap(&DCtx, NULL); + + for(int j = 0; j < 5; j++) { + for(int i = 0; i < 20; i++) { + nReturn = DecodeNestedGetSubSub(&DCtx); + if(nReturn) { + return nReturn; + } + } + + for(int i = 0; i < 20; i++) { + nReturn = DecodeNestedGetEmpty(&DCtx); + if(nReturn ) { + return nReturn; + } + } + + for(int i = 0; i < 20; i++) { + nReturn = DecodeNestedGetZero(&DCtx); + if(nReturn ) { + return nReturn; + } + } + } + + QCBORDecode_ExitMap(&DCtx); + uErr = QCBORDecode_Finish(&DCtx); + if(uErr) { + return (int32_t)uErr + 4100; + } + + return 0; +} + + +/* + [ + 23, + 6000, + h'67616C6163746963', + h'686176656E20746F6B656E' + ] + */ +static const uint8_t spSimpleArray[] = { + 0x84, + 0x17, + 0x19, 0x17, 0x70, + 0x48, 0x67, 0x61, 0x6C, 0x61, 0x63, 0x74, 0x69, 0x63, + 0x4B, 0x68, 0x61, 0x76, 0x65, 0x6E, 0x20, 0x74, 0x6F, 0x6B, 0x65, 0x6E}; + +/* [h'', {}, [], 0] */ +static const uint8_t spArrayOfEmpty[] = {0x84, 0x40, 0xa0, 0x80, 0x00}; + +/* {} */ +static const uint8_t spEmptyMap[] = {0xa0}; + +#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS +/* {} */ +static const uint8_t spEmptyInDefinteLengthMap[] = {0xbf, 0xff}; + + +/* + { + 0: [], + 9: [ + [], + [] + ], + 8: { + 1: [], + 2: {}, + 3: [] + }, + 4: {}, + 5: [], + 6: [ + [], + [] + ] + } + */ +static const uint8_t spMapOfEmpty[] = { + 0xa6, 0x00, 0x80, 0x09, 0x82, 0x80, 0x80, 0x08, + 0xa3, 0x01, 0x80, 0x02, 0xa0, 0x03, 0x80, 0x04, + 0xa0, 0x05, 0x9f, 0xff, 0x06, 0x9f, 0x80, 0x9f, + 0xff, 0xff}; + +#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS */ + + +/* + Too many tags + Duplicate label + Integer overflow + Date overflow + + { + 1: 224(225(226(227(4(0))))), + 3: -18446744073709551616, + 4: 1(1.0e+300), + 5: 0, + 8: 8 + } + */ +static const uint8_t spRecoverableMapErrors[] = { +#ifndef QCBOR_DISABLE_TAGS + 0xa6, + 0x04, 0xc1, 0xfb, 0x7e, 0x37, 0xe4, 0x3c, 0x88, 0x00, 0x75, 0x9c, + 0x01, 0xd8, 0xe0, 0xd8, 0xe1, 0xd8, 0xe2, 0xd8, 0xe3, 0xd8, 0x04, 0x00, +#else + 0xa4, +#endif + 0x03, 0x3b, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x05, 0x00, + 0x05, 0x00, + 0x08, 0x08, +}; + +/* Bad break */ +static const uint8_t spUnRecoverableMapError1[] = { + 0xa2, 0xff, 0x01, 0x00, 0x02, 0x00 +}; + +#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS +/* No more items */ +static const uint8_t spUnRecoverableMapError2[] = { + 0xbf, 0x02, 0xbf, 0xff, 0x01, 0x00, 0x02, 0x00 +}; + +/* Hit end because string is too long */ +static const uint8_t spUnRecoverableMapError3[] = { + 0xbf, 0x02, 0x69, 0x64, 0x64, 0xff +}; + +/* Hit end because string is too long */ +static const uint8_t spUnRecoverableMapError4[] = { + 0xbf, + 0x02, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, + 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff +}; +#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS */ + +const unsigned char not_well_formed_submod_section[] = { + 0xa1, 0x14, 0x1f, +}; + + +/* Array of length 3, but only two items. */ +const unsigned char spBadConsumeInput[] = { + 0x83, 0x00, 0x00 +}; + +/* Tag nesting too deep. */ +const unsigned char spBadConsumeInput2[] = { + 0x81, + 0xD8, 0x37, + 0xD8, 0x2C, + 0xD8, 0x21, + 0xD6, + 0xCB, + 00 +}; + + +const unsigned char spBadConsumeInput4[] = { + 0x81, 0x9f, 0x00, 0xff +}; + +const unsigned char spBadConsumeInput5[] = { + 0xa1, 0x80, 0x00 +}; + +/* + Lots of nesting for various nesting tests. + { 1:1, + 2:{ + 21:21, + 22:{ + 221:[2111, 2112, 2113], + 222:222, + 223: {} + }, + 23: 23 + }, + 3:3, + 4: [ {} ] + } + */ +static const uint8_t spNested[] = { +0xA4, /* Map of 4 */ + 0x01, 0x01, /* Map entry 1 : 1 */ + 0x02, 0xA3, /* Map entry 2 : {, an array of 3 */ + 0x15, 0x15, /* Map entry 21 : 21 */ + 0x16, 0xA3, /* Map entry 22 : {, a map of 3 */ + 0x18, 0xDD, 0x83, /* Map entry 221 : [ an array of 3 */ + 0x19, 0x08, 0x3F, /* Array item 2111 */ + 0x19, 0x08, 0x40, /* Array item 2112 */ + 0x19, 0x08, 0x41, /* Array item 2113 */ + 0x18, 0xDE, 0x18, 0xDE, /* Map entry 222 : 222 */ + 0x18, 0xDF, 0xA0, /* Map entry 223 : {} */ + 0x17, 0x17, /* Map entry 23 : 23 */ + 0x03, 0x03, /* Map entry 3 : 3 */ + 0x04, 0x81, /* Map entry 4: [, an array of 1 */ + 0xA0 /* Array entry {}, an empty map */ +}; + + +static int32_t EnterMapCursorTest(void) +{ + QCBORDecodeContext DCtx; + QCBORItem Item1; + int64_t nInt; + QCBORError uErr; + + QCBORDecode_Init(&DCtx, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spNested), 0); + QCBORDecode_EnterMap(&DCtx, NULL); + QCBORDecode_GetInt64InMapN (&DCtx, 3, &nInt); + uErr = QCBORDecode_GetNext(&DCtx, &Item1); + if(uErr != QCBOR_SUCCESS) { + return 701; + } + if(Item1.uDataType != QCBOR_TYPE_INT64) { + return 700; + } + + + int i; + for(i = 0; i < 13; i++) { + QCBORDecode_Init(&DCtx, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spNested), 0); + QCBORDecode_EnterMap(&DCtx, NULL); + int j; + /* Move travesal cursor */ + for(j = 0; j < i; j++) { + QCBORDecode_GetNext(&DCtx, &Item1); + } + QCBORDecode_EnterMapFromMapN(&DCtx, 2); + QCBORDecode_ExitMap(&DCtx); + QCBORDecode_GetNext(&DCtx, &Item1); + if(Item1.label.int64 != 3) { + return 8000; + } + } + + for(i = 0; i < 13; i++) { + QCBORDecode_Init(&DCtx, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spNested), 0); + QCBORDecode_EnterMap(&DCtx, NULL); + int j; + /* Move travesal cursor */ + for(j = 0; j < i; j++) { + QCBORDecode_GetNext(&DCtx, &Item1); + } + QCBORDecode_EnterMapFromMapN(&DCtx, 2); + QCBORDecode_EnterMapFromMapN(&DCtx, 22); + QCBORDecode_ExitMap(&DCtx); + QCBORDecode_GetNext(&DCtx, &Item1); + if(Item1.label.int64 != 23) { + return 8000; + } + } + + for(i = 0; i < 13; i++) { + QCBORDecode_Init(&DCtx, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spNested), 0); + QCBORDecode_EnterMap(&DCtx, NULL); + int j; + /* Move travesal cursor */ + for(j = 0; j < i; j++) { + QCBORDecode_GetNext(&DCtx, &Item1); + } + QCBORDecode_EnterMapFromMapN(&DCtx, 2); + QCBORDecode_EnterMapFromMapN(&DCtx, 22); + for(j = 0; j < i; j++) { + QCBORDecode_GetNext(&DCtx, &Item1); + } + QCBORDecode_EnterArrayFromMapN(&DCtx, 221); + QCBORDecode_ExitArray(&DCtx); + QCBORDecode_ExitMap(&DCtx); + QCBORDecode_GetNext(&DCtx, &Item1); + if(Item1.label.int64 != 23) { + return 8000; + } + QCBORDecode_ExitMap(&DCtx); + QCBORDecode_GetNext(&DCtx, &Item1); + if(Item1.label.int64 != 3) { + return 8000; + } + } + + return 0; +} + + +int32_t EnterMapTest(void) +{ + QCBORItem Item1; + QCBORDecodeContext DCtx; + int32_t nReturn; + QCBORError uErr; + +#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS + QCBORDecode_Init(&DCtx, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spMapOfEmpty), 0); + QCBORDecode_EnterMap(&DCtx, NULL); + + + QCBORDecode_EnterArray(&DCtx, NULL); // Label 0 + QCBORDecode_ExitArray(&DCtx); + + QCBORDecode_EnterArray(&DCtx, NULL); // Label 9 + QCBORDecode_EnterArray(&DCtx, NULL); + QCBORDecode_ExitArray(&DCtx); + QCBORDecode_EnterArray(&DCtx, NULL); + QCBORDecode_ExitArray(&DCtx); + QCBORDecode_ExitArray(&DCtx); + + QCBORDecode_EnterMap(&DCtx, NULL); // Label 8 + QCBORDecode_EnterArray(&DCtx, NULL); + QCBORDecode_ExitArray(&DCtx); + QCBORDecode_EnterMap(&DCtx, NULL); + QCBORDecode_ExitMap(&DCtx); + QCBORDecode_EnterArray(&DCtx, NULL); + QCBORDecode_ExitArray(&DCtx); + QCBORDecode_ExitMap(&DCtx); + + QCBORDecode_EnterMap(&DCtx, NULL); // Label4 + QCBORDecode_ExitMap(&DCtx); + + QCBORDecode_EnterArray(&DCtx, NULL); // Label 5 + QCBORDecode_ExitArray(&DCtx); + + QCBORDecode_EnterArray(&DCtx, NULL); // Label 6 + QCBORDecode_EnterArray(&DCtx, NULL); + QCBORDecode_ExitArray(&DCtx); + QCBORDecode_EnterArray(&DCtx, NULL); + QCBORDecode_ExitArray(&DCtx); + QCBORDecode_ExitArray(&DCtx); + + QCBORDecode_ExitMap(&DCtx); + + uErr = QCBORDecode_Finish(&DCtx); + if(uErr != QCBOR_SUCCESS){ + return 3011; + } + +#ifndef QCBOR_DISABLE_NON_INTEGER_LABELS + (void)pValidMapIndefEncoded; + nReturn = SpiffyDecodeBasicMap(UsefulBuf_FROM_BYTE_ARRAY_LITERAL(pValidMapIndefEncoded)); + if(nReturn) { + return nReturn + 20000; + } +#endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */ +#endif /* ! QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS */ + +#ifndef QCBOR_DISABLE_NON_INTEGER_LABELS + QCBORItem ArrayItem; + + nReturn = SpiffyDecodeBasicMap(UsefulBuf_FROM_BYTE_ARRAY_LITERAL(pValidMapEncoded)); + if(nReturn) { + return nReturn; + } + + + + // These tests confirm the cursor is at the right place after entering + // a map or array + const UsefulBufC ValidEncodedMap = UsefulBuf_FROM_BYTE_ARRAY_LITERAL(pValidMapEncoded); + + // Confirm cursor is at right place + QCBORDecode_Init(&DCtx, ValidEncodedMap, 0); + QCBORDecode_EnterMap(&DCtx, NULL); + QCBORDecode_GetNext(&DCtx, &Item1); + if(Item1.uDataType != QCBOR_TYPE_INT64) { + return 2001; + } + + + QCBORDecode_Init(&DCtx, ValidEncodedMap, 0); + QCBORDecode_VGetNext(&DCtx, &Item1); + QCBORDecode_VGetNext(&DCtx, &Item1); + QCBORDecode_EnterArray(&DCtx, &ArrayItem); + if(ArrayItem.uLabelType != QCBOR_TYPE_TEXT_STRING || + UsefulBuf_Compare(ArrayItem.label.string, + UsefulBuf_FROM_SZ_LITERAL("an array of two strings"))) { + return 2051; + } + QCBORDecode_GetNext(&DCtx, &Item1); + if(Item1.uDataType != QCBOR_TYPE_TEXT_STRING) { + return 2002; + } + QCBORDecode_ExitArray(&DCtx); + QCBORDecode_EnterMap(&DCtx, &ArrayItem); + if(ArrayItem.uLabelType != QCBOR_TYPE_TEXT_STRING || + UsefulBuf_Compare(ArrayItem.label.string, + UsefulBuf_FROM_SZ_LITERAL("map in a map"))) { + return 2052; + } + + + QCBORDecode_Init(&DCtx, ValidEncodedMap, 0); + QCBORDecode_EnterMap(&DCtx, NULL); + QCBORDecode_GetNext(&DCtx, &Item1); + QCBORDecode_GetNext(&DCtx, &Item1); + QCBORDecode_GetNext(&DCtx, &Item1); + QCBORDecode_EnterMapFromMapSZ(&DCtx, "map in a map"); + QCBORDecode_GetNext(&DCtx, &Item1); + if(Item1.uDataType != QCBOR_TYPE_BYTE_STRING) { + return 2003; + } + + QCBORDecode_Init(&DCtx, ValidEncodedMap, 0); + QCBORDecode_EnterMap(&DCtx, NULL); + QCBORDecode_GetNext(&DCtx, &Item1); + QCBORDecode_GetNext(&DCtx, &Item1); + QCBORDecode_GetNext(&DCtx, &Item1); + QCBORDecode_GetNext(&DCtx, &Item1); + QCBORDecode_GetNext(&DCtx, &Item1); + QCBORDecode_GetNext(&DCtx, &Item1); + QCBORDecode_GetNext(&DCtx, &Item1); + QCBORDecode_EnterArrayFromMapSZ(&DCtx, "an array of two strings"); + QCBORDecode_GetNext(&DCtx, &Item1); + if(Item1.uDataType != QCBOR_TYPE_TEXT_STRING) { + return 2004; + } + + QCBORDecode_Init(&DCtx, ValidEncodedMap, 0); + QCBORDecode_EnterMap(&DCtx, NULL); + QCBORDecode_EnterArrayFromMapSZ(&DCtx, "an array of two strings"); + QCBORDecode_ExitArray(&DCtx); + QCBORDecode_GetNext(&DCtx, &Item1); + if(Item1.uDataType != QCBOR_TYPE_MAP && Item1.uLabelAlloc != QCBOR_TYPE_TEXT_STRING) { + return 2006; + } + QCBORDecode_ExitMap(&DCtx); + if(QCBORDecode_GetNext(&DCtx, &Item1) != QCBOR_ERR_NO_MORE_ITEMS) { + return 2007; + } +#endif /* !QCBOR_DISABLE_NON_INTEGER_LABELS */ + + QCBORDecode_Init(&DCtx, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spSimpleArray), 0); + QCBORDecode_EnterArray(&DCtx, NULL); + int64_t nDecodedInt2; + + UsefulBufC String; + QCBORDecode_GetTextStringInMapN(&DCtx, 88, &String); + uErr = QCBORDecode_GetAndResetError(&DCtx); + if(uErr != QCBOR_ERR_MAP_NOT_ENTERED){ + return 2009; + } +#ifndef QCBOR_DISABLE_NON_INTEGER_LABELS + QCBORDecode_GetInt64InMapSZ(&DCtx, "another int", &nDecodedInt2); + uErr = QCBORDecode_GetAndResetError(&DCtx); + if(uErr != QCBOR_ERR_MAP_NOT_ENTERED){ + return 2008; + } +#endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */ + + + QCBORDecode_Init(&DCtx, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spEmptyMap), 0); + QCBORDecode_EnterMap(&DCtx, NULL); + // This will fail because the map is empty. + QCBORDecode_GetInt64InMapSZ(&DCtx, "another int", &nDecodedInt2); + uErr = QCBORDecode_GetAndResetError(&DCtx); + if(uErr != QCBOR_ERR_LABEL_NOT_FOUND){ + return 2010; + } + QCBORDecode_ExitMap(&DCtx); + uErr = QCBORDecode_Finish(&DCtx); + if(uErr != QCBOR_SUCCESS){ + return 2011; + } + + +#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS + QCBORDecode_Init(&DCtx, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spEmptyInDefinteLengthMap), 0); + QCBORDecode_EnterMap(&DCtx, NULL); + // This will fail because the map is empty. + QCBORDecode_GetInt64InMapSZ(&DCtx, "another int", &nDecodedInt2); + uErr = QCBORDecode_GetAndResetError(&DCtx); + if(uErr != QCBOR_ERR_LABEL_NOT_FOUND){ + return 2012; + } + QCBORDecode_ExitMap(&DCtx); + uErr = QCBORDecode_Finish(&DCtx); + if(uErr != QCBOR_SUCCESS){ + return 2013; + } +#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS */ + + + QCBORDecode_Init(&DCtx, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spArrayOfEmpty), 0); + QCBORDecode_EnterArray(&DCtx, NULL); + QCBORDecode_GetByteString(&DCtx, &String); + QCBORDecode_EnterMap(&DCtx, NULL); + QCBORDecode_ExitMap(&DCtx); + QCBORDecode_EnterArray(&DCtx, NULL); + QCBORDecode_ExitArray(&DCtx); + QCBORDecode_GetInt64(&DCtx, &nDecodedInt2); + QCBORDecode_ExitArray(&DCtx); + uErr = QCBORDecode_Finish(&DCtx); + if(uErr != QCBOR_SUCCESS) { + return 2014; + } + + int64_t nInt; + QCBORDecode_Init(&DCtx, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spRecoverableMapErrors), 0); + QCBORDecode_EnterMap(&DCtx, NULL); +#ifndef QCBOR_DISABLE_TAGS + QCBORDecode_GetInt64InMapN(&DCtx, 0x01, &nInt); + uErr = QCBORDecode_GetError(&DCtx); + if(uErr != QCBOR_ERR_TOO_MANY_TAGS) { + return 2021; + } + if(QCBORDecode_GetNthTagOfLast(&DCtx, 0) != CBOR_TAG_INVALID64) { + return 2121; + } + (void)QCBORDecode_GetAndResetError(&DCtx); +#endif + + + QCBORDecode_GetInt64InMapN(&DCtx, 0x03, &nInt); + uErr = QCBORDecode_GetAndResetError(&DCtx); + if(uErr != QCBOR_ERR_INT_OVERFLOW) { + return 2023; + } + +#ifndef QCBOR_DISABLE_TAGS + QCBORDecode_GetEpochDateInMapN(&DCtx, 0x04, QCBOR_TAG_REQUIREMENT_TAG, &nInt); + uErr = QCBORDecode_GetAndResetError(&DCtx); + if(uErr != FLOAT_ERR_CODE_NO_FLOAT_HW(QCBOR_ERR_DATE_OVERFLOW)) { + return 2024; + } +#endif + + QCBORDecode_GetInt64InMapN(&DCtx, 0x05, &nInt); + uErr = QCBORDecode_GetAndResetError(&DCtx); + if(uErr != QCBOR_ERR_DUPLICATE_LABEL) { + return 2025; + } + + QCBORDecode_GetInt64InMapN(&DCtx, 0x08, &nInt); + + QCBORDecode_ExitMap(&DCtx); + uErr = QCBORDecode_Finish(&DCtx); + if(uErr != QCBOR_SUCCESS) { + return 2026; + } + + QCBORDecode_Init(&DCtx, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spUnRecoverableMapError1), 0); + QCBORDecode_EnterMap(&DCtx, NULL); + QCBORDecode_GetInt64InMapN(&DCtx, 0x01, &nInt); + uErr = QCBORDecode_GetAndResetError(&DCtx); + if(uErr != QCBOR_ERR_BAD_BREAK) { + return 2030; + } + +#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS + QCBORDecode_Init(&DCtx, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spUnRecoverableMapError2), 0); + QCBORDecode_EnterMap(&DCtx, NULL); + QCBORDecode_GetInt64InMapN(&DCtx, 0x01, &nInt); + uErr = QCBORDecode_GetAndResetError(&DCtx); + if(uErr != QCBOR_ERR_NO_MORE_ITEMS) { + return 2031; + } + + QCBORDecode_Init(&DCtx, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spUnRecoverableMapError3), 0); + QCBORDecode_EnterMap(&DCtx, NULL); + QCBORDecode_GetInt64InMapN(&DCtx, 0x01, &nInt); + uErr = QCBORDecode_GetAndResetError(&DCtx); + if(uErr != QCBOR_ERR_HIT_END) { + return 2032; + } + + QCBORDecode_Init(&DCtx, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spUnRecoverableMapError4), 0); + QCBORDecode_EnterMap(&DCtx, NULL); + QCBORDecode_GetInt64InMapN(&DCtx, 0x01, &nInt); + uErr = QCBORDecode_GetAndResetError(&DCtx); + if(uErr != QCBOR_ERR_ARRAY_DECODE_NESTING_TOO_DEEP) { + return 2033; + } +#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS */ + +#ifndef QCBOR_DISABLE_NON_INTEGER_LABELS + QCBORDecode_Init(&DCtx, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(pValidMapEncoded), 0); + QCBORDecode_VGetNextConsume(&DCtx, &Item1); + if(Item1.uDataType != QCBOR_TYPE_MAP) { + return 2401; + } + if(QCBORDecode_GetError(&DCtx)) { + return 2402; + } + + QCBORDecode_Init(&DCtx, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(pValidMapEncoded), 0); + QCBORDecode_VGetNext(&DCtx, &Item1); + if(Item1.uDataType != QCBOR_TYPE_MAP || + Item1.val.uCount != 3 || + Item1.uNextNestLevel != 1) { + return 2403; + } + if(QCBORDecode_GetError(&DCtx)) { + return 2404; + } + QCBORDecode_VGetNextConsume(&DCtx, &Item1); + if(Item1.uDataType != QCBOR_TYPE_INT64 || + Item1.uNextNestLevel != 1 || + Item1.val.int64 != 42) { + return 2405; + } + if(QCBORDecode_GetError(&DCtx)) { + return 2406; + } + QCBORDecode_VGetNextConsume(&DCtx, &Item1); + if(Item1.uDataType != QCBOR_TYPE_ARRAY || + Item1.uNestingLevel != 1 || + Item1.uNextNestLevel != 1 || + Item1.val.uCount != 2) { + return 2407; + } + if(QCBORDecode_GetError(&DCtx)) { + return 2408; + } + QCBORDecode_VGetNextConsume(&DCtx, &Item1); + if(Item1.uDataType != QCBOR_TYPE_MAP || + Item1.uNestingLevel != 1 || + Item1.uNextNestLevel != 0 || + Item1.val.uCount != 4) { + return 2409; + } + if(QCBORDecode_GetError(&DCtx)) { + return 2410; + } +#endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */ + + nReturn = DecodeNestedIterate(); + + + QCBORDecode_Init(&DCtx, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(not_well_formed_submod_section), 0); + QCBORDecode_EnterMap(&DCtx, NULL); + QCBORDecode_EnterMapFromMapN(&DCtx, 20); + if(QCBORDecode_GetError(&DCtx) != QCBOR_ERR_BAD_INT) { + return 2500; + } + + QCBORDecode_Init(&DCtx, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spBadConsumeInput), 0); + QCBORDecode_VGetNextConsume(&DCtx, &Item1); + if(QCBORDecode_GetError(&DCtx) != QCBOR_ERR_NO_MORE_ITEMS) { + return 2600; + } + +#ifndef QCBOR_DISABLE_TAGS + QCBORDecode_Init(&DCtx, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spBadConsumeInput2), 0); + QCBORDecode_VGetNextConsume(&DCtx, &Item1); + if(QCBORDecode_GetError(&DCtx) != QCBOR_SUCCESS) { + return 2700; + } +#endif + + + QCBORDecode_Init(&DCtx, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spBadConsumeInput4), 0); + QCBORDecode_VGetNextConsume(&DCtx, &Item1); +#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS + if(QCBORDecode_GetError(&DCtx) != QCBOR_SUCCESS) { + return 2900; + } +#else + if(QCBORDecode_GetError(&DCtx) != QCBOR_ERR_INDEF_LEN_ARRAYS_DISABLED) { + return 2901; + } +#endif + + QCBORDecode_Init(&DCtx, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spBadConsumeInput5), 0); + QCBORDecode_VGetNextConsume(&DCtx, &Item1); + if(QCBORDecode_GetError(&DCtx) != QCBOR_ERR_MAP_LABEL_TYPE) { + return 3000; + } + + nReturn = EnterMapCursorTest(); + + return nReturn; +} + + +struct NumberConversion { + char *szDescription; + UsefulBufC CBOR; + int64_t nConvertedToInt64; + QCBORError uErrorInt64; + uint64_t uConvertToUInt64; + QCBORError uErrorUint64; + double dConvertToDouble; + QCBORError uErrorDouble; +}; + +#ifndef QCBOR_DISABLE_EXP_AND_MANTISSA +#define EXP_AND_MANTISSA_ERROR(x) x +#else +#define EXP_AND_MANTISSA_ERROR(x) QCBOR_ERR_UNEXPECTED_TYPE +#endif + + +static const struct NumberConversion NumberConversions[] = { +#ifndef QCBOR_DISABLE_TAGS + { + "Big float: INT64_MIN * 2e-1 to test handling of INT64_MIN", + {(uint8_t[]){0xC5, 0x82, 0x20, + 0x3B, 0x7f, 0xff, 0xff, 0xff, 0xff, 0x0ff, 0xff, 0xff, + }, 15}, + -4611686018427387904, /* INT64_MIN / 2 */ + EXP_AND_MANTISSA_ERROR(QCBOR_SUCCESS), + 0, + EXP_AND_MANTISSA_ERROR(QCBOR_ERR_NUMBER_SIGN_CONVERSION), + -4.6116860184273879E+18, + FLOAT_ERR_CODE_NO_FLOAT_HW(EXP_AND_MANTISSA_ERROR(QCBOR_SUCCESS)) + }, + { + "too large to fit into int64_t", + {(uint8_t[]){0xc3, 0x48, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, 10}, + 0, + QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW, + 0, + QCBOR_ERR_NUMBER_SIGN_CONVERSION, + ((double)INT64_MIN) + 1 , + FLOAT_ERR_CODE_NO_FLOAT_HW(QCBOR_SUCCESS) + }, + { + "largest negative int that fits in int64_t", + {(uint8_t[]){0xc3, 0x48, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}, 10}, + INT64_MIN, + QCBOR_SUCCESS, + 0, + QCBOR_ERR_NUMBER_SIGN_CONVERSION, + (double)INT64_MIN, + FLOAT_ERR_CODE_NO_FLOAT_HW(QCBOR_SUCCESS) + }, + { + "negative bignum -1", + {(uint8_t[]){0xc3, 0x41, 0x00}, 3}, + -1, + QCBOR_SUCCESS, + 0, + QCBOR_ERR_NUMBER_SIGN_CONVERSION, + -1.0, + FLOAT_ERR_CODE_NO_FLOAT_HW(QCBOR_SUCCESS) + }, + { + "Decimal Fraction with positive bignum 257 * 10e3", + {(uint8_t[]){0xC4, 0x82, 0x1B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, + 0xC2, 0x42, 0x01, 0x01}, 15}, + 257000, + EXP_AND_MANTISSA_ERROR(QCBOR_SUCCESS), + 257000, + EXP_AND_MANTISSA_ERROR(QCBOR_SUCCESS), + 257000.0, + FLOAT_ERR_CODE_NO_FLOAT_HW(EXP_AND_MANTISSA_ERROR(QCBOR_SUCCESS)) + }, + { + "bigfloat with negative bignum -258 * 2e3", + {(uint8_t[]){0xC5, 0x82, 0x1B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, + 0xC3, 0x42, 0x01, 0x01}, 15}, + -2064, + EXP_AND_MANTISSA_ERROR(QCBOR_SUCCESS), + 0, + EXP_AND_MANTISSA_ERROR(QCBOR_ERR_NUMBER_SIGN_CONVERSION), + -2064.0, + FLOAT_ERR_CODE_NO_FLOAT_HW(EXP_AND_MANTISSA_ERROR(QCBOR_SUCCESS)) + }, + { + "bigfloat with positive bignum 257 * 2e3", + {(uint8_t[]){0xC5, 0x82, 0x1B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, + 0xC2, 0x42, 0x01, 0x01}, 15}, + 2056, + EXP_AND_MANTISSA_ERROR(QCBOR_SUCCESS), + 2056, + EXP_AND_MANTISSA_ERROR(QCBOR_SUCCESS), + 2056.0, + FLOAT_ERR_CODE_NO_FLOAT_HW(EXP_AND_MANTISSA_ERROR(QCBOR_SUCCESS)) + }, + { + "negative bignum 0xc349010000000000000000 -18446744073709551617", + {(uint8_t[]){0xc3, 0x49, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, 11}, + 0, + QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW, + 0, + QCBOR_ERR_NUMBER_SIGN_CONVERSION, + -18446744073709551617.0, + FLOAT_ERR_CODE_NO_FLOAT_HW(QCBOR_SUCCESS) + }, +#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS + { + "Positive bignum 0x01020304 indefinite length string", + {(uint8_t[]){0xC2, 0x5f, 0x42, 0x01, 0x02, 0x41, 0x03, 0x41, 0x04, 0xff}, 10}, + 0x01020304, + QCBOR_SUCCESS, + 0x01020304, + QCBOR_SUCCESS, + 16909060.0, + FLOAT_ERR_CODE_NO_FLOAT_HW(QCBOR_SUCCESS) + }, +#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS */ + { + "Decimal Fraction with neg bignum [9223372036854775807, -4759477275222530853137]", + {(uint8_t[]){0xC4, 0x82, 0x1B, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xC3, 0x4A, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x10,}, 23}, + 0, + EXP_AND_MANTISSA_ERROR(QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW), + 0, + EXP_AND_MANTISSA_ERROR(QCBOR_ERR_NUMBER_SIGN_CONVERSION), + -INFINITY, + FLOAT_ERR_CODE_NO_FLOAT_HW(EXP_AND_MANTISSA_ERROR(QCBOR_SUCCESS)) + }, + { + "big float [9223372036854775806, 9223372036854775806]", + {(uint8_t[]){0xC5, 0x82, 0x1B, 0x7f, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, + 0x1B, 0x7f, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE}, 20}, + 0, + EXP_AND_MANTISSA_ERROR(QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW), + 0, + EXP_AND_MANTISSA_ERROR(QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW), + INFINITY, + FLOAT_ERR_CODE_NO_FLOAT_HW(EXP_AND_MANTISSA_ERROR(QCBOR_SUCCESS)) + }, + { + "Big float 3 * 2^^2", + {(uint8_t[]){0xC5, 0x82, 0x02, 0x03}, 4}, + 12, + EXP_AND_MANTISSA_ERROR(QCBOR_SUCCESS), + 12, + EXP_AND_MANTISSA_ERROR(QCBOR_SUCCESS), + 12.0, + FLOAT_ERR_CODE_NO_FLOAT_HW(EXP_AND_MANTISSA_ERROR(QCBOR_SUCCESS)) + }, + { + "Decimal fraction 3/10", + {(uint8_t[]){0xC4, 0x82, 0x20, 0x03}, 4}, + 0, + EXP_AND_MANTISSA_ERROR(QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW), + 0, + EXP_AND_MANTISSA_ERROR(QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW), + 0.30000000000000004, + FLOAT_ERR_CODE_NO_FLOAT_HW(EXP_AND_MANTISSA_ERROR(QCBOR_SUCCESS)) + }, + { + "Decimal fraction -3/10", + {(uint8_t[]){0xC4, 0x82, 0x20, 0x22}, 4}, + 0, + EXP_AND_MANTISSA_ERROR(QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW), + 0, + EXP_AND_MANTISSA_ERROR(QCBOR_ERR_NUMBER_SIGN_CONVERSION), + -0.30000000000000004, + FLOAT_ERR_CODE_NO_FLOAT_HW(EXP_AND_MANTISSA_ERROR(QCBOR_SUCCESS)) + }, + { + "Decimal fraction -3/10, neg bignum mantissa", + {(uint8_t[]){0xC4, 0x82, 0x20, 0xc3, 0x41, 0x02}, 6}, + 0, + EXP_AND_MANTISSA_ERROR(QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW), + 0, + EXP_AND_MANTISSA_ERROR(QCBOR_ERR_NUMBER_SIGN_CONVERSION), + -0.30000000000000004, + FLOAT_ERR_CODE_NO_FLOAT_HW(EXP_AND_MANTISSA_ERROR(QCBOR_SUCCESS)) + }, + { + "extreme pos bignum", + {(uint8_t[]){0xc2, 0x59, 0x01, 0x90, + // 50 rows of 8 is 400 digits. + 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, + 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, + 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, + 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, + 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, + 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, + 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, + 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, + 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, + 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, + 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, + 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, + 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, + 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, + 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, + 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, + 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, + 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, + 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, + 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, + 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, + 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, + 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, + 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, + 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, + 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, + 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, + 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, + 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, + 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, + 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, + 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, + 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, + 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, + 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, + 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, + 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, + 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, + 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, + 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, + 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, + 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, + 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, + 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, + 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, + 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, + 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, + 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, + 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, + 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0}, + 404}, + 0, + QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW, + 0, + QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW, + INFINITY, + FLOAT_ERR_CODE_NO_FLOAT_HW(QCBOR_SUCCESS), + }, + + { + "extreme neg bignum", + {(uint8_t[]){0xc3, 0x59, 0x01, 0x90, + // 50 rows of 8 is 400 digits. + 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, + 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, + 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, + 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, + 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, + 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, + 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, + 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, + 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, + 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, + 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, + 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, + 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, + 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, + 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, + 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, + 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, + 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, + 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, + 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, + 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, + 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, + 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, + 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, + 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, + 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, + 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, + 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, + 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, + 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, + 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, + 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, + 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, + 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, + 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, + 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, + 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, + 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, + 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, + 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, + 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, + 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, + 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, + 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, + 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, + 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, + 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, + 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, + 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, + 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0}, + 404}, + 0, + QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW, + 0, + QCBOR_ERR_NUMBER_SIGN_CONVERSION, + -INFINITY, + FLOAT_ERR_CODE_NO_FLOAT_HW(QCBOR_SUCCESS) + }, + + { + "big float underflow [9223372036854775806, -9223372036854775806]", + {(uint8_t[]){ + 0xC5, 0x82, + 0x3B, 0x7f, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, + 0x1B, 0x7f, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE}, 20}, + 0, + EXP_AND_MANTISSA_ERROR(QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW), + 0, + EXP_AND_MANTISSA_ERROR(QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW), + 0, + FLOAT_ERR_CODE_NO_FLOAT_HW(EXP_AND_MANTISSA_ERROR(QCBOR_SUCCESS)) + }, + + { + "bigfloat that evaluates to -INFINITY", + {(uint8_t[]){ + 0xC5, 0x82, + 0x1B, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, + 0xC3, 0x42, 0x01, 0x01}, 15}, + 0, + EXP_AND_MANTISSA_ERROR(QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW), + 0, + EXP_AND_MANTISSA_ERROR(QCBOR_ERR_NUMBER_SIGN_CONVERSION), + -INFINITY, + FLOAT_ERR_CODE_NO_FLOAT_HW(EXP_AND_MANTISSA_ERROR(QCBOR_SUCCESS)) + }, + { + "Positive bignum 0xffff", + {(uint8_t[]){0xC2, 0x42, 0xff, 0xff}, 4}, + 65536-1, + QCBOR_SUCCESS, + 0xffff, + QCBOR_SUCCESS, + 65535.0, + FLOAT_ERR_CODE_NO_FLOAT_HW(QCBOR_SUCCESS) + }, +#endif /* QCBOR_DISABLE_TAGS */ + { + "Positive integer 18446744073709551615", + {(uint8_t[]){0x1b, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}, 9}, + 0, + QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW, + 18446744073709551615ULL, + QCBOR_SUCCESS, + 18446744073709551615.0, + FLOAT_ERR_CODE_NO_FLOAT_HW(QCBOR_SUCCESS) + }, + + { + "Postive integer 0", + {(uint8_t[]){0x0}, 1}, + 0LL, + QCBOR_SUCCESS, + 0ULL, + QCBOR_SUCCESS, + 0.0, + FLOAT_ERR_CODE_NO_FLOAT_HW(QCBOR_SUCCESS) + }, + { + "Negative integer -18446744073709551616", + {(uint8_t[]){0x3b, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }, 9}, + -9223372036854775807-1, // INT64_MIN + QCBOR_SUCCESS, + 0ULL, + QCBOR_ERR_NUMBER_SIGN_CONVERSION, + -9223372036854775808.0, + FLOAT_ERR_CODE_NO_FLOAT_HW(QCBOR_SUCCESS) + }, + { + "Double Floating point value 100.3", + {(uint8_t[]){0xfb, 0x40, 0x59, 0x13, 0x33, 0x33, 0x33, 0x33, 0x33}, 9}, + 100L, + FLOAT_ERR_CODE_NO_FLOAT_HW(QCBOR_SUCCESS), + 100ULL, + FLOAT_ERR_CODE_NO_FLOAT_HW(QCBOR_SUCCESS), + 100.3, + FLOAT_ERR_CODE_NO_FLOAT(QCBOR_SUCCESS), + }, + { + "Floating point value NaN 0xfa7fc00000", + {(uint8_t[]){0xfa, 0x7f, 0xc0, 0x00, 0x00}, 5}, + 0, + FLOAT_ERR_CODE_NO_FLOAT_HW(QCBOR_ERR_FLOAT_EXCEPTION), + 0, + FLOAT_ERR_CODE_NO_FLOAT_HW(QCBOR_ERR_FLOAT_EXCEPTION), + NAN, + FLOAT_ERR_CODE_NO_FLOAT_HW(QCBOR_SUCCESS), + }, + { + "half-precision Floating point value -4", + {(uint8_t[]){0xf9, 0xc4, 0x00}, 3}, + // Normal case with all enabled. + -4, + FLOAT_ERR_CODE_NO_HALF_PREC_NO_FLOAT_HW(QCBOR_SUCCESS), + 0, + FLOAT_ERR_CODE_NO_HALF_PREC_NO_FLOAT_HW(QCBOR_ERR_NUMBER_SIGN_CONVERSION), + -4.0, + FLOAT_ERR_CODE_NO_HALF_PREC(QCBOR_SUCCESS) + }, + { + "+inifinity single precision", + {(uint8_t[]){0xfa, 0x7f, 0x80, 0x00, 0x00}, 5}, + 0, + FLOAT_ERR_CODE_NO_FLOAT_HW(QCBOR_ERR_FLOAT_EXCEPTION), + 0, + FLOAT_ERR_CODE_NO_FLOAT_HW(QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW), + INFINITY, + FLOAT_ERR_CODE_NO_FLOAT_HW(QCBOR_SUCCESS) + }, +}; + + + + +static int32_t SetUpDecoder(QCBORDecodeContext *DCtx, UsefulBufC CBOR, UsefulBuf Pool) +{ + QCBORDecode_Init(DCtx, CBOR, QCBOR_DECODE_MODE_NORMAL); +#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS + if(QCBORDecode_SetMemPool(DCtx, Pool, 0)) { + return 1; + } +#else /* QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS */ + (void)Pool; +#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS */ + return 0; +} + + +int32_t IntegerConvertTest(void) +{ + const int nNumTests = C_ARRAY_COUNT(NumberConversions, + struct NumberConversion); + + for(int nIndex = 0; nIndex < nNumTests; nIndex++) { + const struct NumberConversion *pF = &NumberConversions[nIndex]; + + // Set up the decoding context including a memory pool so that + // indefinite length items can be checked + QCBORDecodeContext DCtx; + UsefulBuf_MAKE_STACK_UB(Pool, 100); + + /* ----- test conversion to int64_t ------ */ + if(SetUpDecoder(&DCtx, pF->CBOR, Pool)) { + return (int32_t)(3333+nIndex); + } + + int64_t nInt; + QCBORDecode_GetInt64ConvertAll(&DCtx, 0xffff, &nInt); + if(QCBORDecode_GetError(&DCtx) != pF->uErrorInt64) { + return (int32_t)(2000+nIndex); + } + if(pF->uErrorInt64 == QCBOR_SUCCESS && pF->nConvertedToInt64 != nInt) { + return (int32_t)(3000+nIndex); + } + + /* ----- test conversion to uint64_t ------ */ + if(SetUpDecoder(&DCtx, pF->CBOR, Pool)) { + return (int32_t)(3333+nIndex); + } + + uint64_t uInt; + QCBORDecode_GetUInt64ConvertAll(&DCtx, 0xffff, &uInt); + if(QCBORDecode_GetError(&DCtx) != pF->uErrorUint64) { + return (int32_t)(4000+nIndex); + } + if(pF->uErrorUint64 == QCBOR_SUCCESS && pF->uConvertToUInt64 != uInt) { + return (int32_t)(5000+nIndex); + } + + /* ----- test conversion to double ------ */ + if(SetUpDecoder(&DCtx, pF->CBOR, Pool)) { + return (int32_t)(3333+nIndex); + } + +#ifndef USEFULBUF_DISABLE_ALL_FLOAT + double d; + QCBORDecode_GetDoubleConvertAll(&DCtx, 0xffff, &d); + if(QCBORDecode_GetError(&DCtx) != pF->uErrorDouble) { + return (int32_t)(6000+nIndex); + } + if(pF->uErrorDouble == QCBOR_SUCCESS) { + if(isnan(pF->dConvertToDouble)) { + // NaN's can't be compared for equality. A NaN is + // never equal to anything including another NaN + if(!isnan(d)) { + return (int32_t)(7000+nIndex); + } + } else { + if(pF->dConvertToDouble != d) { + return (int32_t)(8000+nIndex); + } + } + } +#endif /* USEFULBUF_DISABLE_ALL_FLOAT */ + } + + return 0; +} + +#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS + +int32_t CBORTestIssue134(void) +{ + QCBORDecodeContext DCtx; + QCBORItem Item; + QCBORError uCBORError; + const uint8_t spTestIssue134[] = { 0x5F, 0x40, 0xFF }; + + QCBORDecode_Init(&DCtx, + UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spTestIssue134), + QCBOR_DECODE_MODE_NORMAL); + + UsefulBuf_MAKE_STACK_UB(StringBuf, 200); + QCBORDecode_SetMemPool(&DCtx, StringBuf, false); + + do { + uCBORError = QCBORDecode_GetNext(&DCtx, &Item); + } while (QCBOR_SUCCESS == uCBORError); + + uCBORError = QCBORDecode_Finish(&DCtx); + + return (int32_t)uCBORError; +} + +#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS */ + + + +static const uint8_t spSequenceTestInput[] = { + /* 1. The valid date string "1985-04-12" */ + 0x6a, '1','9','8','5','-','0','4','-','1','2', // Date string + + /* 2. */ + 0x00, + + /* 3. A valid epoch date, 1400000000; Tue, 13 May 2014 16:53:20 GMT */ + 0x1a, 0x53, 0x72, 0x4E, 0x00, + + /* 4. */ + 0x62, 'h', 'i', +}; + + +int32_t CBORSequenceDecodeTests(void) +{ + QCBORDecodeContext DCtx; + QCBORItem Item; + QCBORError uCBORError; + size_t uConsumed; + + // --- Test a sequence with extra bytes --- + + QCBORDecode_Init(&DCtx, + UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spSequenceTestInput), + QCBOR_DECODE_MODE_NORMAL); + + // Get 1. + uCBORError = QCBORDecode_GetNext(&DCtx, &Item); + if(uCBORError != QCBOR_SUCCESS) { + return 1; + } + if(Item.uDataType != QCBOR_TYPE_TEXT_STRING ) { + return 2; + } + + uCBORError = QCBORDecode_PartialFinish(&DCtx, &uConsumed); + if(uCBORError != QCBOR_ERR_EXTRA_BYTES || + uConsumed != 11) { + return 102; + } + + // Get 2. + uCBORError = QCBORDecode_GetNext(&DCtx, &Item); + if(uCBORError != QCBOR_SUCCESS) { + return 66; + } + + uCBORError = QCBORDecode_PartialFinish(&DCtx, &uConsumed); + if(uCBORError != QCBOR_ERR_EXTRA_BYTES || + uConsumed != 12) { + return 102; + } + + // Get 3. + uCBORError = QCBORDecode_GetNext(&DCtx, &Item); + if(uCBORError != QCBOR_SUCCESS) { + return 2; + } + if(Item.uDataType != QCBOR_TYPE_INT64) { + return 3; + } + + // A sequence can have stuff at the end that may + // or may not be valid CBOR. The protocol decoder knows + // when to stop by definition of the protocol, not + // when the top-level map or array is ended. + // Finish still has to be called to know that + // maps and arrays (if there were any) were closed + // off correctly. When called like this it + // must return the error QCBOR_ERR_EXTRA_BYTES. + uCBORError = QCBORDecode_Finish(&DCtx); + if(uCBORError != QCBOR_ERR_EXTRA_BYTES) { + return 4; + } + + // --- Test an empty input ---- + uint8_t empty[1]; + UsefulBufC Empty = {empty, 0}; + QCBORDecode_Init(&DCtx, + Empty, + QCBOR_DECODE_MODE_NORMAL); + + uCBORError = QCBORDecode_Finish(&DCtx); + if(uCBORError != QCBOR_SUCCESS) { + return 5; + } + + + // --- Sequence with unclosed indefinite length array --- + static const uint8_t xx[] = {0x01, 0x9f, 0x02}; + + QCBORDecode_Init(&DCtx, + UsefulBuf_FROM_BYTE_ARRAY_LITERAL(xx), + QCBOR_DECODE_MODE_NORMAL); + + // Get the first item + uCBORError = QCBORDecode_GetNext(&DCtx, &Item); + if(uCBORError != QCBOR_SUCCESS) { + return 7; + } + if(Item.uDataType != QCBOR_TYPE_INT64) { + return 8; + } + + // Get a second item + uCBORError = QCBORDecode_GetNext(&DCtx, &Item); +#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS + if(uCBORError != QCBOR_SUCCESS) { + return 9; + } + if(Item.uDataType != QCBOR_TYPE_ARRAY) { + return 10; + } + + // Try to finish before consuming all bytes to confirm + // that the still-open error is returned. + uCBORError = QCBORDecode_Finish(&DCtx); + if(uCBORError != QCBOR_ERR_ARRAY_OR_MAP_UNCONSUMED) { + return 11; + } +#else /* QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS */ + if(uCBORError != QCBOR_ERR_INDEF_LEN_ARRAYS_DISABLED) { + return 20; + } +#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS */ + + + // --- Sequence with a closed indefinite length array --- + static const uint8_t yy[] = {0x01, 0x9f, 0xff}; + + QCBORDecode_Init(&DCtx, + UsefulBuf_FROM_BYTE_ARRAY_LITERAL(yy), + QCBOR_DECODE_MODE_NORMAL); + + // Get the first item + uCBORError = QCBORDecode_GetNext(&DCtx, &Item); + if(uCBORError != QCBOR_SUCCESS) { + return 12; + } + if(Item.uDataType != QCBOR_TYPE_INT64) { + return 13; + } + + // Get a second item + uCBORError = QCBORDecode_GetNext(&DCtx, &Item); +#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS + + if(uCBORError != QCBOR_SUCCESS) { + return 14; + } + if(Item.uDataType != QCBOR_TYPE_ARRAY) { + return 15; + } + + // Try to finish before consuming all bytes to confirm + // that the still-open error is returned. + uCBORError = QCBORDecode_Finish(&DCtx); + if(uCBORError != QCBOR_SUCCESS) { + return 16; + } +#else /* QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS */ + if(uCBORError != QCBOR_ERR_INDEF_LEN_ARRAYS_DISABLED) { + return 20; + } +#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS */ + + + return 0; +} + + + +int32_t IntToTests(void) +{ + int nErrCode; + int32_t n32; + int16_t n16; + int8_t n8; + uint32_t u32; + uint16_t u16; + uint8_t u8; + uint64_t u64; + + nErrCode = QCBOR_Int64ToInt32(1, &n32); + if(nErrCode == -1 || n32 != 1) { + return 1; + } + + nErrCode = QCBOR_Int64ToInt32((int64_t)INT32_MAX, &n32); + if(nErrCode == -1 || n32 != INT32_MAX) { + return 2; + } + + nErrCode = QCBOR_Int64ToInt32((int64_t)INT32_MIN, &n32); + if(nErrCode == -1 || n32 != INT32_MIN) { + return 3; + } + + nErrCode = QCBOR_Int64ToInt32(((int64_t)INT32_MAX)+1, &n32); + if(nErrCode != -1) { + return 4; + } + + nErrCode = QCBOR_Int64ToInt32(((int64_t)INT32_MIN)-1, &n32); + if(nErrCode != -1) { + return 5; + } + + + nErrCode = QCBOR_Int64ToInt16((int64_t)INT16_MAX, &n16); + if(nErrCode == -1 || n16 != INT16_MAX) { + return 6; + } + + nErrCode = QCBOR_Int64ToInt16((int64_t)INT16_MIN, &n16); + if(nErrCode == -1 || n16 != INT16_MIN) { + return 7; + } + + nErrCode = QCBOR_Int64ToInt16(1, &n16); + if(nErrCode == -1 || n16 != 1) { + return 8; + } + + nErrCode = QCBOR_Int64ToInt16(((int64_t)INT16_MAX)+1, &n16); + if(nErrCode != -1) { + return 9; + } + + nErrCode = QCBOR_Int64ToInt16(((int64_t)INT16_MIN)-1, &n16); + if(nErrCode != -1) { + return 10; + } + + + nErrCode = QCBOR_Int64ToInt8(1, &n8); + if(nErrCode == -1 || n8 != 1) { + return 11; + } + + nErrCode = QCBOR_Int64ToInt8((int64_t)INT8_MAX, &n8); + if(nErrCode == -1 || n8 != INT8_MAX) { + return 12; + } + + nErrCode = QCBOR_Int64ToInt8((int64_t)INT8_MIN, &n8); + if(nErrCode == -1 || n8 != INT8_MIN) { + return 13; + } + + nErrCode = QCBOR_Int64ToInt8(((int64_t)INT8_MAX)+1, &n8); + if(nErrCode != -1) { + return 14; + } + + nErrCode = QCBOR_Int64ToInt8(((int64_t)INT8_MIN)-1, &n8); + if(nErrCode != -1) { + return 15; + } + + + nErrCode = QCBOR_Int64ToUInt32(1, &u32); + if(nErrCode == -1 || u32 != 1) { + return 16; + } + + nErrCode = QCBOR_Int64ToUInt32((int64_t)UINT32_MAX, &u32); + if(nErrCode == -1 || u32 != UINT32_MAX) { + return 17; + } + + nErrCode = QCBOR_Int64ToUInt32((int64_t)0, &u32); + if(nErrCode == -1 || u32 != 0) { + return 18; + } + + nErrCode = QCBOR_Int64ToUInt32(((int64_t)UINT32_MAX)+1, &u32); + if(nErrCode != -1) { + return 19; + } + + nErrCode = QCBOR_Int64ToUInt32((int64_t)-1, &u32); + if(nErrCode != -1) { + return 20; + } + + + nErrCode = QCBOR_Int64ToUInt16((int64_t)UINT16_MAX, &u16); + if(nErrCode == -1 || u16 != UINT16_MAX) { + return 21; + } + + nErrCode = QCBOR_Int64ToUInt16((int64_t)0, &u16); + if(nErrCode == -1 || u16 != 0) { + return 22; + } + + nErrCode = QCBOR_Int64ToUInt16(1, &u16); + if(nErrCode == -1 || u16 != 1) { + return 23; + } + + nErrCode = QCBOR_Int64ToUInt16(((int64_t)UINT16_MAX)+1, &u16); + if(nErrCode != -1) { + return 24; + } + + nErrCode = QCBOR_Int64ToUInt16((int64_t)-1, &u16); + if(nErrCode != -1) { + return 25; + } + + + nErrCode = QCBOR_Int64ToUInt8((int64_t)UINT8_MAX, &u8); + if(nErrCode == -1 || u8 != UINT8_MAX) { + return 26; + } + + nErrCode = QCBOR_Int64ToUInt8((int64_t)0, &u8); + if(nErrCode == -1 || u8 != 0) { + return 27; + } + + nErrCode = QCBOR_Int64ToUInt8(1, &u8); + if(nErrCode == -1 || u8 != 1) { + return 28; + } + + nErrCode = QCBOR_Int64ToUInt8(((int64_t)UINT16_MAX)+1, &u8); + if(nErrCode != -1) { + return 29; + } -}; + nErrCode = QCBOR_Int64ToUInt8((int64_t)-1, &u8); + if(nErrCode != -1) { + return 30; + } + nErrCode = QCBOR_Int64ToUInt64(1, &u64); + if(nErrCode == -1 || u64 != 1) { + return 31; + } + nErrCode = QCBOR_Int64ToUInt64(INT64_MAX, &u64); + if(nErrCode == -1 || u64 != INT64_MAX) { + return 32; + } -static int32_t SetUpDecoder(QCBORDecodeContext *DCtx, UsefulBufC CBOR, UsefulBuf Pool) -{ - QCBORDecode_Init(DCtx, CBOR, QCBOR_DECODE_MODE_NORMAL); -#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS - if(QCBORDecode_SetMemPool(DCtx, Pool, 0)) { - return 1; + nErrCode = QCBOR_Int64ToUInt64((int64_t)0, &u64); + if(nErrCode == -1 || u64 != 0) { + return 33; } -#else /* QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS */ - (void)Pool; -#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS */ + + nErrCode = QCBOR_Int64ToUInt64((int64_t)-1, &u64); + if(nErrCode != -1) { + return 34; + } + return 0; } -int32_t IntegerConvertTest(void) + + +/* +A sequence with + A wrapping bstr + containing a map + 1 + 2 + A wrapping bstr + containing an array + 3 + wrapping bstr + 4 + 5 + 6 + array + 7 + 8 + */ + +static UsefulBufC EncodeBstrWrapTestData(UsefulBuf OutputBuffer) { - const int nNumTests = C_ARRAY_COUNT(NumberConversions, - struct NumberConversion); + UsefulBufC Encoded; + QCBOREncodeContext EC; + QCBORError uErr; - for(int nIndex = 0; nIndex < nNumTests; nIndex++) { - const struct NumberConversion *pF = &NumberConversions[nIndex]; + QCBOREncode_Init(&EC, OutputBuffer); - // Set up the decoding context including a memory pool so that - // indefinite length items can be checked - QCBORDecodeContext DCtx; - UsefulBuf_MAKE_STACK_UB(Pool, 100); +#ifndef QCBOR_DISABLE_TAGS + QCBOREncode_AddTag(&EC, CBOR_TAG_CBOR); +#endif /* ! QCBOR_DISABLE_TAGS */ + QCBOREncode_BstrWrap(&EC); + QCBOREncode_OpenMap(&EC); + QCBOREncode_AddInt64ToMapN(&EC, 100, 1); + QCBOREncode_AddInt64ToMapN(&EC, 200, 2); + QCBOREncode_CloseMap(&EC); + QCBOREncode_BstrWrap(&EC); + QCBOREncode_OpenArray(&EC); + QCBOREncode_AddInt64(&EC, 3); + QCBOREncode_BstrWrap(&EC); + QCBOREncode_AddInt64(&EC, 4); + QCBOREncode_CloseBstrWrap(&EC, NULL); + QCBOREncode_AddInt64(&EC, 5); + QCBOREncode_CloseArray(&EC); + QCBOREncode_CloseBstrWrap(&EC, NULL); + QCBOREncode_AddInt64(&EC, 6); + QCBOREncode_CloseBstrWrap(&EC, NULL); + QCBOREncode_OpenArray(&EC); + QCBOREncode_AddInt64(&EC, 7); + QCBOREncode_AddInt64(&EC, 8); + QCBOREncode_CloseArray(&EC); - /* ----- test conversion to int64_t ------ */ - if(SetUpDecoder(&DCtx, pF->CBOR, Pool)) { - return (int32_t)(3333+nIndex); - } + uErr = QCBOREncode_Finish(&EC, &Encoded); + if(uErr) { + Encoded = NULLUsefulBufC; + } - int64_t nInt; - QCBORDecode_GetInt64ConvertAll(&DCtx, 0xffff, &nInt); - if(QCBORDecode_GetError(&DCtx) != pF->uErrorInt64) { - return (int32_t)(2000+nIndex); - } - if(pF->uErrorInt64 == QCBOR_SUCCESS && pF->nConvertedToInt64 != nInt) { - return (int32_t)(3000+nIndex); - } + return Encoded; +} - /* ----- test conversion to uint64_t ------ */ - if(SetUpDecoder(&DCtx, pF->CBOR, Pool)) { - return (int32_t)(3333+nIndex); - } +/* h'FF' */ +static const uint8_t spBreakInByteString[] = { + 0x41, 0xff +}; - uint64_t uInt; - QCBORDecode_GetUInt64ConvertAll(&DCtx, 0xffff, &uInt); - if(QCBORDecode_GetError(&DCtx) != pF->uErrorUint64) { - return (int32_t)(4000+nIndex); - } - if(pF->uErrorUint64 == QCBOR_SUCCESS && pF->uConvertToUInt64 != uInt) { - return (int32_t)(5000+nIndex); - } - /* ----- test conversion to double ------ */ - if(SetUpDecoder(&DCtx, pF->CBOR, Pool)) { - return (int32_t)(3333+nIndex); - } +int32_t EnterBstrTest(void) +{ + UsefulBuf_MAKE_STACK_UB(OutputBuffer, 100); -#ifndef USEFULBUF_DISABLE_ALL_FLOAT - double d; - QCBORDecode_GetDoubleConvertAll(&DCtx, 0xffff, &d); - if(QCBORDecode_GetError(&DCtx) != pF->uErrorDouble) { - return (int32_t)(6000+nIndex); - } - if(pF->uErrorDouble == QCBOR_SUCCESS) { - if(isnan(pF->dConvertToDouble)) { - // NaN's can't be compared for equality. A NaN is - // never equal to anything including another NaN - if(!isnan(d)) { - return (int32_t)(7000+nIndex); - } - } else { - if(pF->dConvertToDouble != d) { - return (int32_t)(8000+nIndex); - } - } - } -#endif /* USEFULBUF_DISABLE_ALL_FLOAT */ + QCBORDecodeContext DC; + + QCBORDecode_Init(&DC, EncodeBstrWrapTestData(OutputBuffer), 0); + + int64_t n1, n2, n3, n4, n5, n6, n7, n8; + +#ifndef QCBOR_DISABLE_TAGS + QCBORDecode_EnterBstrWrapped(&DC, QCBOR_TAG_REQUIREMENT_TAG, NULL); +#else + QCBORDecode_EnterBstrWrapped(&DC, QCBOR_TAG_REQUIREMENT_NOT_A_TAG, NULL); +#endif /* ! QCBOR_DISABLE_TAGS */ + QCBORDecode_EnterMap(&DC, NULL); + QCBORDecode_GetInt64InMapN(&DC, 100, &n1); + QCBORDecode_GetInt64InMapN(&DC, 200, &n2); + QCBORDecode_ExitMap(&DC); + QCBORDecode_EnterBstrWrapped(&DC, QCBOR_TAG_REQUIREMENT_NOT_A_TAG, NULL); + QCBORDecode_EnterArray(&DC, NULL); + QCBORDecode_GetInt64(&DC, &n3); + QCBORDecode_EnterBstrWrapped(&DC, QCBOR_TAG_REQUIREMENT_NOT_A_TAG, NULL); + QCBORDecode_GetInt64(&DC, &n4); + QCBORDecode_ExitBstrWrapped(&DC); + QCBORDecode_GetInt64(&DC, &n5); + QCBORDecode_ExitArray(&DC); + QCBORDecode_ExitBstrWrapped(&DC); + QCBORDecode_GetInt64(&DC, &n6); + QCBORDecode_ExitBstrWrapped(&DC); + QCBORDecode_EnterArray(&DC, NULL); + QCBORDecode_GetInt64(&DC, &n7); + QCBORDecode_GetInt64(&DC, &n8); + QCBORDecode_ExitArray(&DC); + + QCBORError uErr = QCBORDecode_Finish(&DC); + if(uErr) { + return (int32_t)uErr; + } + + + /* Enter and exit byte string wrapped CBOR that is bad. It has just a break. + * Successful because no items are fetched from byte string. + */ + QCBORDecode_Init(&DC, + UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spBreakInByteString), + 0); + QCBORDecode_EnterBstrWrapped(&DC, QCBOR_TAG_REQUIREMENT_NOT_A_TAG, NULL); + uErr = QCBORDecode_GetError(&DC); + if(uErr) { + return 100 + (int32_t)uErr; + } + + QCBORDecode_ExitBstrWrapped(&DC); + uErr = QCBORDecode_GetError(&DC); + if(uErr) { + return 200 + (int32_t)uErr; + } + + /* Try to get item that is a break out of a byte string wrapped CBOR. + * It fails because there should be no break. + */ + QCBORDecode_Init(&DC, + UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spBreakInByteString), + 0); + QCBORDecode_EnterBstrWrapped(&DC, QCBOR_TAG_REQUIREMENT_NOT_A_TAG, NULL); + QCBORItem Item; + uErr = QCBORDecode_GetNext(&DC, &Item); + if(uErr != QCBOR_ERR_BAD_BREAK) { + return 300 + (int32_t)uErr; } return 0; } -#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS -int32_t CBORTestIssue134(void) -{ - QCBORDecodeContext DCtx; - QCBORItem Item; - QCBORError uCBORError; - const uint8_t spTestIssue134[] = { 0x5F, 0x40, 0xFF }; - QCBORDecode_Init(&DCtx, - UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spTestIssue134), - QCBOR_DECODE_MODE_NORMAL); - UsefulBuf_MAKE_STACK_UB(StringBuf, 200); - QCBORDecode_SetMemPool(&DCtx, StringBuf, false); +static const uint8_t spTaggedTypes[] = { + 0xb2, + + // Date string + 0x00, + 0xc0, 0x74, 0x32, 0x30, 0x30, 0x33, 0x2D, 0x31, 0x32, 0x2D, + 0x31, 0x33, 0x54, 0x31, 0x38, 0x3A, 0x33, 0x30, 0x3A, 0x30, + 0x32, 0x5A, + + 0x01, + 0x74, 0x32, 0x30, 0x30, 0x33, 0x2D, 0x31, 0x32, 0x2D, 0x31, + 0x33, 0x54, 0x31, 0x38, 0x3A, 0x33, 0x30, 0x3A, 0x30, 0x32, + 0x5A, + + // Bignum + 10, + 0xC2, 0x4A, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, + 0x09, 0x10, + + 11, + 0xC3, 0x4A, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, + 0x09, 0x10, + + // URL + 20, + 0xd8, 0x20, 0x6f, 0x68, 0x74, 0x74, 0x70, 0x3A, 0x2F, 0x2F, + 0x63, 0x62, 0x6F, 0x72, 0x2E, 0x6D, 0x65, 0x2F, + + 21, + 0x6f, 0x68, 0x74, 0x74, 0x70, 0x3A, 0x2F, 0x2F, 0x63, 0x62, + 0x6F, 0x72, 0x2E, 0x6D, 0x65, 0x2F, + + // B64 + 0x18, 0x1e, + 0xd8, 0x22, 0x6c, 0x63, 0x47, 0x78, 0x6C, 0x59, 0x58, 0x4E, + 0x31, 0x63, 0x6D, 0x55, 0x75, + + 0x18, 0x1f, + 0x6c, 0x63, 0x47, 0x78, 0x6C, 0x59, 0x58, 0x4E, 0x31, 0x63, + 0x6D, 0x55, 0x75, - do { - uCBORError = QCBORDecode_GetNext(&DCtx, &Item); - } while (QCBOR_SUCCESS == uCBORError); + // B64URL + 0x18, 0x28, + 0xd8, 0x21, 0x6c, 0x63, 0x47, 0x78, 0x6C, 0x59, 0x58, 0x4E, + 0x31, 0x63, 0x6D, 0x55, 0x75, - uCBORError = QCBORDecode_Finish(&DCtx); + 0x18, 0x29, + 0x6c, 0x63, 0x47, 0x78, 0x6C, 0x59, 0x58, 0x4E, 0x31, 0x63, + 0x6D, 0x55, 0x75, - return (int32_t)uCBORError; -} + // Regex + 0x18, 0x32, + 0xd8, 0x23, 0x68, 0x31, 0x30, 0x30, 0x5C, 0x73, 0x2A, 0x6D, + 0x6B, -#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS */ + 0x18, 0x33, + 0x68, 0x31, 0x30, 0x30, 0x5C, 0x73, 0x2A, 0x6D, 0x6B, + // MIME + 0x18, 0x3c, + 0xd8, 0x24, 0x72, 0x4D, 0x49, 0x4D, 0x45, 0x2D, 0x56, 0x65, + 0x72, 0x73, 0x69, 0x6F, 0x6E, 0x3A, 0x20, 0x31, 0x2E, 0x30, + 0x0A, + 0x18, 0x3d, + 0x72, 0x4D, 0x49, 0x4D, 0x45, 0x2D, 0x56, 0x65, 0x72, 0x73, + 0x69, 0x6F, 0x6E, 0x3A, 0x20, 0x31, 0x2E, 0x30, 0x0A, -static const uint8_t spSequenceTestInput[] = { - /* 1. The valid date string "1985-04-12" */ - 0x6a, '1','9','8','5','-','0','4','-','1','2', // Date string + 0x18, 0x3e, + 0xd9, 0x01, 0x01, 0x52, 0x4D, 0x49, 0x4D, 0x45, 0x2D, 0x56, + 0x65, 0x72, 0x73, 0x69, 0x6F, 0x6E, 0x3A, 0x20, 0x31, 0x2E, + 0x30, 0x0A, - /* 2. */ - 0x00, + 0x18, 0x3f, + 0x52, 0x4D, 0x49, 0x4D, 0x45, 0x2D, 0x56, 0x65, 0x72, 0x73, + 0x69, 0x6F, 0x6E, 0x3A, 0x20, 0x31, 0x2E, 0x30, 0x0A, - /* 3. A valid epoch date, 1400000000; Tue, 13 May 2014 16:53:20 GMT */ - 0x1a, 0x53, 0x72, 0x4E, 0x00, + // UUID + 0x18, 0x46, + 0xd8, 0x25, 0x50, 0x53, 0x4D, 0x41, 0x52, 0x54, 0x43, 0x53, + 0x4C, 0x54, 0x54, 0x43, 0x46, 0x49, 0x43, 0x41, 0x32, - /* 4. */ - 0x62, 'h', 'i', + 0x18, 0x47, + 0x50, 0x53, 0x4D, 0x41, 0x52, 0x54, 0x43, 0x53, 0x4C, 0x54, + 0x54, 0x43, 0x46, 0x49, 0x43, 0x41, 0x32 }; - -int32_t CBORSequenceDecodeTests(void) +int32_t DecodeTaggedTypeTests(void) { - QCBORDecodeContext DCtx; - QCBORItem Item; - QCBORError uCBORError; - size_t uConsumed; + QCBORDecodeContext DC; + QCBORError uErr; - // --- Test a sequence with extra bytes --- + QCBORDecode_Init(&DC, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spTaggedTypes), 0); - QCBORDecode_Init(&DCtx, - UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spSequenceTestInput), - QCBOR_DECODE_MODE_NORMAL); + UsefulBufC String; + bool bNeg; - // Get 1. - uCBORError = QCBORDecode_GetNext(&DCtx, &Item); - if(uCBORError != QCBOR_SUCCESS) { + QCBORDecode_EnterMap(&DC, NULL); + QCBORDecode_GetDateStringInMapN(&DC, 0, QCBOR_TAG_REQUIREMENT_TAG, &String); + QCBORDecode_GetDateStringInMapN(&DC, 0, QCBOR_TAG_REQUIREMENT_OPTIONAL_TAG, &String); + if(QCBORDecode_GetError(&DC) != QCBOR_SUCCESS) { return 1; } - if(Item.uDataType != QCBOR_TYPE_TEXT_STRING ) { - return 2; - } - - uCBORError = QCBORDecode_PartialFinish(&DCtx, &uConsumed); - if(uCBORError != QCBOR_ERR_EXTRA_BYTES || - uConsumed != 11) { - return 102; - } - - // Get 2. - uCBORError = QCBORDecode_GetNext(&DCtx, &Item); - if(uCBORError != QCBOR_SUCCESS) { - return 66; - } - - uCBORError = QCBORDecode_PartialFinish(&DCtx, &uConsumed); - if(uCBORError != QCBOR_ERR_EXTRA_BYTES || - uConsumed != 12) { - return 102; - } - - // Get 3. - uCBORError = QCBORDecode_GetNext(&DCtx, &Item); - if(uCBORError != QCBOR_SUCCESS) { + QCBORDecode_GetDateStringInMapN(&DC, 0, QCBOR_TAG_REQUIREMENT_NOT_A_TAG, &String); + if(QCBORDecode_GetAndResetError(&DC) != QCBOR_ERR_UNEXPECTED_TYPE) { return 2; } - if(Item.uDataType != QCBOR_TYPE_INT64) { + QCBORDecode_GetDateStringInMapN(&DC, 1, QCBOR_TAG_REQUIREMENT_TAG, &String); + if(QCBORDecode_GetAndResetError(&DC) != QCBOR_ERR_UNEXPECTED_TYPE) { return 3; } - - // A sequence can have stuff at the end that may - // or may not be valid CBOR. The protocol decoder knows - // when to stop by definition of the protocol, not - // when the top-level map or array is ended. - // Finish still has to be called to know that - // maps and arrays (if there were any) were closed - // off correctly. When called like this it - // must return the error QCBOR_ERR_EXTRA_BYTES. - uCBORError = QCBORDecode_Finish(&DCtx); - if(uCBORError != QCBOR_ERR_EXTRA_BYTES) { + QCBORDecode_GetDateStringInMapN(&DC, 1, QCBOR_TAG_REQUIREMENT_OPTIONAL_TAG, &String); + QCBORDecode_GetDateStringInMapN(&DC, 1, QCBOR_TAG_REQUIREMENT_NOT_A_TAG, &String); + if(QCBORDecode_GetAndResetError(&DC) != QCBOR_SUCCESS) { return 4; } - - // --- Test an empty input ---- - uint8_t empty[1]; - UsefulBufC Empty = {empty, 0}; - QCBORDecode_Init(&DCtx, - Empty, - QCBOR_DECODE_MODE_NORMAL); - - uCBORError = QCBORDecode_Finish(&DCtx); - if(uCBORError != QCBOR_SUCCESS) { + QCBORDecode_GetDateStringInMapSZ(&DC, "xxx", QCBOR_TAG_REQUIREMENT_OPTIONAL_TAG, &String); + if(QCBORDecode_GetAndResetError(&DC) != QCBOR_ERR_LABEL_NOT_FOUND) { return 5; } - - // --- Sequence with unclosed indefinite length array --- - static const uint8_t xx[] = {0x01, 0x9f, 0x02}; - - QCBORDecode_Init(&DCtx, - UsefulBuf_FROM_BYTE_ARRAY_LITERAL(xx), - QCBOR_DECODE_MODE_NORMAL); - - // Get the first item - uCBORError = QCBORDecode_GetNext(&DCtx, &Item); - if(uCBORError != QCBOR_SUCCESS) { - return 7; - } - if(Item.uDataType != QCBOR_TYPE_INT64) { - return 8; - } - - // Get a second item - uCBORError = QCBORDecode_GetNext(&DCtx, &Item); -#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS - if(uCBORError != QCBOR_SUCCESS) { - return 9; - } - if(Item.uDataType != QCBOR_TYPE_ARRAY) { + QCBORDecode_GetBignumInMapN(&DC, 10, QCBOR_TAG_REQUIREMENT_TAG, &String, &bNeg); + if(QCBORDecode_GetAndResetError(&DC) != QCBOR_SUCCESS || + bNeg != false) { return 10; } - - // Try to finish before consuming all bytes to confirm - // that the still-open error is returned. - uCBORError = QCBORDecode_Finish(&DCtx); - if(uCBORError != QCBOR_ERR_ARRAY_OR_MAP_UNCONSUMED) { + QCBORDecode_GetBignumInMapN(&DC, 11, QCBOR_TAG_REQUIREMENT_TAG, &String, &bNeg); + if(QCBORDecode_GetAndResetError(&DC) != QCBOR_SUCCESS || + bNeg != true) { return 11; } -#else /* QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS */ - if(uCBORError != QCBOR_ERR_INDEF_LEN_ARRAYS_DISABLED) { - return 20; - } -#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS */ - - - // --- Sequence with a closed indefinite length array --- - static const uint8_t yy[] = {0x01, 0x9f, 0xff}; - - QCBORDecode_Init(&DCtx, - UsefulBuf_FROM_BYTE_ARRAY_LITERAL(yy), - QCBOR_DECODE_MODE_NORMAL); - - // Get the first item - uCBORError = QCBORDecode_GetNext(&DCtx, &Item); - if(uCBORError != QCBOR_SUCCESS) { + QCBORDecode_GetBignumInMapN(&DC, 11, QCBOR_TAG_REQUIREMENT_NOT_A_TAG, &String, &bNeg); + if(QCBORDecode_GetAndResetError(&DC) != QCBOR_ERR_UNEXPECTED_TYPE) { return 12; } - if(Item.uDataType != QCBOR_TYPE_INT64) { + QCBORDecode_GetBignumInMapN(&DC, 14, QCBOR_TAG_REQUIREMENT_NOT_A_TAG, &String, &bNeg); + if(QCBORDecode_GetAndResetError(&DC) != QCBOR_ERR_LABEL_NOT_FOUND) { return 13; } - - // Get a second item - uCBORError = QCBORDecode_GetNext(&DCtx, &Item); -#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS - - if(uCBORError != QCBOR_SUCCESS) { + QCBORDecode_GetBignumInMapSZ(&DC, "xxx", QCBOR_TAG_REQUIREMENT_NOT_A_TAG, &String, &bNeg); + if(QCBORDecode_GetAndResetError(&DC) != QCBOR_ERR_LABEL_NOT_FOUND) { return 14; } - if(Item.uDataType != QCBOR_TYPE_ARRAY) { - return 15; - } - // Try to finish before consuming all bytes to confirm - // that the still-open error is returned. - uCBORError = QCBORDecode_Finish(&DCtx); - if(uCBORError != QCBOR_SUCCESS) { - return 16; - } -#else /* QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS */ - if(uCBORError != QCBOR_ERR_INDEF_LEN_ARRAYS_DISABLED) { + QCBORDecode_GetURIInMapN(&DC, 20, QCBOR_TAG_REQUIREMENT_TAG, &String); + if(QCBORDecode_GetAndResetError(&DC) != QCBOR_SUCCESS) { return 20; } -#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS */ - - - return 0; -} - - - -int32_t IntToTests(void) -{ - int nErrCode; - int32_t n32; - int16_t n16; - int8_t n8; - uint32_t u32; - uint16_t u16; - uint8_t u8; - uint64_t u64; + QCBORDecode_GetURIInMapN(&DC, 21, QCBOR_TAG_REQUIREMENT_NOT_A_TAG, &String); + if(QCBORDecode_GetAndResetError(&DC) != QCBOR_SUCCESS) { + return 21; + } + QCBORDecode_GetURIInMapN(&DC, 22, QCBOR_TAG_REQUIREMENT_TAG, &String); + if(QCBORDecode_GetAndResetError(&DC) != QCBOR_ERR_LABEL_NOT_FOUND) { + return 22; + } + QCBORDecode_GetURIInMapSZ(&DC, "xxx", QCBOR_TAG_REQUIREMENT_TAG, &String); + if(QCBORDecode_GetAndResetError(&DC) != QCBOR_ERR_LABEL_NOT_FOUND) { + return 23; + } - nErrCode = QCBOR_Int64ToInt32(1, &n32); - if(nErrCode == -1 || n32 != 1) { - return 1; +#ifndef QCBOR_DISABLE_UNCOMMON_TAGS + QCBORDecode_GetB64InMapN(&DC, 30, QCBOR_TAG_REQUIREMENT_TAG, &String); + if(QCBORDecode_GetAndResetError(&DC) != QCBOR_SUCCESS) { + return 30; + } +#endif + QCBORDecode_GetB64InMapN(&DC, 31, QCBOR_TAG_REQUIREMENT_NOT_A_TAG, &String); + if(QCBORDecode_GetAndResetError(&DC) != QCBOR_SUCCESS) { + return 31; } - - nErrCode = QCBOR_Int64ToInt32((int64_t)INT32_MAX, &n32); - if(nErrCode == -1 || n32 != INT32_MAX) { - return 2; + QCBORDecode_GetB64InMapN(&DC, 32, QCBOR_TAG_REQUIREMENT_NOT_A_TAG, &String); + if(QCBORDecode_GetAndResetError(&DC) != QCBOR_ERR_LABEL_NOT_FOUND) { + return 32; } - - nErrCode = QCBOR_Int64ToInt32((int64_t)INT32_MIN, &n32); - if(nErrCode == -1 || n32 != INT32_MIN) { - return 3; + QCBORDecode_GetB64InMapSZ(&DC, "xxx", QCBOR_TAG_REQUIREMENT_NOT_A_TAG, &String); + if(QCBORDecode_GetAndResetError(&DC) != QCBOR_ERR_LABEL_NOT_FOUND) { + return 33; } - nErrCode = QCBOR_Int64ToInt32(((int64_t)INT32_MAX)+1, &n32); - if(nErrCode != -1) { - return 4; +#ifndef QCBOR_DISABLE_UNCOMMON_TAGS + QCBORDecode_GetB64URLInMapN(&DC, 40, QCBOR_TAG_REQUIREMENT_TAG, &String); + if(QCBORDecode_GetAndResetError(&DC) != QCBOR_SUCCESS) { + return 40; } - - nErrCode = QCBOR_Int64ToInt32(((int64_t)INT32_MIN)-1, &n32); - if(nErrCode != -1) { - return 5; +#endif + QCBORDecode_GetB64URLInMapN(&DC, 41, QCBOR_TAG_REQUIREMENT_NOT_A_TAG, &String); + if(QCBORDecode_GetAndResetError(&DC) != QCBOR_SUCCESS) { + return 41; } - - - nErrCode = QCBOR_Int64ToInt16((int64_t)INT16_MAX, &n16); - if(nErrCode == -1 || n16 != INT16_MAX) { - return 6; + QCBORDecode_GetB64URLInMapN(&DC, 42, QCBOR_TAG_REQUIREMENT_NOT_A_TAG, &String); + if(QCBORDecode_GetAndResetError(&DC) != QCBOR_ERR_LABEL_NOT_FOUND) { + return 42; } - - nErrCode = QCBOR_Int64ToInt16((int64_t)INT16_MIN, &n16); - if(nErrCode == -1 || n16 != INT16_MIN) { - return 7; + QCBORDecode_GetB64URLInMapSZ(&DC, "xxx", QCBOR_TAG_REQUIREMENT_NOT_A_TAG, &String); + if(QCBORDecode_GetAndResetError(&DC) != QCBOR_ERR_LABEL_NOT_FOUND) { + return 43; } - nErrCode = QCBOR_Int64ToInt16(1, &n16); - if(nErrCode == -1 || n16 != 1) { - return 8; +#ifndef QCBOR_DISABLE_UNCOMMON_TAGS + QCBORDecode_GetRegexInMapN(&DC, 50, QCBOR_TAG_REQUIREMENT_TAG, &String); + if(QCBORDecode_GetAndResetError(&DC) != QCBOR_SUCCESS) { + return 50; } - - nErrCode = QCBOR_Int64ToInt16(((int64_t)INT16_MAX)+1, &n16); - if(nErrCode != -1) { - return 9; +#endif + QCBORDecode_GetRegexInMapN(&DC, 51, QCBOR_TAG_REQUIREMENT_NOT_A_TAG, &String); + if(QCBORDecode_GetAndResetError(&DC) != QCBOR_SUCCESS) { + return 51; } - - nErrCode = QCBOR_Int64ToInt16(((int64_t)INT16_MIN)-1, &n16); - if(nErrCode != -1) { - return 10; + QCBORDecode_GetRegexInMapN(&DC, 52, QCBOR_TAG_REQUIREMENT_TAG, &String); + if(QCBORDecode_GetAndResetError(&DC) != QCBOR_ERR_LABEL_NOT_FOUND) { + return 52; } - - - nErrCode = QCBOR_Int64ToInt8(1, &n8); - if(nErrCode == -1 || n8 != 1) { - return 11; + QCBORDecode_GetRegexInMapSZ(&DC, "xxx", QCBOR_TAG_REQUIREMENT_TAG, &String); + if(QCBORDecode_GetAndResetError(&DC) != QCBOR_ERR_LABEL_NOT_FOUND) { + return 53; } - nErrCode = QCBOR_Int64ToInt8((int64_t)INT8_MAX, &n8); - if(nErrCode == -1 || n8 != INT8_MAX) { - return 12; +#ifndef QCBOR_DISABLE_UNCOMMON_TAGS + // MIME + bool bIsNot7Bit; + QCBORDecode_GetMIMEMessageInMapN(&DC, 60, QCBOR_TAG_REQUIREMENT_TAG, &String, &bIsNot7Bit); + if(QCBORDecode_GetAndResetError(&DC) != QCBOR_SUCCESS || + bIsNot7Bit == true) { + return 60; } - - nErrCode = QCBOR_Int64ToInt8((int64_t)INT8_MIN, &n8); - if(nErrCode == -1 || n8 != INT8_MIN) { - return 13; + QCBORDecode_GetMIMEMessageInMapN(&DC, 61, QCBOR_TAG_REQUIREMENT_NOT_A_TAG, &String, &bIsNot7Bit); + if(QCBORDecode_GetAndResetError(&DC) != QCBOR_SUCCESS || + bIsNot7Bit == true) { + return 61; } - - nErrCode = QCBOR_Int64ToInt8(((int64_t)INT8_MAX)+1, &n8); - if(nErrCode != -1) { - return 14; + QCBORDecode_GetMIMEMessageInMapN(&DC, 62, QCBOR_TAG_REQUIREMENT_TAG, &String, &bIsNot7Bit); + if(QCBORDecode_GetAndResetError(&DC) != QCBOR_SUCCESS || + bIsNot7Bit == false) { + return 62; } - - nErrCode = QCBOR_Int64ToInt8(((int64_t)INT8_MIN)-1, &n8); - if(nErrCode != -1) { - return 15; + QCBORDecode_GetMIMEMessageInMapN(&DC, 63, QCBOR_TAG_REQUIREMENT_NOT_A_TAG, &String, &bIsNot7Bit); + if(QCBORDecode_GetAndResetError(&DC) != QCBOR_SUCCESS || + bIsNot7Bit == false) { + return 63; + } + QCBORDecode_GetMIMEMessageInMapN(&DC, 64, QCBOR_TAG_REQUIREMENT_TAG, &String, &bNeg); + if(QCBORDecode_GetAndResetError(&DC) != QCBOR_ERR_LABEL_NOT_FOUND) { + return 64; + } + QCBORDecode_GetMIMEMessageInMapSZ(&DC, "zzz", QCBOR_TAG_REQUIREMENT_TAG, &String, &bNeg); + if(QCBORDecode_GetAndResetError(&DC) != QCBOR_ERR_LABEL_NOT_FOUND) { + return 65; } - nErrCode = QCBOR_Int64ToUInt32(1, &u32); - if(nErrCode == -1 || u32 != 1) { - return 16; + QCBORDecode_GetBinaryUUIDInMapN(&DC, 70, QCBOR_TAG_REQUIREMENT_TAG, &String); + if(QCBORDecode_GetAndResetError(&DC) != QCBOR_SUCCESS) { + return 70; } +#endif /* #ifndef QCBOR_DISABLE_UNCOMMON_TAGS */ - nErrCode = QCBOR_Int64ToUInt32((int64_t)UINT32_MAX, &u32); - if(nErrCode == -1 || u32 != UINT32_MAX) { - return 17; + QCBORDecode_GetBinaryUUIDInMapN(&DC, 71, QCBOR_TAG_REQUIREMENT_NOT_A_TAG, &String); + if(QCBORDecode_GetAndResetError(&DC) != QCBOR_SUCCESS) { + return 71; } - - nErrCode = QCBOR_Int64ToUInt32((int64_t)0, &u32); - if(nErrCode == -1 || u32 != 0) { - return 18; + QCBORDecode_GetBinaryUUIDInMapN(&DC, 72, QCBOR_TAG_REQUIREMENT_TAG, &String); + if(QCBORDecode_GetAndResetError(&DC) != QCBOR_ERR_LABEL_NOT_FOUND) { + return 72; } - - nErrCode = QCBOR_Int64ToUInt32(((int64_t)UINT32_MAX)+1, &u32); - if(nErrCode != -1) { - return 19; + QCBORDecode_GetBinaryUUIDInMapSZ(&DC, "xxx", QCBOR_TAG_REQUIREMENT_TAG, &String); + if(QCBORDecode_GetAndResetError(&DC) != QCBOR_ERR_LABEL_NOT_FOUND) { + return 73; } - nErrCode = QCBOR_Int64ToUInt32((int64_t)-1, &u32); - if(nErrCode != -1) { - return 20; - } + // Improvement: add some more error test cases + QCBORDecode_ExitMap(&DC); - nErrCode = QCBOR_Int64UToInt16((int64_t)UINT16_MAX, &u16); - if(nErrCode == -1 || u16 != UINT16_MAX) { - return 21; + uErr = QCBORDecode_Finish(&DC); + if(uErr != QCBOR_SUCCESS) { + return 100; } - nErrCode = QCBOR_Int64UToInt16((int64_t)0, &u16); - if(nErrCode == -1 || u16 != 0) { - return 22; - } + return 0; +} - nErrCode = QCBOR_Int64UToInt16(1, &u16); - if(nErrCode == -1 || u16 != 1) { - return 23; - } - nErrCode = QCBOR_Int64UToInt16(((int64_t)UINT16_MAX)+1, &u16); - if(nErrCode != -1) { - return 24; - } - nErrCode = QCBOR_Int64UToInt16((int64_t)-1, &u16); - if(nErrCode != -1) { - return 25; - } +/* + [ + "aaaaaaaaaa", + {} + ] + */ +static const uint8_t spTooLarge1[] = { + 0x9f, + 0x6a, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, + 0xa0, + 0xff +}; - nErrCode = QCBOR_Int64ToUInt8((int64_t)UINT8_MAX, &u8); - if(nErrCode == -1 || u8 != UINT8_MAX) { - return 26; - } +/* + [ + { + 0: "aaaaaaaaaa" + } + ] + */ +static const uint8_t spTooLarge2[] = { + 0x9f, + 0xa1, + 0x00, + 0x6a, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, + 0xff +}; - nErrCode = QCBOR_Int64ToUInt8((int64_t)0, &u8); - if(nErrCode == -1 || u8 != 0) { - return 27; - } +/* + h'A1006A61616161616161616161' - nErrCode = QCBOR_Int64ToUInt8(1, &u8); - if(nErrCode == -1 || u8 != 1) { - return 28; + { + 0: "aaaaaaaaaa" } + */ +static const uint8_t spTooLarge3[] = { + 0x4d, + 0xa1, + 0x00, + 0x6a, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, +}; - nErrCode = QCBOR_Int64ToUInt8(((int64_t)UINT16_MAX)+1, &u8); - if(nErrCode != -1) { - return 29; - } +int32_t TooLargeInputTest(void) +{ + QCBORDecodeContext DC; + QCBORError uErr; + UsefulBufC String; - nErrCode = QCBOR_Int64ToUInt8((int64_t)-1, &u8); - if(nErrCode != -1) { - return 30; - } + // These tests require a build with QCBOR_MAX_DECODE_INPUT_SIZE set + // to 10 There's not really any way to test this error + // condition. The error condition is not complex, so setting + // QCBOR_MAX_DECODE_INPUT_SIZE gives an OK test. + + // The input CBOR is only too large because the + // QCBOR_MAX_DECODE_INPUT_SIZE is 10. + // + // This test is disabled for the normal test runs because of the + // special build requirement. - nErrCode = QCBOR_Int64ToUInt64(1, &u64); - if(nErrCode == -1 || u64 != 1) { - return 31; + // Tests the start of a map being too large + QCBORDecode_Init(&DC, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spTooLarge1), QCBOR_DECODE_MODE_NORMAL); + QCBORDecode_EnterArray(&DC, NULL); + QCBORDecode_GetTextString(&DC, &String); + uErr = QCBORDecode_GetError(&DC); + if(uErr != QCBOR_SUCCESS) { + return 1; + } + QCBORDecode_EnterMap(&DC, NULL); + uErr = QCBORDecode_GetError(&DC); + if(uErr != QCBOR_ERR_INPUT_TOO_LARGE) { + return 2; } - nErrCode = QCBOR_Int64ToUInt64(INT64_MAX, &u64); - if(nErrCode == -1 || u64 != INT64_MAX) { - return 32; + // Tests the end of a map being too large + QCBORDecode_Init(&DC, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spTooLarge2), QCBOR_DECODE_MODE_NORMAL); + QCBORDecode_EnterArray(&DC, NULL); + QCBORDecode_EnterMap(&DC, NULL); + uErr = QCBORDecode_GetError(&DC); + if(uErr != QCBOR_SUCCESS) { + return 3; } - - nErrCode = QCBOR_Int64ToUInt64((int64_t)0, &u64); - if(nErrCode == -1 || u64 != 0) { - return 33; + QCBORDecode_ExitMap(&DC); + uErr = QCBORDecode_GetError(&DC); + if(uErr != QCBOR_ERR_INPUT_TOO_LARGE) { + return 4; } - nErrCode = QCBOR_Int64ToUInt64((int64_t)-1, &u64); - if(nErrCode != -1) { - return 34; + // Tests the entire input CBOR being too large when processing bstr wrapping + QCBORDecode_Init(&DC, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spTooLarge3), QCBOR_DECODE_MODE_NORMAL); + QCBORDecode_EnterBstrWrapped(&DC, QCBOR_TAG_REQUIREMENT_NOT_A_TAG, NULL); + uErr = QCBORDecode_GetError(&DC); + if(uErr != QCBOR_ERR_INPUT_TOO_LARGE) { + return 5; } return 0; } - +#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS /* -A sequence with - A wrapping bstr - containing a map - 1 - 2 - A wrapping bstr - containing an array - 3 - wrapping bstr - 4 - 5 - 6 - array - 7 - 8 + An array of three map entries + 1) Indefinite length string label for indefinite lenght byte string + 2) Indefinite length string label for an integer + 3) Indefinite length string label for an indefinite-length negative big num */ - -static UsefulBufC EncodeBstrWrapTestData(UsefulBuf OutputBuffer) -{ - UsefulBufC Encoded; - QCBOREncodeContext EC; - QCBORError uErr; - - QCBOREncode_Init(&EC, OutputBuffer); - - QCBOREncode_BstrWrap(&EC); - QCBOREncode_OpenMap(&EC); - QCBOREncode_AddInt64ToMapN(&EC, 100, 1); - QCBOREncode_AddInt64ToMapN(&EC, 200, 2); - QCBOREncode_CloseMap(&EC); - QCBOREncode_BstrWrap(&EC); - QCBOREncode_OpenArray(&EC); - QCBOREncode_AddInt64(&EC, 3); - QCBOREncode_BstrWrap(&EC); - QCBOREncode_AddInt64(&EC, 4); - QCBOREncode_CloseBstrWrap(&EC, NULL); - QCBOREncode_AddInt64(&EC, 5); - QCBOREncode_CloseArray(&EC); - QCBOREncode_CloseBstrWrap(&EC, NULL); - QCBOREncode_AddInt64(&EC, 6); - QCBOREncode_CloseBstrWrap(&EC, NULL); - QCBOREncode_OpenArray(&EC); - QCBOREncode_AddInt64(&EC, 7); - QCBOREncode_AddInt64(&EC, 8); - QCBOREncode_CloseArray(&EC); - - uErr = QCBOREncode_Finish(&EC, &Encoded); - if(uErr) { - Encoded = NULLUsefulBufC; - } - - return Encoded; -} - -/* h'FF' */ -static const uint8_t spBreakInByteString[] = { - 0x41, 0xff +static const uint8_t spMapWithIndefLenStrings[] = { + 0xa3, + 0x7f, 0x61, 'l', 0x64, 'a', 'b', 'e', 'l' , 0x61, '1', 0xff, + 0x5f, 0x42, 0x01, 0x02, 0x43, 0x03, 0x04, 0x05, 0xff, + 0x7f, 0x62, 'd', 'y', 0x61, 'm', 0x61, 'o', 0xff, + 0x03, + 0x7f, 0x62, 'l', 'a', 0x63, 'b', 'e', 'l', 0x61, '2', 0xff, + 0xc3, + 0x5f, 0x42, 0x00, 0x01, 0x42, 0x00, 0x01, 0x41, 0x01, 0xff, }; - -int32_t EnterBstrTest(void) +int32_t SpiffyIndefiniteLengthStringsTests(void) { - UsefulBuf_MAKE_STACK_UB(OutputBuffer, 100); + QCBORDecodeContext DCtx; - QCBORDecodeContext DC; + QCBORDecode_Init(&DCtx, + UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spMapWithIndefLenStrings), + QCBOR_DECODE_MODE_NORMAL); - QCBORDecode_Init(&DC, EncodeBstrWrapTestData(OutputBuffer), 0); + UsefulBuf_MAKE_STACK_UB(StringBuf, 200); + QCBORDecode_SetMemPool(&DCtx, StringBuf, false); - int64_t n1, n2, n3, n4, n5, n6, n7, n8; + UsefulBufC ByteString; + QCBORDecode_EnterMap(&DCtx, NULL); + QCBORDecode_GetByteStringInMapSZ(&DCtx, "label1", &ByteString); +#ifndef QCBOR_DISABLE_TAGS + if(QCBORDecode_GetAndResetError(&DCtx)) { + return 1; + } - QCBORDecode_EnterBstrWrapped(&DC, QCBOR_TAG_REQUIREMENT_NOT_A_TAG, NULL); - QCBORDecode_EnterMap(&DC, NULL); - QCBORDecode_GetInt64InMapN(&DC, 100, &n1); - QCBORDecode_GetInt64InMapN(&DC, 200, &n2); - QCBORDecode_ExitMap(&DC); - QCBORDecode_EnterBstrWrapped(&DC, QCBOR_TAG_REQUIREMENT_NOT_A_TAG, NULL); - QCBORDecode_EnterArray(&DC, NULL); - QCBORDecode_GetInt64(&DC, &n3); - QCBORDecode_EnterBstrWrapped(&DC, QCBOR_TAG_REQUIREMENT_NOT_A_TAG, NULL); - QCBORDecode_GetInt64(&DC, &n4); - QCBORDecode_ExitBstrWrapped(&DC); - QCBORDecode_GetInt64(&DC, &n5); - QCBORDecode_ExitArray(&DC); - QCBORDecode_ExitBstrWrapped(&DC); - QCBORDecode_GetInt64(&DC, &n6); - QCBORDecode_ExitBstrWrapped(&DC); - QCBORDecode_EnterArray(&DC, NULL); - QCBORDecode_GetInt64(&DC, &n7); - QCBORDecode_GetInt64(&DC, &n8); - QCBORDecode_ExitArray(&DC); + const uint8_t pExectedBytes[] = {0x01, 0x02, 0x03, 0x04, 0x05}; + if(UsefulBuf_Compare(ByteString, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(pExectedBytes))) { + return 2; + } - QCBORError uErr = QCBORDecode_Finish(&DC); - if(uErr) { - return (int32_t)uErr; + uint64_t uInt; + QCBORDecode_GetUInt64InMapSZ(&DCtx, "dymo", &uInt); + if(QCBORDecode_GetAndResetError(&DCtx)) { + return 3; + } + if(uInt != 3) { + return 4; } +#ifndef USEFULBUF_DISABLE_ALL_FLOAT + double uDouble; + QCBORDecode_GetDoubleConvertAllInMapSZ(&DCtx, + "label2", + 0xff, + &uDouble); - /* Enter and exit byte string wrapped CBOR that is bad. It has just a break. - * Successful because no items are fetched from byte string. - */ - QCBORDecode_Init(&DC, - UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spBreakInByteString), - 0); - QCBORDecode_EnterBstrWrapped(&DC, QCBOR_TAG_REQUIREMENT_NOT_A_TAG, NULL); - uErr = QCBORDecode_GetError(&DC); - if(uErr) { - return 100 + (int32_t)uErr; +#ifndef QCBOR_DISABLE_FLOAT_HW_USE + if(QCBORDecode_GetAndResetError(&DCtx)) { + return 5; + } + if(uDouble != -16777474) { + return 6; + } +#else /* QCBOR_DISABLE_FLOAT_HW_USE */ + if(QCBORDecode_GetAndResetError(&DCtx) != QCBOR_ERR_HW_FLOAT_DISABLED) { + return 7; } +#endif /* QCBOR_DISABLE_FLOAT_HW_USE */ +#endif /* USEFULBUF_DISABLE_ALL_FLOAT */ - QCBORDecode_ExitBstrWrapped(&DC); - uErr = QCBORDecode_GetError(&DC); - if(uErr) { - return 200 + (int32_t)uErr; + QCBORDecode_ExitMap(&DCtx); + + if(QCBORDecode_Finish(&DCtx)) { + return 99; } - /* Try to get item that is a break out of a byte string wrapped CBOR. - * It fails because there should be no break. +#else /* QCBOR_DISABLE_TAGS */ + /* The big num in the input is a CBOR tag and you can't do + * map lookups in a map with a tag so this test does very little + * when tags are disabled. That is OK, the test coverage is still + * good when they are not. */ - QCBORDecode_Init(&DC, - UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spBreakInByteString), - 0); - QCBORDecode_EnterBstrWrapped(&DC, QCBOR_TAG_REQUIREMENT_NOT_A_TAG, NULL); - QCBORItem Item; - uErr = QCBORDecode_GetNext(&DC, &Item); - if(uErr != QCBOR_ERR_BAD_BREAK) { - return 300 + (int32_t)uErr; + if(QCBORDecode_GetAndResetError(&DCtx) != QCBOR_ERR_TAGS_DISABLED) { + return 1002; } +#endif /*QCBOR_DISABLE_TAGS */ return 0; } +#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS */ +#ifndef QCBOR_DISABLE_NON_INTEGER_LABELS +/* + * An array of an integer and an array. The second array contains + * a bstr-wrapped map. + * + * [7, [h'A36D6669... (see next lines) 73']] + * + * {"first integer": 42, + * "an array of two strings": ["string1", "string2"], + * "map in a map": + * { "bytes 1": h'78787878', + * "bytes 2": h'79797979', + * "another int": 98, + * "text 2": "lies, damn lies and statistics" + * } + * } + */ +static const uint8_t pValidWrappedMapEncoded[] = { + 0x82, 0x07, 0x81, 0x58, 0x97, + 0xa3, 0x6d, 0x66, 0x69, 0x72, 0x73, 0x74, 0x20, 0x69, 0x6e, + 0x74, 0x65, 0x67, 0x65, 0x72, 0x18, 0x2a, 0x77, 0x61, 0x6e, + 0x20, 0x61, 0x72, 0x72, 0x61, 0x79, 0x20, 0x6f, 0x66, 0x20, + 0x74, 0x77, 0x6f, 0x20, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, + 0x73, 0x82, 0x67, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x31, + 0x67, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x32, 0x6c, 0x6d, + 0x61, 0x70, 0x20, 0x69, 0x6e, 0x20, 0x61, 0x20, 0x6d, 0x61, + 0x70, 0xa4, 0x67, 0x62, 0x79, 0x74, 0x65, 0x73, 0x20, 0x31, + 0x44, 0x78, 0x78, 0x78, 0x78, 0x67, 0x62, 0x79, 0x74, 0x65, + 0x73, 0x20, 0x32, 0x44, 0x79, 0x79, 0x79, 0x79, 0x6b, 0x61, + 0x6e, 0x6f, 0x74, 0x68, 0x65, 0x72, 0x20, 0x69, 0x6e, 0x74, + 0x18, 0x62, 0x66, 0x74, 0x65, 0x78, 0x74, 0x20, 0x32, 0x78, + 0x1e, 0x6c, 0x69, 0x65, 0x73, 0x2c, 0x20, 0x64, 0x61, 0x6d, + 0x6e, 0x20, 0x6c, 0x69, 0x65, 0x73, 0x20, 0x61, 0x6e, 0x64, + 0x20, 0x73, 0x74, 0x61, 0x74, 0x69, 0x73, 0x74, 0x69, 0x63, + 0x73 +}; -static const uint8_t spTaggedTypes[] = { - 0xb2, - - // Date string - 0x00, - 0xc0, 0x74, 0x32, 0x30, 0x30, 0x33, 0x2D, 0x31, 0x32, 0x2D, - 0x31, 0x33, 0x54, 0x31, 0x38, 0x3A, 0x33, 0x30, 0x3A, 0x30, - 0x32, 0x5A, - - 0x01, - 0x74, 0x32, 0x30, 0x30, 0x33, 0x2D, 0x31, 0x32, 0x2D, 0x31, - 0x33, 0x54, 0x31, 0x38, 0x3A, 0x33, 0x30, 0x3A, 0x30, 0x32, - 0x5A, - - // Bignum - 10, - 0xC2, 0x4A, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, - 0x09, 0x10, - - 11, - 0xC3, 0x4A, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, - 0x09, 0x10, - - // URL - 20, - 0xd8, 0x20, 0x6f, 0x68, 0x74, 0x74, 0x70, 0x3A, 0x2F, 0x2F, - 0x63, 0x62, 0x6F, 0x72, 0x2E, 0x6D, 0x65, 0x2F, - - 21, - 0x6f, 0x68, 0x74, 0x74, 0x70, 0x3A, 0x2F, 0x2F, 0x63, 0x62, - 0x6F, 0x72, 0x2E, 0x6D, 0x65, 0x2F, - - // B64 - 0x18, 0x1e, - 0xd8, 0x22, 0x6c, 0x63, 0x47, 0x78, 0x6C, 0x59, 0x58, 0x4E, - 0x31, 0x63, 0x6D, 0x55, 0x75, - - 0x18, 0x1f, - 0x6c, 0x63, 0x47, 0x78, 0x6C, 0x59, 0x58, 0x4E, 0x31, 0x63, - 0x6D, 0x55, 0x75, +#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS - // B64URL - 0x18, 0x28, - 0xd8, 0x21, 0x6c, 0x63, 0x47, 0x78, 0x6C, 0x59, 0x58, 0x4E, - 0x31, 0x63, 0x6D, 0x55, 0x75, +/* As above, but the arrays are indefinite length */ +static const uint8_t pValidIndefWrappedMapEncoded[] = { + 0x9f, 0x07, 0x9f, 0x58, 0x97, + 0xa3, 0x6d, 0x66, 0x69, 0x72, 0x73, 0x74, 0x20, 0x69, 0x6e, + 0x74, 0x65, 0x67, 0x65, 0x72, 0x18, 0x2a, 0x77, 0x61, 0x6e, + 0x20, 0x61, 0x72, 0x72, 0x61, 0x79, 0x20, 0x6f, 0x66, 0x20, + 0x74, 0x77, 0x6f, 0x20, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, + 0x73, 0x82, 0x67, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x31, + 0x67, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x32, 0x6c, 0x6d, + 0x61, 0x70, 0x20, 0x69, 0x6e, 0x20, 0x61, 0x20, 0x6d, 0x61, + 0x70, 0xa4, 0x67, 0x62, 0x79, 0x74, 0x65, 0x73, 0x20, 0x31, + 0x44, 0x78, 0x78, 0x78, 0x78, 0x67, 0x62, 0x79, 0x74, 0x65, + 0x73, 0x20, 0x32, 0x44, 0x79, 0x79, 0x79, 0x79, 0x6b, 0x61, + 0x6e, 0x6f, 0x74, 0x68, 0x65, 0x72, 0x20, 0x69, 0x6e, 0x74, + 0x18, 0x62, 0x66, 0x74, 0x65, 0x78, 0x74, 0x20, 0x32, 0x78, + 0x1e, 0x6c, 0x69, 0x65, 0x73, 0x2c, 0x20, 0x64, 0x61, 0x6d, + 0x6e, 0x20, 0x6c, 0x69, 0x65, 0x73, 0x20, 0x61, 0x6e, 0x64, + 0x20, 0x73, 0x74, 0x61, 0x74, 0x69, 0x73, 0x74, 0x69, 0x63, + 0x73, + 0xff, 0xff +}; +#endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */ - 0x18, 0x29, - 0x6c, 0x63, 0x47, 0x78, 0x6C, 0x59, 0x58, 0x4E, 0x31, 0x63, - 0x6D, 0x55, 0x75, +static const uint8_t pWithEmptyMap[] = {0x82, 0x18, 0x64, 0xa0}; - // Regex - 0x18, 0x32, - 0xd8, 0x23, 0x68, 0x31, 0x30, 0x30, 0x5C, 0x73, 0x2A, 0x6D, - 0x6B, - 0x18, 0x33, - 0x68, 0x31, 0x30, 0x30, 0x5C, 0x73, 0x2A, 0x6D, 0x6B, +#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS +static const uint8_t pWithEmptyMapInDef[] = {0x9f, 0x18, 0x64, 0xbf, 0xff, 0xff}; +#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS */ - // MIME - 0x18, 0x3c, - 0xd8, 0x24, 0x72, 0x4D, 0x49, 0x4D, 0x45, 0x2D, 0x56, 0x65, - 0x72, 0x73, 0x69, 0x6F, 0x6E, 0x3A, 0x20, 0x31, 0x2E, 0x30, - 0x0A, +#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS +/* + * An array of one that contains a byte string that is an indefinite + * length string that CBOR wraps an array of three numbers [42, 43, + * 44]. The byte string is an implicit tag 24. + * + * [ + * (_ h'83', h'18', h'2A182B', h'182C') + * ] + */ +static const uint8_t pWrappedByIndefiniteLength[] = { + 0x81, + 0x5f, + 0x41, 0x83, + 0x41, 0x18, + 0x43, 0x2A, 0x18, 0x2B, + 0x42, 0x18, 0x2C, + 0xff +}; +#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS */ - 0x18, 0x3d, - 0x72, 0x4D, 0x49, 0x4D, 0x45, 0x2D, 0x56, 0x65, 0x72, 0x73, - 0x69, 0x6F, 0x6E, 0x3A, 0x20, 0x31, 0x2E, 0x30, 0x0A, +#endif - 0x18, 0x3e, - 0xd9, 0x01, 0x01, 0x52, 0x4D, 0x49, 0x4D, 0x45, 0x2D, 0x56, - 0x65, 0x72, 0x73, 0x69, 0x6F, 0x6E, 0x3A, 0x20, 0x31, 0x2E, - 0x30, 0x0A, +#ifndef QCBOR_DISABLE_NON_INTEGER_LABELS +int32_t PeekAndRewindTest(void) +{ + QCBORItem Item; + QCBORError nCBORError; + QCBORDecodeContext DCtx; - 0x18, 0x3f, - 0x52, 0x4D, 0x49, 0x4D, 0x45, 0x2D, 0x56, 0x65, 0x72, 0x73, - 0x69, 0x6F, 0x6E, 0x3A, 0x20, 0x31, 0x2E, 0x30, 0x0A, + // Improvement: rework this test to use only integer labels. - // UUID - 0x18, 0x46, - 0xd8, 0x25, 0x50, 0x53, 0x4D, 0x41, 0x52, 0x54, 0x43, 0x53, - 0x4C, 0x54, 0x54, 0x43, 0x46, 0x49, 0x43, 0x41, 0x32, + QCBORDecode_Init(&DCtx, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(pValidMapEncoded), 0); - 0x18, 0x47, - 0x50, 0x53, 0x4D, 0x41, 0x52, 0x54, 0x43, 0x53, 0x4C, 0x54, - 0x54, 0x43, 0x46, 0x49, 0x43, 0x41, 0x32 -}; + if((nCBORError = QCBORDecode_PeekNext(&DCtx, &Item))) { + return 100+(int32_t)nCBORError; + } + if(Item.uDataType != QCBOR_TYPE_MAP || Item.val.uCount != 3) { + return 200; + } -int32_t DecodeTaggedTypeTests(void) -{ - QCBORDecodeContext DC; - QCBORError uErr; + QCBORDecode_VPeekNext(&DCtx, &Item); + if((nCBORError = QCBORDecode_GetError(&DCtx))) { + return 150+(int32_t)nCBORError; + } + if(Item.uDataType != QCBOR_TYPE_MAP || Item.val.uCount != 3) { + return 250; + } - QCBORDecode_Init(&DC, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spTaggedTypes), 0); + if((nCBORError = QCBORDecode_PeekNext(&DCtx, &Item))) { + return (int32_t)nCBORError; + } + if(Item.uDataType != QCBOR_TYPE_MAP || Item.val.uCount != 3) { + return 300; + } - UsefulBufC String; - bool bNeg; + if((nCBORError = QCBORDecode_PeekNext(&DCtx, &Item))) { + return 400 + (int32_t)nCBORError; + } + if(Item.uDataType != QCBOR_TYPE_MAP || Item.val.uCount != 3) { + return 500; + } - QCBORDecode_EnterMap(&DC, NULL); - QCBORDecode_GetDateStringInMapN(&DC, 0, QCBOR_TAG_REQUIREMENT_TAG, &String); - QCBORDecode_GetDateStringInMapN(&DC, 0, QCBOR_TAG_REQUIREMENT_OPTIONAL_TAG, &String); - if(QCBORDecode_GetError(&DC) != QCBOR_SUCCESS) { - return 1; + if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { + return (int32_t)nCBORError; } - QCBORDecode_GetDateStringInMapN(&DC, 0, QCBOR_TAG_REQUIREMENT_NOT_A_TAG, &String); - if(QCBORDecode_GetAndResetError(&DC) != QCBOR_ERR_UNEXPECTED_TYPE) { - return 2; + if(Item.uDataType != QCBOR_TYPE_MAP || Item.val.uCount != 3) { + return 600; } - QCBORDecode_GetDateStringInMapN(&DC, 1, QCBOR_TAG_REQUIREMENT_TAG, &String); - if(QCBORDecode_GetAndResetError(&DC) != QCBOR_ERR_UNEXPECTED_TYPE) { - return 3; + + if((nCBORError = QCBORDecode_PeekNext(&DCtx, &Item))) { + return 900 + (int32_t)nCBORError; } - QCBORDecode_GetDateStringInMapN(&DC, 1, QCBOR_TAG_REQUIREMENT_OPTIONAL_TAG, &String); - QCBORDecode_GetDateStringInMapN(&DC, 1, QCBOR_TAG_REQUIREMENT_NOT_A_TAG, &String); - if(QCBORDecode_GetAndResetError(&DC) != QCBOR_SUCCESS) { - return 4; + if(Item.uLabelType != QCBOR_TYPE_TEXT_STRING || + Item.uDataType != QCBOR_TYPE_INT64 || + Item.val.int64 != 42 || + Item.uDataAlloc || + Item.uLabelAlloc || + UsefulBufCompareToSZ(Item.label.string, "first integer")) { + return 1000; } - QCBORDecode_GetDateStringInMapSZ(&DC, "xxx", QCBOR_TAG_REQUIREMENT_OPTIONAL_TAG, &String); - if(QCBORDecode_GetAndResetError(&DC) != QCBOR_ERR_LABEL_NOT_FOUND) { - return 5; + + if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { + return 1100 + (int32_t)nCBORError; } - QCBORDecode_GetBignumInMapN(&DC, 10, QCBOR_TAG_REQUIREMENT_TAG, &String, &bNeg); - if(QCBORDecode_GetAndResetError(&DC) != QCBOR_SUCCESS || - bNeg != false) { - return 10; + if(Item.uLabelType != QCBOR_TYPE_TEXT_STRING || + Item.uDataType != QCBOR_TYPE_INT64 || + Item.val.int64 != 42 || + Item.uDataAlloc || + Item.uLabelAlloc || + UsefulBufCompareToSZ(Item.label.string, "first integer")) { + return 1200; } - QCBORDecode_GetBignumInMapN(&DC, 11, QCBOR_TAG_REQUIREMENT_TAG, &String, &bNeg); - if(QCBORDecode_GetAndResetError(&DC) != QCBOR_SUCCESS || - bNeg != true) { - return 11; + + + if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { + return 1300 + (int32_t)nCBORError; } - QCBORDecode_GetBignumInMapN(&DC, 11, QCBOR_TAG_REQUIREMENT_NOT_A_TAG, &String, &bNeg); - if(QCBORDecode_GetAndResetError(&DC) != QCBOR_ERR_UNEXPECTED_TYPE) { - return 12; + if(Item.uLabelType != QCBOR_TYPE_TEXT_STRING || + Item.uDataAlloc || + Item.uLabelAlloc || + UsefulBufCompareToSZ(Item.label.string, "an array of two strings") || + Item.uDataType != QCBOR_TYPE_ARRAY || + Item.val.uCount != 2) { + return 1400; } - QCBORDecode_GetBignumInMapN(&DC, 14, QCBOR_TAG_REQUIREMENT_NOT_A_TAG, &String, &bNeg); - if(QCBORDecode_GetAndResetError(&DC) != QCBOR_ERR_LABEL_NOT_FOUND) { - return 13; + + if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { + return 1500 + (int32_t)nCBORError; } - QCBORDecode_GetBignumInMapSZ(&DC, "xxx", QCBOR_TAG_REQUIREMENT_NOT_A_TAG, &String, &bNeg); - if(QCBORDecode_GetAndResetError(&DC) != QCBOR_ERR_LABEL_NOT_FOUND) { - return 14; + if(Item.uDataType != QCBOR_TYPE_TEXT_STRING || + Item.uDataAlloc || + Item.uLabelAlloc || + UsefulBufCompareToSZ(Item.val.string, "string1")) { + return 1600; } - QCBORDecode_GetURIInMapN(&DC, 20, QCBOR_TAG_REQUIREMENT_TAG, &String); - if(QCBORDecode_GetAndResetError(&DC) != QCBOR_SUCCESS) { - return 20; + if((nCBORError = QCBORDecode_PeekNext(&DCtx, &Item))) { + return 1700 + (int32_t)nCBORError; } - QCBORDecode_GetURIInMapN(&DC, 21, QCBOR_TAG_REQUIREMENT_NOT_A_TAG, &String); - if(QCBORDecode_GetAndResetError(&DC) != QCBOR_SUCCESS) { - return 21; + if(Item.uDataType != QCBOR_TYPE_TEXT_STRING || + Item.uDataAlloc || + Item.uLabelAlloc || + UsefulBufCompareToSZ(Item.val.string, "string2")) { + return 1800; } - QCBORDecode_GetURIInMapN(&DC, 22, QCBOR_TAG_REQUIREMENT_TAG, &String); - if(QCBORDecode_GetAndResetError(&DC) != QCBOR_ERR_LABEL_NOT_FOUND) { - return 22; + + if((nCBORError = QCBORDecode_PeekNext(&DCtx, &Item))) { + return (int32_t)nCBORError; } - QCBORDecode_GetURIInMapSZ(&DC, "xxx", QCBOR_TAG_REQUIREMENT_TAG, &String); - if(QCBORDecode_GetAndResetError(&DC) != QCBOR_ERR_LABEL_NOT_FOUND) { - return 23; + if(Item.uDataType != QCBOR_TYPE_TEXT_STRING || + Item.uDataAlloc || + Item.uLabelAlloc || + UsefulBufCompareToSZ(Item.val.string, "string2")) { + return 1900; + } + + if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { + return (int32_t)nCBORError; + } + if(Item.uDataType != QCBOR_TYPE_TEXT_STRING || + Item.uDataAlloc || + Item.uLabelAlloc || + UsefulBufCompareToSZ(Item.val.string, "string2")) { + return 2000; } -#ifndef QCBOR_DISABLE_UNCOMMON_TAGS - QCBORDecode_GetB64InMapN(&DC, 30, QCBOR_TAG_REQUIREMENT_TAG, &String); - if(QCBORDecode_GetAndResetError(&DC) != QCBOR_SUCCESS) { - return 30; + + if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { + return 2100 + (int32_t)nCBORError; } -#endif - QCBORDecode_GetB64InMapN(&DC, 31, QCBOR_TAG_REQUIREMENT_NOT_A_TAG, &String); - if(QCBORDecode_GetAndResetError(&DC) != QCBOR_SUCCESS) { - return 31; + if(Item.uLabelType != QCBOR_TYPE_TEXT_STRING || + Item.uDataAlloc || + Item.uLabelAlloc || + UsefulBufCompareToSZ(Item.label.string, "map in a map") || + Item.uDataType != QCBOR_TYPE_MAP || + Item.val.uCount != 4) { + return 2100; } - QCBORDecode_GetB64InMapN(&DC, 32, QCBOR_TAG_REQUIREMENT_NOT_A_TAG, &String); - if(QCBORDecode_GetAndResetError(&DC) != QCBOR_ERR_LABEL_NOT_FOUND) { - return 32; + + if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { + return 2200 + (int32_t)nCBORError; } - QCBORDecode_GetB64InMapSZ(&DC, "xxx", QCBOR_TAG_REQUIREMENT_NOT_A_TAG, &String); - if(QCBORDecode_GetAndResetError(&DC) != QCBOR_ERR_LABEL_NOT_FOUND) { - return 33; + if(Item.uLabelType != QCBOR_TYPE_TEXT_STRING || + UsefulBuf_Compare(Item.label.string, UsefulBuf_FromSZ("bytes 1"))|| + Item.uDataType != QCBOR_TYPE_BYTE_STRING || + Item.uDataAlloc || + Item.uLabelAlloc || + UsefulBufCompareToSZ(Item.val.string, "xxxx")) { + return 2300; } -#ifndef QCBOR_DISABLE_UNCOMMON_TAGS - QCBORDecode_GetB64URLInMapN(&DC, 40, QCBOR_TAG_REQUIREMENT_TAG, &String); - if(QCBORDecode_GetAndResetError(&DC) != QCBOR_SUCCESS) { - return 40; + if((nCBORError = QCBORDecode_PeekNext(&DCtx, &Item))) { + return 2400 + (int32_t)nCBORError; } -#endif - QCBORDecode_GetB64URLInMapN(&DC, 41, QCBOR_TAG_REQUIREMENT_NOT_A_TAG, &String); - if(QCBORDecode_GetAndResetError(&DC) != QCBOR_SUCCESS) { - return 41; + if(Item.uLabelType != QCBOR_TYPE_TEXT_STRING || + UsefulBufCompareToSZ(Item.label.string, "bytes 2") || + Item.uDataType != QCBOR_TYPE_BYTE_STRING || + Item.uDataAlloc || + Item.uLabelAlloc || + UsefulBufCompareToSZ(Item.val.string, "yyyy")) { + return 2500; } - QCBORDecode_GetB64URLInMapN(&DC, 42, QCBOR_TAG_REQUIREMENT_NOT_A_TAG, &String); - if(QCBORDecode_GetAndResetError(&DC) != QCBOR_ERR_LABEL_NOT_FOUND) { - return 42; + + if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { + return 2600 + (int32_t)nCBORError; } - QCBORDecode_GetB64URLInMapSZ(&DC, "xxx", QCBOR_TAG_REQUIREMENT_NOT_A_TAG, &String); - if(QCBORDecode_GetAndResetError(&DC) != QCBOR_ERR_LABEL_NOT_FOUND) { - return 43; + if(Item.uLabelType != QCBOR_TYPE_TEXT_STRING || + UsefulBufCompareToSZ(Item.label.string, "bytes 2") || + Item.uDataType != QCBOR_TYPE_BYTE_STRING || + Item.uDataAlloc || + Item.uLabelAlloc || + UsefulBufCompareToSZ(Item.val.string, "yyyy")) { + return 2700; } -#ifndef QCBOR_DISABLE_UNCOMMON_TAGS - QCBORDecode_GetRegexInMapN(&DC, 50, QCBOR_TAG_REQUIREMENT_TAG, &String); - if(QCBORDecode_GetAndResetError(&DC) != QCBOR_SUCCESS) { - return 50; + if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { + return 2800 + (int32_t)nCBORError; } -#endif - QCBORDecode_GetRegexInMapN(&DC, 51, QCBOR_TAG_REQUIREMENT_NOT_A_TAG, &String); - if(QCBORDecode_GetAndResetError(&DC) != QCBOR_SUCCESS) { - return 51; + if(Item.uLabelType != QCBOR_TYPE_TEXT_STRING || + Item.uDataAlloc || + Item.uLabelAlloc || + UsefulBufCompareToSZ(Item.label.string, "another int") || + Item.uDataType != QCBOR_TYPE_INT64 || + Item.val.int64 != 98) { + return 2900; } - QCBORDecode_GetRegexInMapN(&DC, 52, QCBOR_TAG_REQUIREMENT_TAG, &String); - if(QCBORDecode_GetAndResetError(&DC) != QCBOR_ERR_LABEL_NOT_FOUND) { - return 52; + + if((nCBORError = QCBORDecode_PeekNext(&DCtx, &Item))) { + return 3000 + (int32_t)nCBORError; } - QCBORDecode_GetRegexInMapSZ(&DC, "xxx", QCBOR_TAG_REQUIREMENT_TAG, &String); - if(QCBORDecode_GetAndResetError(&DC) != QCBOR_ERR_LABEL_NOT_FOUND) { - return 53; + if(Item.uLabelType != QCBOR_TYPE_TEXT_STRING || + UsefulBuf_Compare(Item.label.string, UsefulBuf_FromSZ("text 2"))|| + Item.uDataType != QCBOR_TYPE_TEXT_STRING || + Item.uDataAlloc || + Item.uLabelAlloc || + UsefulBufCompareToSZ(Item.val.string, "lies, damn lies and statistics")) { + return 3100; } -#ifndef QCBOR_DISABLE_UNCOMMON_TAGS - // MIME - bool bIsNot7Bit; - QCBORDecode_GetMIMEMessageInMapN(&DC, 60, QCBOR_TAG_REQUIREMENT_TAG, &String, &bIsNot7Bit); - if(QCBORDecode_GetAndResetError(&DC) != QCBOR_SUCCESS || - bIsNot7Bit == true) { - return 60; - } - QCBORDecode_GetMIMEMessageInMapN(&DC, 61, QCBOR_TAG_REQUIREMENT_NOT_A_TAG, &String, &bIsNot7Bit); - if(QCBORDecode_GetAndResetError(&DC) != QCBOR_SUCCESS || - bIsNot7Bit == true) { - return 61; + if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { + return 3200 + (int32_t)nCBORError; } - QCBORDecode_GetMIMEMessageInMapN(&DC, 62, QCBOR_TAG_REQUIREMENT_TAG, &String, &bIsNot7Bit); - if(QCBORDecode_GetAndResetError(&DC) != QCBOR_SUCCESS || - bIsNot7Bit == false) { - return 62; + if(Item.uLabelType != QCBOR_TYPE_TEXT_STRING || + UsefulBuf_Compare(Item.label.string, UsefulBuf_FromSZ("text 2"))|| + Item.uDataType != QCBOR_TYPE_TEXT_STRING || + Item.uDataAlloc || + Item.uLabelAlloc || + UsefulBufCompareToSZ(Item.val.string, "lies, damn lies and statistics")) { + return 3300; } - QCBORDecode_GetMIMEMessageInMapN(&DC, 63, QCBOR_TAG_REQUIREMENT_NOT_A_TAG, &String, &bIsNot7Bit); - if(QCBORDecode_GetAndResetError(&DC) != QCBOR_SUCCESS || - bIsNot7Bit == false) { - return 63; + + nCBORError = QCBORDecode_PeekNext(&DCtx, &Item); + if(nCBORError != QCBOR_ERR_NO_MORE_ITEMS) { + return 3300 + (int32_t)nCBORError; } - QCBORDecode_GetMIMEMessageInMapN(&DC, 64, QCBOR_TAG_REQUIREMENT_TAG, &String, &bNeg); - if(QCBORDecode_GetAndResetError(&DC) != QCBOR_ERR_LABEL_NOT_FOUND) { - return 64; + + QCBORDecode_VPeekNext(&DCtx, &Item); + nCBORError = QCBORDecode_GetError(&DCtx); + if(nCBORError != QCBOR_ERR_NO_MORE_ITEMS) { + return 3400 + (int32_t)nCBORError; } - QCBORDecode_GetMIMEMessageInMapSZ(&DC, "zzz", QCBOR_TAG_REQUIREMENT_TAG, &String, &bNeg); - if(QCBORDecode_GetAndResetError(&DC) != QCBOR_ERR_LABEL_NOT_FOUND) { - return 65; + + QCBORDecode_VPeekNext(&DCtx, &Item); + nCBORError = QCBORDecode_GetError(&DCtx); + if(nCBORError != QCBOR_ERR_NO_MORE_ITEMS) { + return 3500 + (int32_t)nCBORError; } - QCBORDecode_GetBinaryUUIDInMapN(&DC, 70, QCBOR_TAG_REQUIREMENT_TAG, &String); - if(QCBORDecode_GetAndResetError(&DC) != QCBOR_SUCCESS) { - return 70; - } -#endif /* #ifndef QCBOR_DISABLE_UNCOMMON_TAGS */ + // Rewind to top level after entering several maps + QCBORDecode_Init(&DCtx, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(pValidMapEncoded), 0); + + if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { + return (int32_t)nCBORError; + } + if(Item.uDataType != QCBOR_TYPE_MAP || + Item.val.uCount != 3) { + return 400; + } + + if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { + return 4000+(int32_t)nCBORError; + } + + if(Item.uLabelType != QCBOR_TYPE_TEXT_STRING || + Item.uDataType != QCBOR_TYPE_INT64 || + Item.val.int64 != 42 || + Item.uDataAlloc || + Item.uLabelAlloc || + UsefulBufCompareToSZ(Item.label.string, "first integer")) { + return 4100; + } + + if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { + return 4100+(int32_t)nCBORError; + } + if(Item.uLabelType != QCBOR_TYPE_TEXT_STRING || + Item.uDataAlloc || + Item.uLabelAlloc || + UsefulBufCompareToSZ(Item.label.string, "an array of two strings") || + Item.uDataType != QCBOR_TYPE_ARRAY || + Item.val.uCount != 2) { + return 4200; + } + + if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { + return 4200+(int32_t)nCBORError; + } + if(Item.uDataType != QCBOR_TYPE_TEXT_STRING || + Item.uDataAlloc || + Item.uLabelAlloc || + UsefulBufCompareToSZ(Item.val.string, "string1")) { + return 4300; + } + + if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { + return 4300+(int32_t)nCBORError; + } + if(Item.uDataType != QCBOR_TYPE_TEXT_STRING || + Item.uDataAlloc || + Item.uLabelAlloc || + UsefulBufCompareToSZ(Item.val.string, "string2")) { + return 4400; + } + + QCBORDecode_Rewind(&DCtx); + + if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { + return 4400+(int32_t)nCBORError; + } + if(Item.uDataType != QCBOR_TYPE_MAP || + Item.val.uCount != 3) { + return 4500; + } + + if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { + return (int32_t)nCBORError; + } + + if(Item.uLabelType != QCBOR_TYPE_TEXT_STRING || + Item.uDataType != QCBOR_TYPE_INT64 || + Item.val.int64 != 42 || + Item.uDataAlloc || + Item.uLabelAlloc || + UsefulBufCompareToSZ(Item.label.string, "first integer")) { + return 4600; + } + + if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { + return (int32_t)nCBORError; + } + if(Item.uLabelType != QCBOR_TYPE_TEXT_STRING || + Item.uDataAlloc || + Item.uLabelAlloc || + UsefulBufCompareToSZ(Item.label.string, "an array of two strings") || + Item.uDataType != QCBOR_TYPE_ARRAY || + Item.val.uCount != 2) { + return 4700; + } + + if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { + return (int32_t)nCBORError; + } + if(Item.uDataType != QCBOR_TYPE_TEXT_STRING || + Item.uDataAlloc || + Item.uLabelAlloc || + UsefulBufCompareToSZ(Item.val.string, "string1")) { + return 4800; + } - QCBORDecode_GetBinaryUUIDInMapN(&DC, 71, QCBOR_TAG_REQUIREMENT_NOT_A_TAG, &String); - if(QCBORDecode_GetAndResetError(&DC) != QCBOR_SUCCESS) { - return 71; - } - QCBORDecode_GetBinaryUUIDInMapN(&DC, 72, QCBOR_TAG_REQUIREMENT_TAG, &String); - if(QCBORDecode_GetAndResetError(&DC) != QCBOR_ERR_LABEL_NOT_FOUND) { - return 72; - } - QCBORDecode_GetBinaryUUIDInMapSZ(&DC, "xxx", QCBOR_TAG_REQUIREMENT_TAG, &String); - if(QCBORDecode_GetAndResetError(&DC) != QCBOR_ERR_LABEL_NOT_FOUND) { - return 73; - } + if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { + return 4900+(int32_t)nCBORError; + } + if(Item.uDataType != QCBOR_TYPE_TEXT_STRING || + Item.uDataAlloc || + Item.uLabelAlloc || + UsefulBufCompareToSZ(Item.val.string, "string2")) { + return 5000; + } - // Improvement: add some more error test cases - QCBORDecode_ExitMap(&DC); + // Rewind an entered map + QCBORDecode_Init(&DCtx, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(pValidMapEncoded), 0); - uErr = QCBORDecode_Finish(&DC); - if(uErr != QCBOR_SUCCESS) { - return 100; + QCBORDecode_EnterMap(&DCtx, NULL); + + if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { + return 5100+(int32_t)nCBORError; } - return 0; -} + if(Item.uLabelType != QCBOR_TYPE_TEXT_STRING || + Item.uDataType != QCBOR_TYPE_INT64 || + Item.val.int64 != 42 || + Item.uDataAlloc || + Item.uLabelAlloc || + UsefulBufCompareToSZ(Item.label.string, "first integer")) { + return 5200; + } + if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { + return 5200+(int32_t)nCBORError; + } + if(Item.uLabelType != QCBOR_TYPE_TEXT_STRING || + Item.uDataAlloc || + Item.uLabelAlloc || + UsefulBufCompareToSZ(Item.label.string, "an array of two strings") || + Item.uDataType != QCBOR_TYPE_ARRAY || + Item.val.uCount != 2) { + return -5300; + } + QCBORDecode_Rewind(&DCtx); + if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { + return 5300+(int32_t)nCBORError; + } -/* - [ - "aaaaaaaaaa", - {} - ] - */ -static const uint8_t spTooLarge1[] = { - 0x9f, - 0x6a, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, - 0xa0, - 0xff -}; + if(Item.uLabelType != QCBOR_TYPE_TEXT_STRING || + Item.uDataType != QCBOR_TYPE_INT64 || + Item.val.int64 != 42 || + Item.uDataAlloc || + Item.uLabelAlloc || + UsefulBufCompareToSZ(Item.label.string, "first integer")) { + return 5400; + } -/* - [ - { - 0: "aaaaaaaaaa" - } - ] - */ -static const uint8_t spTooLarge2[] = { - 0x9f, - 0xa1, - 0x00, - 0x6a, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, - 0xff -}; + if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { + return 5400+(int32_t)nCBORError; + } + if(Item.uLabelType != QCBOR_TYPE_TEXT_STRING || + Item.uDataAlloc || + Item.uLabelAlloc || + UsefulBufCompareToSZ(Item.label.string, "an array of two strings") || + Item.uDataType != QCBOR_TYPE_ARRAY || + Item.val.uCount != 2) { + return 5500; + } -/* - h'A1006A61616161616161616161' - { - 0: "aaaaaaaaaa" - } - */ -static const uint8_t spTooLarge3[] = { - 0x4d, - 0xa1, - 0x00, - 0x6a, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, -}; + // Rewind and entered array inside an entered map + QCBORDecode_Init(&DCtx, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(pValidMapEncoded), 0); -int32_t TooLargeInputTest(void) -{ - QCBORDecodeContext DC; - QCBORError uErr; - UsefulBufC String; + QCBORDecode_EnterMap(&DCtx, NULL); - // These tests require a build with QCBOR_MAX_DECODE_INPUT_SIZE set - // to 10 There's not really any way to test this error - // condition. The error condition is not complex, so setting - // QCBOR_MAX_DECODE_INPUT_SIZE gives an OK test. + QCBORDecode_EnterArrayFromMapSZ(&DCtx, "an array of two strings"); - // The input CBOR is only too large because the - // QCBOR_MAX_DECODE_INPUT_SIZE is 10. - // - // This test is disabled for the normal test runs because of the - // special build requirement. + if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { + return 5600+(int32_t)nCBORError; + } + if(Item.uDataType != QCBOR_TYPE_TEXT_STRING || + Item.uDataAlloc || + Item.uLabelAlloc || + UsefulBufCompareToSZ(Item.val.string, "string1")) { + return 5700; + } + QCBORDecode_Rewind(&DCtx); - // Tests the start of a map being too large - QCBORDecode_Init(&DC, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spTooLarge1), QCBOR_DECODE_MODE_NORMAL); - QCBORDecode_EnterArray(&DC, NULL); - QCBORDecode_GetTextString(&DC, &String); - uErr = QCBORDecode_GetError(&DC); - if(uErr != QCBOR_SUCCESS) { - return 1; + if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { + return 5700+(int32_t)nCBORError; } - QCBORDecode_EnterMap(&DC, NULL); - uErr = QCBORDecode_GetError(&DC); - if(uErr != QCBOR_ERR_INPUT_TOO_LARGE) { - return 2; + if(Item.uDataType != QCBOR_TYPE_TEXT_STRING || + Item.uDataAlloc || + Item.uLabelAlloc || + UsefulBufCompareToSZ(Item.val.string, "string1")) { + return 5800; } - // Tests the end of a map being too large - QCBORDecode_Init(&DC, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spTooLarge2), QCBOR_DECODE_MODE_NORMAL); - QCBORDecode_EnterArray(&DC, NULL); - QCBORDecode_EnterMap(&DC, NULL); - uErr = QCBORDecode_GetError(&DC); - if(uErr != QCBOR_SUCCESS) { - return 3; + if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { + return (int32_t)nCBORError; } - QCBORDecode_ExitMap(&DC); - uErr = QCBORDecode_GetError(&DC); - if(uErr != QCBOR_ERR_INPUT_TOO_LARGE) { - return 4; + if(Item.uDataType != QCBOR_TYPE_TEXT_STRING || + Item.uDataAlloc || + Item.uLabelAlloc || + UsefulBufCompareToSZ(Item.val.string, "string2")) { + return 5900; } - // Tests the entire input CBOR being too large when processing bstr wrapping - QCBORDecode_Init(&DC, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spTooLarge3), QCBOR_DECODE_MODE_NORMAL); - QCBORDecode_EnterBstrWrapped(&DC, QCBOR_TAG_REQUIREMENT_NOT_A_TAG, NULL); - uErr = QCBORDecode_GetError(&DC); - if(uErr != QCBOR_ERR_INPUT_TOO_LARGE) { - return 5; + QCBORDecode_Rewind(&DCtx); + + if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { + return 5900+(int32_t)nCBORError; + } + if(Item.uDataType != QCBOR_TYPE_TEXT_STRING || + Item.uDataAlloc || + Item.uLabelAlloc || + UsefulBufCompareToSZ(Item.val.string, "string1")) { + return 6000; } - return 0; -} + // Rewind a byte string inside an array inside an array + QCBORDecode_Init(&DCtx, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(pValidWrappedMapEncoded), 0); -#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS + QCBORDecode_EnterArray(&DCtx, NULL); -/* - An array of three map entries - 1) Indefinite length string label for indefinite lenght byte string - 2) Indefinite length string label for an integer - 3) Indefinite length string label for an indefinite-length negative big num - */ -static const uint8_t spMapWithIndefLenStrings[] = { - 0xa3, - 0x7f, 0x61, 'l', 0x64, 'a', 'b', 'e', 'l' , 0x61, '1', 0xff, - 0x5f, 0x42, 0x01, 0x02, 0x43, 0x03, 0x04, 0x05, 0xff, - 0x7f, 0x62, 'd', 'y', 0x61, 'm', 0x61, 'o', 0xff, - 0x03, - 0x7f, 0x62, 'l', 'a', 0x63, 'b', 'e', 'l', 0x61, '2', 0xff, - 0xc3, - 0x5f, 0x42, 0x00, 0x01, 0x42, 0x00, 0x01, 0x41, 0x01, 0xff, -}; + uint64_t i; + QCBORDecode_GetUInt64(&DCtx, &i); -int32_t SpiffyIndefiniteLengthStringsTests(void) -{ - QCBORDecodeContext DCtx; + QCBORDecode_EnterArray(&DCtx, NULL); - QCBORDecode_Init(&DCtx, - UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spMapWithIndefLenStrings), - QCBOR_DECODE_MODE_NORMAL); + QCBORDecode_EnterBstrWrapped(&DCtx, QCBOR_TAG_REQUIREMENT_NOT_A_TAG, NULL); + if(QCBORDecode_GetError(&DCtx)) { + return 6100; + } - UsefulBuf_MAKE_STACK_UB(StringBuf, 200); - QCBORDecode_SetMemPool(&DCtx, StringBuf, false); + if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { + return (int32_t)nCBORError; + } + if(Item.uDataType != QCBOR_TYPE_MAP || Item.val.uCount != 3) { + return 6200; + } - UsefulBufC ByteString; - QCBORDecode_EnterMap(&DCtx, NULL); - QCBORDecode_GetByteStringInMapSZ(&DCtx, "label1", &ByteString); + QCBORDecode_Rewind(&DCtx); + + if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { + return 6300+(int32_t)nCBORError; + } + if(Item.uDataType != QCBOR_TYPE_MAP || Item.val.uCount != 3) { + return 6400; + } + +#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS + // Rewind a byte string inside an indefinite-length array inside + // indefinite-length array + + QCBORDecode_Init(&DCtx, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(pValidIndefWrappedMapEncoded), 0); + + QCBORDecode_EnterArray(&DCtx, NULL); -#ifndef QCBOR_DISABLE_TAGS - if(QCBORDecode_GetAndResetError(&DCtx)) { - return 1; - } + QCBORDecode_GetUInt64(&DCtx, &i); - const uint8_t pExectedBytes[] = {0x01, 0x02, 0x03, 0x04, 0x05}; - if(UsefulBuf_Compare(ByteString, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(pExectedBytes))) { - return 2; + QCBORDecode_EnterArray(&DCtx, NULL); + + QCBORDecode_EnterBstrWrapped(&DCtx, QCBOR_TAG_REQUIREMENT_NOT_A_TAG, NULL); + if(QCBORDecode_GetError(&DCtx)) { + return 6500; } - uint64_t uInt; - QCBORDecode_GetUInt64InMapSZ(&DCtx, "dymo", &uInt); - if(QCBORDecode_GetAndResetError(&DCtx)) { - return 3; + if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { + return 6600+(int32_t)nCBORError; } - if(uInt != 3) { - return 4; + if(Item.uDataType != QCBOR_TYPE_MAP || Item.val.uCount != 3) { + return 6700; } -#ifndef USEFULBUF_DISABLE_ALL_FLOAT - double uDouble; - QCBORDecode_GetDoubleConvertAllInMapSZ(&DCtx, - "label2", - 0xff, - &uDouble); + QCBORDecode_Rewind(&DCtx); -#ifndef QCBOR_DISABLE_FLOAT_HW_USE - if(QCBORDecode_GetAndResetError(&DCtx)) { - return 5; + if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { + return 6800+(int32_t)nCBORError; } - if(uDouble != -16777474) { - return 6; + if(Item.uDataType != QCBOR_TYPE_MAP || Item.val.uCount != 3) { + return 6900; } -#else /* QCBOR_DISABLE_FLOAT_HW_USE */ - if(QCBORDecode_GetAndResetError(&DCtx) != QCBOR_ERR_HW_FLOAT_DISABLED) { - return 7; +#endif + + // Rewind an empty map + // [100, {}] + QCBORDecode_Init(&DCtx, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(pWithEmptyMap), 0); + QCBORDecode_EnterArray(&DCtx, NULL); + QCBORDecode_GetUInt64(&DCtx, &i); + if(i != 100) { + return 7010; } -#endif /* QCBOR_DISABLE_FLOAT_HW_USE */ -#endif /* USEFULBUF_DISABLE_ALL_FLOAT */ + QCBORDecode_EnterMap(&DCtx, NULL); + /* Do it 5 times to be sure multiple rewinds work */ + for(int n = 0; n < 5; n++) { + nCBORError = QCBORDecode_GetNext(&DCtx, &Item); + if(nCBORError != QCBOR_ERR_NO_MORE_ITEMS) { + return 7000 + n; + } + QCBORDecode_Rewind(&DCtx); + } QCBORDecode_ExitMap(&DCtx); - - if(QCBORDecode_Finish(&DCtx)) { - return 99; + QCBORDecode_Rewind(&DCtx); + QCBORDecode_GetUInt64(&DCtx, &i); + if(i != 100) { + return 7010; + } + QCBORDecode_ExitArray(&DCtx); + QCBORDecode_Rewind(&DCtx); + QCBORDecode_EnterArray(&DCtx, NULL); + i = 9; + QCBORDecode_GetUInt64(&DCtx, &i); + if(i != 100) { + return 7020; + } + if(QCBORDecode_GetError(&DCtx)){ + return 7030; } -#else /* QCBOR_DISABLE_TAGS */ - /* The big num in the input is a CBOR tag and you can't do - * map lookups in a map with a tag so this test does very little - * when tags are disabled. That is OK, the test coverage is still - * good when they are not. - */ - if(QCBORDecode_GetAndResetError(&DCtx) != QCBOR_ERR_TAGS_DISABLED) { - return 1002; + // Rewind an empty indefinite length map +#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS + QCBORDecode_Init(&DCtx, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(pWithEmptyMapInDef), 0); + QCBORDecode_EnterArray(&DCtx, NULL); + QCBORDecode_GetUInt64(&DCtx, &i); + if(i != 100) { + return 7810; } -#endif /*QCBOR_DISABLE_TAGS */ + QCBORDecode_EnterMap(&DCtx, NULL); - return 0; -} -#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS */ + /* Do it 5 times to be sure multiple rewinds work */ + for(int n = 0; n < 5; n++) { + nCBORError = QCBORDecode_GetNext(&DCtx, &Item); + if(nCBORError != QCBOR_ERR_NO_MORE_ITEMS) { + return 7800 + n; + } + QCBORDecode_Rewind(&DCtx); + } + QCBORDecode_ExitMap(&DCtx); + QCBORDecode_Rewind(&DCtx); + QCBORDecode_GetUInt64(&DCtx, &i); + if(i != 100) { + return 7810; + } + QCBORDecode_ExitArray(&DCtx); + QCBORDecode_Rewind(&DCtx); + QCBORDecode_EnterArray(&DCtx, NULL); + i = 9; + QCBORDecode_GetUInt64(&DCtx, &i); + if(i != 100) { + return 7820; + } + if(QCBORDecode_GetError(&DCtx)){ + return 7830; + } +#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS */ + // Rewind an indefnite length byte-string wrapped sequence +#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS + QCBORDecode_Init(&DCtx, + UsefulBuf_FROM_BYTE_ARRAY_LITERAL(pWrappedByIndefiniteLength), + 0); + UsefulBuf_MAKE_STACK_UB(Pool, 100); + QCBORDecode_SetMemPool(&DCtx, Pool, 0); -/* - * An array of an integer and an array. The second array contains - * a bstr-wrapped map. - * - * [7, [h'A36D6669... (see next lines) 73']] - * - * {"first integer": 42, - * "an array of two strings": ["string1", "string2"], - * "map in a map": - * { "bytes 1": h'78787878', - * "bytes 2": h'79797979', - * "another int": 98, - * "text 2": "lies, damn lies and statistics" - * } - * } - */ + QCBORDecode_EnterArray(&DCtx, NULL); + QCBORDecode_EnterBstrWrapped(&DCtx, 2, NULL); + if(QCBORDecode_GetError(&DCtx) != QCBOR_ERR_CANNOT_ENTER_ALLOCATED_STRING) { + return 7300; + } -static const uint8_t pValidWrappedMapEncoded[] = { - 0x82, 0x07, 0x81, 0x58, 0x97, - 0xa3, 0x6d, 0x66, 0x69, 0x72, 0x73, 0x74, 0x20, 0x69, 0x6e, - 0x74, 0x65, 0x67, 0x65, 0x72, 0x18, 0x2a, 0x77, 0x61, 0x6e, - 0x20, 0x61, 0x72, 0x72, 0x61, 0x79, 0x20, 0x6f, 0x66, 0x20, - 0x74, 0x77, 0x6f, 0x20, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, - 0x73, 0x82, 0x67, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x31, - 0x67, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x32, 0x6c, 0x6d, - 0x61, 0x70, 0x20, 0x69, 0x6e, 0x20, 0x61, 0x20, 0x6d, 0x61, - 0x70, 0xa4, 0x67, 0x62, 0x79, 0x74, 0x65, 0x73, 0x20, 0x31, - 0x44, 0x78, 0x78, 0x78, 0x78, 0x67, 0x62, 0x79, 0x74, 0x65, - 0x73, 0x20, 0x32, 0x44, 0x79, 0x79, 0x79, 0x79, 0x6b, 0x61, - 0x6e, 0x6f, 0x74, 0x68, 0x65, 0x72, 0x20, 0x69, 0x6e, 0x74, - 0x18, 0x62, 0x66, 0x74, 0x65, 0x78, 0x74, 0x20, 0x32, 0x78, - 0x1e, 0x6c, 0x69, 0x65, 0x73, 0x2c, 0x20, 0x64, 0x61, 0x6d, - 0x6e, 0x20, 0x6c, 0x69, 0x65, 0x73, 0x20, 0x61, 0x6e, 0x64, - 0x20, 0x73, 0x74, 0x61, 0x74, 0x69, 0x73, 0x74, 0x69, 0x63, - 0x73 -}; + /* + Improvement: Fix QCBORDecode_EnterBstrWrapped() so it can work on + allocated strings. This is a fairly big job because of all the + UsefulBuf internal book keeping that needs tweaking. + QCBORDecode_GetUInt64(&DCtx, &i); + if(i != 42) { + return 7110; + } + QCBORDecode_Rewind(&DCtx); + QCBORDecode_GetUInt64(&DCtx, &i); + if(i != 42) { + return 7220; + } + */ -#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS +#endif /* ! QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS */ -/* As above, but the arrays are indefinite length */ -static const uint8_t pValidIndefWrappedMapEncoded[] = { - 0x9f, 0x07, 0x9f, 0x58, 0x97, - 0xa3, 0x6d, 0x66, 0x69, 0x72, 0x73, 0x74, 0x20, 0x69, 0x6e, - 0x74, 0x65, 0x67, 0x65, 0x72, 0x18, 0x2a, 0x77, 0x61, 0x6e, - 0x20, 0x61, 0x72, 0x72, 0x61, 0x79, 0x20, 0x6f, 0x66, 0x20, - 0x74, 0x77, 0x6f, 0x20, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, - 0x73, 0x82, 0x67, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x31, - 0x67, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x32, 0x6c, 0x6d, - 0x61, 0x70, 0x20, 0x69, 0x6e, 0x20, 0x61, 0x20, 0x6d, 0x61, - 0x70, 0xa4, 0x67, 0x62, 0x79, 0x74, 0x65, 0x73, 0x20, 0x31, - 0x44, 0x78, 0x78, 0x78, 0x78, 0x67, 0x62, 0x79, 0x74, 0x65, - 0x73, 0x20, 0x32, 0x44, 0x79, 0x79, 0x79, 0x79, 0x6b, 0x61, - 0x6e, 0x6f, 0x74, 0x68, 0x65, 0x72, 0x20, 0x69, 0x6e, 0x74, - 0x18, 0x62, 0x66, 0x74, 0x65, 0x78, 0x74, 0x20, 0x32, 0x78, - 0x1e, 0x6c, 0x69, 0x65, 0x73, 0x2c, 0x20, 0x64, 0x61, 0x6d, - 0x6e, 0x20, 0x6c, 0x69, 0x65, 0x73, 0x20, 0x61, 0x6e, 0x64, - 0x20, 0x73, 0x74, 0x61, 0x74, 0x69, 0x73, 0x74, 0x69, 0x63, - 0x73, - 0xff, 0xff -}; -#endif + // Rewind an indefnite length byte-string wrapped sequence -static const uint8_t pWithEmptyMap[] = {0x82, 0x18, 0x64, 0xa0}; + return 0; +} -#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS -static const uint8_t pWithEmptyMapInDef[] = {0x9f, 0x18, 0x64, 0xbf, 0xff, 0xff}; -#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS */ +#endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */ -#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS -/* -An array of one that contains - a byte string that is tagged 24 which means CBOR-encoded data - the byte string is an indefinite length string - the wrapped byte string is an array of three numbers - [42, 43, 44] - -[ - 24( - (_ h'83', h'18', h'2A182B', h'182C') - ) -] - */ -static const uint8_t pWrappedByIndefiniteLength[] = { - 0x81, - 0xd8, 0x18, - 0x5f, - 0x41, 0x83, - 0x41, 0x18, - 0x43, 0x2A, 0x18, 0x2B, - 0x42, 0x18, 0x2C, - 0xff +static const uint8_t spBooleansInMap[] = +{ + 0xa1, 0x08, 0xf5 }; -#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS */ - -int32_t PeekAndRewindTest(void) +static const uint8_t spBooleansInMapWrongType[] = { - QCBORItem Item; - QCBORError nCBORError; - QCBORDecodeContext DCtx; - - QCBORDecode_Init(&DCtx, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(pValidMapEncoded), 0); - - if((nCBORError = QCBORDecode_PeekNext(&DCtx, &Item))) { - return 100+(int32_t)nCBORError; - } - if(Item.uDataType != QCBOR_TYPE_MAP || Item.val.uCount != 3) { - return 200; - } + 0xa1, 0x08, 0xf6 +}; - QCBORDecode_VPeekNext(&DCtx, &Item); - if((nCBORError = QCBORDecode_GetError(&DCtx))) { - return 150+(int32_t)nCBORError; - } - if(Item.uDataType != QCBOR_TYPE_MAP || Item.val.uCount != 3) { - return 250; - } +static const uint8_t spBooleansInMapNWF[] = +{ + 0xa1, 0x08, 0x1a +}; - if((nCBORError = QCBORDecode_PeekNext(&DCtx, &Item))) { - return (int32_t)nCBORError; - } - if(Item.uDataType != QCBOR_TYPE_MAP || Item.val.uCount != 3) { - return 300; - } +static const uint8_t spNullInMap[] = +{ + 0xa1, 0x08, 0xf6 +}; - if((nCBORError = QCBORDecode_PeekNext(&DCtx, &Item))) { - return 400 + (int32_t)nCBORError; - } - if(Item.uDataType != QCBOR_TYPE_MAP || Item.val.uCount != 3) { - return 500; - } +static const uint8_t spUndefinedInMap[] = +{ + 0xa1, 0x08, 0xf7 +}; - if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { - return (int32_t)nCBORError; - } - if(Item.uDataType != QCBOR_TYPE_MAP || Item.val.uCount != 3) { - return 600; - } - if((nCBORError = QCBORDecode_PeekNext(&DCtx, &Item))) { - return 900 + (int32_t)nCBORError; - } - if(Item.uLabelType != QCBOR_TYPE_TEXT_STRING || - Item.uDataType != QCBOR_TYPE_INT64 || - Item.val.int64 != 42 || - Item.uDataAlloc || - Item.uLabelAlloc || - UsefulBufCompareToSZ(Item.label.string, "first integer")) { - return 1000; - } +#ifndef QCBOR_DISABLE_TAGS +static const uint8_t spTaggedSimples[] = +{ + 0xd8, 0x58, 0xd8, 0x2c, 0xd6, 0xf5, + 0xd9, 0x0f, 0xA0, 0xf7 +}; +#endif /* ! QCBOR_DISABLE_TAGS */ - if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { - return 1100 + (int32_t)nCBORError; - } - if(Item.uLabelType != QCBOR_TYPE_TEXT_STRING || - Item.uDataType != QCBOR_TYPE_INT64 || - Item.val.int64 != 42 || - Item.uDataAlloc || - Item.uLabelAlloc || - UsefulBufCompareToSZ(Item.label.string, "first integer")) { - return 1200; - } +int32_t BoolTest(void) +{ + QCBORDecodeContext DCtx; + bool b; - if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { - return 1300 + (int32_t)nCBORError; - } - if(Item.uLabelType != QCBOR_TYPE_TEXT_STRING || - Item.uDataAlloc || - Item.uLabelAlloc || - UsefulBufCompareToSZ(Item.label.string, "an array of two strings") || - Item.uDataType != QCBOR_TYPE_ARRAY || - Item.val.uCount != 2) { - return 1400; + QCBORDecode_Init(&DCtx, + UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spBooleansInMap), + 0); + QCBORDecode_EnterMap(&DCtx, NULL); + QCBORDecode_GetBool(&DCtx, &b); + if(QCBORDecode_GetAndResetError(&DCtx) || !b) { + return 1; } - if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { - return 1500 + (int32_t)nCBORError; - } - if(Item.uDataType != QCBOR_TYPE_TEXT_STRING || - Item.uDataAlloc || - Item.uLabelAlloc || - UsefulBufCompareToSZ(Item.val.string, "string1")) { - return 1600; + QCBORDecode_GetBoolInMapN(&DCtx, 7, &b); + if(QCBORDecode_GetAndResetError(&DCtx) != QCBOR_ERR_LABEL_NOT_FOUND) { + return 2; } - if((nCBORError = QCBORDecode_PeekNext(&DCtx, &Item))) { - return 1700 + (int32_t)nCBORError; - } - if(Item.uDataType != QCBOR_TYPE_TEXT_STRING || - Item.uDataAlloc || - Item.uLabelAlloc || - UsefulBufCompareToSZ(Item.val.string, "string2")) { - return 1800; + QCBORDecode_GetBoolInMapN(&DCtx, 8, &b); + if(QCBORDecode_GetAndResetError(&DCtx) || !b) { + return 3; } - if((nCBORError = QCBORDecode_PeekNext(&DCtx, &Item))) { - return (int32_t)nCBORError; - } - if(Item.uDataType != QCBOR_TYPE_TEXT_STRING || - Item.uDataAlloc || - Item.uLabelAlloc || - UsefulBufCompareToSZ(Item.val.string, "string2")) { - return 1900; - } - if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { - return (int32_t)nCBORError; + QCBORDecode_GetBoolInMapSZ(&DCtx, "xx", &b); + if(QCBORDecode_GetAndResetError(&DCtx) != QCBOR_ERR_LABEL_NOT_FOUND) { + return 4; + } + + QCBORDecode_Init(&DCtx, + UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spBooleansInMapWrongType), + 0); + QCBORDecode_EnterMap(&DCtx, NULL); + QCBORDecode_GetBool(&DCtx, &b); + if(QCBORDecode_GetAndResetError(&DCtx) != QCBOR_ERR_UNEXPECTED_TYPE) { + return 5; } - if(Item.uDataType != QCBOR_TYPE_TEXT_STRING || - Item.uDataAlloc || - Item.uLabelAlloc || - UsefulBufCompareToSZ(Item.val.string, "string2")) { - return 2000; + + QCBORDecode_Init(&DCtx, + UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spBooleansInMapNWF), + 0); + QCBORDecode_EnterMap(&DCtx, NULL); + QCBORDecode_GetBool(&DCtx, &b); + if(QCBORDecode_GetAndResetError(&DCtx) != QCBOR_ERR_HIT_END) { + return 6; } - if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { - return 2100 + (int32_t)nCBORError; - } - if(Item.uLabelType != QCBOR_TYPE_TEXT_STRING || - Item.uDataAlloc || - Item.uLabelAlloc || - UsefulBufCompareToSZ(Item.label.string, "map in a map") || - Item.uDataType != QCBOR_TYPE_MAP || - Item.val.uCount != 4) { - return 2100; + QCBORDecode_Init(&DCtx, + UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spNullInMap), + 0); + QCBORDecode_EnterMap(&DCtx, NULL); + QCBORDecode_GetNull(&DCtx); + if(QCBORDecode_GetAndResetError(&DCtx)) { + return 7; } - if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { - return 2200 + (int32_t)nCBORError; - } - if(Item.uLabelType != QCBOR_TYPE_TEXT_STRING || - UsefulBuf_Compare(Item.label.string, UsefulBuf_FromSZ("bytes 1"))|| - Item.uDataType != QCBOR_TYPE_BYTE_STRING || - Item.uDataAlloc || - Item.uLabelAlloc || - UsefulBufCompareToSZ(Item.val.string, "xxxx")) { - return 2300; + QCBORDecode_Init(&DCtx, + UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spBooleansInMap), + 0); + QCBORDecode_EnterMap(&DCtx, NULL); + QCBORDecode_GetNull(&DCtx); + if(QCBORDecode_GetAndResetError(&DCtx) != QCBOR_ERR_UNEXPECTED_TYPE) { + return 8; } - if((nCBORError = QCBORDecode_PeekNext(&DCtx, &Item))) { - return 2400 + (int32_t)nCBORError; - } - if(Item.uLabelType != QCBOR_TYPE_TEXT_STRING || - UsefulBufCompareToSZ(Item.label.string, "bytes 2") || - Item.uDataType != QCBOR_TYPE_BYTE_STRING || - Item.uDataAlloc || - Item.uLabelAlloc || - UsefulBufCompareToSZ(Item.val.string, "yyyy")) { - return 2500; + QCBORDecode_Init(&DCtx, + UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spNullInMap), + 0); + QCBORDecode_EnterMap(&DCtx, NULL); + QCBORDecode_GetNullInMapN(&DCtx, 8); + if(QCBORDecode_GetAndResetError(&DCtx)) { + return 9; } - if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { - return 2600 + (int32_t)nCBORError; - } - if(Item.uLabelType != QCBOR_TYPE_TEXT_STRING || - UsefulBufCompareToSZ(Item.label.string, "bytes 2") || - Item.uDataType != QCBOR_TYPE_BYTE_STRING || - Item.uDataAlloc || - Item.uLabelAlloc || - UsefulBufCompareToSZ(Item.val.string, "yyyy")) { - return 2700; + QCBORDecode_Init(&DCtx, + UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spBooleansInMap), + 0); + QCBORDecode_EnterMap(&DCtx, NULL); + QCBORDecode_GetNullInMapN(&DCtx, 8); + if(QCBORDecode_GetAndResetError(&DCtx) != QCBOR_ERR_UNEXPECTED_TYPE) { + return 10; } - if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { - return 2800 + (int32_t)nCBORError; - } - if(Item.uLabelType != QCBOR_TYPE_TEXT_STRING || - Item.uDataAlloc || - Item.uLabelAlloc || - UsefulBufCompareToSZ(Item.label.string, "another int") || - Item.uDataType != QCBOR_TYPE_INT64 || - Item.val.int64 != 98) { - return 2900; + QCBORDecode_Init(&DCtx, + UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spBooleansInMapNWF), + 0); + QCBORDecode_EnterMap(&DCtx, NULL); + QCBORDecode_GetUndefined(&DCtx); + if(QCBORDecode_GetAndResetError(&DCtx) != QCBOR_ERR_HIT_END) { + return 11; } - if((nCBORError = QCBORDecode_PeekNext(&DCtx, &Item))) { - return 3000 + (int32_t)nCBORError; - } - if(Item.uLabelType != QCBOR_TYPE_TEXT_STRING || - UsefulBuf_Compare(Item.label.string, UsefulBuf_FromSZ("text 2"))|| - Item.uDataType != QCBOR_TYPE_TEXT_STRING || - Item.uDataAlloc || - Item.uLabelAlloc || - UsefulBufCompareToSZ(Item.val.string, "lies, damn lies and statistics")) { - return 3100; + QCBORDecode_Init(&DCtx, + UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spUndefinedInMap), + 0); + QCBORDecode_EnterMap(&DCtx, NULL); + QCBORDecode_GetUndefined(&DCtx); + if(QCBORDecode_GetAndResetError(&DCtx)) { + return 12; } - if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { - return 3200 + (int32_t)nCBORError; + QCBORDecode_Init(&DCtx, + UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spBooleansInMap), + 0); + QCBORDecode_EnterMap(&DCtx, NULL); + QCBORDecode_GetUndefined(&DCtx); + if(QCBORDecode_GetAndResetError(&DCtx) != QCBOR_ERR_UNEXPECTED_TYPE) { + return 13; } - if(Item.uLabelType != QCBOR_TYPE_TEXT_STRING || - UsefulBuf_Compare(Item.label.string, UsefulBuf_FromSZ("text 2"))|| - Item.uDataType != QCBOR_TYPE_TEXT_STRING || - Item.uDataAlloc || - Item.uLabelAlloc || - UsefulBufCompareToSZ(Item.val.string, "lies, damn lies and statistics")) { - return 3300; + + QCBORDecode_Init(&DCtx, + UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spUndefinedInMap), + 0); + QCBORDecode_EnterMap(&DCtx, NULL); + QCBORDecode_GetUndefinedInMapN(&DCtx, 8); + if(QCBORDecode_GetAndResetError(&DCtx)) { + return 14; } - nCBORError = QCBORDecode_PeekNext(&DCtx, &Item); - if(nCBORError != QCBOR_ERR_NO_MORE_ITEMS) { - return 3300 + (int32_t)nCBORError; + QCBORDecode_Init(&DCtx, + UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spBooleansInMap), + 0); + QCBORDecode_EnterMap(&DCtx, NULL); + QCBORDecode_GetUndefinedInMapN(&DCtx, 8); + if(QCBORDecode_GetAndResetError(&DCtx) != QCBOR_ERR_UNEXPECTED_TYPE) { + return 15; } - QCBORDecode_VPeekNext(&DCtx, &Item); - nCBORError = QCBORDecode_GetError(&DCtx); - if(nCBORError != QCBOR_ERR_NO_MORE_ITEMS) { - return 3400 + (int32_t)nCBORError; + QCBORDecode_Init(&DCtx, + UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spBooleansInMapNWF), + 0); + QCBORDecode_EnterMap(&DCtx, NULL); + QCBORDecode_GetUndefined(&DCtx); + if(QCBORDecode_GetAndResetError(&DCtx) != QCBOR_ERR_HIT_END) { + return 15; } - QCBORDecode_VPeekNext(&DCtx, &Item); - nCBORError = QCBORDecode_GetError(&DCtx); - if(nCBORError != QCBOR_ERR_NO_MORE_ITEMS) { - return 3500 + (int32_t)nCBORError; +#ifndef QCBOR_DISABLE_TAGS + QCBORDecode_Init(&DCtx, + UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spTaggedSimples), + 0); + QCBORDecode_GetBool(&DCtx, &b); + if(QCBORDecode_GetNthTagOfLast(&DCtx, 0) != 22) { + return 401; } + if(QCBORDecode_GetNthTagOfLast(&DCtx, 1) != 44) { + return 402; + } + if(QCBORDecode_GetNthTagOfLast(&DCtx, 2) != 88) { + return 403; + } + if(QCBORDecode_GetNthTagOfLast(&DCtx, 3) != CBOR_TAG_INVALID64) { + return 404; + } + QCBORDecode_GetUndefined(&DCtx); + if(QCBORDecode_GetNthTagOfLast(&DCtx, 0) != 4000) { + return 405; + } + if(QCBORDecode_GetNthTagOfLast(&DCtx, 1) != CBOR_TAG_INVALID64) { + return 406; + } + QCBORDecode_GetNull(&DCtx); /* Off the end */ + if(QCBORDecode_GetNthTagOfLast(&DCtx, 0) != CBOR_TAG_INVALID64) { + return 407; + } +#endif /* ! QCBOR_DISABLE_TAGS */ + return 0; +} - // Rewind to top level after entering several maps - QCBORDecode_Init(&DCtx, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(pValidMapEncoded), 0); - - if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { - return (int32_t)nCBORError; - } - if(Item.uDataType != QCBOR_TYPE_MAP || - Item.val.uCount != 3) { - return 400; - } - - if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { - return 4000+(int32_t)nCBORError; - } - - if(Item.uLabelType != QCBOR_TYPE_TEXT_STRING || - Item.uDataType != QCBOR_TYPE_INT64 || - Item.val.int64 != 42 || - Item.uDataAlloc || - Item.uLabelAlloc || - UsefulBufCompareToSZ(Item.label.string, "first integer")) { - return 4100; - } - - if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { - return 4100+(int32_t)nCBORError; - } - if(Item.uLabelType != QCBOR_TYPE_TEXT_STRING || - Item.uDataAlloc || - Item.uLabelAlloc || - UsefulBufCompareToSZ(Item.label.string, "an array of two strings") || - Item.uDataType != QCBOR_TYPE_ARRAY || - Item.val.uCount != 2) { - return 4200; - } - - if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { - return 4200+(int32_t)nCBORError; - } - if(Item.uDataType != QCBOR_TYPE_TEXT_STRING || - Item.uDataAlloc || - Item.uLabelAlloc || - UsefulBufCompareToSZ(Item.val.string, "string1")) { - return 4300; - } - if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { - return 4300+(int32_t)nCBORError; - } - if(Item.uDataType != QCBOR_TYPE_TEXT_STRING || - Item.uDataAlloc || - Item.uLabelAlloc || - UsefulBufCompareToSZ(Item.val.string, "string2")) { - return 4400; - } +#ifndef QCBOR_DISABLE_NON_INTEGER_LABELS +static const uint8_t spExpectedArray2s[] = { + 0x82, 0x67, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, + 0x31, 0x67, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, + 0x32}; - QCBORDecode_Rewind(&DCtx); +#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS +static const uint8_t spExpectedArray2sIndef[] = { + 0x9f, 0x67, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, + 0x31, 0x67, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, + 0x32, 0xff}; +#endif - if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { - return 4400+(int32_t)nCBORError; - } - if(Item.uDataType != QCBOR_TYPE_MAP || - Item.val.uCount != 3) { - return 4500; - } +static const uint8_t spExpectedMap4[] = { + 0xa4, 0x67, 0x62, 0x79, 0x74, 0x65, 0x73, 0x20, + 0x31, 0x44, 0x78, 0x78, 0x78, 0x78, 0x67, 0x62, + 0x79, 0x74, 0x65, 0x73, 0x20, 0x32, 0x44, 0x79, + 0x79, 0x79, 0x79, 0x6b, 0x61, 0x6e, 0x6f, 0x74, + 0x68, 0x65, 0x72, 0x20, 0x69, 0x6e, 0x74, 0x18, + 0x62, 0x66, 0x74, 0x65, 0x78, 0x74, 0x20, 0x32, + 0x78, 0x1e, 0x6c, 0x69, 0x65, 0x73, 0x2c, 0x20, + 0x64, 0x61, 0x6d, 0x6e, 0x20, 0x6c, 0x69, 0x65, + 0x73, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x73, 0x74, + 0x61, 0x74, 0x69, 0x73, 0x74, 0x69, 0x63, 0x73}; - if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { - return (int32_t)nCBORError; - } - if(Item.uLabelType != QCBOR_TYPE_TEXT_STRING || - Item.uDataType != QCBOR_TYPE_INT64 || - Item.val.int64 != 42 || - Item.uDataAlloc || - Item.uLabelAlloc || - UsefulBufCompareToSZ(Item.label.string, "first integer")) { - return 4600; - } +#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS - if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { - return (int32_t)nCBORError; - } - if(Item.uLabelType != QCBOR_TYPE_TEXT_STRING || - Item.uDataAlloc || - Item.uLabelAlloc || - UsefulBufCompareToSZ(Item.label.string, "an array of two strings") || - Item.uDataType != QCBOR_TYPE_ARRAY || - Item.val.uCount != 2) { - return 4700; - } +static const uint8_t spExpectedMap4Indef[] = { + 0xbf, 0x67, 0x62, 0x79, 0x74, 0x65, 0x73, 0x20, + 0x31, 0x44, 0x78, 0x78, 0x78, 0x78, 0x67, 0x62, + 0x79, 0x74, 0x65, 0x73, 0x20, 0x32, 0x44, 0x79, + 0x79, 0x79, 0x79, 0x6b, 0x61, 0x6e, 0x6f, 0x74, + 0x68, 0x65, 0x72, 0x20, 0x69, 0x6e, 0x74, 0x18, + 0x62, 0x66, 0x74, 0x65, 0x78, 0x74, 0x20, 0x32, + 0x78, 0x1e, 0x6c, 0x69, 0x65, 0x73, 0x2c, 0x20, + 0x64, 0x61, 0x6d, 0x6e, 0x20, 0x6c, 0x69, 0x65, + 0x73, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x73, 0x74, + 0x61, 0x74, 0x69, 0x73, 0x74, 0x69, 0x63, 0x73, + 0xff}; - if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { - return (int32_t)nCBORError; - } - if(Item.uDataType != QCBOR_TYPE_TEXT_STRING || - Item.uDataAlloc || - Item.uLabelAlloc || - UsefulBufCompareToSZ(Item.val.string, "string1")) { - return 4800; - } +/* + * [[[[[0, []]]]], 0] + */ +static const uint8_t spDefAndIndef[] = { + 0x82, + 0x9f, 0x9f, 0x9f, 0x82, 0x00, 0x9f, 0xff, 0xff, 0xff, 0xff, 0x00 +}; +#endif /* !QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS */ - if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { - return 4900+(int32_t)nCBORError; - } - if(Item.uDataType != QCBOR_TYPE_TEXT_STRING || - Item.uDataAlloc || - Item.uLabelAlloc || - UsefulBufCompareToSZ(Item.val.string, "string2")) { - return 5000; - } +#ifndef QCBOR_DISABLE_TAGS +/* An exp / mant tag in two nested arrays */ +static const uint8_t spExpMant[] = {0x81, 0x81, 0xC4, 0x82, 0x20, 0x03}; +#endif /* !QCBOR_DISABLE_TAGS */ +#endif +#ifndef QCBOR_DISABLE_NON_INTEGER_LABELS +int32_t GetMapAndArrayTest(void) +{ + QCBORDecodeContext DCtx; + size_t uPosition ; + QCBORItem Item; + UsefulBufC ReturnedEncodedCBOR; - // Rewind an entered map - QCBORDecode_Init(&DCtx, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(pValidMapEncoded), 0); + // Improvement: rework so it can run with QCBOR_DISABLE_NON_INTEGER_LABELS + QCBORDecode_Init(&DCtx, + UsefulBuf_FROM_BYTE_ARRAY_LITERAL(pValidMapEncoded), + 0); QCBORDecode_EnterMap(&DCtx, NULL); - - if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { - return 5100+(int32_t)nCBORError; + QCBORDecode_VGetNextConsume(&DCtx, &Item); + QCBORDecode_GetArray(&DCtx, &Item, &ReturnedEncodedCBOR); + if(QCBORDecode_GetError(&DCtx)) { + return 1; + } + if(Item.val.uCount != 2) { + return 2; + } + if(UsefulBuf_Compare(ReturnedEncodedCBOR, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spExpectedArray2s))) { + return 3; } if(Item.uLabelType != QCBOR_TYPE_TEXT_STRING || - Item.uDataType != QCBOR_TYPE_INT64 || - Item.val.int64 != 42 || - Item.uDataAlloc || - Item.uLabelAlloc || - UsefulBufCompareToSZ(Item.label.string, "first integer")) { - return 5200; - } + UsefulBuf_Compare(Item.label.string, UsefulBuf_FROM_SZ_LITERAL("an array of two strings"))) { + return 4; + } - if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { - return 5200+(int32_t)nCBORError; - } - if(Item.uLabelType != QCBOR_TYPE_TEXT_STRING || - Item.uDataAlloc || - Item.uLabelAlloc || - UsefulBufCompareToSZ(Item.label.string, "an array of two strings") || - Item.uDataType != QCBOR_TYPE_ARRAY || - Item.val.uCount != 2) { - return -5300; - } + uPosition = QCBORDecode_Tell(&DCtx); + + + QCBORDecode_GetMap(&DCtx, &Item, &ReturnedEncodedCBOR); + if(QCBORDecode_GetError(&DCtx)) { + return 10; + } + if(Item.val.uCount != 4) { + return 11; + } + if(UsefulBuf_Compare(ReturnedEncodedCBOR, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spExpectedMap4))) { + return 12; + } + uPosition = QCBORDecode_Tell(&DCtx); + QCBORDecode_GetArrayFromMapSZ(&DCtx, + "an array of two strings", + &Item, + &ReturnedEncodedCBOR); + if(QCBORDecode_GetError(&DCtx)) { + return 20; + } + if(Item.val.uCount != 2) { + return 21; + } + if(UsefulBuf_Compare(ReturnedEncodedCBOR, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spExpectedArray2s))) { + return 22; + } + if(uPosition != QCBORDecode_Tell(&DCtx)) { + return 23; + } QCBORDecode_Rewind(&DCtx); - if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { - return 5300+(int32_t)nCBORError; + uPosition = QCBORDecode_Tell(&DCtx); + QCBORDecode_GetMapFromMapSZ(&DCtx, "map in a map", &Item, &ReturnedEncodedCBOR); + if(QCBORDecode_GetError(&DCtx)) { + return 30; + } + if(Item.val.uCount != 4) { + return 31; + } + if(UsefulBuf_Compare(ReturnedEncodedCBOR, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spExpectedMap4))) { + return 32; + } + if(uPosition != QCBORDecode_Tell(&DCtx)) { + return 33; } - if(Item.uLabelType != QCBOR_TYPE_TEXT_STRING || - Item.uDataType != QCBOR_TYPE_INT64 || - Item.val.int64 != 42 || - Item.uDataAlloc || - Item.uLabelAlloc || - UsefulBufCompareToSZ(Item.label.string, "first integer")) { - return 5400; + uPosition = QCBORDecode_Tell(&DCtx); + QCBORDecode_GetArrayFromMapSZ(&DCtx, "map in a map", &Item, &ReturnedEncodedCBOR); + if(QCBORDecode_GetError(&DCtx) != QCBOR_ERR_UNEXPECTED_TYPE) { + return 40; + } + if(UINT32_MAX != QCBORDecode_Tell(&DCtx)) { + return 41; + } + QCBORDecode_GetAndResetError(&DCtx); + if(uPosition != QCBORDecode_Tell(&DCtx)) { + return 42; } - if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { - return 5400+(int32_t)nCBORError; + +#ifndef QCBOR_DISABLE_TAGS + UsefulBufC ExpMant = UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spExpMant); + QCBORDecode_Init(&DCtx, ExpMant, 0); + QCBORDecode_EnterArray(&DCtx, NULL); + QCBORDecode_EnterArray(&DCtx, NULL); + QCBORDecode_GetArray(&DCtx, &Item, &ReturnedEncodedCBOR); + if(QCBORDecode_GetError(&DCtx) != QCBOR_SUCCESS) { + return 200; + } + if(Item.uDataType != QCBOR_TYPE_ARRAY) { + return 201; + } + if(!QCBORDecode_IsTagged(&DCtx, &Item, CBOR_TAG_DECIMAL_FRACTION)) { + return 202; } - if(Item.uLabelType != QCBOR_TYPE_TEXT_STRING || - Item.uDataAlloc || - Item.uLabelAlloc || - UsefulBufCompareToSZ(Item.label.string, "an array of two strings") || - Item.uDataType != QCBOR_TYPE_ARRAY || - Item.val.uCount != 2) { - return 5500; + if(Item.val.uCount != 2) { + return 201; } + if(UsefulBuf_Compare(ReturnedEncodedCBOR, UsefulBuf_Tail(ExpMant, 2))) { + return 205; + } +#endif /* !QCBOR_DISABLE_TAGS */ - // Rewind and entered array inside an entered map - QCBORDecode_Init(&DCtx, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(pValidMapEncoded), 0); - - QCBORDecode_EnterMap(&DCtx, NULL); - - QCBORDecode_EnterArrayFromMapSZ(&DCtx, "an array of two strings"); +#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS - if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { - return 5600+(int32_t)nCBORError; + UsefulBufC DefAndIndef = UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spDefAndIndef); + QCBORDecode_Init(&DCtx, DefAndIndef, 0); + QCBORDecode_EnterArray(&DCtx, NULL); + QCBORDecode_GetArray(&DCtx, &Item, &ReturnedEncodedCBOR); + if(QCBORDecode_GetError(&DCtx) != QCBOR_SUCCESS) { + return 50; } - if(Item.uDataType != QCBOR_TYPE_TEXT_STRING || - Item.uDataAlloc || - Item.uLabelAlloc || - UsefulBufCompareToSZ(Item.val.string, "string1")) { - return 5700; + if(UsefulBuf_Compare(ReturnedEncodedCBOR, UsefulBuf_Tail(UsefulBuf_Head(DefAndIndef, 11), 1))) { + return 51; } - QCBORDecode_Rewind(&DCtx); + QCBORDecode_Init(&DCtx, DefAndIndef, 0); + QCBORDecode_EnterArray(&DCtx, NULL); + QCBORDecode_EnterArray(&DCtx, NULL); + QCBORDecode_GetArray(&DCtx, &Item, &ReturnedEncodedCBOR); + if(QCBORDecode_GetError(&DCtx) != QCBOR_SUCCESS) { + return 52; + } + if(UsefulBuf_Compare(ReturnedEncodedCBOR, UsefulBuf_Tail(UsefulBuf_Head(DefAndIndef, 10), 2))) { + return 53; + } - if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { - return 5700+(int32_t)nCBORError; + QCBORDecode_Init(&DCtx, DefAndIndef, 0); + QCBORDecode_EnterArray(&DCtx, NULL); + QCBORDecode_EnterArray(&DCtx, NULL); + QCBORDecode_EnterArray(&DCtx, NULL); + QCBORDecode_GetArray(&DCtx, &Item, &ReturnedEncodedCBOR); + if(QCBORDecode_GetError(&DCtx) != QCBOR_SUCCESS) { + return 54; } - if(Item.uDataType != QCBOR_TYPE_TEXT_STRING || - Item.uDataAlloc || - Item.uLabelAlloc || - UsefulBufCompareToSZ(Item.val.string, "string1")) { - return 5800; + if(UsefulBuf_Compare(ReturnedEncodedCBOR, UsefulBuf_Tail(UsefulBuf_Head(DefAndIndef, 9), 3))) { + return 55; + } + QCBORDecode_Init(&DCtx, DefAndIndef, 0); + QCBORDecode_EnterArray(&DCtx, NULL); + QCBORDecode_EnterArray(&DCtx, NULL); + QCBORDecode_EnterArray(&DCtx, NULL); + QCBORDecode_EnterArray(&DCtx, NULL); + QCBORDecode_GetArray(&DCtx, &Item, &ReturnedEncodedCBOR); + if(QCBORDecode_GetError(&DCtx) != QCBOR_SUCCESS) { + return 56; + } + if(UsefulBuf_Compare(ReturnedEncodedCBOR, UsefulBuf_Tail(UsefulBuf_Head(DefAndIndef, 8), 4))) { + return 57; } - if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { - return (int32_t)nCBORError; + QCBORDecode_Init(&DCtx, DefAndIndef, 0); + QCBORDecode_EnterArray(&DCtx, NULL); + QCBORDecode_EnterArray(&DCtx, NULL); + QCBORDecode_EnterArray(&DCtx, NULL); + QCBORDecode_EnterArray(&DCtx, NULL); + QCBORDecode_EnterArray(&DCtx, NULL); + QCBORDecode_VGetNextConsume(&DCtx, &Item); + QCBORDecode_GetArray(&DCtx, &Item, &ReturnedEncodedCBOR); + if(QCBORDecode_GetError(&DCtx) != QCBOR_SUCCESS) { + return 58; } - if(Item.uDataType != QCBOR_TYPE_TEXT_STRING || - Item.uDataAlloc || - Item.uLabelAlloc || - UsefulBufCompareToSZ(Item.val.string, "string2")) { - return 5900; + if(UsefulBuf_Compare(ReturnedEncodedCBOR, UsefulBuf_Tail(UsefulBuf_Head(DefAndIndef, 8), 6))) { + return 59; } - QCBORDecode_Rewind(&DCtx); - if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { - return 5900+(int32_t)nCBORError; + QCBORDecode_Init(&DCtx, + UsefulBuf_FROM_BYTE_ARRAY_LITERAL(pValidMapIndefEncoded), + 0); + + QCBORDecode_EnterMap(&DCtx, NULL); + QCBORDecode_VGetNextConsume(&DCtx, &Item); + QCBORDecode_GetArray(&DCtx, &Item, &ReturnedEncodedCBOR); + if(QCBORDecode_GetError(&DCtx)) { + return 60; } - if(Item.uDataType != QCBOR_TYPE_TEXT_STRING || - Item.uDataAlloc || - Item.uLabelAlloc || - UsefulBufCompareToSZ(Item.val.string, "string1")) { - return 6000; + if(Item.val.uCount != UINT16_MAX) { + return 61; + } + if(UsefulBuf_Compare(ReturnedEncodedCBOR, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spExpectedArray2sIndef))) { + return 62; } + if(Item.uLabelType != QCBOR_TYPE_TEXT_STRING || + UsefulBuf_Compare(Item.label.string, UsefulBuf_FROM_SZ_LITERAL("an array of two strings"))) { + return 63; + } - // Rewind a byte string inside an array inside an array - QCBORDecode_Init(&DCtx, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(pValidWrappedMapEncoded), 0); + uPosition = QCBORDecode_Tell(&DCtx); - QCBORDecode_EnterArray(&DCtx, NULL); - uint64_t i; - QCBORDecode_GetUInt64(&DCtx, &i); + QCBORDecode_GetMap(&DCtx, &Item, &ReturnedEncodedCBOR); + if(QCBORDecode_GetError(&DCtx)) { + return 70; + } + if(Item.val.uCount != UINT16_MAX) { + return 71; + } + if(UsefulBuf_Compare(ReturnedEncodedCBOR, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spExpectedMap4Indef))) { + return 72; + } - QCBORDecode_EnterArray(&DCtx, NULL); - QCBORDecode_EnterBstrWrapped(&DCtx, QCBOR_TAG_REQUIREMENT_NOT_A_TAG, NULL); + uPosition = QCBORDecode_Tell(&DCtx); + QCBORDecode_GetArrayFromMapSZ(&DCtx, + "an array of two strings", + &Item, + &ReturnedEncodedCBOR); if(QCBORDecode_GetError(&DCtx)) { - return 6100; + return 80; } - - if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { - return (int32_t)nCBORError; + if(Item.val.uCount != UINT16_MAX) { + return 81; } - if(Item.uDataType != QCBOR_TYPE_MAP || Item.val.uCount != 3) { - return 6200; + if(UsefulBuf_Compare(ReturnedEncodedCBOR, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spExpectedArray2sIndef))) { + return 82; + } + if(uPosition != QCBORDecode_Tell(&DCtx)) { + return 83; } QCBORDecode_Rewind(&DCtx); - if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { - return 6300+(int32_t)nCBORError; + uPosition = QCBORDecode_Tell(&DCtx); + QCBORDecode_GetMapFromMapSZ(&DCtx, "map in a map", &Item, &ReturnedEncodedCBOR); + if(QCBORDecode_GetError(&DCtx)) { + return 90; } - if(Item.uDataType != QCBOR_TYPE_MAP || Item.val.uCount != 3) { - return 6400; + if(Item.val.uCount != UINT16_MAX) { + return 91; + } + if(UsefulBuf_Compare(ReturnedEncodedCBOR, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spExpectedMap4Indef))) { + return 92; + } + if(uPosition != QCBORDecode_Tell(&DCtx)) { + return 93; } -#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS - // Rewind a byte string inside an indefinite-length array inside - // indefinite-length array + uPosition = QCBORDecode_Tell(&DCtx); + QCBORDecode_GetArrayFromMapSZ(&DCtx, "map in a map", &Item, &ReturnedEncodedCBOR); + if(QCBORDecode_GetError(&DCtx) != QCBOR_ERR_UNEXPECTED_TYPE) { + return 100; + } + if(UINT32_MAX != QCBORDecode_Tell(&DCtx)) { + return 101; + } + QCBORDecode_GetAndResetError(&DCtx); + if(uPosition != QCBORDecode_Tell(&DCtx)) { + return 102; + } +#endif /* ! QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS */ - QCBORDecode_Init(&DCtx, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(pValidIndefWrappedMapEncoded), 0); + return 0; +} +#endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */ - QCBORDecode_EnterArray(&DCtx, NULL); + +int32_t +ErrorHandlingTests(void) +{ + QCBORDecodeContext DCtx; + QCBORItem Item; + QCBORError uError; + int64_t integer; - QCBORDecode_GetUInt64(&DCtx, &i); + /* Test QCBORDecode_SetError() */ + QCBORDecode_Init(&DCtx, + UsefulBuf_FROM_BYTE_ARRAY_LITERAL(pValidMapEncoded), + QCBOR_DECODE_MODE_NORMAL); - QCBORDecode_EnterArray(&DCtx, NULL); + QCBORDecode_SetError(&DCtx, QCBOR_ERR_FIRST_USER_DEFINED); - QCBORDecode_EnterBstrWrapped(&DCtx, QCBOR_TAG_REQUIREMENT_NOT_A_TAG, NULL); - if(QCBORDecode_GetError(&DCtx)) { - return 6500; - } + QCBORDecode_VGetNext(&DCtx, &Item); - if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { - return 6600+(int32_t)nCBORError; + uError = QCBORDecode_GetError(&DCtx); + + if(uError != QCBOR_ERR_FIRST_USER_DEFINED) { + return -1; } - if(Item.uDataType != QCBOR_TYPE_MAP || Item.val.uCount != 3) { - return 6700; + + if(Item.uLabelType != QCBOR_TYPE_NONE || + Item.uDataType != QCBOR_TYPE_NONE) { + return -2; } - QCBORDecode_Rewind(&DCtx); - if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { - return 6800+(int32_t)nCBORError; - } - if(Item.uDataType != QCBOR_TYPE_MAP || Item.val.uCount != 3) { - return 6900; + /* Test data type returned from previous error */ + QCBORDecode_Init(&DCtx, + UsefulBuf_FROM_BYTE_ARRAY_LITERAL(pValidMapEncoded), + QCBOR_DECODE_MODE_NORMAL); + QCBORDecode_GetInt64(&DCtx, &integer); + uError = QCBORDecode_GetError(&DCtx); + if(uError != QCBOR_ERR_UNEXPECTED_TYPE) { + return -3; } -#endif - // Rewind an empty map - // [100, {}] - QCBORDecode_Init(&DCtx, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(pWithEmptyMap), 0); - QCBORDecode_EnterArray(&DCtx, NULL); - QCBORDecode_GetUInt64(&DCtx, &i); - if(i != 100) { - return 7010; + QCBORDecode_VGetNext(&DCtx, &Item); + if(Item.uLabelType != QCBOR_TYPE_NONE || + Item.uDataType != QCBOR_TYPE_NONE) { + return -2; } - QCBORDecode_EnterMap(&DCtx, NULL); - - /* Do it 5 times to be sure multiple rewinds work */ - for(int n = 0; n < 5; n++) { - nCBORError = QCBORDecode_GetNext(&DCtx, &Item); - if(nCBORError != QCBOR_ERR_NO_MORE_ITEMS) { - return 7000 + n; - } - QCBORDecode_Rewind(&DCtx); + uError = QCBORDecode_GetError(&DCtx); + if(uError != QCBOR_ERR_UNEXPECTED_TYPE) { + return -3; } - QCBORDecode_ExitMap(&DCtx); - QCBORDecode_Rewind(&DCtx); - QCBORDecode_GetUInt64(&DCtx, &i); - if(i != 100) { - return 7010; + + + /* Test error classification functions */ + + if(!QCBORDecode_IsUnrecoverableError(QCBOR_ERR_INDEFINITE_STRING_CHUNK)) { + return -10; } - QCBORDecode_ExitArray(&DCtx); - QCBORDecode_Rewind(&DCtx); - QCBORDecode_EnterArray(&DCtx, NULL); - i = 9; - QCBORDecode_GetUInt64(&DCtx, &i); - if(i != 100) { - return 7020; + if(QCBORDecode_IsUnrecoverableError(QCBOR_SUCCESS)) { + return -11; } - if(QCBORDecode_GetError(&DCtx)){ - return 7030; + if(!QCBORDecode_IsUnrecoverableError(QCBOR_ERR_INDEFINITE_STRING_CHUNK)) { + return -12; } - - // Rewind an empty indefinite length map -#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS - QCBORDecode_Init(&DCtx, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(pWithEmptyMapInDef), 0); - QCBORDecode_EnterArray(&DCtx, NULL); - QCBORDecode_GetUInt64(&DCtx, &i); - if(i != 100) { - return 7810; + if(QCBORDecode_IsUnrecoverableError(QCBOR_ERR_DUPLICATE_LABEL)) { + return -13; } - QCBORDecode_EnterMap(&DCtx, NULL); - /* Do it 5 times to be sure multiple rewinds work */ - for(int n = 0; n < 5; n++) { - nCBORError = QCBORDecode_GetNext(&DCtx, &Item); - if(nCBORError != QCBOR_ERR_NO_MORE_ITEMS) { - return 7800 + n; - } - QCBORDecode_Rewind(&DCtx); + if(!QCBORDecode_IsNotWellFormedError(QCBOR_ERR_BAD_TYPE_7)) { + return -20; } - QCBORDecode_ExitMap(&DCtx); - QCBORDecode_Rewind(&DCtx); - QCBORDecode_GetUInt64(&DCtx, &i); - if(i != 100) { - return 7810; + if(!QCBORDecode_IsNotWellFormedError(QCBOR_ERR_BAD_BREAK)) { + return -21; } - QCBORDecode_ExitArray(&DCtx); - QCBORDecode_Rewind(&DCtx); - QCBORDecode_EnterArray(&DCtx, NULL); - i = 9; - QCBORDecode_GetUInt64(&DCtx, &i); - if(i != 100) { - return 7820; + if(QCBORDecode_IsNotWellFormedError(QCBOR_SUCCESS)) { + return -22; } - if(QCBORDecode_GetError(&DCtx)){ - return 7830; + if(QCBORDecode_IsNotWellFormedError(QCBOR_ERR_ARRAY_DECODE_TOO_LONG)) { + return -23; } -#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS */ - // Rewind an indefnite length byte-string wrapped sequence -#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS - // TODO: rewrite this test to not use tags - QCBORDecode_Init(&DCtx, - UsefulBuf_FROM_BYTE_ARRAY_LITERAL(pWrappedByIndefiniteLength), - 0); - UsefulBuf_MAKE_STACK_UB(Pool, 100); - QCBORDecode_SetMemPool(&DCtx, Pool, 0); + /* Test error strings */ + const char *szErrString; - QCBORDecode_EnterArray(&DCtx, NULL); - QCBORDecode_EnterBstrWrapped(&DCtx, 2, NULL); -#ifndef QCBOR_DISABLE_TAGS - if(QCBORDecode_GetError(&DCtx) != QCBOR_ERR_INPUT_TOO_LARGE) { - /* TODO: This is what happens when trying to enter - * indefinite-length byte string wrapped CBOR. Tolerate for - * now. Eventually it needs to be fixed so this works, but that - * is not simple. - */ - return 7300; + szErrString = qcbor_err_to_str(QCBOR_ERR_ARRAY_DECODE_TOO_LONG); + if(szErrString == NULL) { + return -100; + } + if(strcmp(szErrString, "QCBOR_ERR_ARRAY_DECODE_TOO_LONG")) { + return -101; } - /* - QCBORDecode_GetUInt64(&DCtx, &i); - if(i != 42) { - return 7110; + szErrString = qcbor_err_to_str(QCBOR_SUCCESS); + if(szErrString == NULL) { + return -102; + } + if(strcmp(szErrString, "QCBOR_SUCCESS")) { + return -103; } - QCBORDecode_Rewind(&DCtx); - QCBORDecode_GetUInt64(&DCtx, &i); - if(i != 42) { - return 7220; - }*/ -#else /* QCBOR_DISABLE_TAGS */ - if(QCBORDecode_GetError(&DCtx) != QCBOR_ERR_TAGS_DISABLED) { - return 7301; + szErrString = qcbor_err_to_str(100); + if(szErrString == NULL) { + return -104; + } + if(strcmp(szErrString, "Unidentified QCBOR error")) { + return -105; } -#endif /* QCBOR_DISABLE_TAGS */ -#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS */ + szErrString = qcbor_err_to_str(200); + if(szErrString == NULL) { + return -106; + } + if(strcmp(szErrString, "USER_DEFINED_200")) { + return -107; + } + QCBORDecode_Init(&DCtx, + UsefulBuf_FROM_BYTE_ARRAY_LITERAL(pValidMapEncoded), + QCBOR_DECODE_MODE_NORMAL); - // Rewind an indefnite length byte-string wrapped sequence + UsefulBufC Xx = QCBORDecode_RetrieveUndecodedInput(&DCtx); + if(Xx.ptr != pValidMapEncoded) { + return -200; + } + if(Xx.len != sizeof(pValidMapEncoded)) { + return -201; + } return 0; } - - -static const uint8_t spBooleansInMap[] = -{ - 0xa1, 0x08, 0xf5 -}; - -static const uint8_t spBooleansInMapWrongType[] = -{ - 0xa1, 0x08, 0xf6 -}; - -static const uint8_t spBooleansInMapNWF[] = -{ - 0xa1, 0x08, 0x1a -}; - -static const uint8_t spNullInMap[] = -{ - 0xa1, 0x08, 0xf6 -}; - -static const uint8_t spUndefinedInMap[] = -{ - 0xa1, 0x08, 0xf7 -}; - - -int32_t BoolTest(void) +int32_t TellTests(void) { QCBORDecodeContext DCtx; - bool b; + QCBORItem Item; + uint32_t uPosition; + int nIndex; + int64_t nDecodedInt; + // Improvement: rewrite so this can run with only integer labels + static const uint32_t aPos[] = + {0, 1, 17, 42, 50, 58, 72, 85, 98, 112, 151}; QCBORDecode_Init(&DCtx, - UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spBooleansInMap), + UsefulBuf_FROM_BYTE_ARRAY_LITERAL(pValidMapEncoded), 0); - QCBORDecode_EnterMap(&DCtx, NULL); - QCBORDecode_GetBool(&DCtx, &b); - if(QCBORDecode_GetAndResetError(&DCtx) || !b) { - return 1; - } + for(nIndex = 0; ; nIndex++) { + uPosition = QCBORDecode_Tell(&DCtx); + if(uPosition != aPos[nIndex]) { + return nIndex; + } - QCBORDecode_GetBoolInMapN(&DCtx, 7, &b); - if(QCBORDecode_GetAndResetError(&DCtx) != QCBOR_ERR_LABEL_NOT_FOUND) { - return 2; - } + if(QCBORDecode_EndCheck(&DCtx)) { + break; + } - QCBORDecode_GetBoolInMapN(&DCtx, 8, &b); - if(QCBORDecode_GetAndResetError(&DCtx) || !b) { - return 3; + QCBORDecode_VGetNext(&DCtx, &Item); } - - QCBORDecode_GetBoolInMapSZ(&DCtx, "xx", &b); - if(QCBORDecode_GetAndResetError(&DCtx) != QCBOR_ERR_LABEL_NOT_FOUND) { - return 4; - } - +#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS + static const uint32_t aPosIndef[] = + {0, 1, 17, 42, 50, 59, 73, 86, 99, 113, 154}; QCBORDecode_Init(&DCtx, - UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spBooleansInMapWrongType), + UsefulBuf_FROM_BYTE_ARRAY_LITERAL(pValidMapIndefEncoded), 0); - QCBORDecode_EnterMap(&DCtx, NULL); - QCBORDecode_GetBool(&DCtx, &b); - if(QCBORDecode_GetAndResetError(&DCtx) != QCBOR_ERR_UNEXPECTED_TYPE) { - return 5; + + for(nIndex = 0; ; nIndex++) { + uPosition = QCBORDecode_Tell(&DCtx); + if(uPosition != aPosIndef[nIndex]) { + return nIndex + 100; + } + + if(QCBORDecode_EndCheck(&DCtx)) { + break; + } + + QCBORDecode_VGetNext(&DCtx, &Item); } +#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS */ + /* Next, some tests with entered maps and arrays */ QCBORDecode_Init(&DCtx, - UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spBooleansInMapNWF), + UsefulBuf_FROM_BYTE_ARRAY_LITERAL(pValidMapEncoded), 0); - QCBORDecode_EnterMap(&DCtx, NULL); - QCBORDecode_GetBool(&DCtx, &b); - if(QCBORDecode_GetAndResetError(&DCtx) != QCBOR_ERR_HIT_END) { - return 6; + QCBORDecode_EnterMap(&DCtx, &Item); + if(QCBORDecode_Tell(&DCtx) != 1) { + return 1001; + } + QCBORDecode_GetInt64InMapSZ(&DCtx, "first integer", &nDecodedInt); + if(QCBORDecode_Tell(&DCtx) != 1) { + return 1002; + } + QCBORDecode_EnterMapFromMapSZ(&DCtx, "map in a map"); + if(QCBORDecode_Tell(&DCtx) != 72) { + return 1003; } + QCBORDecode_GetInt64InMapSZ(&DCtx, "another int", &nDecodedInt); + if(nDecodedInt != 98) { + return 1004; + } + /* Getting non-aggregate types doesn't affect cursor position. */ + if(QCBORDecode_Tell(&DCtx) != 72) { + return 1005; + } + QCBORDecode_VGetNext(&DCtx, &Item); + if(QCBORDecode_Tell(&DCtx) != 85) { + return 1006; + } + QCBORDecode_GetInt64InMapSZ(&DCtx, "another int", &nDecodedInt); + if(nDecodedInt != 98) { + return 1007; + } + /* Getting non-aggregate types doesn't affect cursor position. */ + if(QCBORDecode_Tell(&DCtx) != 85) { + return 1008; + } - QCBORDecode_Init(&DCtx, - UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spNullInMap), - 0); - QCBORDecode_EnterMap(&DCtx, NULL); - QCBORDecode_GetNull(&DCtx); - if(QCBORDecode_GetAndResetError(&DCtx)) { - return 7; + QCBORDecode_ExitMap(&DCtx); + if(QCBORDecode_Tell(&DCtx) != 151) { + return 1009; + } + if(QCBORDecode_GetNext(&DCtx, &Item) != QCBOR_ERR_NO_MORE_ITEMS) { + return 1010; } +#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS + /* Next, some tests with entered maps and arrays */ QCBORDecode_Init(&DCtx, - UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spBooleansInMap), + UsefulBuf_FROM_BYTE_ARRAY_LITERAL(pValidMapIndefEncoded), 0); - QCBORDecode_EnterMap(&DCtx, NULL); - QCBORDecode_GetNull(&DCtx); - if(QCBORDecode_GetAndResetError(&DCtx) != QCBOR_ERR_UNEXPECTED_TYPE) { - return 8; + QCBORDecode_EnterMap(&DCtx, &Item); + if(QCBORDecode_Tell(&DCtx) != 1) { + return 2000; + } + QCBORDecode_GetInt64InMapSZ(&DCtx, "first integer", &nDecodedInt); + if(QCBORDecode_Tell(&DCtx) != 1) { + return 2001; + } + QCBORDecode_EnterMapFromMapSZ(&DCtx, "map in a map"); + if(QCBORDecode_Tell(&DCtx) != 73) { + return 2002; } - QCBORDecode_Init(&DCtx, - UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spNullInMap), - 0); - QCBORDecode_EnterMap(&DCtx, NULL); - QCBORDecode_GetNullInMapN(&DCtx, 8); - if(QCBORDecode_GetAndResetError(&DCtx)) { - return 9; + QCBORDecode_GetInt64InMapSZ(&DCtx, "another int", &nDecodedInt); + if(nDecodedInt != 98) { + return 2003; + } + /* Getting non-aggregate types doesn't affect cursor position. */ + if(QCBORDecode_Tell(&DCtx) != 73) { + return 2004; + } + QCBORDecode_VGetNext(&DCtx, &Item); + if(QCBORDecode_Tell(&DCtx) != 86) { + return 2005; + } + QCBORDecode_GetInt64InMapSZ(&DCtx, "another int", &nDecodedInt); + if(nDecodedInt != 98) { + return 2006; + } + /* Getting non-aggregate types doesn't affect cursor position. */ + if(QCBORDecode_Tell(&DCtx) != 86) { + return 2007; } - QCBORDecode_Init(&DCtx, - UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spBooleansInMap), - 0); - QCBORDecode_EnterMap(&DCtx, NULL); - QCBORDecode_GetNullInMapN(&DCtx, 8); - if(QCBORDecode_GetAndResetError(&DCtx) != QCBOR_ERR_UNEXPECTED_TYPE) { - return 10; + QCBORDecode_ExitMap(&DCtx); + if(QCBORDecode_Tell(&DCtx) != 154) { + return 2008; + } + if(QCBORDecode_GetNext(&DCtx, &Item) != QCBOR_ERR_NO_MORE_ITEMS) { + return 2010; } +#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS */ + + + /* Error state test */ QCBORDecode_Init(&DCtx, - UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spBooleansInMapNWF), + UsefulBuf_FROM_BYTE_ARRAY_LITERAL(pValidMapEncoded), 0); - QCBORDecode_EnterMap(&DCtx, NULL); - QCBORDecode_GetUndefined(&DCtx); - if(QCBORDecode_GetAndResetError(&DCtx) != QCBOR_ERR_HIT_END) { - return 11; + /* Cause an error */ + QCBORDecode_GetInt64InMapSZ(&DCtx, "another int", &nDecodedInt); + if(QCBORDecode_Tell(&DCtx) != UINT32_MAX) { + return 3000; + } + if(QCBORDecode_EndCheck(&DCtx) != QCBOR_ERR_MAP_NOT_ENTERED) { + return 3001; } - QCBORDecode_Init(&DCtx, - UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spUndefinedInMap), - 0); - QCBORDecode_EnterMap(&DCtx, NULL); - QCBORDecode_GetUndefined(&DCtx); - if(QCBORDecode_GetAndResetError(&DCtx)) { - return 12; + + /* Empties tests */ + const uint8_t pMinimalCBOR[] = {0xa0}; // One empty map + QCBORDecode_Init(&DCtx, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(pMinimalCBOR),0); + if(QCBORDecode_Tell(&DCtx) != 0) { + return 4000; + } + if(QCBORDecode_EndCheck(&DCtx) != QCBOR_SUCCESS) { + return 4008; + } + QCBORDecode_EnterMap(&DCtx, &Item); + if(QCBORDecode_GetError(&DCtx) != QCBOR_SUCCESS) { + return 4001; + } + if(QCBORDecode_Tell(&DCtx) != 1) { + return 4002; + } + QCBORDecode_ExitMap(&DCtx); + if(QCBORDecode_GetError(&DCtx) != QCBOR_SUCCESS) { + return 4003; + } + if(QCBORDecode_Tell(&DCtx) != 1) { + return 4004; + } + if(QCBORDecode_EndCheck(&DCtx) != QCBOR_ERR_NO_MORE_ITEMS) { + return 4005; + } + if(QCBORDecode_GetNext(&DCtx, &Item) != QCBOR_ERR_NO_MORE_ITEMS) { + return 4010; } - QCBORDecode_Init(&DCtx, - UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spBooleansInMap), - 0); - QCBORDecode_EnterMap(&DCtx, NULL); - QCBORDecode_GetUndefined(&DCtx); - if(QCBORDecode_GetAndResetError(&DCtx) != QCBOR_ERR_UNEXPECTED_TYPE) { - return 13; +#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS + const uint8_t pMinimalIndefCBOR[] = {0xbf, 0xff}; // One empty map + QCBORDecode_Init(&DCtx, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(pMinimalIndefCBOR),0); + if(QCBORDecode_Tell(&DCtx) != 0) { + return 4100; + } + QCBORDecode_EnterMap(&DCtx, &Item); + if(QCBORDecode_GetError(&DCtx) != QCBOR_SUCCESS) { + return 4101; + } + if(QCBORDecode_Tell(&DCtx) != 2) { + return 4102; + } + QCBORDecode_ExitMap(&DCtx); + if(QCBORDecode_GetError(&DCtx) != QCBOR_SUCCESS) { + return 4103; + } + if(QCBORDecode_Tell(&DCtx) != 2) { + return 4104; + } + if(QCBORDecode_EndCheck(&DCtx) != QCBOR_ERR_NO_MORE_ITEMS) { + return 4005; + } + if(QCBORDecode_GetNext(&DCtx, &Item) != QCBOR_ERR_NO_MORE_ITEMS) { + return 4110; + } +#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS */ + + /* Test on a CBOR sequence */ + QCBORDecode_Init(&DCtx, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spSequenceTestInput),0); + if(QCBORDecode_Tell(&DCtx) != 0) { + return 5000; + } + QCBORDecode_VGetNext(&DCtx, &Item); + if(QCBORDecode_GetError(&DCtx) != QCBOR_SUCCESS) { + return 5001; } + if(QCBORDecode_Tell(&DCtx) != 11) { + return 5002; + } + QCBORDecode_VGetNext(&DCtx, &Item); + if(QCBORDecode_GetError(&DCtx) != QCBOR_SUCCESS) { + return 5003; + } + if(QCBORDecode_Tell(&DCtx) != 12) { + return 5004; + } + QCBORDecode_VGetNext(&DCtx, &Item); + if(QCBORDecode_GetError(&DCtx) != QCBOR_SUCCESS) { + return 5005; + } + if(QCBORDecode_Tell(&DCtx) != 17) { + return 5006; + } + QCBORDecode_VGetNext(&DCtx, &Item); + if(QCBORDecode_GetError(&DCtx) != QCBOR_SUCCESS) { + return 5007; + } + if(QCBORDecode_Tell(&DCtx) != 20) { + return 5008; + } + if(QCBORDecode_GetNext(&DCtx, &Item) != QCBOR_ERR_NO_MORE_ITEMS) { + return 5010; + } + QCBORDecode_Init(&DCtx, - UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spUndefinedInMap), + UsefulBuf_FROM_BYTE_ARRAY_LITERAL(pValidMapEncoded), 0); - QCBORDecode_EnterMap(&DCtx, NULL); - QCBORDecode_GetUndefinedInMapN(&DCtx, 8); - if(QCBORDecode_GetAndResetError(&DCtx)) { - return 14; + QCBORDecode_EnterMap(&DCtx, &Item); + QCBORDecode_EnterArrayFromMapSZ(&DCtx, "an array of two strings"); + if(QCBORDecode_Tell(&DCtx) != 42) { + return 6001; + } + QCBORDecode_VGetNext(&DCtx, &Item); + if(QCBORDecode_Tell(&DCtx) != 50) { + return 6002; + } + QCBORDecode_VGetNext(&DCtx, &Item); + if(QCBORDecode_Tell(&DCtx) != 58) { + return 6008; + } + QCBORDecode_VGetNext(&DCtx, &Item); + (void)QCBORDecode_GetAndResetError(&DCtx); + if(QCBORDecode_Tell(&DCtx) != 58) { + return 6003; + } + QCBORDecode_ExitArray(&DCtx); + if(QCBORDecode_Tell(&DCtx) != 58) { + return 6004; } + static const uint32_t aEmptiesPos[] = + {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 11, 13, 15}; QCBORDecode_Init(&DCtx, - UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spBooleansInMap), + UsefulBuf_FROM_BYTE_ARRAY_LITERAL(sEmpties), 0); - QCBORDecode_EnterMap(&DCtx, NULL); - QCBORDecode_GetUndefinedInMapN(&DCtx, 8); - if(QCBORDecode_GetAndResetError(&DCtx) != QCBOR_ERR_UNEXPECTED_TYPE) { - return 15; + for(nIndex = 0; ; nIndex++) { + uPosition = QCBORDecode_Tell(&DCtx); + if(uPosition != aEmptiesPos[nIndex]) { + return nIndex + 200; + } + + if(QCBORDecode_EndCheck(&DCtx)) { + break; + } + + QCBORDecode_VGetNext(&DCtx, &Item); } +#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS + static const uint32_t aIndefEmptiesPos[] = + {0, 1, 2, 4, 5, 7, 8, 10, 12, 13, 16, 19, 25}; QCBORDecode_Init(&DCtx, - UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spBooleansInMapNWF), + UsefulBuf_FROM_BYTE_ARRAY_LITERAL(sEmptiesIndef), 0); - QCBORDecode_EnterMap(&DCtx, NULL); - QCBORDecode_GetUndefined(&DCtx); - if(QCBORDecode_GetAndResetError(&DCtx) != QCBOR_ERR_HIT_END) { - return 15; + for(nIndex = 0; ; nIndex++) { + uPosition = QCBORDecode_Tell(&DCtx); + if(uPosition != aIndefEmptiesPos[nIndex]) { + return nIndex + 300; + } + + if(QCBORDecode_EndCheck(&DCtx)) { + break; + } + + QCBORDecode_VGetNext(&DCtx, &Item); } +#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS */ + return 0; } diff --git a/3rdparty/exported/QCBOR/test/qcbor_decode_tests.h b/3rdparty/exported/QCBOR/test/qcbor_decode_tests.h index 11fdc94bca4a..a08a3afda645 100644 --- a/3rdparty/exported/QCBOR/test/qcbor_decode_tests.h +++ b/3rdparty/exported/QCBOR/test/qcbor_decode_tests.h @@ -126,7 +126,7 @@ int32_t ParseMapAsArrayTest(void); /* Test parsing of some simple values like true, false, null... */ -int32_t ParseSimpleTest(void); +int32_t SimpleValueDecodeTests(void); /* @@ -318,4 +318,17 @@ Test GitHub issue #134: decode an indefinite-length string with a zero-length fi */ int32_t CBORTestIssue134(void); + + +int32_t ErrorHandlingTests(void); + + +/* + * Test QCBORDecode_GetArray and QCBORDecode_GetMap + */ +int32_t GetMapAndArrayTest(void); + +int32_t TellTests(void); + + #endif /* defined(__QCBOR__qcbort_decode_tests__) */ diff --git a/3rdparty/exported/QCBOR/test/qcbor_encode_tests.c b/3rdparty/exported/QCBOR/test/qcbor_encode_tests.c index 6e569cac82fb..14bcc63d0795 100644 --- a/3rdparty/exported/QCBOR/test/qcbor_encode_tests.c +++ b/3rdparty/exported/QCBOR/test/qcbor_encode_tests.c @@ -1,6 +1,6 @@ /*============================================================================== Copyright (c) 2016-2018, The Linux Foundation. - Copyright (c) 2018-2021, Laurence Lundblade. + Copyright (c) 2018-2024, Laurence Lundblade. Copyright (c) 2022, Arm Limited. All rights reserved. Redistribution and use in source and binary forms, with or without @@ -73,11 +73,11 @@ static void printencoded(const uint8_t *pEncoded, size_t nLen) static int UsefulBuf_Compare_Print(UsefulBufC U1, UsefulBufC U2) { size_t i; for(i = 0; i < U1.len; i++) { - if(((uint8_t *)U1.ptr)[i] != ((uint8_t *)U2.ptr)[i]) { - printf("Position: %d Actual: 0x%x Expected: 0x%x\n", + if(((const uint8_t *)U1.ptr)[i] != ((const uint8_t *)U2.ptr)[i]) { + printf("Position: %u Actual: 0x%x Expected: 0x%x\n", (uint32_t)i, - ((uint8_t *)U1.ptr)[i], - ((uint8_t *)U2.ptr)[i]); + ((const uint8_t *)U1.ptr)[i], + ((const uint8_t *)U2.ptr)[i]); return 1; } } @@ -180,6 +180,11 @@ int32_t BasicEncodeTest(void) } + UsefulBuf Tmp = QCBOREncode_RetrieveOutputStorage(&EC); + if(Tmp.ptr != spBigBuf && Tmp.len != sizeof(spBigBuf)) { + return -111; + } + // Make another encoded message with the CBOR from the previous // put into this one UsefulBuf_MAKE_STACK_UB(MemoryForEncoded2, 20); @@ -196,6 +201,8 @@ int32_t BasicEncodeTest(void) if(QCBOREncode_Finish(&EC, &Encoded2)) { return -5; } + + /* [ // 0 1:3 451, // 1 1:2 @@ -516,6 +523,9 @@ this is the attachment text\n\ static void AddAll(QCBOREncodeContext *pECtx) { + /* This calls a mix of deprecated and non-deprecated to test both. + * Sometimes only deprecated because the deprecated calls the + * non-deprecated */ QCBOREncode_OpenArray(pECtx); /* Some ints that are tagged and have strings preceeding them @@ -543,7 +553,7 @@ static void AddAll(QCBOREncodeContext *pECtx) /* Epoch date with labels */ QCBOREncode_OpenMap(pECtx); QCBOREncode_AddDateEpochToMap(pECtx, "LongLiveDenisRitchie", 1400000000); - QCBOREncode_AddDateEpochToMap(pECtx, "time()", 1477263730); + QCBOREncode_AddTDateEpochToMapSZ(pECtx, "time()", QCBOR_ENCODE_AS_TAG, 1477263730); QCBOREncode_AddDateEpochToMapN(pECtx, -1969, 1477263222); QCBOREncode_CloseMap(pECtx); @@ -556,7 +566,7 @@ static void AddAll(QCBOREncodeContext *pECtx) QCBOREncode_AddTag(pECtx, 100000); QCBOREncode_AddBytes(pECtx, ((UsefulBufC) {(uint8_t []){0x00}, 1})); QCBOREncode_AddBytesToMap(pECtx, "empty", NULLUsefulBufC); // Empty string - QCBOREncode_AddBytesToMap(pECtx, "blabel", ((UsefulBufC) {(uint8_t []){0x01, 0x02, 0x03}, 3})); + QCBOREncode_AddBytesToMapSZ(pECtx, "blabel", ((UsefulBufC) {(uint8_t []){0x01, 0x02, 0x03}, 3})); QCBOREncode_AddBytesToMapN(pECtx, 0, ((UsefulBufC){(uint8_t []){0x04, 0x02, 0x03, 0xfe}, 4})); QCBOREncode_CloseMap(pECtx); @@ -575,7 +585,7 @@ static void AddAll(QCBOREncodeContext *pECtx) /* text blobs in maps */ QCBOREncode_OpenMap(pECtx); QCBOREncode_AddTextToMap(pECtx, "#####", UsefulBuf_FROM_SZ_LITERAL("foo bar foo foo")); - QCBOREncode_AddTextToMap(pECtx, "____", UsefulBuf_FROM_SZ_LITERAL("foo bar")); + QCBOREncode_AddTextToMapSZ(pECtx, "____", UsefulBuf_FROM_SZ_LITERAL("foo bar")); QCBOREncode_AddSZString(pECtx, "()()()"); QCBOREncode_AddTag(pECtx, 1000); QCBOREncode_AddSZString(pECtx, "rab rab oof"); @@ -602,13 +612,13 @@ static void AddAll(QCBOREncodeContext *pECtx) QCBOREncode_CloseMap(pECtx); /* true / false ... */ - QCBOREncode_AddSimple(pECtx, CBOR_SIMPLEV_UNDEF); + QCBOREncode_AddUndef(pECtx); QCBOREncode_OpenMap(pECtx); QCBOREncode_AddSZString(pECtx, "dare"); QCBOREncode_AddTag(pECtx, 66); QCBOREncode_AddBool(pECtx, true); QCBOREncode_AddBoolToMap(pECtx, "uu", false); - QCBOREncode_AddSimpleToMapN(pECtx, 737634, CBOR_SIMPLEV_NULL); + QCBOREncode_AddNULLToMapN(pECtx, 737634); QCBOREncode_CloseMap(pECtx); /* opening an array */ @@ -671,7 +681,7 @@ static void AddAll(QCBOREncodeContext *pECtx) QCBOREncode_AddBool(pECtx, true); QCBOREncode_AddBool(pECtx, false); QCBOREncode_OpenMap(pECtx); - QCBOREncode_AddBoolToMap(pECtx, "George is the man", true); + QCBOREncode_AddBoolToMapSZ(pECtx, "George is the man", true); QCBOREncode_AddBoolToMapN(pECtx, 010101, true); QCBOREncode_CloseMap(pECtx); @@ -912,14 +922,14 @@ int32_t SimpleValuesTest1(void) QCBOREncode_Init(&ECtx, UsefulBuf_FROM_BYTE_ARRAY(spBigBuf)); QCBOREncode_OpenArray(&ECtx); - QCBOREncode_AddSimple(&ECtx, CBOR_SIMPLEV_TRUE); - QCBOREncode_AddSimple(&ECtx, CBOR_SIMPLEV_FALSE); - QCBOREncode_AddSimple(&ECtx, CBOR_SIMPLEV_NULL); - QCBOREncode_AddSimple(&ECtx, CBOR_SIMPLEV_UNDEF); + QCBOREncode_AddBool(&ECtx, true); + QCBOREncode_AddBool(&ECtx, false); + QCBOREncode_AddNULL(&ECtx); + QCBOREncode_AddUndef(&ECtx); QCBOREncode_OpenMap(&ECtx); - QCBOREncode_AddSimpleToMap(&ECtx, "UNDef", CBOR_SIMPLEV_UNDEF); + QCBOREncode_AddUndefToMapSZ(&ECtx, "UNDef"); QCBOREncode_CloseMap(&ECtx); QCBOREncode_CloseArray(&ECtx); @@ -935,6 +945,7 @@ int32_t SimpleValuesTest1(void) return(nReturn); } +#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS /* 9F # array(5) F5 # primitive(21) @@ -951,36 +962,61 @@ int32_t SimpleValuesTest1(void) static const uint8_t spExpectedEncodedSimpleIndefiniteLength[] = { 0x9f, 0xf5, 0xf4, 0xf6, 0xf7, 0xbf, 0x65, 0x55, 0x4e, 0x44, 0x65, 0x66, 0xf7, 0xff, 0xff}; -int32_t SimpleValuesIndefiniteLengthTest1(void) +int32_t IndefiniteLengthTest(void) { QCBOREncodeContext ECtx; - int nReturn = 0; QCBOREncode_Init(&ECtx, UsefulBuf_FROM_BYTE_ARRAY(spBigBuf)); QCBOREncode_OpenArrayIndefiniteLength(&ECtx); - QCBOREncode_AddSimple(&ECtx, CBOR_SIMPLEV_TRUE); - QCBOREncode_AddSimple(&ECtx, CBOR_SIMPLEV_FALSE); - QCBOREncode_AddSimple(&ECtx, CBOR_SIMPLEV_NULL); - QCBOREncode_AddSimple(&ECtx, CBOR_SIMPLEV_UNDEF); + QCBOREncode_AddBool(&ECtx, true); + QCBOREncode_AddBool(&ECtx, false); + QCBOREncode_AddNULL(&ECtx); + QCBOREncode_AddUndef(&ECtx); QCBOREncode_OpenMapIndefiniteLength(&ECtx); - QCBOREncode_AddSimpleToMap(&ECtx, "UNDef", CBOR_SIMPLEV_UNDEF); + QCBOREncode_AddUndefToMap(&ECtx, "UNDef"); QCBOREncode_CloseMapIndefiniteLength(&ECtx); QCBOREncode_CloseArrayIndefiniteLength(&ECtx); UsefulBufC ECBOR; if(QCBOREncode_Finish(&ECtx, &ECBOR)) { - nReturn = -1; + return -1; } - if(CheckResults(ECBOR, spExpectedEncodedSimpleIndefiniteLength)) + if(CheckResults(ECBOR, spExpectedEncodedSimpleIndefiniteLength)) { return -2; + } - return(nReturn); + +#ifndef QCBOR_DISABLE_ENCODE_USAGE_GUARDS + QCBOREncode_Init(&ECtx, UsefulBuf_FROM_BYTE_ARRAY(spBigBuf)); + QCBOREncode_OpenArrayIndefiniteLength(&ECtx); + QCBOREncode_CloseArray(&ECtx); + if(QCBOREncode_GetErrorState(&ECtx) != QCBOR_ERR_CLOSE_MISMATCH) { + return -3; + } + + QCBOREncode_Init(&ECtx, UsefulBuf_FROM_BYTE_ARRAY(spBigBuf)); + QCBOREncode_OpenArray(&ECtx); + QCBOREncode_CloseArrayIndefiniteLength(&ECtx); + if(QCBOREncode_GetErrorState(&ECtx) != QCBOR_ERR_CLOSE_MISMATCH) { + return -3; + } + + QCBOREncode_Init(&ECtx, UsefulBuf_FROM_BYTE_ARRAY(spBigBuf)); + QCBOREncode_OpenArrayIndefiniteLength(&ECtx); + QCBOREncode_CloseMapIndefiniteLength(&ECtx); + if(QCBOREncode_GetErrorState(&ECtx) != QCBOR_ERR_CLOSE_MISMATCH) { + return -3; + } +#endif /* ! QCBOR_DISABLE_ENCODE_USAGE_GUARDS */ + + return 0; } +#endif /* A5 # map(5) @@ -1155,32 +1191,32 @@ int32_t EncodeLengthThirtyoneTest(void) QCBOREncode_OpenMap(&ECtx); // add array with 31 items - QCBOREncode_OpenArrayInMap(&ECtx, "arr"); + QCBOREncode_OpenArrayInMapSZ(&ECtx, "arr"); for (size_t ix = 0; ix < 31; ix++) { QCBOREncode_AddInt64(&ECtx, (int64_t)ix); } QCBOREncode_CloseArray(&ECtx); // add map with 31 items - QCBOREncode_OpenMapInMap(&ECtx, "map"); + QCBOREncode_OpenMapInMapSZ(&ECtx, "map"); for (int ix = 0; ix < 31; ix++) { // make sure we have unique keys in the map (a-z then follow by A-Z) int c = 'a'; if (ix < 26) c = c + ix; else c = 'A' + (ix - 26); char buffer[2] = { (char)c, 0 }; - QCBOREncode_AddInt64ToMap(&ECtx, buffer, ix); + QCBOREncode_AddInt64ToMapSZ(&ECtx, buffer, ix); } QCBOREncode_CloseMap(&ECtx); // add -31 and +31 - QCBOREncode_AddInt64ToMap(&ECtx, "min31", -31); - QCBOREncode_AddInt64ToMap(&ECtx, "plus31", 31); + QCBOREncode_AddInt64ToMapSZ(&ECtx, "min31", -31); + QCBOREncode_AddInt64ToMapSZ(&ECtx, "plus31", 31); // add string with length 31 const char *str = "testtesttesttesttesttestqcbor11"; UsefulBufC str_b = { str, 31 }; - QCBOREncode_AddTextToMap(&ECtx, "str", str_b); + QCBOREncode_AddTextToMapSZ(&ECtx, "str", str_b); QCBOREncode_CloseMap(&ECtx); @@ -1259,9 +1295,10 @@ int32_t EncodeDateTest(void) QCBOREncode_OpenMap(&ECtx); - QCBOREncode_AddDateStringToMap(&ECtx, - "Sample Date from RFC 3339", - "1985-04-12T23:20:50.52Z"); + QCBOREncode_AddTDateStringToMapSZ(&ECtx, + "Sample Date from RFC 3339", + QCBOR_ENCODE_AS_TAG, + "1985-04-12T23:20:50.52Z"); QCBOREncode_AddDateEpochToMap(&ECtx, "SD", 999); QCBOREncode_AddTDaysStringToMapSZ(&ECtx, "Sample Date from RFC 8943", @@ -1501,16 +1538,16 @@ static int32_t CreateMap(uint8_t **pEncoded, size_t *pEncodedLen) do { QCBOREncode_Init(&ECtx, (UsefulBuf){*pEncoded, *pEncodedLen}); QCBOREncode_OpenMap(&ECtx); - QCBOREncode_AddInt64ToMap(&ECtx, "first integer", 42); - QCBOREncode_OpenArrayInMap(&ECtx, "an array of two strings"); + QCBOREncode_AddInt64ToMapSZ(&ECtx, "first integer", 42); + QCBOREncode_OpenArrayInMapSZ(&ECtx, "an array of two strings"); QCBOREncode_AddText(&ECtx, ((UsefulBufC) {"string1", 7})); QCBOREncode_AddText(&ECtx, ((UsefulBufC) {"string2", 7})); QCBOREncode_CloseArray(&ECtx); - QCBOREncode_OpenMapInMap(&ECtx, "map in a map"); + QCBOREncode_OpenMapInMapSZ(&ECtx, "map in a map"); QCBOREncode_AddBytesToMap(&ECtx,"bytes 1", ((UsefulBufC) { "xxxx", 4})); - QCBOREncode_AddBytesToMap(&ECtx, "bytes 2",((UsefulBufC) { "yyyy", 4})); - QCBOREncode_AddInt64ToMap(&ECtx, "another int", 98); - QCBOREncode_AddTextToMap(&ECtx, "text 2", ((UsefulBufC) {"lies, damn lies and statistics", 30})); + QCBOREncode_AddBytesToMapSZ(&ECtx, "bytes 2",((UsefulBufC) { "yyyy", 4})); + QCBOREncode_AddInt64ToMapSZ(&ECtx, "another int", 98); + QCBOREncode_AddTextToMapSZ(&ECtx, "text 2", ((UsefulBufC) {"lies, damn lies and statistics", 30})); QCBOREncode_CloseMap(&ECtx); QCBOREncode_CloseMap(&ECtx); @@ -1647,10 +1684,10 @@ FormatRTICResults(uint8_t uRResult, // The result: 0 if scan happened and found nothing; 1 if it happened and // found something wrong; 2 if it didn't happen - QCBOREncode_AddSimpleToMap(&ECtx, "integrity", uRResult); + QCBOREncode_AddSimpleToMapSZ(&ECtx, "integrity", uRResult); // Add the diagnostic code - QCBOREncode_AddSZStringToMap(&ECtx, "type", szType); + QCBOREncode_AddSZStringToMapSZ(&ECtx, "type", szType); // Add a time stamp if(time) { @@ -1658,24 +1695,24 @@ FormatRTICResults(uint8_t uRResult, } // Add the diagnostic code - QCBOREncode_AddSZStringToMap(&ECtx, "diag", szAlexString); + QCBOREncode_AddSZStringToMapSZ(&ECtx, "diag", szAlexString); // Open a subordinate map for telemtry data - QCBOREncode_OpenMapInMap(&ECtx, "telemetry"); + QCBOREncode_OpenMapInMapSZ(&ECtx, "telemetry"); { // Brace / indention just to show CBOR encoding nesting // Add a few fake integers and buffers for now. - QCBOREncode_AddInt64ToMap(&ECtx, "Shoe Size", 12); + QCBOREncode_AddInt64ToMapSZ(&ECtx, "Shoe Size", 12); // Add a few fake integers and buffers for now. - QCBOREncode_AddInt64ToMap(&ECtx, "IQ", 0xffffffff); + QCBOREncode_AddInt64ToMapSZ(&ECtx, "IQ", 0xffffffff); // Add a few fake integers and buffers for now. static const uint8_t pPV[] = {0x66, 0x67, 0x00, 0x56, 0xaa, 0xbb, 0x01, 0x01}; const UsefulBufC WSPV = {pPV, sizeof(pPV)}; - QCBOREncode_AddBytesToMap(&ECtx, "WhaleSharkPatternVector", WSPV); + QCBOREncode_AddBytesToMapSZ(&ECtx, "WhaleSharkPatternVector", WSPV); } } @@ -1896,6 +1933,24 @@ int32_t BstrWrapTest(void) return -11; } +#ifndef QCBOR_DISABLE_ENCODE_USAGE_GUARDS + // Seventh test, erroneous cancel + QCBOREncode_Init(&EC, UsefulBuf_FROM_BYTE_ARRAY(spBigBuf)); + QCBOREncode_CancelBstrWrap(&EC); + uErr = QCBOREncode_GetErrorState(&EC); + if(uErr != QCBOR_ERR_TOO_MANY_CLOSES) { + return -12; + } + + QCBOREncode_Init(&EC, UsefulBuf_FROM_BYTE_ARRAY(spBigBuf)); + QCBOREncode_OpenArray(&EC); + QCBOREncode_CancelBstrWrap(&EC); + uErr = QCBOREncode_GetErrorState(&EC); + if(uErr != QCBOR_ERR_CLOSE_MISMATCH) { + return -13; + } +#endif /* ! QCBOR_DISABLE_ENCODE_USAGE_GUARDS */ + return 0; } @@ -2483,6 +2538,8 @@ int32_t EncodeErrorTests(void) { QCBOREncodeContext EC; QCBORError uErr; + UsefulBufC EncodedResult; + MakeUsefulBufOnStack(SmallBuffer, 4); // ------ Test for QCBOR_ERR_BUFFER_TOO_LARGE ------ @@ -2648,6 +2705,12 @@ int32_t EncodeErrorTests(void) return -11; } + UsefulBuf Tmp; + Tmp = QCBOREncode_RetrieveOutputStorage(&EC); + if(Tmp.ptr != NULL && Tmp.len != UINT32_MAX) { + return -111; + } + /* ------ QCBOR_ERR_UNSUPPORTED -------- */ QCBOREncode_Init(&EC, Large); QCBOREncode_OpenArray(&EC); @@ -2678,6 +2741,62 @@ int32_t EncodeErrorTests(void) } #endif /* QCBOR_DISABLE_ENCODE_USAGE_GUARDS */ + /* Test that still-open error sticks */ + QCBOREncode_Init(&EC, Large); + QCBOREncode_OpenArray(&EC); + QCBOREncode_Finish(&EC, &EncodedResult); +#ifndef QCBOR_DISABLE_ENCODE_USAGE_GUARDS + if(QCBOREncode_GetErrorState(&EC) != QCBOR_ERR_ARRAY_OR_MAP_STILL_OPEN) { + return -120; + } +#else /* QCBOR_DISABLE_ENCODE_USAGE_GUARDS */ + if(QCBOREncode_GetErrorState(&EC) != QCBOR_SUCCESS) { + return -122; + } +#endif /* QCBOR_DISABLE_ENCODE_USAGE_GUARDS */ + + /* Test that too-small error is sticky */ + QCBOREncode_Init(&EC, SmallBuffer); + QCBOREncode_OpenArray(&EC); + QCBOREncode_AddInt64(&EC, INT64_MAX); + QCBOREncode_AddInt64(&EC, INT64_MAX); + QCBOREncode_AddInt64(&EC, INT64_MAX); + QCBOREncode_CloseArray(&EC); + QCBOREncode_Finish(&EC, &EncodedResult); + if(QCBOREncode_GetErrorState(&EC) != QCBOR_ERR_BUFFER_TOO_SMALL) { + return -130; + } + + +#ifndef QCBOR_DISABLE_ENCODE_USAGE_GUARDS + /* ------ QCBOR_ERR_ARRAY_TOO_LONG -------- */ + QCBOREncode_Init(&EC, Large); + QCBOREncode_OpenArray(&EC); + int i; + for(i = 0; i < QCBOR_MAX_ITEMS_IN_ARRAY; i++) { + QCBOREncode_AddInt64(&EC, 0); + } + if(QCBOREncode_GetErrorState(&EC)) { + return 250; + } + QCBOREncode_AddInt64(&EC, 0); + if(QCBOREncode_GetErrorState(&EC) != QCBOR_ERR_ARRAY_TOO_LONG) { + return 251; + } + + QCBOREncode_Init(&EC, Large); + QCBOREncode_OpenMap(&EC); + for(i = 0; i < QCBOR_MAX_ITEMS_IN_MAP; i++) { + QCBOREncode_AddInt64ToMapN(&EC, 0,0); + } + if(QCBOREncode_GetErrorState(&EC)) { + return 250; + } + QCBOREncode_AddInt64ToMapN(&EC, 0,0); + if(QCBOREncode_GetErrorState(&EC) != QCBOR_ERR_ARRAY_TOO_LONG) { + return 251; + } +#endif /* ! QCBOR_DISABLE_ENCODE_USAGE_GUARDS */ return 0; } @@ -2687,26 +2806,34 @@ int32_t EncodeErrorTests(void) /* [ 4([-1, 3]), + [-1, 4], 4([-20, 4759477275222530853136]), + [2, 4759477275222530853136], 4([9223372036854775807, -4759477275222530853137]), 5([300, 100]), + [600, 200], 5([-20, 4759477275222530853136]), - 5([-9223372036854775808, -4759477275222530853137]) - ] + [4, 4759477275222530853136], + 5([-9223372036854775808, -4759477275222530853137])] + ] */ static const uint8_t spExpectedExponentAndMantissaArray[] = { - 0x86, 0xC4, 0x82, 0x20, 0x03, 0xC4, 0x82, 0x33, - 0xC2, 0x4A, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, - 0x07, 0x08, 0x09, 0x10, 0xC4, 0x82, 0x1B, 0x7F, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC3, - 0x4A, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, - 0x08, 0x09, 0x10, 0xC5, 0x82, 0x19, 0x01, 0x2C, - 0x18, 0x64, 0xC5, 0x82, 0x33, 0xC2, 0x4A, 0x01, - 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, - 0x10, 0xC5, 0x82, 0x3B, 0x7F, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xC3, 0x4A, 0x01, 0x02, - 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x10}; - + 0x8A, 0xC4, 0x82, 0x20, 0x03, 0x82, 0x20, 0x04, + 0xC4, 0x82, 0x33, 0xC2, 0x4A, 0x01, 0x02, 0x03, + 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x10, 0x82, + 0x02, 0xC2, 0x4A, 0x01, 0x02, 0x03, 0x04, 0x05, + 0x06, 0x07, 0x08, 0x09, 0x10, 0xC4, 0x82, 0x1B, + 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xC3, 0x4A, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, + 0x07, 0x08, 0x09, 0x10, 0xC5, 0x82, 0x19, 0x01, + 0x2C, 0x18, 0x64, 0x82, 0x19, 0x02, 0x58, 0x18, + 0xC8, 0xC5, 0x82, 0x33, 0xC2, 0x4A, 0x01, 0x02, + 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x10, + 0x82, 0x04, 0xC2, 0x4A, 0x01, 0x02, 0x03, 0x04, + 0x05, 0x06, 0x07, 0x08, 0x09, 0x10, 0xC5, 0x82, + 0x3B, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xC3, 0x4A, 0x01, 0x02, 0x03, 0x04, 0x05, + 0x06, 0x07, 0x08, 0x09, 0x10}; /* { @@ -2785,11 +2912,15 @@ int32_t ExponentAndMantissaEncodeTests(void) QCBOREncode_Init(&EC, UsefulBuf_FROM_BYTE_ARRAY(spBigBuf)); QCBOREncode_OpenArray(&EC); QCBOREncode_AddDecimalFraction(&EC, 3, -1); // 3 * (10 ^ -1) + QCBOREncode_AddTDecimalFraction(&EC, QCBOR_ENCODE_AS_BORROWED, 4, -1); // 3 * (10 ^ -1) QCBOREncode_AddDecimalFractionBigNum(&EC, BigNum , false, -20); - QCBOREncode_AddDecimalFractionBigNum(&EC, BigNum, true, INT64_MAX); + QCBOREncode_AddTDecimalFractionBigNum(&EC, QCBOR_ENCODE_AS_BORROWED, BigNum , false, 2); + QCBOREncode_AddTDecimalFractionBigNum(&EC, QCBOR_ENCODE_AS_TAG, BigNum, true, INT64_MAX); QCBOREncode_AddBigFloat(&EC, 100, 300); + QCBOREncode_AddTBigFloat(&EC, QCBOR_ENCODE_AS_BORROWED, 200, 600); QCBOREncode_AddBigFloatBigNum(&EC, BigNum, false, -20); - QCBOREncode_AddBigFloatBigNum(&EC, BigNum, true, INT64_MIN); + QCBOREncode_AddTBigFloatBigNum(&EC, QCBOR_ENCODE_AS_BORROWED, BigNum, false, 4); + QCBOREncode_AddTBigFloatBigNum(&EC, QCBOR_ENCODE_AS_TAG, BigNum, true, INT64_MIN); QCBOREncode_CloseArray(&EC); if(QCBOREncode_Finish(&EC, &EncodedExponentAndMantissa)) { @@ -2822,17 +2953,19 @@ int32_t ExponentAndMantissaEncodeTests(void) false, INT32_MAX); - QCBOREncode_AddDecimalFractionBigNumToMapSZ(&EC, - "decimal fraction bignum negative", - BigNum, - true, - INT64_MAX); + QCBOREncode_AddTDecimalFractionBigNumToMapSZ(&EC, + "decimal fraction bignum negative", + QCBOR_ENCODE_AS_TAG, + BigNum, + true, + INT64_MAX); - QCBOREncode_AddDecimalFractionBigNumToMapN(&EC, - 500, - BigNum, - true, - INT64_MAX); + QCBOREncode_AddTDecimalFractionBigNumToMapN(&EC, + 500, + QCBOR_ENCODE_AS_TAG, + BigNum, + true, + INT64_MAX); QCBOREncode_AddBigFloatToMap(&EC, "big float", 100, 300); @@ -2850,17 +2983,19 @@ int32_t ExponentAndMantissaEncodeTests(void) false, -20); - QCBOREncode_AddBigFloatBigNumToMap(&EC, - "big float bignum negative", - BigNum, - true, - INT64_MIN); + QCBOREncode_AddTBigFloatBigNumToMapSZ(&EC, + "big float bignum negative", + QCBOR_ENCODE_AS_TAG, + BigNum, + true, + INT64_MIN); - QCBOREncode_AddBigFloatBigNumToMapN(&EC, - 800, - BigNum, - true, - INT64_MIN); + QCBOREncode_AddTBigFloatBigNumToMapN(&EC, + 800, + QCBOR_ENCODE_AS_TAG, + BigNum, + true, + INT64_MIN); QCBOREncode_CloseMap(&EC); @@ -3080,3 +3215,85 @@ OpenCloseBytesTest(void) return 0; } + + +int32_t SubStringTest(void) +{ + QCBOREncodeContext EC; + size_t uStart; + size_t uCurrent; + UsefulBufC SS; + UsefulBufC Encoded; + QCBORError uErr; + + QCBOREncode_Init(&EC, UsefulBuf_FROM_BYTE_ARRAY(spBigBuf)); + QCBOREncode_OpenArray(&EC); + uStart = QCBOREncode_Tell(&EC); + QCBOREncode_AddInt64(&EC, 0); + SS = QCBOREncode_SubString(&EC, uStart); + if(UsefulBuf_Compare(SS, (UsefulBufC){"\x00", 1})) { + return 1; + } + + QCBOREncode_OpenArray(&EC); + + QCBOREncode_CloseArray(&EC); + SS = QCBOREncode_SubString(&EC, uStart); + if(UsefulBuf_Compare(SS, (UsefulBufC){"\x00\x80", 2})) { + return 3; + } + + + /* Try it on a sequence */ + QCBOREncode_Init(&EC, UsefulBuf_FROM_BYTE_ARRAY(spBigBuf)); + uStart = QCBOREncode_Tell(&EC); + QCBOREncode_AddInt64(&EC, 1); + QCBOREncode_AddInt64(&EC, 1); + QCBOREncode_AddInt64(&EC, 1); + QCBOREncode_AddInt64(&EC, 1); + SS = QCBOREncode_SubString(&EC, uStart); + if(UsefulBuf_Compare(SS, (UsefulBufC){"\x01\x01\x01\x01", 4})) { + return 10; + } + + uCurrent = QCBOREncode_Tell(&EC); + if(!UsefulBuf_IsNULLC(QCBOREncode_SubString(&EC, uCurrent+1))) { + return 11; + } + +#ifndef QCBOR_DISABLE_ENCODE_USAGE_GUARDS + /* Now cause an error */ + QCBOREncode_OpenMap(&EC); + QCBOREncode_CloseArray(&EC); + if(!UsefulBuf_IsNULLC(QCBOREncode_SubString(&EC, uStart))) { + return 15; + } +#endif /* ! QCBOR_DISABLE_ENCODE_USAGE_GUARDS */ + + + QCBOREncode_Init(&EC, UsefulBuf_FROM_BYTE_ARRAY(spBigBuf)); + QCBOREncode_AddInt64(&EC, 1); + QCBOREncode_AddInt64(&EC, 1); + uStart = QCBOREncode_Tell(&EC); + QCBOREncode_OpenMap(&EC); + QCBOREncode_OpenMapInMapN(&EC, 3); + QCBOREncode_OpenArrayInMapN(&EC, 4); + QCBOREncode_AddInt64(&EC, 0); + QCBOREncode_CloseArray(&EC); + QCBOREncode_CloseMap(&EC); + QCBOREncode_CloseMap(&EC); + SS = QCBOREncode_SubString(&EC, uStart); + if(UsefulBuf_Compare(SS, (UsefulBufC){"\xA1\x03\xA1\x04\x81\x00", 6})) { + return 20; + } + + uErr = QCBOREncode_Finish(&EC, &Encoded); + if(uErr) { + return 21; + } + if(UsefulBuf_Compare(Encoded, (UsefulBufC){"\x01\x01\xA1\x03\xA1\x04\x81\x00", 8})) { + return 22; + } + + return 0; +} diff --git a/3rdparty/exported/QCBOR/test/qcbor_encode_tests.h b/3rdparty/exported/QCBOR/test/qcbor_encode_tests.h index bac1085987e6..bc47c55429cf 100644 --- a/3rdparty/exported/QCBOR/test/qcbor_encode_tests.h +++ b/3rdparty/exported/QCBOR/test/qcbor_encode_tests.h @@ -80,9 +80,8 @@ int32_t ArrayNestingTest3(void); /* - This tests the QCBOREncode_AddRaw() function by adding two chunks or - RAWCBOR to an array and comparing with expected values. This is an - encoding test. + This tests the QCBOREncode_AddRaw() function by adding two chunks of + raw CBOR to an array and comparing with expected values. */ int32_t EncodeRawTest(void); @@ -109,7 +108,7 @@ int32_t SimpleValuesTest1(void); /* Encodes basic maps and arrays with indefinite length */ -int32_t SimpleValuesIndefiniteLengthTest1(void); +int32_t IndefiniteLengthTest(void); /* @@ -192,5 +191,7 @@ int32_t QCBORHeadTest(void); int32_t OpenCloseBytesTest(void); +int32_t SubStringTest(void); + #endif /* defined(__QCBOR__qcbor_encode_tests__) */ diff --git a/3rdparty/exported/QCBOR/test/run_tests.c b/3rdparty/exported/QCBOR/test/run_tests.c index f2baaf114efa..cf806e94b144 100644 --- a/3rdparty/exported/QCBOR/test/run_tests.c +++ b/3rdparty/exported/QCBOR/test/run_tests.c @@ -1,12 +1,12 @@ /*============================================================================== run_tests.c -- test aggregator and results reporting - Copyright (c) 2018-2021, Laurence Lundblade. All rights reserved. + Copyright (c) 2018-2024, Laurence Lundblade. All rights reserved. Copyright (c) 2021, Arm Limited. All rights reserved. SPDX-License-Identifier: BSD-3-Clause - See BSD-3-Clause license in README.md + See BSD-3-Clause license in file named "LICENSE" Created on 9/30/18 =============================================================================*/ @@ -66,6 +66,13 @@ static test_entry2 s_tests2[] = { static test_entry s_tests[] = { +#ifndef QCBOR_DISABLE_NON_INTEGER_LABELS + TEST_ENTRY(GetMapAndArrayTest), + TEST_ENTRY(TellTests), + TEST_ENTRY(ParseMapAsArrayTest), + TEST_ENTRY(SpiffyDateDecodeTest), +#endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */ + TEST_ENTRY(ErrorHandlingTests), TEST_ENTRY(OpenCloseBytesTest), TEST_ENTRY(EnterBstrTest), TEST_ENTRY(IntegerConvertTest), @@ -73,13 +80,12 @@ static test_entry s_tests[] = { TEST_ENTRY(QCBORHeadTest), TEST_ENTRY(EmptyMapsAndArraysTest), TEST_ENTRY(NotWellFormedTests), - TEST_ENTRY(ParseMapAsArrayTest), #ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS TEST_ENTRY(IndefiniteLengthNestTest), TEST_ENTRY(IndefiniteLengthArrayMapTest), TEST_ENTRY(NestedMapTestIndefLen), #endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS */ - TEST_ENTRY(ParseSimpleTest), + TEST_ENTRY(SimpleValueDecodeTests), TEST_ENTRY(DecodeFailureTests), TEST_ENTRY(EncodeRawTest), TEST_ENTRY(RTICResultsTest), @@ -95,7 +101,9 @@ static test_entry s_tests[] = { TEST_ENTRY(AllAddMethodsTest), TEST_ENTRY(ParseTooDeepArrayTest), TEST_ENTRY(ComprehensiveInputTest), +#ifndef QCBOR_DISABLE_NON_INTEGER_LABELS TEST_ENTRY(ParseMapTest), +#endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */ TEST_ENTRY(BasicEncodeTest), TEST_ENTRY(NestedMapTest), TEST_ENTRY(BignumParseTest), @@ -104,7 +112,6 @@ static test_entry s_tests[] = { TEST_ENTRY(DateParseTest), TEST_ENTRY(DecodeTaggedTypeTests), #endif /* QCBOR_DISABLE_TAGS */ - TEST_ENTRY(SpiffyDateDecodeTest), TEST_ENTRY(ShortBufferParseTest2), TEST_ENTRY(ShortBufferParseTest), TEST_ENTRY(ParseDeepArrayTest), @@ -114,16 +121,17 @@ static test_entry s_tests[] = { TEST_ENTRY(AllocAllStringsTest), TEST_ENTRY(MemPoolTest), TEST_ENTRY(IndefiniteLengthStringTest), +#ifndef QCBOR_DISABLE_NON_INTEGER_LABELS TEST_ENTRY(SpiffyIndefiniteLengthStringsTests), +#endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */ TEST_ENTRY(SetUpAllocatorTest), TEST_ENTRY(CBORTestIssue134), #endif /* #ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS */ +#ifndef USEFULBUF_DISABLE_ALL_FLOAT #ifndef QCBOR_DISABLE_PREFERRED_FLOAT - TEST_ENTRY(HalfPrecisionDecodeBasicTests), - TEST_ENTRY(DoubleAsSmallestTest), - TEST_ENTRY(HalfPrecisionAgainstRFCCodeTest), + TEST_ENTRY(HalfPrecisionAgainstRFCCodeTest), + TEST_ENTRY(FloatValuesTests), #endif /* QCBOR_DISABLE_PREFERRED_FLOAT */ -#ifndef USEFULBUF_DISABLE_ALL_FLOAT TEST_ENTRY(GeneralFloatEncodeTests), TEST_ENTRY(GeneralFloatDecodeTests), #endif /* USEFULBUF_DISABLE_ALL_FLOAT */ @@ -131,15 +139,21 @@ static test_entry s_tests[] = { TEST_ENTRY(BstrWrapErrorTest), TEST_ENTRY(BstrWrapNestTest), TEST_ENTRY(CoseSign1TBSTest), +#ifndef QCBOR_DISABLE_NON_INTEGER_LABELS TEST_ENTRY(StringDecoderModeFailTest), +#endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */ TEST_ENTRY_DISABLED(BigComprehensiveInputTest), TEST_ENTRY_DISABLED(TooLargeInputTest), TEST_ENTRY(EncodeErrorTests), - TEST_ENTRY(SimpleValuesIndefiniteLengthTest1), +#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS + TEST_ENTRY(IndefiniteLengthTest), +#endif TEST_ENTRY(EncodeLengthThirtyoneTest), TEST_ENTRY(CBORSequenceDecodeTests), TEST_ENTRY(IntToTests), +#ifndef QCBOR_DISABLE_NON_INTEGER_LABELS TEST_ENTRY(PeekAndRewindTest), +#endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */ #ifndef QCBOR_DISABLE_EXP_AND_MANTISSA TEST_ENTRY(ExponentAndMantissaDecodeTests), #ifndef QCBOR_DISABLE_TAGS @@ -148,6 +162,7 @@ static test_entry s_tests[] = { TEST_ENTRY(ExponentAndMantissaEncodeTests), #endif /* QCBOR_DISABLE_EXP_AND_MANTISSA */ TEST_ENTRY(ParseEmptyMapInMapTest), + TEST_ENTRY(SubStringTest), TEST_ENTRY(BoolTest) }; @@ -346,6 +361,6 @@ void PrintSizesQCBOR(OutputStringCB pfOutput, void *pOutCtx) PrintSize("sizeof(QCBORItem)", (uint32_t)sizeof(QCBORItem), pfOutput, pOutCtx); PrintSize("sizeof(QCBORTagListIn)", (uint32_t)sizeof(QCBORTagListIn), pfOutput, pOutCtx); PrintSize("sizeof(QCBORTagListOut)", (uint32_t)sizeof(QCBORTagListOut), pfOutput, pOutCtx); - PrintSize("sizeof(TagSpecification)", (uint32_t)sizeof(TagSpecification), pfOutput, pOutCtx); + PrintSize("sizeof(TagSpecification)", (uint32_t)sizeof(QCBOR_Private_TagSpec),pfOutput, pOutCtx); (*pfOutput)("", pOutCtx, 1); } diff --git a/3rdparty/exported/QCBOR/test/run_tests.h b/3rdparty/exported/QCBOR/test/run_tests.h index ce44673fd48e..370558aae086 100644 --- a/3rdparty/exported/QCBOR/test/run_tests.h +++ b/3rdparty/exported/QCBOR/test/run_tests.h @@ -5,7 +5,7 @@ SPDX-License-Identifier: BSD-3-Clause - See BSD-3-Clause license in README.md + See BSD-3-Clause license in file named "LICENSE" Created 9/30/18 =============================================================================*/ @@ -60,7 +60,7 @@ int RunTestsQCBOR(const char *szTestNames[], /** - @brief Print sizes of encoder / decoder contexts. + @brief Print sizes of encoder-decoder contexts. @param[in] pfOutput Function that is called to output text strings. @param[in] pOutCtx Context pointer passed to output function. diff --git a/3rdparty/exported/QCBOR/ub-example.c b/3rdparty/exported/QCBOR/ub-example.c index 996cf3a9071e..ec776dca366a 100644 --- a/3rdparty/exported/QCBOR/ub-example.c +++ b/3rdparty/exported/QCBOR/ub-example.c @@ -5,7 +5,7 @@ SPDX-License-Identifier: BSD-3-Clause - See BSD-3-Clause license in README.md + See BSD-3-Clause license in file named "LICENSE" Created on 4/8/22 ========================================================================== */ diff --git a/3rdparty/exported/QCBOR/ub-example.h b/3rdparty/exported/QCBOR/ub-example.h index 131c807668ab..93449f4a3323 100644 --- a/3rdparty/exported/QCBOR/ub-example.h +++ b/3rdparty/exported/QCBOR/ub-example.h @@ -5,7 +5,7 @@ SPDX-License-Identifier: BSD-3-Clause - See BSD-3-Clause license in README.md + See BSD-3-Clause license in file named "LICENSE" Created on 4/8/22 ========================================================================== */ diff --git a/3rdparty/exported/t_cose/CMakeLists.txt b/3rdparty/exported/t_cose/CMakeLists.txt index 4f0c8682c63b..aca76d525407 100644 --- a/3rdparty/exported/t_cose/CMakeLists.txt +++ b/3rdparty/exported/t_cose/CMakeLists.txt @@ -2,7 +2,7 @@ cmake_minimum_required(VERSION 3.12) project(t_cose DESCRIPTION "t_cose" LANGUAGES C - VERSION 1.0.1) + VERSION 1.1.3) # Constants set(CRYPTO_PROVIDERS "OpenSSL" "MbedTLS" "Test") diff --git a/3rdparty/exported/t_cose/CONTRIBUTING.md b/3rdparty/exported/t_cose/CONTRIBUTING.md index e4c069eb9814..4aa1ffc3c747 100644 --- a/3rdparty/exported/t_cose/CONTRIBUTING.md +++ b/3rdparty/exported/t_cose/CONTRIBUTING.md @@ -16,19 +16,33 @@ will be merged. ### Basic tests -Running the standard make will produce `t_cose_test` for a particular -crypto library. It runs a thorough set of tests. +Make will produce the executable t_cose_test. Running it will perform +all the regression tests. When new features are added regression tests +for them must be added here. + +However, it only runs with one crypto library, one compiler and one +set of #defines at a time. See tdv/b.sh for that. ### CI tests -GitHub CI is used to build and test against several crypto libraries. +GitHub CI is used to provide the general benefit of CI. It gives test +fanout for the standard major crypto libraries and versions, plus +build environments. It does NOT give full fanout for #define +configurations or for other special configurations. See tdv/b.sh for +that. + +The time GitHub CI takes to run must be kept to a few minutes so as to +not cause excess delay in the commit/merge cycle and disrupt the +human workflow. This is the main reason testing done by it is +limited. The full fanout from tdv/b.sh takes tens of minutes so +it can't be run during CI. ### tdv/b.sh tests In the "tdv" repository there are some makes files and build scripts -that do some more thorough testing. They are too large and take too -long to run to make them part of normal CI. Here's a few things they -do: +run the full configuration fan out testing. They are too large and +take too long to run to make them part of normal CI. Here's a few +things they do: * Build with a fairly maximal set of compiler warning flags set (e.g., -Wall) @@ -83,3 +97,84 @@ guidelines](https://git.trustedfirmware.org/TF-M/trusted-firmware-m.git/tree/doc resulting in code with mixed styles. For better or worse, an Arm-style version of UsefulBuf is created and used and so there is a duplicate of UsefulBuf. The two are identical. They just have different names. + + +## Features and conditionality + +The goal is for t_cose's use of #defines to be much simpler than most other libraries. + +A couple of principles govern feature variation and conditional compiliation: + +* A #define is NOT required to enable features. All features are "on" by + default. + +* The internal function link dependency of t_cose is designed to work + well with the compiler -dead_strip option so linked object code is + minimized. + +* Attempts to call t_cose APIs or use t_cose features which are not + supported by the crypto library often result in an error code being + returned and sometimes in a link error. + +* The primary use of #defines is to disable features to reduce object + code size for use cases that need small code size. + +### Users of t_cose + +Most users of t_cose do not need to be concerned with #defines as they +are not needed to enable features in the library. All the features are +already enabled. + +Users may find that sometimes they get error codes indicating a +feature isn't supported. This will usually be because the underlying +crypto library they are linking against doesn't support the feature, +not because the feature needs to be enabled in t_cose. + +Users may also find that sometimes they get a link error reporting an +undefined symbol. This will again usually be because the underlying +crypto library being linked against doesn't support the feature. + +For example, t_cose works with several versions of MbedTLS older +versions of which don't support AES key wrap. You can use t_cose with +these older versions just fine as long as you don't call any t_cose +APIs or use any t_cose features that need key wrap. If you do, you'll +probably get a T_COSE_ERR_UNSUPPORTED_XX error. + +If your use case needs small object code, then it may be time to make +use of T_COSE_DISABLE_XXXX #defines and recompile the t_cose library. +But it also might be that the minimized link dependency and +-dead_strip does everything you need too. + + +### Contributing to t_cose + +If you are adding a feature to t_cose don't assume that a #define will +be needed and try hard to avoid one. + +Try to implement with minimal symbol/link dependency. One way to do +this is to create a new signer or recipient object just for the +feature. This might involve a new function in the crypto adaptor layer +for a new feature from the crypto library put to use. The new function +is only linked when the new feature is used. + +The crypto layer has a facility for listing and discovering crypto +algorithms that are supported by a particular crypto library. This +facility is mostly used to know what to test, but not exclusively. + +If a feature can work in multiple modes or have multiple behaviors, +don't control that with a #define. Instead control that with an option +flag or with some API methods. That makes install and configuration of +the library simpler. It also works much better for a shared library +because different users of it can use different modes. + +Then, in the end, the only reason to use a #ifdef should be to reduce +object code if there's no other way. + +When an #fdef has to be used, it should be in the least intrusive way +and it shouldn't make the code hard to read. Maybe even restructure +the code a little so the #ifdef is cleaner. + + + + + diff --git a/3rdparty/exported/t_cose/Makefile.ossl b/3rdparty/exported/t_cose/Makefile.ossl index 1df2d06a26d9..da00b226e034 100644 --- a/3rdparty/exported/t_cose/Makefile.ossl +++ b/3rdparty/exported/t_cose/Makefile.ossl @@ -58,8 +58,8 @@ TEST_OBJ=test/t_cose_test.o test/run_tests.o test/t_cose_sign_verify_test.o test # ---- the main body that is invariant ---- -INC=-I inc -I test -I src -ALL_INC=$(INC) $(CRYPTO_INC) $(QCBOR_INC) +T_COSE_INC=-I inc -I test -I src +ALL_INC=$(T_COSE_INC) $(QCBOR_INC) $(CRYPTO_INC) CFLAGS=$(CMD_LINE) $(ALL_INC) $(C_OPTS) $(TEST_CONFIG_OPTS) $(CRYPTO_CONFIG_OPTS) SRC_OBJ=src/t_cose_sign1_verify.o src/t_cose_sign1_sign.o src/t_cose_util.o src/t_cose_parameters.o src/t_cose_short_circuit.o diff --git a/3rdparty/exported/t_cose/Makefile.psa b/3rdparty/exported/t_cose/Makefile.psa index 3f9c28f1b4f3..3604beb0eefb 100644 --- a/3rdparty/exported/t_cose/Makefile.psa +++ b/3rdparty/exported/t_cose/Makefile.psa @@ -60,8 +60,8 @@ TEST_OBJ=test/t_cose_test.o test/run_tests.o test/t_cose_sign_verify_test.o test # ---- the main body that is invariant ---- -INC=-I inc -I test -I src -ALL_INC=$(INC) $(CRYPTO_INC) $(QCBOR_INC) +T_COSE_INC=-I inc -I test -I src +ALL_INC=$(T_COSE_INC) $(QCBOR_INC) $(CRYPTO_INC) CFLAGS=$(CMD_LINE) $(ALL_INC) $(C_OPTS) $(TEST_CONFIG_OPTS) $(CRYPTO_CONFIG_OPTS) SRC_OBJ=src/t_cose_sign1_verify.o src/t_cose_sign1_sign.o src/t_cose_util.o src/t_cose_parameters.o src/t_cose_short_circuit.o diff --git a/3rdparty/exported/t_cose/Makefile.test b/3rdparty/exported/t_cose/Makefile.test index 7a233758c3b4..c5d40049bfcb 100644 --- a/3rdparty/exported/t_cose/Makefile.test +++ b/3rdparty/exported/t_cose/Makefile.test @@ -16,8 +16,10 @@ # ---- QCBOR location ---- # Adjust this to the location of QCBOR in your build environment -#QCBOR_INC= -I ../../QCBOR/master/inc -#QCBOR_LIB=../../QCBOR/master/libqcbor.a +#QCBOR_DIR=../../QCBOR/master +#QCBOR_INC=-I $(QCBOR_DIR)/inc +#QCBOR_LIB=$(QCBOR_DIR)/libqcbor.a + QCBOR_INC= -I/usr/include -I/usr/local/include QCBOR_LIB= -l qcbor @@ -42,8 +44,8 @@ TEST_OBJ=test/t_cose_test.o test/run_tests.o test/t_cose_make_test_messages.o $( # ---- the main body that is invariant ---- -INC=-I inc -I test -I src -ALL_INC=$(INC) $(CRYPTO_INC) $(QCBOR_INC) +T_COSE_INC=-I inc -I test -I src +ALL_INC=$(T_COSE_INC) $(QCBOR_INC) $(CRYPTO_INC) CFLAGS=$(CMD_LINE) $(ALL_INC) $(C_OPTS) $(TEST_CONFIG_OPTS) $(CRYPTO_CONFIG_OPTS) SRC_OBJ=src/t_cose_sign1_verify.o src/t_cose_sign1_sign.o src/t_cose_util.o src/t_cose_parameters.o src/t_cose_short_circuit.o diff --git a/3rdparty/exported/t_cose/README.md b/3rdparty/exported/t_cose/README.md index ba5c473e1969..56452d4c2e2f 100644 --- a/3rdparty/exported/t_cose/README.md +++ b/3rdparty/exported/t_cose/README.md @@ -30,7 +30,7 @@ useful for embedded implementations that have to run in small fixed memory. ## Documentation -[API documentation is here](https://laurencelundblade.github.io/t_cose/) +[API documentation is here](https://www.securitytheory.com/t_cose-docs) ## Code Status @@ -45,17 +45,16 @@ fully supported. t_cose 1.0 only supports COSE Sign1, signing with one recipeint. -## Future Work +## t_cose 2.0 -As of March 2022, work is underway to support encryption, MAC and -other COSE features. When a good set of these are complete to -commercial quality, a 2.0 version of t_cose will be released. - -Note that there is no committed time line to complete t_cose -2.0. t_cose is mostly implemented on a volunteer basis. You can -volunteer! Work like adding support for more algorithms is not too -difficult and is nicely framed up. +As of August 2022, there are alpha releases of t_cose 2.0. It supports: +* COSE_Sign +* Multiple signatures +* COSE_MAC0 +* COSE_Encrypt and COSE_Encrypt0 +* Encryption with ECDH per RFC 9053 +See the dev branch and the releases. ## Building and Dependencies @@ -71,6 +70,9 @@ If QCBOR is installed in /usr/local, then the makefiles should find it. If not then QCBOR may need to be downloaded. The makefiles can be modified to reference it other than in /usr/local. +This works with both QCBOR v1 and v2. When running with v2 it +uses the QCBOR v1 compatibility mode for tag decoding. + ### Supported Cryptographic Libraries Here's three crypto library configurations that are supported. Others diff --git a/3rdparty/exported/t_cose/inc/t_cose/t_cose_common.h b/3rdparty/exported/t_cose/inc/t_cose/t_cose_common.h index 501c480a48fe..93a975ef2d12 100644 --- a/3rdparty/exported/t_cose/inc/t_cose/t_cose_common.h +++ b/3rdparty/exported/t_cose/inc/t_cose/t_cose_common.h @@ -1,7 +1,7 @@ /* * t_cose_common.h * - * Copyright 2019-2022, Laurence Lundblade + * Copyright 2019-2024, Laurence Lundblade * * SPDX-License-Identifier: BSD-3-Clause * @@ -59,6 +59,14 @@ extern "C" { */ +/** + * Semantic versioning for t_cose x.y.z. Note that these were not defined + * for some releases of t_cose 1.x so !defined(T_COSE_VERSION_MAJOR) + * indicates t_cose 1.x. + */ +#define T_COSE_VERSION_MAJOR 1 +#define T_COSE_VERSION_MINOR 1 +#define T_COSE_VERSION_PATCH 3 /** diff --git a/3rdparty/exported/t_cose/mainpage.dox b/3rdparty/exported/t_cose/mainpage.dox new file mode 100644 index 000000000000..0fb69c71f88c --- /dev/null +++ b/3rdparty/exported/t_cose/mainpage.dox @@ -0,0 +1,18 @@ +/*! @mainpage t_cose Documentation + +t_cose 1.x is available for download [here on github](http://github.com/laurencelundblade/t_cose) +(alpha release of t_cose 2.x which supports encryption, multiple signature and mac is also available). + +This documentation is for t_cose 1.x. + +@par Table of Contents + +API Reference: +- Common + - Error codes and common constants: @ref inc/t_cose/t_cose_common.h "t_cose_common.h" +- Signing + - Main/Basic signing functions: @ref inc/t_cose/t_cose_sign1_sign.h "t_cose_sign1_sign.h" +- Verification + - Main/Basic verification functions: @ref inc/t_cose/t_cose_sign1_verify.h "t_cose_sign1_verify.h" + +*/ diff --git a/3rdparty/exported/t_cose/src/t_cose_sign1_sign.c b/3rdparty/exported/t_cose/src/t_cose_sign1_sign.c index 9aca0e88fab7..18c8f9209ded 100644 --- a/3rdparty/exported/t_cose/src/t_cose_sign1_sign.c +++ b/3rdparty/exported/t_cose/src/t_cose_sign1_sign.c @@ -1,7 +1,7 @@ /* * t_cose_sign1_sign.c * - * Copyright (c) 2018-2021, Laurence Lundblade. All rights reserved. + * Copyright (c) 2018-2024, Laurence Lundblade. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause * @@ -15,11 +15,13 @@ #include "t_cose_util.h" #include "t_cose_short_circuit.h" -#ifndef QCBOR_1_1 -// The OpenBytes API we use was only added in 1.1. + +#if !(defined(QCBOR_1_1) || QCBOR_VERSION_MAJOR >= 2 || (QCBOR_VERSION_MAJOR == 1 && QCBOR_VERSION_MINOR >= 1)) +/* The OpenBytes API we use was only added in 1.1. */ #error t_cose requires QCBOR 1.1 or greater #endif + /** * \file t_cose_sign1_sign.c * diff --git a/3rdparty/exported/t_cose/src/t_cose_sign1_verify.c b/3rdparty/exported/t_cose/src/t_cose_sign1_verify.c index e4d004acac13..c332089c9984 100644 --- a/3rdparty/exported/t_cose/src/t_cose_sign1_verify.c +++ b/3rdparty/exported/t_cose/src/t_cose_sign1_verify.c @@ -389,9 +389,14 @@ t_cose_sign1_verify_internal(struct t_cose_sign1_verify_ctx *me, clear_label_list(&critical_parameter_labels); clear_cose_parameters(¶meters); +#if QCBOR_VERSION_MAJOR >= 2 + const int decode_config = QCBOR_DECODE_ALLOW_UNPROCESSED_TAG_NUMBERS; +#else + const int decode_config = QCBOR_DECODE_MODE_NORMAL; +#endif /* === Decoding of the array of four starts here === */ - QCBORDecode_Init(&decode_context, cose_sign1, QCBOR_DECODE_MODE_NORMAL); + QCBORDecode_Init(&decode_context, cose_sign1, decode_config); /* --- The array of 4 and tags --- */ QCBORDecode_EnterArray(&decode_context, NULL); diff --git a/3rdparty/exported/t_cose/t_cose.xcodeproj/project.pbxproj b/3rdparty/exported/t_cose/t_cose.xcodeproj/project.pbxproj index 2b4a0423306f..9f50be993a31 100644 --- a/3rdparty/exported/t_cose/t_cose.xcodeproj/project.pbxproj +++ b/3rdparty/exported/t_cose/t_cose.xcodeproj/project.pbxproj @@ -812,7 +812,7 @@ CLANG_WARN_CONSTANT_CONVERSION = YES; CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_DOCUMENTATION_COMMENTS = NO; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_IMPLICIT_SIGN_CONVERSION = YES; @@ -878,7 +878,7 @@ CLANG_WARN_CONSTANT_CONVERSION = YES; CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_DOCUMENTATION_COMMENTS = NO; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_IMPLICIT_SIGN_CONVERSION = YES; diff --git a/cgmanifest.json b/cgmanifest.json index 1d6d643d57f8..cc06358cb525 100644 --- a/cgmanifest.json +++ b/cgmanifest.json @@ -114,7 +114,7 @@ "type": "git", "git": { "repositoryUrl": "https://github.com/laurencelundblade/QCBOR", - "commitHash": "92d3f89030baff4af7be8396c563e6c8ef263622" + "commitHash": "24cd62a415161c2851327e96a023b47bb0897e64" } } }, @@ -123,7 +123,7 @@ "type": "git", "git": { "repositoryUrl": "https://github.com/laurencelundblade/t_cose", - "commitHash": "7d1b6686990e5bf6b84df422f93fb7f547669012" + "commitHash": "64fbc64dd5982a7f75834d2b9a2a8c9ba8207776" } } },