aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEd Maste <emaste@FreeBSD.org>2023-04-20 23:17:42 +0000
committerEd Maste <emaste@FreeBSD.org>2023-04-20 23:17:42 +0000
commit058aa793d837f38f112acc154816397251019319 (patch)
tree6703990f4d118959eeb50f39c44bc62dbffa4f26
parent5b2defbd2a1aa991bd0a2855eef8e15107572747 (diff)
downloadsrc-vendor/libcbor.tar.gz
src-vendor/libcbor.zip
Vendor import of libcbor 0.10.2vendor/libcbor/0.10.2vendor/libcbor
-rw-r--r--.circleci/config.yml224
-rw-r--r--.github/ISSUE_TEMPLATE/bug_report.md20
-rw-r--r--.github/PULL_REQUEST_TEMPLATE15
-rw-r--r--.github/workflows/fuzz-pr.yml25
-rw-r--r--.github/workflows/fuzz.yml6
-rw-r--r--.gitignore8
-rw-r--r--.travis.yml66
-rw-r--r--Bazel.md100
-rw-r--r--CHANGELOG.md47
-rw-r--r--CMakeLists.txt54
-rw-r--r--CMakeModules/FindCMocka.cmake8
-rw-r--r--CMakeModules/JoinPaths.cmake23
-rw-r--r--CONTRIBUTING.md35
-rw-r--r--Doxyfile778
-rw-r--r--README.md54
-rw-r--r--appveyor.yml19
-rwxr-xr-xclang-format.sh9
-rw-r--r--codecov.yml9
-rw-r--r--doc/source/api.rst4
-rw-r--r--doc/source/api/encoding.rst4
-rw-r--r--doc/source/api/item_reference_counting.rst19
-rw-r--r--doc/source/api/streaming_decoding.rst (renamed from doc/source/streaming/decoding.rst)14
-rw-r--r--doc/source/api/streaming_encoding.rst65
-rw-r--r--doc/source/api/type_2.rst5
-rw-r--r--doc/source/api/type_3.rst6
-rw-r--r--doc/source/api/type_4.rst9
-rw-r--r--doc/source/api/type_5.rst26
-rw-r--r--doc/source/api/type_7.rst9
-rw-r--r--doc/source/conf.py4
-rw-r--r--doc/source/getting_started.rst7
-rw-r--r--doc/source/index.rst1
-rw-r--r--doc/source/requirements.txt60
-rw-r--r--doc/source/rfc_conformance.rst4
-rw-r--r--doc/source/streaming.rst13
-rw-r--r--doc/source/streaming/encoding.rst4
-rw-r--r--doc/source/using.rst11
-rw-r--r--examples/CMakeLists.txt3
-rw-r--r--examples/bazel/README.md33
-rw-r--r--examples/bazel/WORKSPACE19
-rw-r--r--examples/bazel/src/BUILD46
-rw-r--r--examples/bazel/src/hello.cc7
-rw-r--r--examples/bazel/src/hello.h8
-rw-r--r--examples/bazel/src/hello_test.cc10
-rw-r--r--examples/bazel/src/main.cc10
-rw-r--r--examples/bazel/third_party/BUILD1
-rw-r--r--examples/bazel/third_party/libcbor.BUILD21
-rw-r--r--examples/bazel/third_party/libcbor/BUILD11
-rw-r--r--examples/bazel/third_party/libcbor/cbor/cbor_export.h42
-rw-r--r--examples/bazel/third_party/libcbor/cbor/configuration.h15
-rw-r--r--examples/cjson2cbor.c8
-rw-r--r--examples/create_items.c25
-rw-r--r--examples/hello.c3
-rw-r--r--examples/readfile.c3
-rw-r--r--examples/sort.c15
-rw-r--r--examples/streaming_array.c47
-rw-r--r--examples/streaming_parser.c10
-rwxr-xr-xmisc/update_version.py29
-rwxr-xr-xoss-fuzz/build.sh2
-rw-r--r--oss-fuzz/cbor_load_fuzzer.cc54
-rwxr-xr-xrelease.sh8
-rw-r--r--src/CMakeLists.txt18
-rw-r--r--src/cbor.c144
-rw-r--r--src/cbor.h26
-rw-r--r--src/cbor/arrays.c22
-rw-r--r--src/cbor/arrays.h71
-rw-r--r--src/cbor/bytestrings.c40
-rw-r--r--src/cbor/bytestrings.h54
-rw-r--r--src/cbor/callbacks.c153
-rw-r--r--src/cbor/callbacks.h14
-rw-r--r--src/cbor/common.c29
-rw-r--r--src/cbor/common.h152
-rw-r--r--src/cbor/configuration.h.in1
-rw-r--r--src/cbor/data.h11
-rw-r--r--src/cbor/encoding.c20
-rw-r--r--src/cbor/encoding.h103
-rw-r--r--src/cbor/floats_ctrls.c64
-rw-r--r--src/cbor/floats_ctrls.h114
-rw-r--r--src/cbor/internal/builder_callbacks.c230
-rw-r--r--src/cbor/internal/builder_callbacks.h12
-rw-r--r--src/cbor/internal/encoders.c28
-rw-r--r--src/cbor/internal/encoders.h5
-rw-r--r--src/cbor/internal/loaders.c2
-rw-r--r--src/cbor/internal/loaders.h9
-rw-r--r--src/cbor/internal/memory_utils.c17
-rw-r--r--src/cbor/internal/memory_utils.h13
-rw-r--r--src/cbor/internal/stack.c6
-rw-r--r--src/cbor/internal/stack.h14
-rw-r--r--src/cbor/internal/unicode.c9
-rw-r--r--src/cbor/internal/unicode.h7
-rw-r--r--src/cbor/ints.c59
-rw-r--r--src/cbor/ints.h61
-rw-r--r--src/cbor/maps.c21
-rw-r--r--src/cbor/maps.h65
-rw-r--r--src/cbor/serialization.c276
-rw-r--r--src/cbor/serialization.h135
-rw-r--r--src/cbor/streaming.c181
-rw-r--r--src/cbor/streaming.h10
-rw-r--r--src/cbor/strings.c39
-rw-r--r--src/cbor/strings.h87
-rw-r--r--src/cbor/tags.c11
-rw-r--r--src/cbor/tags.h35
-rw-r--r--src/libcbor.pc.in4
-rw-r--r--test/CMakeLists.txt14
-rw-r--r--test/array_encoders_test.c (renamed from test/type_4_encoders_test.c)31
-rw-r--r--test/array_test.c222
-rw-r--r--test/assertions.c32
-rw-r--r--test/assertions.h20
-rw-r--r--test/bad_inputs_test.c43
-rw-r--r--test/bytestring_encoders_test.c (renamed from test/type_2_encoders_test.c)20
-rw-r--r--test/bytestring_test.c (renamed from test/type_2_test.c)122
-rw-r--r--test/callbacks_test.c374
-rw-r--r--test/cbor_serialize_test.c490
-rw-r--r--test/cbor_stream_decode_test.c274
-rw-r--r--test/copy_test.c346
-rw-r--r--test/float_ctrl_encoders_test.c213
-rw-r--r--test/float_ctrl_test.c (renamed from test/type_7_test.c)80
-rw-r--r--test/fuzz_test.c15
-rw-r--r--test/map_encoders_test.c (renamed from test/type_5_encoders_test.c)21
-rw-r--r--test/map_test.c (renamed from test/type_5_test.c)120
-rw-r--r--test/memory_allocation_test.c277
-rw-r--r--test/memory_utils_test.c59
-rw-r--r--test/negint_encoders_test.c (renamed from test/type_1_encoders_test.c)49
-rw-r--r--test/negint_test.c (renamed from test/type_1_test.c)40
-rw-r--r--test/pretty_printer_test.c9
-rw-r--r--test/stack_over_limit_test.c15
-rw-r--r--test/stream_expectations.c107
-rw-r--r--test/stream_expectations.h71
-rw-r--r--test/string_encoders_test.c (renamed from test/type_3_encoders_test.c)21
-rw-r--r--test/string_test.c (renamed from test/type_3_test.c)112
-rw-r--r--test/tag_encoders_test.c (renamed from test/type_6_encoders_test.c)15
-rw-r--r--test/tag_test.c (renamed from test/type_6_test.c)59
-rw-r--r--test/test_allocator.c89
-rw-r--r--test/test_allocator.h35
-rw-r--r--test/type_4_test.c127
-rw-r--r--test/type_7_encoders_test.c109
-rw-r--r--test/uint_encoders_test.c (renamed from test/type_0_encoders_test.c)46
-rw-r--r--test/uint_test.c (renamed from test/type_0_test.c)58
-rw-r--r--test/unicode_test.c23
138 files changed, 5666 insertions, 2659 deletions
diff --git a/.circleci/config.yml b/.circleci/config.yml
new file mode 100644
index 000000000000..69371b67d624
--- /dev/null
+++ b/.circleci/config.yml
@@ -0,0 +1,224 @@
+version: 2.1
+
+commands:
+ linux-setup:
+ steps:
+ - run: sudo apt-get update
+ - run: sudo apt-get install -y cmake ${TOOLCHAIN_PACKAGES}
+ - run: sudo apt install libcmocka-dev
+ build:
+ steps:
+ - run: >
+ cmake -DWITH_TESTS=ON \
+ -DCMAKE_BUILD_TYPE=Debug \
+ -DSANITIZE=OFF \
+ -DCOVERAGE="${CMAKE_COVERAGE:='OFF'}" \
+ .
+ - run: make -j 16 VERBOSE=1
+ build-release:
+ steps:
+ - run: >
+ cmake -DWITH_TESTS=ON \
+ -DCMAKE_BUILD_TYPE=Release \
+ .
+ - run: make -j 16 VERBOSE=1
+ test:
+ steps:
+ - run: ctest -VV
+
+orbs:
+ codecov: codecov/codecov@3.2.2
+
+jobs:
+ static-test:
+ machine:
+ image: ubuntu-2204:2022.10.2
+ environment:
+ TOOLCHAIN_PACKAGES: g++
+ steps:
+ - checkout
+ - linux-setup
+ - run: sudo apt-get install -y clang-format doxygen cppcheck
+ - run: cppcheck --inline-suppr --error-exitcode=1 .
+ - run: bash clang-format.sh --verbose
+ - run: >
+ if ! $(git diff-index --quiet HEAD); then
+ echo "Code formatting doesn't conform to clang-format"
+ echo "Please run clang-format.sh, commit the diff, and push to re-run CI"
+ echo "Excerpt of the diff follows"
+ git diff | head -n 20
+ fi
+ - run: >
+ if doxygen Doxyfile | grep 'warning: '; then
+ echo "Doxygen warning (see above) -- misformatted docs?"
+ exit 1
+ fi
+ - run: >
+ cd doc &&
+ pip3 install -r source/requirements.txt &&
+ make html
+
+ build-and-test:
+ machine:
+ image: ubuntu-2204:2022.10.2
+ environment:
+ TOOLCHAIN_PACKAGES: g++
+ CMAKE_COVERAGE: ON
+ steps:
+ - checkout
+ - linux-setup
+ - run: sudo apt-get install -y valgrind
+ - build
+ - test
+ - run: ctest -T Coverage
+ - codecov/upload
+ - run: ctest --output-on-failure -T memcheck | tee memcheck.out
+ - run: >
+ if grep -q 'Memory Leak\|IPW\|Uninitialized Memory Conditional\|Uninitialized Memory Read' memcheck.out; then
+ cat Testing/Temporary/MemoryChecker*
+ exit 1
+ fi;
+
+ build-and-test-clang:
+ machine:
+ image: ubuntu-2204:2022.10.2
+ environment:
+ TOOLCHAIN_PACKAGES: clang
+ CC: clang
+ CXX: clang++
+ steps:
+ - checkout
+ - linux-setup
+ - build
+ - test
+
+ build-and-test-32b:
+ machine:
+ image: ubuntu-2204:2022.10.2
+ steps:
+ - checkout
+ - run: sudo apt-get update
+ - run: sudo apt-get install -y cmake gcc-multilib g++-multilib libc6-dev-i386
+ # Make cmocka from source w/ 32b setup
+ - run: git clone https://git.cryptomilk.org/projects/cmocka.git ~/cmocka
+ - run: >
+ cd $(mktemp -d /tmp/build.XXXX) &&
+ cmake ~/cmocka -DCMAKE_TOOLCHAIN_FILE=~/cmocka/cmake/Toolchain-cross-m32.cmake &&
+ make &&
+ sudo make install
+ # Piggyback on the cmocka 32b toolchain
+ - run: >
+ cmake -DWITH_TESTS=ON \
+ -DCMAKE_BUILD_TYPE=Debug \
+ -DCMAKE_TOOLCHAIN_FILE=~/cmocka/cmake/Toolchain-cross-m32.cmake \
+ .
+ - run: make -j 16 VERBOSE=1
+ - test
+
+ build-and-test-release-clang:
+ machine:
+ image: ubuntu-2204:2022.10.2
+ environment:
+ TOOLCHAIN_PACKAGES: clang
+ CC: clang
+ CXX: clang++
+ steps:
+ - checkout
+ - linux-setup
+ - build-release
+ - test
+
+ llvm-coverage:
+ machine:
+ image: ubuntu-2204:2022.10.2
+ environment:
+ TOOLCHAIN_PACKAGES: clang
+ CC: clang
+ CXX: clang++
+ CMAKE_COVERAGE: ON
+ steps:
+ - checkout
+ - linux-setup
+ - build
+ - run: make llvm-coverage
+
+
+ build-and-test-arm:
+ machine:
+ image: ubuntu-2204:2022.10.2
+ environment:
+ TOOLCHAIN_PACKAGES: g++
+ resource_class: arm.medium
+ steps:
+ - checkout
+ - linux-setup
+ - build
+ - test
+
+ build-bazel:
+ machine:
+ image: ubuntu-2204:2022.10.2
+ environment:
+ TOOLCHAIN_PACKAGES: g++
+ steps:
+ - checkout
+ - linux-setup
+ - run: sudo apt install apt-transport-https curl gnupg
+ - run: curl -fsSL https://bazel.build/bazel-release.pub.gpg | gpg --dearmor > bazel.gpg
+ - run: sudo mv bazel.gpg /etc/apt/trusted.gpg.d/
+ - run: echo "deb [arch=amd64] https://storage.googleapis.com/bazel-apt stable jdk1.8" | sudo tee /etc/apt/sources.list.d/bazel.list
+ - run: sudo apt update
+ - run: sudo apt install bazel
+ - run: bazel --version
+ - run: >
+ pushd examples/bazel &&
+ bazel run -s src:hello
+
+ build-and-test-osx:
+ macos:
+ xcode: 12.5.1
+ steps:
+ - checkout
+ - run: bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
+ - run: brew install cmocka cmake
+ - build
+ - test
+
+
+ build-and-test-win:
+ resource_class: 'windows.medium'
+ machine:
+ image: 'windows-server-2022-gui:current'
+ shell: 'bash.exe'
+ steps:
+ - checkout
+ - run: choco install cmake -y
+ - run: git clone https://git.cryptomilk.org/projects/cmocka.git
+ - run: cd cmocka && git checkout tags/cmocka-1.1.5
+ - run: /c/Program\ Files/Cmake/bin/cmake -S cmocka -B cmocka_build
+ - run: /c/Program\ Files/Cmake/bin/cmake --build cmocka_build
+ - run: /c/Program\ Files/Cmake/bin/cmake -S . -B libcbor_build -DWITH_TESTS=ON -DCMOCKA_INCLUDE_DIR=cmocka/include -DCMOCKA_LIBRARIES=$(pwd)/cmocka_build/src/Debug/cmocka.lib
+ - run: /c/Program\ Files/Cmake/bin/cmake --build libcbor_build
+ - run: >
+ export PATH="$(pwd)/cmocka_build/src/Debug/:$PATH" &&
+ /c/Program\ Files/Cmake/bin/ctest.exe --test-dir libcbor_build --output-on-failure
+
+workflows:
+ build-and-test:
+ jobs:
+ - static-test
+ - build-and-test
+ - build-and-test-clang
+ - build-and-test-32b
+ - build-and-test-release-clang
+ - build-and-test-arm
+ - build-and-test-win
+ - build-bazel
+ - llvm-coverage
+ # OSX builds are expensive, run only on master
+ - build-and-test-osx:
+ requires:
+ - build-and-test
+ filters:
+ branches:
+ only: [master]
diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md
new file mode 100644
index 000000000000..75997d8424cc
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/bug_report.md
@@ -0,0 +1,20 @@
+---
+name: Bug report
+about: Create a report to help us improve
+title: ''
+labels: bug
+assignees: PJK
+
+---
+
+**Describe the bug**
+A clear and concise description of what the bug is.
+
+**To Reproduce**
+Steps to reproduce the behavior. If possible, please attach a runnable code snippet.
+
+**Expected behavior**
+A clear and concise description of what you expected to happen.
+
+**Environment**
+libcbor version and build configuration flags (or source package version if using a package manager).
diff --git a/.github/PULL_REQUEST_TEMPLATE b/.github/PULL_REQUEST_TEMPLATE
new file mode 100644
index 000000000000..1174d56f9c7a
--- /dev/null
+++ b/.github/PULL_REQUEST_TEMPLATE
@@ -0,0 +1,15 @@
+## Description
+
+What changes and why
+
+## Checklist
+
+- [ ] I have read followed [CONTRIBUTING.md](https://github.com/PJK/libcbor/blob/master/CONTRIBUTING.md)
+ - [ ] I have added tests
+ - [ ] I have updated the documentation
+ - [ ] I have updated the CHANGELOG
+- [ ] Are there any breaking changes?
+ - [ ] If yes: I have marked them in the CHANGELOG ([example](https://github.com/PJK/libcbor/blob/87e2d48a127968d39f158cbfc2b79d6285bd039d/CHANGELOG.md?plain=1#L16))
+- [ ] Does this PR introduce any platform specific code?
+- [ ] Security: Does this PR potentially affect security?
+- [ ] Performance: Does this PR potentially affect performance?
diff --git a/.github/workflows/fuzz-pr.yml b/.github/workflows/fuzz-pr.yml
new file mode 100644
index 000000000000..0e3c4fde4e02
--- /dev/null
+++ b/.github/workflows/fuzz-pr.yml
@@ -0,0 +1,25 @@
+# A quick CIFuzz sanity check. Fuzzing time is kept low provide fast feedback
+# on PRs; fuzz.yml schedules a daily long-running fuzzing job.
+name: CIFuzz PR check
+on: [pull_request]
+jobs:
+ Fuzzing:
+ runs-on: ubuntu-latest
+ steps:
+ - name: Build Fuzzers
+ uses: google/oss-fuzz/infra/cifuzz/actions/build_fuzzers@master
+ with:
+ oss-fuzz-project-name: 'libcbor'
+ dry-run: false
+ - name: Smoke Test Fuzzers
+ uses: google/oss-fuzz/infra/cifuzz/actions/run_fuzzers@master
+ with:
+ oss-fuzz-project-name: 'libcbor'
+ fuzz-seconds: 10
+ dry-run: false
+ - name: Upload Crash
+ uses: actions/upload-artifact@v1
+ if: failure()
+ with:
+ name: artifacts
+ path: ./out/artifacts
diff --git a/.github/workflows/fuzz.yml b/.github/workflows/fuzz.yml
index c5275121868f..8603cc2f338e 100644
--- a/.github/workflows/fuzz.yml
+++ b/.github/workflows/fuzz.yml
@@ -1,5 +1,7 @@
name: CIFuzz
-on: [pull_request]
+on:
+ schedule:
+ - cron: '0 4 * * *'
jobs:
Fuzzing:
runs-on: ubuntu-latest
@@ -13,7 +15,7 @@ jobs:
uses: google/oss-fuzz/infra/cifuzz/actions/run_fuzzers@master
with:
oss-fuzz-project-name: 'libcbor'
- fuzz-seconds: 600
+ fuzz-seconds: 14400 # 4 hours
dry-run: false
- name: Upload Crash
uses: actions/upload-artifact@v1
diff --git a/.gitignore b/.gitignore
index b6fe00f938ad..61f88a874965 100644
--- a/.gitignore
+++ b/.gitignore
@@ -6,3 +6,11 @@ doxygen_docs
*/*.out
cmake-build-debug
venv
+**.DS_Store
+.vscode
+# No top-level requirements, see doc/source
+requirements.txt
+examples/bazel/bazel-bazel
+examples/bazel/bazel-bin
+examples/bazel/bazel-out
+examples/bazel/bazel-testlogs
diff --git a/.travis.yml b/.travis.yml
deleted file mode 100644
index 288de2903399..000000000000
--- a/.travis.yml
+++ /dev/null
@@ -1,66 +0,0 @@
-language: c
-
-matrix:
- include:
- - arch: amd64
- os: linux
- dist: bionic
- compiler: clang
- env: TRAVIS_ARCH="amd64"
- - arch: amd64
- os: linux
- dist: bionic
- compiler: gcc
- env: TRAVIS_ARCH="amd64"
- - arch: arm64
- os: linux
- dist: bionic
- compiler: gcc
- env: TRAVIS_ARCH="arm64"
- - arch: ppc64le
- os: linux
- dist: bionic
- compiler: gcc
- env: TRAVIS_ARCH="ppc64le"
- - arch: amd64
- os: osx
- compiler: gcc
- env: TRAVIS_ARCH="amd64"
-
-before_install:
- - pushd ${HOME}
- - git clone https://gitlab.com/cmocka/cmocka.git
- - cd cmocka && mkdir build && cd build
- - cmake .. && make -j2 && sudo make install
- - cd .. && popd
- - if [ "$TRAVIS_OS_NAME" = "linux" ]; then sudo apt-get update -qq; sudo apt-get install -y clang-format-8 cppcheck; fi
- - if [ "$TRAVIS_OS_NAME" = "linux" -a "$CC" = "gcc" -a "$TRAVIS_ARCH" = "amd64" ]; then pip install --user codecov; export CFLAGS="-coverage"; fi
-
-script:
- - >
- if [ "$TRAVIS_OS_NAME" = "linux" ]; then
- cppcheck . --error-exitcode=1
- # Fail if re-formatting creates diffs (implying bad formatting)
- /clang-format.sh --verbose
- git diff-index --quiet HEAD
- fi;
- - mkdir build && cd build
- - cmake -DWITH_TESTS=ON
- -DCBOR_CUSTOM_ALLOC=ON
- -DCMAKE_BUILD_TYPE=Debug
- -DSANITIZE=OFF
- ..
- - make VERBOSE=1
- - ctest -VV
- - ctest -T memcheck | tee memcheck.out
- - >
- if grep -q 'Memory Leak\|IPW\|Uninitialized Memory Conditional\|Uninitialized Memory Read' memcheck.out; then
- exit 1
- fi;
-
-
-after_success:
- - if [ "$TRAVIS_OS_NAME" = "linux" -a "$CC" = "gcc" -a "$TRAVIS_ARCH" = "amd64" ]; then codecov; fi
-
-notifications:
- email: false
diff --git a/Bazel.md b/Bazel.md
new file mode 100644
index 000000000000..9fa2081f58fc
--- /dev/null
+++ b/Bazel.md
@@ -0,0 +1,100 @@
+# Use as a Bazel Dependency
+
+To use libcbor in your
+[Baze](https://bazel.build/)
+project, first add the following section to your project's `WORKSPACE` file.
+Note the location of the `third_party/libcbor.BUILD` file - you may use a
+different location if you wish, but you the file must be make available to
+`WORKSPACE`.
+
+## WORKSPACE
+
+Note, this imports version `0.8.0` - you may need to update the version and
+the sha256 hash.
+
+```python
+# libcbor
+http_archive(
+ name = "libcbor",
+ build_file = "//third_party:libcbor.BUILD",
+ sha256 = "dd04ea1a7df484217058d389e027e7a0143a4f245aa18a9f89a5dd3e1a4fcc9a",
+ strip_prefix = "libcbor-0.8.0",
+ urls = ["https://github.com/PJK/libcbor/archive/refs/tags/v0.8.0.zip"],
+)
+```
+
+## third_party/libcbor.BUILD
+
+Bazel will unzip the libcbor zip file, then copy this file in as `BUILD`.
+Bazel will then use this file to compile libcbor.
+[Cmake](https://cmake.org/)
+is used in two passes: to create the Makefiles, and then to invoke Make to build
+the `libcbor.a` static library. `libcbor.a` and the `.h` files are then made
+available for other packages to use.
+
+```python
+genrule(
+ name = "cbor_cmake",
+ srcs = glob(["**"]),
+ outs = ["libcbor.a", "cbor.h", "cbor/arrays.h", "cbor/bytestrings.h",
+ "cbor/callbacks.h", "cbor/cbor_export.h", "cbor/common.h", "cbor/configuration.h", "cbor/data.h",
+ "cbor/encoding.h", "cbor/floats_ctrls.h", "cbor/ints.h", "cbor/maps.h",
+ "cbor/serialization.h", "cbor/streaming.h", "cbor/strings.h", "cbor/tags.h"],
+ cmd = " && ".join([
+ # Remember where output should go.
+ "INITIAL_WD=`pwd`",
+ # Build libcbor library.
+ "cd `dirname $(location CMakeLists.txt)`",
+ "cmake -DCMAKE_BUILD_TYPE=Release .",
+ "cmake --build .",
+ # Export the .a and .h files for cbor rule, below.
+ "cp src/libcbor.a src/cbor.h $$INITIAL_WD/$(RULEDIR)",
+ "cp src/cbor/*h cbor/configuration.h $$INITIAL_WD/$(RULEDIR)/cbor"]),
+ visibility = ["//visibility:private"],
+)
+
+cc_import(
+ name = "cbor",
+ hdrs = ["cbor.h", "cbor/arrays.h", "cbor/bytestrings.h",
+ "cbor/callbacks.h", "cbor/cbor_export.h", "cbor/common.h", "cbor/configuration.h", "cbor/data.h",
+ "cbor/encoding.h", "cbor/floats_ctrls.h", "cbor/ints.h", "cbor/maps.h",
+ "cbor/serialization.h", "cbor/streaming.h", "cbor/strings.h", "cbor/tags.h"],
+ static_library = "libcbor.a",
+ visibility = ["//visibility:public"],
+)
+```
+
+## third_party/BUILD
+
+The `libcbor.BUILD` file must be make available to the top-level `WORKSPACE`
+file:
+
+```python
+exports_files(["libcbor.BUILD"]))
+```
+
+## Your BUILD File
+
+Add libcbor dependency to your package's `BUILD` file like so:
+
+```python
+cc_library(
+ name = "...",
+ srcs = [ ... ],
+ hdrs = [ ... ],
+ deps = [
+ ...
+ "@libcbor//:cbor",
+ ],
+)
+```
+
+## Your C File
+
+Now you may simply include `cbor.h`:
+
+```c
+#include "cbor.h"
+
+static const uint8_t version = cbor_major_version;
+```
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 0f13a45d6b24..f2475f308c7a 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,6 +1,53 @@
+Template:
+- [Fix issue X in feature Y](https://github.com/PJK/libcbor/pull/XXX) (by [YYY](https://github.com/YYY))
+
Next
---------------------
+0.10.2 (2023-01-31)
+---------------------
+- [Fixed minor test bug causing failures for x86 Linux](https://github.com/PJK/libcbor/pull/266) (discovered by [trofi](https://github.com/PJK/libcbor/issues/263))
+ - Actual libcbor functionality not affected, bug was in the test suite
+- [Made tests platform-independent](https://github.com/PJK/libcbor/pull/272)
+
+0.10.1 (2022-12-30)
+---------------------
+- [Fix a regression in `cbor_serialize_alloc` that caused serialization of zero-length strings and bytestrings or byte/strings with zero-length chunks to fail](https://github.com/PJK/libcbor/pull/260) (discovered by [martelletto](https://github.com/martelletto))
+
+0.10.0 (2022-12-29)
+---------------------
+- Make the buffer_size optional in `cbor_serialize_alloc` [[#205]](https://github.com/PJK/libcbor/pull/205) (by [hughsie](https://github.com/hughsie))
+- BREAKING: Improved half-float encoding for denormalized numbers. [[#208]](https://github.com/PJK/libcbor/pull/208) (by [ranvis](https://github.com/ranvis))
+ - Denormalized half-floats will now preserve data in the mantissa
+ - Note: Half-float NaNs still lose data (https://github.com/PJK/libcbor/issues/215)
+- BUILD BREAKING: Minimum CMake version is 3.0 [[#201]](https://github.com/PJK/libcbor/pull/201) (by [thewtex@](https://github.com/thewtex))
+ - See https://repology.org/project/cmake/versions for support; the vast majority of users should not be affected.
+- Fix a potential memory leak when the allocator fails during array or map decoding [[#224]](https://github.com/PJK/libcbor/pull/224) (by [James-ZHANG](https://github.com/James-ZHANG))
+- [Fix a memory leak when the allocator fails when adding chunks to indefinite bytestrings.](https://github.com/PJK/libcbor/pull/242) ([discovered](https://github.com/PJK/libcbor/pull/228) by [James-ZHANG](https://github.com/James-ZHANG))
+- [Fix a memory leak when the allocator fails when adding chunks to indefinite strings](https://github.com/PJK/libcbor/pull/246)
+- Potentially BUILD BREAKING: [Add nodiscard attributes to most functions](https://github.com/PJK/libcbor/pull/248)
+ - **Warning**: This may cause new build warnings and (in rare cases, depending on your configuration) errors
+- BREAKING: [Fix `cbor_copy` leaking memory and creating invalid items when the allocator fails](https://github.com/PJK/libcbor/pull/249).
+ - Previously, the failures were not handled in the interface. Now, `cbor_copy` may return `NULL` upon failure; clients should check the return value
+- [Fix `cbor_build_tag` illegal memory behavior when the allocator fails](https://github.com/PJK/libcbor/pull/249)
+- [Add a new `cbor_serialized_size` API](https://github.com/PJK/libcbor/pull/250)
+- [Reworked `cbor_serialize_alloc` to allocate the exact amount of memory necessary upfront](https://github.com/PJK/libcbor/pull/251)
+ - This should significantly speed up `cbor_serialize_alloc` for large items by avoiding multiple reallocation iterations
+ - Clients should not use the return value of `cbor_serialize_alloc`. It may be removed in the future.
+- BUILD BREAKING: [Deprecate CBOR_CUSTOM_ALLOC](https://github.com/PJK/libcbor/pull/237)
+ - `cbor_set_allocs` will always be enabled from now on
+ - Note: The flag will be kept as a no-op triggering a warning when used for one version and then removed completely
+
+0.9.0 (2021-11-14)
+---------------------
+- Improved pkg-config paths handling [[#164]](https://github.com/PJK/libcbor/pull/164) (by [jtojnar@](https://github.com/jtojnar))
+- Use explicit math.h linkage [[#170]](https://github.com/PJK/libcbor/pull/170)
+- BREAKING: Fixed handling of items that exceed the host size_t range [[#186]](https://github.com/PJK/libcbor/pull/186hg)
+ - Callbacks for bytestrings, strings, arrays, and maps use uint64_t instead of size_t to allow handling of large items that exceed size_t even if size_t < uint64_t
+ - cbor_decode explicitly checks size to avoid overflows (previously broken, potentially resulting in erroneous decoding on affected systems)
+ - The change should be a noop for 64b systems
+- Added a [Bazel](https://bazel.build/) build example [[#196]](https://github.com/PJK/libcbor/pull/196) (by [andyjgf@](https://github.com/andyjgf))
+
0.8.0 (2020-09-20)
---------------------
- BUILD BREAKING: Use BUILD_SHARED_LIBS to determine how to build libraries (fixed Windows linkage) [[#148]](https://github.com/PJK/libcbor/pull/148) (by [intelligide@](https://github.com/intelligide))
diff --git a/CMakeLists.txt b/CMakeLists.txt
index edba03720d2f..5c0a7846cfa3 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1,11 +1,11 @@
-cmake_minimum_required(VERSION 2.8)
+cmake_minimum_required(VERSION 3.0)
project(libcbor)
-set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/CMakeModules/")
+set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/CMakeModules/")
include(CTest)
SET(CBOR_VERSION_MAJOR "0")
-SET(CBOR_VERSION_MINOR "8")
-SET(CBOR_VERSION_PATCH "0")
+SET(CBOR_VERSION_MINOR "10")
+SET(CBOR_VERSION_PATCH "2")
SET(CBOR_VERSION ${CBOR_VERSION_MAJOR}.${CBOR_VERSION_MINOR}.${CBOR_VERSION_PATCH})
set(CMAKE_SKIP_INSTALL_ALL_DEPENDENCY true)
@@ -18,6 +18,13 @@ if(BIG_ENDIAN)
endif()
option(CBOR_CUSTOM_ALLOC "Custom, dynamically defined allocator support" OFF)
+if(CBOR_CUSTOM_ALLOC)
+ message(WARNING
+ "CBOR_CUSTOM_ALLOC has been deprecated. Custom allocators are now enabled by default."
+ "The flag is a no-op and will be removed in the next version. "
+ "Please remove CBOR_CUSTOM_ALLOC from your build configuation.")
+endif(CBOR_CUSTOM_ALLOC)
+
option(CBOR_PRETTY_PRINTER "Include a pretty-printing routine" ON)
set(CBOR_BUFFER_GROWTH "2" CACHE STRING "Factor for buffer growth & shrinking")
set(CBOR_MAX_STACK_SIZE "2048" CACHE STRING "maximum size for decoding context stack")
@@ -85,7 +92,7 @@ set(CMAKE_EXE_LINKER_FLAGS_DEBUG "-g")
include(CheckTypeSize)
check_type_size("size_t" SIZEOF_SIZE_T)
if(SIZEOF_SIZE_T LESS 8)
- message(WARNING "Your size_t is less than 8 bytes. Long items with 64b length specifiers might not work as expected. Make sure to run the tests!")
+ message(WARNING "Your size_t is less than 8 bytes. Decoding of huge items that would exceed the memory address space will always fail. Consider implementing a custom streaming decoder if you need to deal with huge items.")
else()
add_definitions(-DEIGHT_BYTE_SIZE_T)
endif()
@@ -99,19 +106,36 @@ add_custom_target(coverage
COMMAND ctest
COMMAND lcov --capture --directory . --output-file coverage.info
COMMAND genhtml coverage.info --highlight --legend --output-directory coverage_html
- COMMAND echo "Coverage report ready: file://${CMAKE_CURRENT_BINARY_DIR}/coverage_html/index.html")
+ COMMAND echo "Coverage report ready: ${CMAKE_CURRENT_BINARY_DIR}/coverage_html/index.html")
+
+add_custom_target(llvm-coverage
+ COMMAND make -j 16
+ COMMAND rm -rf coverage_profiles
+ COMMAND mkdir coverage_profiles
+ COMMAND bash -c [[ for TEST in $(ls test/*_test); do LLVM_PROFILE_FILE="coverage_profiles/$(basename -- ${TEST}).profraw" ./${TEST}; done ]]
+ # VERBATIM makes escaping working, but breaks shell expansions, so we need to explicitly use bash
+ COMMAND bash -c [[ llvm-profdata merge -sparse $(ls coverage_profiles/*.profraw) -o coverage_profiles/combined.profdata ]]
+ COMMAND bash -c [[ llvm-cov show -instr-profile=coverage_profiles/combined.profdata test/*_test -format=html > coverage_profiles/report.html ]]
+ COMMAND bash -c [[ llvm-cov report -instr-profile=coverage_profiles/combined.profdata test/*_test ]]
+ COMMAND echo "Coverage report ready: ${CMAKE_CURRENT_BINARY_DIR}/coverage_profiles/report.html"
+ VERBATIM)
+
include_directories(src)
-option(COVERAGE "Enable code coverage instrumentation" OFF)
+option(c "Enable code coverage instrumentation" OFF)
if (COVERAGE)
message("Configuring code coverage instrumentation")
- if(NOT CMAKE_C_COMPILER MATCHES "gcc")
- message(WARNING "Gcov instrumentation only works with GCC")
+ if(CMAKE_C_COMPILER_ID MATCHES "GNU")
+ # https://gcc.gnu.org/onlinedocs/gcc/Debugging-Options.html
+ set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -g -fprofile-arcs -ftest-coverage --coverage")
+ set(CMAKE_EXE_LINKER_FLAGS_DEBUG "${CMAKE_EXE_LINKER_FLAGS_DEBUG} -g -fprofile-arcs -ftest-coverage --coverage")
+ elseif(CMAKE_C_COMPILER_ID MATCHES "Clang")
+ set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fprofile-instr-generate -fcoverage-mapping")
+ set(CMAKE_EXE_LINKER_FLAGS_DEBUG "${CMAKE_EXE_LINKER_FLAGS_DEBUG} -fprofile-instr-generate")
+ else()
+ message(WARNING "Code coverage build not implemented for compiler ${CMAKE_C_COMPILER_ID}")
endif()
- # https://gcc.gnu.org/onlinedocs/gcc/Debugging-Options.html
- set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -g -fprofile-arcs -ftest-coverage --coverage")
- set(CMAKE_EXE_LINKER_FLAGS_DEBUG "${CMAKE_EXE_LINKER_FLAGS_DEBUG} -g -fprofile-arcs -ftest-coverage --coverage")
endif (COVERAGE)
@@ -139,20 +163,20 @@ else()
message(STATUS "LTO is not enabled")
endif(use_lto)
-subdirs(src)
+add_subdirectory(src)
if(use_lto)
set_property(DIRECTORY src PROPERTY INTERPROCEDURAL_OPTIMIZATION TRUE)
endif(use_lto)
if (WITH_TESTS)
- subdirs(test)
+ add_subdirectory(test)
if(use_lto)
set_property(DIRECTORY test PROPERTY INTERPROCEDURAL_OPTIMIZATION TRUE)
endif(use_lto)
endif (WITH_TESTS)
if (WITH_EXAMPLES)
- subdirs(examples)
+ add_subdirectory(examples)
if(use_lto)
set_property(DIRECTORY examples PROPERTY INTERPROCEDURAL_OPTIMIZATION TRUE)
endif(use_lto)
diff --git a/CMakeModules/FindCMocka.cmake b/CMakeModules/FindCMocka.cmake
index 770b44afc426..29e57ae87f1b 100644
--- a/CMakeModules/FindCMocka.cmake
+++ b/CMakeModules/FindCMocka.cmake
@@ -21,7 +21,14 @@
#=============================================================================
#
+find_package(PkgConfig QUIET)
+if(PKG_CONFIG_FOUND)
+ pkg_check_modules(PC_CMOCKA QUIET cmocka)
+ set(CMOCKA_DEFINITIONS ${PC_CMOCKA_CFLAGS_OTHER})
+endif()
+
find_path(CMOCKA_INCLUDE_DIR
+ HINTS ${PC_CMOCKA_INCLUDEDIR} ${PC_CMOCKA_INCLUDE_DIRS}
NAMES
cmocka.h
PATHS
@@ -29,6 +36,7 @@ find_path(CMOCKA_INCLUDE_DIR
)
find_library(CMOCKA_LIBRARY
+ HINTS ${PC_CMOCKA_LIBDIR} ${PC_CMOCKA_LIBRARY_DIRS}
NAMES
cmocka cmocka_shared
PATHS
diff --git a/CMakeModules/JoinPaths.cmake b/CMakeModules/JoinPaths.cmake
new file mode 100644
index 000000000000..c68d91b84dbc
--- /dev/null
+++ b/CMakeModules/JoinPaths.cmake
@@ -0,0 +1,23 @@
+# This module provides function for joining paths
+# known from most languages
+#
+# SPDX-License-Identifier: (MIT OR CC0-1.0)
+# Copyright 2020 Jan Tojnar
+# https://github.com/jtojnar/cmake-snips
+#
+# Modelled after Python’s os.path.join
+# https://docs.python.org/3.7/library/os.path.html#os.path.join
+# Windows not supported
+function(join_paths joined_path first_path_segment)
+ set(temp_path "${first_path_segment}")
+ foreach(current_segment IN LISTS ARGN)
+ if(NOT ("${current_segment}" STREQUAL ""))
+ if(IS_ABSOLUTE "${current_segment}")
+ set(temp_path "${current_segment}")
+ else()
+ set(temp_path "${temp_path}/${current_segment}")
+ endif()
+ endif()
+ endforeach()
+ set(${joined_path} "${temp_path}" PARENT_SCOPE)
+endfunction()
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
new file mode 100644
index 000000000000..cc834d21a46b
--- /dev/null
+++ b/CONTRIBUTING.md
@@ -0,0 +1,35 @@
+# Contributing to libcbor
+
+libcbor is maintained by [@PJK](https://github.com/PJK) in his spare time on a best-effort basis.
+
+Community contributions are welcome as long as they align with the [project priorities](https://github.com/PJK/libcbor#main-features) and [goals](https://libcbor.readthedocs.io/en/latest/development.html#goals) and follow the guidelines described belows.
+
+## Principles
+
+**Bug reports and questions:** Bug reports and specific technical questions are always welcome. Feel free to open an [issue](https://github.com/PJK/libcbor/issues).
+
+**Incremental improvements:** Bug fixes (including build scripts, examples, test, typos, CI/CD config, etc.) and documentation improvements (fixes of typos, inaccuracies, out of date content, etc.) are always welcome. Feel free to open a [PR](https://github.com/PJK/libcbor/pulls).
+
+**New features:** I am looking to keep the scope of libcbor small. If you would like to add a feature, please open an issue with your proposal (or reach out to me privately) to discuss if the feature fits into libcbor before opening a PR.
+
+**Major changes:** Please open an issue with your proposal (or reach out to me privately) to discuss if the improvement fits into cbor before opening a PR.
+
+## Pull Request Process
+
+1. Ensure that all CI checks pass
+2. Check that the PR is complete and of good quality
+ - Include a descriptive summary of the change. If the PR addresses an open issue, please link it.
+ - Code changes: Add tests
+ - If necessary: Update documentation, including any links
+3. Code changes: Update [the changelog](https://github.com/PJK/libcbor/blob/master/CHANGELOG.md). Do *not* change the version number.
+
+## Interactions
+
+I work on libcbor on a best effort basis. The typical response time is a few days.
+
+If you do not receive a response in a few weeks, feel free to ping the PR or issue.
+
+## Resources
+
+- [Development documentation](https://libcbor.readthedocs.io/en/latest/development.html)
+
diff --git a/Doxyfile b/Doxyfile
index b197d2bcdedc..2571057646d7 100644
--- a/Doxyfile
+++ b/Doxyfile
@@ -1,4 +1,4 @@
-# Doxyfile 1.8.12
+# Doxyfile 1.9.6
# This file describes the settings to be used by the documentation system
# doxygen (www.doxygen.org) for a project.
@@ -12,16 +12,26 @@
# For lists, items can also be appended using:
# TAG += value [value, ...]
# Values that contain spaces should be placed between quotes (\" \").
+#
+# Note:
+#
+# Use doxygen to compare the used configuration file with the template
+# configuration file:
+# doxygen -x [configFile]
+# Use doxygen to compare the used configuration file with the template
+# configuration file without replacing the environment variables or CMake type
+# replacement variables:
+# doxygen -x_noenv [configFile]
#---------------------------------------------------------------------------
# Project related configuration options
#---------------------------------------------------------------------------
-# This tag specifies the encoding used for all characters in the config file
-# that follow. The default is UTF-8 which is also the encoding used for all text
-# before the first occurrence of this tag. Doxygen uses libiconv (or the iconv
-# built into libc) for the transcoding. See http://www.gnu.org/software/libiconv
-# for the list of possible encodings.
+# This tag specifies the encoding used for all characters in the configuration
+# file that follow. The default is UTF-8 which is also the encoding used for all
+# text before the first occurrence of this tag. Doxygen uses libiconv (or the
+# iconv built into libc) for the transcoding. See
+# https://www.gnu.org/software/libiconv/ for the list of possible encodings.
# The default value is: UTF-8.
DOXYFILE_ENCODING = UTF-8
@@ -32,13 +42,13 @@ DOXYFILE_ENCODING = UTF-8
# title of most generated pages and in a few other places.
# The default value is: My Project.
-PROJECT_NAME = "libcbor"
+PROJECT_NAME = libcbor
# The PROJECT_NUMBER tag can be used to enter a project or revision number. This
# could be handy for archiving the generated documentation or if some version
# control system is used.
-PROJECT_NUMBER = 0.8.0
+PROJECT_NUMBER = 0.10.2
# Using the PROJECT_BRIEF tag one can provide an optional one line description
# for a project that appears at the top of each page and should give viewer a
@@ -60,16 +70,28 @@ PROJECT_LOGO =
OUTPUT_DIRECTORY = doc/build/doxygen
-# If the CREATE_SUBDIRS tag is set to YES then doxygen will create 4096 sub-
-# directories (in 2 levels) under the output directory of each output format and
-# will distribute the generated files over these directories. Enabling this
+# If the CREATE_SUBDIRS tag is set to YES then doxygen will create up to 4096
+# sub-directories (in 2 levels) under the output directory of each output format
+# and will distribute the generated files over these directories. Enabling this
# option can be useful when feeding doxygen a huge amount of source files, where
# putting all generated files in the same directory would otherwise causes
-# performance problems for the file system.
+# performance problems for the file system. Adapt CREATE_SUBDIRS_LEVEL to
+# control the number of sub-directories.
# The default value is: NO.
CREATE_SUBDIRS = NO
+# Controls the number of sub-directories that will be created when
+# CREATE_SUBDIRS tag is set to YES. Level 0 represents 16 directories, and every
+# level increment doubles the number of directories, resulting in 4096
+# directories at level 8 which is the default and also the maximum value. The
+# sub-directories are organized in 2 levels, the first level always has a fixed
+# number of 16 directories.
+# Minimum value: 0, maximum value: 8, default value: 8.
+# This tag requires that the tag CREATE_SUBDIRS is set to YES.
+
+CREATE_SUBDIRS_LEVEL = 8
+
# If the ALLOW_UNICODE_NAMES tag is set to YES, doxygen will allow non-ASCII
# characters to appear in the names of generated files. If set to NO, non-ASCII
# characters will be escaped, for example _xE3_x81_x84 will be used for Unicode
@@ -81,14 +103,14 @@ ALLOW_UNICODE_NAMES = NO
# The OUTPUT_LANGUAGE tag is used to specify the language in which all
# documentation generated by doxygen is written. Doxygen will use this
# information to generate all constant output in the proper language.
-# Possible values are: Afrikaans, Arabic, Armenian, Brazilian, Catalan, Chinese,
-# Chinese-Traditional, Croatian, Czech, Danish, Dutch, English (United States),
-# Esperanto, Farsi (Persian), Finnish, French, German, Greek, Hungarian,
-# Indonesian, Italian, Japanese, Japanese-en (Japanese with English messages),
-# Korean, Korean-en (Korean with English messages), Latvian, Lithuanian,
-# Macedonian, Norwegian, Persian (Farsi), Polish, Portuguese, Romanian, Russian,
-# Serbian, Serbian-Cyrillic, Slovak, Slovene, Spanish, Swedish, Turkish,
-# Ukrainian and Vietnamese.
+# Possible values are: Afrikaans, Arabic, Armenian, Brazilian, Bulgarian,
+# Catalan, Chinese, Chinese-Traditional, Croatian, Czech, Danish, Dutch, English
+# (United States), Esperanto, Farsi (Persian), Finnish, French, German, Greek,
+# Hindi, Hungarian, Indonesian, Italian, Japanese, Japanese-en (Japanese with
+# English messages), Korean, Korean-en (Korean with English messages), Latvian,
+# Lithuanian, Macedonian, Norwegian, Persian (Farsi), Polish, Portuguese,
+# Romanian, Russian, Serbian, Serbian-Cyrillic, Slovak, Slovene, Spanish,
+# Swedish, Turkish, Ukrainian and Vietnamese.
# The default value is: English.
OUTPUT_LANGUAGE = English
@@ -179,6 +201,16 @@ SHORT_NAMES = NO
JAVADOC_AUTOBRIEF = YES
+# If the JAVADOC_BANNER tag is set to YES then doxygen will interpret a line
+# such as
+# /***************
+# as being the beginning of a Javadoc-style comment "banner". If set to NO, the
+# Javadoc-style will behave just like regular comments and it will not be
+# interpreted by doxygen.
+# The default value is: NO.
+
+JAVADOC_BANNER = NO
+
# If the QT_AUTOBRIEF tag is set to YES then doxygen will interpret the first
# line (until the first dot) of a Qt-style comment as the brief description. If
# set to NO, the Qt-style will behave just like regular Qt-style comments (thus
@@ -199,6 +231,14 @@ QT_AUTOBRIEF = NO
MULTILINE_CPP_IS_BRIEF = NO
+# By default Python docstrings are displayed as preformatted text and doxygen's
+# special commands cannot be used. By setting PYTHON_DOCSTRING to NO the
+# doxygen's special commands can be used and the contents of the docstring
+# documentation blocks is shown as doxygen documentation.
+# The default value is: YES.
+
+PYTHON_DOCSTRING = YES
+
# If the INHERIT_DOCS tag is set to YES then an undocumented member inherits the
# documentation from any documented member that it re-implements.
# The default value is: YES.
@@ -222,21 +262,20 @@ TAB_SIZE = 4
# the documentation. An alias has the form:
# name=value
# For example adding
-# "sideeffect=@par Side Effects:\n"
+# "sideeffect=@par Side Effects:^^"
# will allow you to put the command \sideeffect (or @sideeffect) in the
# documentation, which will result in a user-defined paragraph with heading
-# "Side Effects:". You can put \n's in the value part of an alias to insert
-# newlines.
+# "Side Effects:". Note that you cannot put \n's in the value part of an alias
+# to insert newlines (in the resulting output). You can put ^^ in the value part
+# of an alias to insert a newline as if a physical newline was in the original
+# file. When you need a literal { or } or , in the value part of an alias you
+# have to escape them by means of a backslash (\), this can lead to conflicts
+# with the commands \{ and \} for these it is advised to use the version @{ and
+# @} or use a double escape (\\{ and \\})
ALIASES = "rst=\verbatim embed:rst:leading-asterisk" \
"endrst=\endverbatim"
-# This tag can be used to specify a number of word-keyword mappings (TCL only).
-# A mapping has the form "name=value". For example adding "class=itcl::class"
-# will allow you to use the command class in the itcl::class meaning.
-
-TCL_SUBST =
-
# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources
# only. Doxygen will then generate output that is more tailored for C. For
# instance, some of the names that are used will be different. The list of all
@@ -265,28 +304,40 @@ OPTIMIZE_FOR_FORTRAN = NO
OPTIMIZE_OUTPUT_VHDL = NO
+# Set the OPTIMIZE_OUTPUT_SLICE tag to YES if your project consists of Slice
+# sources only. Doxygen will then generate output that is more tailored for that
+# language. For instance, namespaces will be presented as modules, types will be
+# separated into more groups, etc.
+# The default value is: NO.
+
+OPTIMIZE_OUTPUT_SLICE = NO
+
# Doxygen selects the parser to use depending on the extension of the files it
# parses. With this tag you can assign which parser to use for a given
# extension. Doxygen has a built-in mapping, but you can override or extend it
# using this tag. The format is ext=language, where ext is a file extension, and
-# language is one of the parsers supported by doxygen: IDL, Java, Javascript,
-# C#, C, C++, D, PHP, Objective-C, Python, Fortran (fixed format Fortran:
-# FortranFixed, free formatted Fortran: FortranFree, unknown formatted Fortran:
-# Fortran. In the later case the parser tries to guess whether the code is fixed
-# or free formatted code, this is the default for Fortran type files), VHDL. For
-# instance to make doxygen treat .inc files as Fortran files (default is PHP),
-# and .f files as C (default is Fortran), use: inc=Fortran f=C.
+# language is one of the parsers supported by doxygen: IDL, Java, JavaScript,
+# Csharp (C#), C, C++, Lex, D, PHP, md (Markdown), Objective-C, Python, Slice,
+# VHDL, Fortran (fixed format Fortran: FortranFixed, free formatted Fortran:
+# FortranFree, unknown formatted Fortran: Fortran. In the later case the parser
+# tries to guess whether the code is fixed or free formatted code, this is the
+# default for Fortran type files). For instance to make doxygen treat .inc files
+# as Fortran files (default is PHP), and .f files as C (default is Fortran),
+# use: inc=Fortran f=C.
#
# Note: For files without extension you can use no_extension as a placeholder.
#
# Note that for custom extensions you also need to set FILE_PATTERNS otherwise
-# the files are not read by doxygen.
+# the files are not read by doxygen. When specifying no_extension you should add
+# * to the FILE_PATTERNS.
+#
+# Note see also the list of default file extension mappings.
EXTENSION_MAPPING =
# If the MARKDOWN_SUPPORT tag is enabled then doxygen pre-processes all comments
# according to the Markdown format, which allows for more readable
-# documentation. See http://daringfireball.net/projects/markdown/ for details.
+# documentation. See https://daringfireball.net/projects/markdown/ for details.
# The output of markdown processing is further processed by doxygen, so you can
# mix doxygen, HTML, and XML commands with Markdown formatting. Disable only in
# case of backward compatibilities issues.
@@ -298,7 +349,7 @@ MARKDOWN_SUPPORT = YES
# to that level are automatically included in the table of contents, even if
# they do not have an id attribute.
# Note: This feature currently applies only to Markdown headings.
-# Minimum value: 0, maximum value: 99, default value: 0.
+# Minimum value: 0, maximum value: 99, default value: 5.
# This tag requires that the tag MARKDOWN_SUPPORT is set to YES.
TOC_INCLUDE_HEADINGS = 0
@@ -328,7 +379,7 @@ BUILTIN_STL_SUPPORT = NO
CPP_CLI_SUPPORT = NO
# Set the SIP_SUPPORT tag to YES if your project consists of sip (see:
-# http://www.riverbankcomputing.co.uk/software/sip/intro) sources only. Doxygen
+# https://www.riverbankcomputing.com/software/sip/intro) sources only. Doxygen
# will parse them like normal C++ but will assume all classes use public instead
# of private inheritance when no explicit protection keyword is present.
# The default value is: NO.
@@ -414,6 +465,19 @@ TYPEDEF_HIDES_STRUCT = NO
LOOKUP_CACHE_SIZE = 0
+# The NUM_PROC_THREADS specifies the number of threads doxygen is allowed to use
+# during processing. When set to 0 doxygen will based this on the number of
+# cores available in the system. You can set it explicitly to a value larger
+# than 0 to get more control over the balance between CPU load and processing
+# speed. At this moment only the input processing can be done using multiple
+# threads. Since this is still an experimental feature the default is set to 1,
+# which effectively disables parallel processing. Please report any issues you
+# encounter. Generating dot graphs in parallel is controlled by the
+# DOT_NUM_THREADS setting.
+# Minimum value: 0, maximum value: 32, default value: 1.
+
+NUM_PROC_THREADS = 1
+
#---------------------------------------------------------------------------
# Build related configuration options
#---------------------------------------------------------------------------
@@ -434,6 +498,12 @@ EXTRACT_ALL = YES
EXTRACT_PRIVATE = NO
+# If the EXTRACT_PRIV_VIRTUAL tag is set to YES, documented private virtual
+# methods of a class will be included in the documentation.
+# The default value is: NO.
+
+EXTRACT_PRIV_VIRTUAL = NO
+
# If the EXTRACT_PACKAGE tag is set to YES, all members with package or internal
# scope will be included in the documentation.
# The default value is: NO.
@@ -471,6 +541,13 @@ EXTRACT_LOCAL_METHODS = NO
EXTRACT_ANON_NSPACES = NO
+# If this flag is set to YES, the name of an unnamed parameter in a declaration
+# will be determined by the corresponding definition. By default unnamed
+# parameters remain unnamed in the output.
+# The default value is: YES.
+
+RESOLVE_UNNAMED_PARAMS = YES
+
# If the HIDE_UNDOC_MEMBERS tag is set to YES, doxygen will hide all
# undocumented members inside documented classes or files. If set to NO these
# members will be included in the various overviews, but no documentation
@@ -482,14 +559,15 @@ HIDE_UNDOC_MEMBERS = NO
# If the HIDE_UNDOC_CLASSES tag is set to YES, doxygen will hide all
# undocumented classes that are normally visible in the class hierarchy. If set
# to NO, these classes will be included in the various overviews. This option
-# has no effect if EXTRACT_ALL is enabled.
+# will also hide undocumented C++ concepts if enabled. This option has no effect
+# if EXTRACT_ALL is enabled.
# The default value is: NO.
HIDE_UNDOC_CLASSES = NO
# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, doxygen will hide all friend
-# (class|struct|union) declarations. If set to NO, these declarations will be
-# included in the documentation.
+# declarations. If set to NO, these declarations will be included in the
+# documentation.
# The default value is: NO.
HIDE_FRIEND_COMPOUNDS = NO
@@ -508,12 +586,20 @@ HIDE_IN_BODY_DOCS = NO
INTERNAL_DOCS = NO
-# If the CASE_SENSE_NAMES tag is set to NO then doxygen will only generate file
-# names in lower-case letters. If set to YES, upper-case letters are also
-# allowed. This is useful if you have classes or files whose names only differ
-# in case and if your file system supports case sensitive file names. Windows
-# and Mac users are advised to set this option to NO.
-# The default value is: system dependent.
+# With the correct setting of option CASE_SENSE_NAMES doxygen will better be
+# able to match the capabilities of the underlying filesystem. In case the
+# filesystem is case sensitive (i.e. it supports files in the same directory
+# whose names only differ in casing), the option must be set to YES to properly
+# deal with such files in case they appear in the input. For filesystems that
+# are not case sensitive the option should be set to NO to properly deal with
+# output files written for symbols that only differ in casing, such as for two
+# classes, one named CLASS and the other named Class, and to also support
+# references to files without having to specify the exact matching casing. On
+# Windows (including Cygwin) and MacOS, users should typically set this option
+# to NO, whereas on Linux or other Unix flavors it should typically be set to
+# YES.
+# Possible values are: SYSTEM, NO and YES.
+# The default value is: SYSTEM.
CASE_SENSE_NAMES = YES
@@ -531,6 +617,12 @@ HIDE_SCOPE_NAMES = NO
HIDE_COMPOUND_REFERENCE= NO
+# If the SHOW_HEADERFILE tag is set to YES then the documentation for a class
+# will show which file needs to be included to use the class.
+# The default value is: YES.
+
+SHOW_HEADERFILE = YES
+
# If the SHOW_INCLUDE_FILES tag is set to YES then doxygen will put a list of
# the files that are included by a file in the documentation of that file.
# The default value is: YES.
@@ -688,7 +780,8 @@ FILE_VERSION_FILTER =
# output files in an output format independent way. To create the layout file
# that represents doxygen's defaults, run doxygen with the -l option. You can
# optionally specify a file name after the option, if omitted DoxygenLayout.xml
-# will be used as the name of the layout file.
+# will be used as the name of the layout file. See also section "Changing the
+# layout of pages" for information.
#
# Note that if you run doxygen from a directory containing a file called
# DoxygenLayout.xml, doxygen will parse it automatically even if the LAYOUT_FILE
@@ -699,7 +792,7 @@ LAYOUT_FILE = doxygen-theme/DoxygenLayout.xml
# The CITE_BIB_FILES tag can be used to specify one or more bib files containing
# the reference definitions. This must be a list of .bib files. The .bib
# extension is automatically appended if omitted. This requires the bibtex tool
-# to be installed. See also http://en.wikipedia.org/wiki/BibTeX for more info.
+# to be installed. See also https://en.wikipedia.org/wiki/BibTeX for more info.
# For LaTeX the style of the bibliography can be controlled using
# LATEX_BIB_STYLE. To use this feature you need bibtex and perl available in the
# search path. See also \cite for info how to create references.
@@ -734,23 +827,43 @@ WARNINGS = YES
WARN_IF_UNDOCUMENTED = YES
# If the WARN_IF_DOC_ERROR tag is set to YES, doxygen will generate warnings for
-# potential errors in the documentation, such as not documenting some parameters
-# in a documented function, or documenting parameters that don't exist or using
-# markup commands wrongly.
+# potential errors in the documentation, such as documenting some parameters in
+# a documented function twice, or documenting parameters that don't exist or
+# using markup commands wrongly.
# The default value is: YES.
WARN_IF_DOC_ERROR = YES
+# If WARN_IF_INCOMPLETE_DOC is set to YES, doxygen will warn about incomplete
+# function parameter documentation. If set to NO, doxygen will accept that some
+# parameters have no documentation without warning.
+# The default value is: YES.
+
+WARN_IF_INCOMPLETE_DOC = YES
+
# This WARN_NO_PARAMDOC option can be enabled to get warnings for functions that
# are documented, but have no documentation for their parameters or return
-# value. If set to NO, doxygen will only warn about wrong or incomplete
-# parameter documentation, but not about the absence of documentation.
+# value. If set to NO, doxygen will only warn about wrong parameter
+# documentation, but not about the absence of documentation. If EXTRACT_ALL is
+# set to YES then this flag will automatically be disabled. See also
+# WARN_IF_INCOMPLETE_DOC
# The default value is: NO.
WARN_NO_PARAMDOC = NO
+# If WARN_IF_UNDOC_ENUM_VAL option is set to YES, doxygen will warn about
+# undocumented enumeration values. If set to NO, doxygen will accept
+# undocumented enumeration values. If EXTRACT_ALL is set to YES then this flag
+# will automatically be disabled.
+# The default value is: NO.
+
+WARN_IF_UNDOC_ENUM_VAL = NO
+
# If the WARN_AS_ERROR tag is set to YES then doxygen will immediately stop when
-# a warning is encountered.
+# a warning is encountered. If the WARN_AS_ERROR tag is set to FAIL_ON_WARNINGS
+# then doxygen will continue running as if WARN_AS_ERROR tag is set to NO, but
+# at the end of the doxygen process doxygen will return with a non-zero status.
+# Possible values are: NO, YES and FAIL_ON_WARNINGS.
# The default value is: NO.
WARN_AS_ERROR = NO
@@ -761,13 +874,27 @@ WARN_AS_ERROR = NO
# and the warning text. Optionally the format may contain $version, which will
# be replaced by the version of the file (if it could be obtained via
# FILE_VERSION_FILTER)
+# See also: WARN_LINE_FORMAT
# The default value is: $file:$line: $text.
WARN_FORMAT = "$file:$line: $text"
+# In the $text part of the WARN_FORMAT command it is possible that a reference
+# to a more specific place is given. To make it easier to jump to this place
+# (outside of doxygen) the user can define a custom "cut" / "paste" string.
+# Example:
+# WARN_LINE_FORMAT = "'vi $file +$line'"
+# See also: WARN_FORMAT
+# The default value is: at line $line of file $file.
+
+WARN_LINE_FORMAT = "at line $line of file $file"
+
# The WARN_LOGFILE tag can be used to specify a file to which warning and error
# messages should be written. If left blank the output is written to standard
-# error (stderr).
+# error (stderr). In case the file specified cannot be opened for writing the
+# warning and error messages are written to standard error. When as file - is
+# specified the warning and error messages are written to standard output
+# (stdout).
WARN_LOGFILE =
@@ -787,12 +914,23 @@ INPUT = src \
# This tag can be used to specify the character encoding of the source files
# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses
# libiconv (or the iconv built into libc) for the transcoding. See the libiconv
-# documentation (see: http://www.gnu.org/software/libiconv) for the list of
-# possible encodings.
+# documentation (see:
+# https://www.gnu.org/software/libiconv/) for the list of possible encodings.
+# See also: INPUT_FILE_ENCODING
# The default value is: UTF-8.
INPUT_ENCODING = UTF-8
+# This tag can be used to specify the character encoding of the source files
+# that doxygen parses The INPUT_FILE_ENCODING tag can be used to specify
+# character encoding on a per file pattern basis. Doxygen will compare the file
+# name with each pattern and apply the encoding instead of the default
+# INPUT_ENCODING) if there is a match. The character encodings are a list of the
+# form: pattern=encoding (like *.php=ISO-8859-1). See cfg_input_encoding
+# "INPUT_ENCODING" for further information on supported encodings.
+
+INPUT_FILE_ENCODING =
+
# If the value of the INPUT tag contains directories, you can use the
# FILE_PATTERNS tag to specify one or more wildcard patterns (like *.cpp and
# *.h) to filter out the source-files in the directories.
@@ -801,11 +939,15 @@ INPUT_ENCODING = UTF-8
# need to set EXTENSION_MAPPING for the extension otherwise the files are not
# read by doxygen.
#
+# Note the list of default checked file patterns might differ from the list of
+# default file extension mappings.
+#
# If left blank the following patterns are tested:*.c, *.cc, *.cxx, *.cpp,
# *.c++, *.java, *.ii, *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h,
-# *.hh, *.hxx, *.hpp, *.h++, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, *.inc,
-# *.m, *.markdown, *.md, *.mm, *.dox, *.py, *.pyw, *.f90, *.f95, *.f03, *.f08,
-# *.f, *.for, *.tcl, *.vhd, *.vhdl, *.ucf and *.qsf.
+# *.hh, *.hxx, *.hpp, *.h++, *.l, *.cs, *.d, *.php, *.php4, *.php5, *.phtml,
+# *.inc, *.m, *.markdown, *.md, *.mm, *.dox (to be provided as doxygen C
+# comment), *.py, *.pyw, *.f90, *.f95, *.f03, *.f08, *.f18, *.f, *.for, *.vhd,
+# *.vhdl, *.ucf, *.qsf and *.ice.
FILE_PATTERNS =
@@ -844,7 +986,7 @@ EXCLUDE_PATTERNS =
# (namespaces, classes, functions, etc.) that should be excluded from the
# output. The symbol name can be a fully qualified name, a word, or if the
# wildcard * is used, a substring. Examples: ANamespace, AClass,
-# AClass::ANamespace, ANamespace::*Test
+# ANamespace::AClass, ANamespace::*Test
#
# Note that the wildcards are matched against the file with absolute path, so to
# exclude all test directories use the pattern */test/*
@@ -892,6 +1034,11 @@ IMAGE_PATH =
# code is scanned, but not when the output code is generated. If lines are added
# or removed, the anchors will not be placed correctly.
#
+# Note that doxygen will use the data processed and written to standard output
+# for further processing, therefore nothing else, like debug statements or used
+# commands (so in case of a Windows batch file always use @echo OFF), should be
+# written to standard output.
+#
# Note that for custom extensions or not directly supported extensions you also
# need to set EXTENSION_MAPPING for the extension otherwise the files are not
# properly processed by doxygen.
@@ -933,6 +1080,15 @@ FILTER_SOURCE_PATTERNS =
USE_MDFILE_AS_MAINPAGE = doc/doxy_frontpage.md
+# The Fortran standard specifies that for fixed formatted Fortran code all
+# characters from position 72 are to be considered as comment. A common
+# extension is to allow longer lines before the automatic comment starts. The
+# setting FORTRAN_COMMENT_AFTER will also make it possible that longer lines can
+# be processed before the automatic comment starts.
+# Minimum value: 7, maximum value: 10000, default value: 72.
+
+FORTRAN_COMMENT_AFTER = 72
+
#---------------------------------------------------------------------------
# Configuration options related to source browsing
#---------------------------------------------------------------------------
@@ -960,7 +1116,7 @@ INLINE_SOURCES = NO
STRIP_CODE_COMMENTS = YES
# If the REFERENCED_BY_RELATION tag is set to YES then for each documented
-# function all documented functions referencing it will be listed.
+# entity all documented functions referencing it will be listed.
# The default value is: NO.
REFERENCED_BY_RELATION = NO
@@ -992,12 +1148,12 @@ SOURCE_TOOLTIPS = YES
# If the USE_HTAGS tag is set to YES then the references to source code will
# point to the HTML generated by the htags(1) tool instead of doxygen built-in
# source browser. The htags tool is part of GNU's global source tagging system
-# (see http://www.gnu.org/software/global/global.html). You will need version
+# (see https://www.gnu.org/software/global/global.html). You will need version
# 4.8.6 or higher.
#
# To use it do the following:
# - Install the latest version of global
-# - Enable SOURCE_BROWSER and USE_HTAGS in the config file
+# - Enable SOURCE_BROWSER and USE_HTAGS in the configuration file
# - Make sure the INPUT points to the root of the source tree
# - Run doxygen as normal
#
@@ -1030,17 +1186,11 @@ VERBATIM_HEADERS = YES
ALPHABETICAL_INDEX = YES
-# The COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns in
-# which the alphabetical index list will be split.
-# Minimum value: 1, maximum value: 20, default value: 5.
-# This tag requires that the tag ALPHABETICAL_INDEX is set to YES.
-
-COLS_IN_ALPHA_INDEX = 5
-
-# In case all classes in a project start with a common prefix, all classes will
-# be put under the same header in the alphabetical index. The IGNORE_PREFIX tag
-# can be used to specify a prefix (or a list of prefixes) that should be ignored
-# while generating the index headers.
+# The IGNORE_PREFIX tag can be used to specify a prefix (or a list of prefixes)
+# that should be ignored while generating the index headers. The IGNORE_PREFIX
+# tag works for classes, function and member names. The entity will be placed in
+# the alphabetical list under the first letter of the entity name that remains
+# after removing the prefix.
# This tag requires that the tag ALPHABETICAL_INDEX is set to YES.
IGNORE_PREFIX =
@@ -1119,7 +1269,12 @@ HTML_STYLESHEET =
# Doxygen will copy the style sheet files to the output directory.
# Note: The order of the extra style sheet files is of importance (e.g. the last
# style sheet in the list overrules the setting of the previous ones in the
-# list). For an example see the documentation.
+# list).
+# Note: Since the styling of scrollbars can currently not be overruled in
+# Webkit/Chromium, the styling will be left out of the default doxygen.css if
+# one or more extra stylesheets have been specified. So if scrollbar
+# customization is desired it has to be added explicitly. For an example see the
+# documentation.
# This tag requires that the tag GENERATE_HTML is set to YES.
HTML_EXTRA_STYLESHEET = doxygen-theme/customdoxygen.css
@@ -1134,10 +1289,23 @@ HTML_EXTRA_STYLESHEET = doxygen-theme/customdoxygen.css
HTML_EXTRA_FILES =
+# The HTML_COLORSTYLE tag can be used to specify if the generated HTML output
+# should be rendered with a dark or light theme.
+# Possible values are: LIGHT always generate light mode output, DARK always
+# generate dark mode output, AUTO_LIGHT automatically set the mode according to
+# the user preference, use light mode if no preference is set (the default),
+# AUTO_DARK automatically set the mode according to the user preference, use
+# dark mode if no preference is set and TOGGLE allow to user to switch between
+# light and dark mode via a button.
+# The default value is: AUTO_LIGHT.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_COLORSTYLE = AUTO_LIGHT
+
# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen
# will adjust the colors in the style sheet and background images according to
-# this color. Hue is specified as an angle on a colorwheel, see
-# http://en.wikipedia.org/wiki/Hue for more information. For instance the value
+# this color. Hue is specified as an angle on a color-wheel, see
+# https://en.wikipedia.org/wiki/Hue for more information. For instance the value
# 0 represents red, 60 is yellow, 120 is green, 180 is cyan, 240 is blue, 300
# purple, and 360 is red again.
# Minimum value: 0, maximum value: 359, default value: 220.
@@ -1146,7 +1314,7 @@ HTML_EXTRA_FILES =
HTML_COLORSTYLE_HUE = 220
# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of the colors
-# in the HTML output. For a value of 0 the output will use grayscales only. A
+# in the HTML output. For a value of 0 the output will use gray-scales only. A
# value of 255 will produce the most vivid colors.
# Minimum value: 0, maximum value: 255, default value: 100.
# This tag requires that the tag GENERATE_HTML is set to YES.
@@ -1173,6 +1341,17 @@ HTML_COLORSTYLE_GAMMA = 80
HTML_TIMESTAMP = YES
+# If the HTML_DYNAMIC_MENUS tag is set to YES then the generated HTML
+# documentation will contain a main index with vertical navigation menus that
+# are dynamically created via JavaScript. If disabled, the navigation index will
+# consists of multiple levels of tabs that are statically embedded in every HTML
+# page. Disable this option to support browsers that do not have JavaScript,
+# like the Qt help browser.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_DYNAMIC_MENUS = YES
+
# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML
# documentation will contain sections that can be hidden and shown after the
# page has loaded.
@@ -1196,13 +1375,14 @@ HTML_INDEX_NUM_ENTRIES = 100
# If the GENERATE_DOCSET tag is set to YES, additional index files will be
# generated that can be used as input for Apple's Xcode 3 integrated development
-# environment (see: http://developer.apple.com/tools/xcode/), introduced with
-# OSX 10.5 (Leopard). To create a documentation set, doxygen will generate a
-# Makefile in the HTML output directory. Running make will produce the docset in
-# that directory and running make install will install the docset in
+# environment (see:
+# https://developer.apple.com/xcode/), introduced with OSX 10.5 (Leopard). To
+# create a documentation set, doxygen will generate a Makefile in the HTML
+# output directory. Running make will produce the docset in that directory and
+# running make install will install the docset in
# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find it at
-# startup. See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html
-# for more information.
+# startup. See https://developer.apple.com/library/archive/featuredarticles/Doxy
+# genXcode/_index.html for more information.
# The default value is: NO.
# This tag requires that the tag GENERATE_HTML is set to YES.
@@ -1216,6 +1396,13 @@ GENERATE_DOCSET = NO
DOCSET_FEEDNAME = "Doxygen generated docs"
+# This tag determines the URL of the docset feed. A documentation feed provides
+# an umbrella under which multiple documentation sets from a single provider
+# (such as a company or product suite) can be grouped.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_FEEDURL =
+
# This tag specifies a string that should uniquely identify the documentation
# set bundle. This should be a reverse domain-name style string, e.g.
# com.mycompany.MyDocSet. Doxygen will append .docset to the name.
@@ -1241,8 +1428,12 @@ DOCSET_PUBLISHER_NAME = Publisher
# If the GENERATE_HTMLHELP tag is set to YES then doxygen generates three
# additional HTML index files: index.hhp, index.hhc, and index.hhk. The
# index.hhp is a project file that can be read by Microsoft's HTML Help Workshop
-# (see: http://www.microsoft.com/en-us/download/details.aspx?id=21138) on
-# Windows.
+# on Windows. In the beginning of 2021 Microsoft took the original page, with
+# a.o. the download links, offline the HTML help workshop was already many years
+# in maintenance mode). You can download the HTML help workshop from the web
+# archives at Installation executable (see:
+# http://web.archive.org/web/20160201063255/http://download.microsoft.com/downlo
+# ad/0/A/9/0A939EF6-E31C-430F-A3DF-DFAE7960D564/htmlhelp.exe).
#
# The HTML Help Workshop contains a compiler that can convert all HTML output
# generated by doxygen into a single compiled HTML file (.chm). Compiled HTML
@@ -1272,7 +1463,7 @@ CHM_FILE =
HHC_LOCATION =
# The GENERATE_CHI flag controls if a separate .chi index file is generated
-# (YES) or that it should be included in the master .chm file (NO).
+# (YES) or that it should be included in the main .chm file (NO).
# The default value is: NO.
# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
@@ -1317,7 +1508,8 @@ QCH_FILE =
# The QHP_NAMESPACE tag specifies the namespace to use when generating Qt Help
# Project output. For more information please see Qt Help Project / Namespace
-# (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#namespace).
+# (see:
+# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#namespace).
# The default value is: org.doxygen.Project.
# This tag requires that the tag GENERATE_QHP is set to YES.
@@ -1325,8 +1517,8 @@ QHP_NAMESPACE = org.doxygen.Project
# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating Qt
# Help Project output. For more information please see Qt Help Project / Virtual
-# Folders (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#virtual-
-# folders).
+# Folders (see:
+# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#virtual-folders).
# The default value is: doc.
# This tag requires that the tag GENERATE_QHP is set to YES.
@@ -1334,30 +1526,30 @@ QHP_VIRTUAL_FOLDER = doc
# If the QHP_CUST_FILTER_NAME tag is set, it specifies the name of a custom
# filter to add. For more information please see Qt Help Project / Custom
-# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom-
-# filters).
+# Filters (see:
+# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#custom-filters).
# This tag requires that the tag GENERATE_QHP is set to YES.
QHP_CUST_FILTER_NAME =
# The QHP_CUST_FILTER_ATTRS tag specifies the list of the attributes of the
# custom filter to add. For more information please see Qt Help Project / Custom
-# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom-
-# filters).
+# Filters (see:
+# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#custom-filters).
# This tag requires that the tag GENERATE_QHP is set to YES.
QHP_CUST_FILTER_ATTRS =
# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this
# project's filter section matches. Qt Help Project / Filter Attributes (see:
-# http://qt-project.org/doc/qt-4.8/qthelpproject.html#filter-attributes).
+# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#filter-attributes).
# This tag requires that the tag GENERATE_QHP is set to YES.
QHP_SECT_FILTER_ATTRS =
-# The QHG_LOCATION tag can be used to specify the location of Qt's
-# qhelpgenerator. If non-empty doxygen will try to run qhelpgenerator on the
-# generated .qhp file.
+# The QHG_LOCATION tag can be used to specify the location (absolute path
+# including file name) of Qt's qhelpgenerator. If non-empty doxygen will try to
+# run qhelpgenerator on the generated .qhp file.
# This tag requires that the tag GENERATE_QHP is set to YES.
QHG_LOCATION =
@@ -1400,16 +1592,28 @@ DISABLE_INDEX = NO
# to work a browser that supports JavaScript, DHTML, CSS and frames is required
# (i.e. any modern browser). Windows users are probably better off using the
# HTML help feature. Via custom style sheets (see HTML_EXTRA_STYLESHEET) one can
-# further fine-tune the look of the index. As an example, the default style
-# sheet generated by doxygen has an example that shows how to put an image at
-# the root of the tree instead of the PROJECT_NAME. Since the tree basically has
-# the same information as the tab index, you could consider setting
-# DISABLE_INDEX to YES when enabling this option.
+# further fine tune the look of the index (see "Fine-tuning the output"). As an
+# example, the default style sheet generated by doxygen has an example that
+# shows how to put an image at the root of the tree instead of the PROJECT_NAME.
+# Since the tree basically has the same information as the tab index, you could
+# consider setting DISABLE_INDEX to YES when enabling this option.
# The default value is: NO.
# This tag requires that the tag GENERATE_HTML is set to YES.
GENERATE_TREEVIEW = NO
+# When both GENERATE_TREEVIEW and DISABLE_INDEX are set to YES, then the
+# FULL_SIDEBAR option determines if the side bar is limited to only the treeview
+# area (value NO) or if it should extend to the full height of the window (value
+# YES). Setting this to YES gives a layout similar to
+# https://docs.readthedocs.io with more room for contents, but less room for the
+# project logo, title, and description. If either GENERATE_TREEVIEW or
+# DISABLE_INDEX is set to NO, this option has no effect.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+FULL_SIDEBAR = NO
+
# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values that
# doxygen will group on one line in the generated HTML documentation.
#
@@ -1434,6 +1638,24 @@ TREEVIEW_WIDTH = 250
EXT_LINKS_IN_WINDOW = NO
+# If the OBFUSCATE_EMAILS tag is set to YES, doxygen will obfuscate email
+# addresses.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+OBFUSCATE_EMAILS = YES
+
+# If the HTML_FORMULA_FORMAT option is set to svg, doxygen will use the pdf2svg
+# tool (see https://github.com/dawbarton/pdf2svg) or inkscape (see
+# https://inkscape.org) to generate formulas as SVG images instead of PNGs for
+# the HTML output. These images will generally look nicer at scaled resolutions.
+# Possible values are: png (the default) and svg (looks nicer but requires the
+# pdf2svg or inkscape tool).
+# The default value is: png.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_FORMULA_FORMAT = png
+
# Use this tag to change the font size of LaTeX formulas included as images in
# the HTML documentation. When you change the font size after a successful
# doxygen run you need to manually remove any form_*.png images from the HTML
@@ -1443,19 +1665,14 @@ EXT_LINKS_IN_WINDOW = NO
FORMULA_FONTSIZE = 10
-# Use the FORMULA_TRANPARENT tag to determine whether or not the images
-# generated for formulas are transparent PNGs. Transparent PNGs are not
-# supported properly for IE 6.0, but are supported on all modern browsers.
-#
-# Note that when changing this option you need to delete any form_*.png files in
-# the HTML output directory before the changes have effect.
-# The default value is: YES.
-# This tag requires that the tag GENERATE_HTML is set to YES.
+# The FORMULA_MACROFILE can contain LaTeX \newcommand and \renewcommand commands
+# to create new LaTeX commands to be used in formulas as building blocks. See
+# the section "Including formulas" for details.
-FORMULA_TRANSPARENT = YES
+FORMULA_MACROFILE =
# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see
-# http://www.mathjax.org) which uses client side Javascript for the rendering
+# https://www.mathjax.org) which uses client side JavaScript for the rendering
# instead of using pre-rendered bitmaps. Use this if you do not have LaTeX
# installed or if you want to formulas look prettier in the HTML output. When
# enabled you may also need to install MathJax separately and configure the path
@@ -1465,11 +1682,29 @@ FORMULA_TRANSPARENT = YES
USE_MATHJAX = NO
+# With MATHJAX_VERSION it is possible to specify the MathJax version to be used.
+# Note that the different versions of MathJax have different requirements with
+# regards to the different settings, so it is possible that also other MathJax
+# settings have to be changed when switching between the different MathJax
+# versions.
+# Possible values are: MathJax_2 and MathJax_3.
+# The default value is: MathJax_2.
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_VERSION = MathJax_2
+
# When MathJax is enabled you can set the default output format to be used for
-# the MathJax output. See the MathJax site (see:
-# http://docs.mathjax.org/en/latest/output.html) for more details.
+# the MathJax output. For more details about the output format see MathJax
+# version 2 (see:
+# http://docs.mathjax.org/en/v2.7-latest/output.html) and MathJax version 3
+# (see:
+# http://docs.mathjax.org/en/latest/web/components/output.html).
# Possible values are: HTML-CSS (which is slower, but has the best
-# compatibility), NativeMML (i.e. MathML) and SVG.
+# compatibility. This is the name for Mathjax version 2, for MathJax version 3
+# this will be translated into chtml), NativeMML (i.e. MathML. Only supported
+# for NathJax 2. For MathJax version 3 chtml will be used instead.), chtml (This
+# is the name for Mathjax version 3, for MathJax version 2 this will be
+# translated into HTML-CSS) and SVG.
# The default value is: HTML-CSS.
# This tag requires that the tag USE_MATHJAX is set to YES.
@@ -1482,22 +1717,29 @@ MATHJAX_FORMAT = HTML-CSS
# MATHJAX_RELPATH should be ../mathjax. The default value points to the MathJax
# Content Delivery Network so you can quickly see the result without installing
# MathJax. However, it is strongly recommended to install a local copy of
-# MathJax from http://www.mathjax.org before deployment.
-# The default value is: http://cdn.mathjax.org/mathjax/latest.
+# MathJax from https://www.mathjax.org before deployment. The default value is:
+# - in case of MathJax version 2: https://cdn.jsdelivr.net/npm/mathjax@2
+# - in case of MathJax version 3: https://cdn.jsdelivr.net/npm/mathjax@3
# This tag requires that the tag USE_MATHJAX is set to YES.
MATHJAX_RELPATH = http://cdn.mathjax.org/mathjax/latest
# The MATHJAX_EXTENSIONS tag can be used to specify one or more MathJax
# extension names that should be enabled during MathJax rendering. For example
+# for MathJax version 2 (see
+# https://docs.mathjax.org/en/v2.7-latest/tex.html#tex-and-latex-extensions):
# MATHJAX_EXTENSIONS = TeX/AMSmath TeX/AMSsymbols
+# For example for MathJax version 3 (see
+# http://docs.mathjax.org/en/latest/input/tex/extensions/index.html):
+# MATHJAX_EXTENSIONS = ams
# This tag requires that the tag USE_MATHJAX is set to YES.
MATHJAX_EXTENSIONS =
# The MATHJAX_CODEFILE tag can be used to specify a file with javascript pieces
# of code that will be used on startup of the MathJax code. See the MathJax site
-# (see: http://docs.mathjax.org/en/latest/output.html) for more details. For an
+# (see:
+# http://docs.mathjax.org/en/v2.7-latest/output.html) for more details. For an
# example see the documentation.
# This tag requires that the tag USE_MATHJAX is set to YES.
@@ -1525,7 +1767,7 @@ MATHJAX_CODEFILE =
SEARCHENGINE = YES
# When the SERVER_BASED_SEARCH tag is enabled the search engine will be
-# implemented using a web server instead of a web client using Javascript. There
+# implemented using a web server instead of a web client using JavaScript. There
# are two flavors of web server based searching depending on the EXTERNAL_SEARCH
# setting. When disabled, doxygen will generate a PHP script for searching and
# an index file used by the script. When EXTERNAL_SEARCH is enabled the indexing
@@ -1544,7 +1786,8 @@ SERVER_BASED_SEARCH = NO
#
# Doxygen ships with an example indexer (doxyindexer) and search engine
# (doxysearch.cgi) which are based on the open source search engine library
-# Xapian (see: http://xapian.org/).
+# Xapian (see:
+# https://xapian.org/).
#
# See the section "External Indexing and Searching" for details.
# The default value is: NO.
@@ -1557,8 +1800,9 @@ EXTERNAL_SEARCH = NO
#
# Doxygen ships with an example indexer (doxyindexer) and search engine
# (doxysearch.cgi) which are based on the open source search engine library
-# Xapian (see: http://xapian.org/). See the section "External Indexing and
-# Searching" for details.
+# Xapian (see:
+# https://xapian.org/). See the section "External Indexing and Searching" for
+# details.
# This tag requires that the tag SEARCHENGINE is set to YES.
SEARCHENGINE_URL =
@@ -1609,21 +1853,35 @@ LATEX_OUTPUT = latex
# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be
# invoked.
#
-# Note that when enabling USE_PDFLATEX this option is only used for generating
-# bitmaps for formulas in the HTML output, but not in the Makefile that is
-# written to the output directory.
-# The default file is: latex.
+# Note that when not enabling USE_PDFLATEX the default is latex when enabling
+# USE_PDFLATEX the default is pdflatex and when in the later case latex is
+# chosen this is overwritten by pdflatex. For specific output languages the
+# default can have been set differently, this depends on the implementation of
+# the output language.
# This tag requires that the tag GENERATE_LATEX is set to YES.
LATEX_CMD_NAME = latex
# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to generate
# index for LaTeX.
+# Note: This tag is used in the Makefile / make.bat.
+# See also: LATEX_MAKEINDEX_CMD for the part in the generated output file
+# (.tex).
# The default file is: makeindex.
# This tag requires that the tag GENERATE_LATEX is set to YES.
MAKEINDEX_CMD_NAME = makeindex
+# The LATEX_MAKEINDEX_CMD tag can be used to specify the command name to
+# generate index for LaTeX. In case there is no backslash (\) as first character
+# it will be automatically added in the LaTeX code.
+# Note: This tag is used in the generated output file (.tex).
+# See also: MAKEINDEX_CMD_NAME for the part in the Makefile / make.bat.
+# The default value is: makeindex.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_MAKEINDEX_CMD = makeindex
+
# If the COMPACT_LATEX tag is set to YES, doxygen generates more compact LaTeX
# documents. This may be useful for small projects and may help to save some
# trees in general.
@@ -1653,29 +1911,31 @@ PAPER_TYPE = a4
EXTRA_PACKAGES =
-# The LATEX_HEADER tag can be used to specify a personal LaTeX header for the
-# generated LaTeX document. The header should contain everything until the first
-# chapter. If it is left blank doxygen will generate a standard header. See
-# section "Doxygen usage" for information on how to let doxygen write the
-# default header to a separate file.
+# The LATEX_HEADER tag can be used to specify a user-defined LaTeX header for
+# the generated LaTeX document. The header should contain everything until the
+# first chapter. If it is left blank doxygen will generate a standard header. It
+# is highly recommended to start with a default header using
+# doxygen -w latex new_header.tex new_footer.tex new_stylesheet.sty
+# and then modify the file new_header.tex. See also section "Doxygen usage" for
+# information on how to generate the default header that doxygen normally uses.
#
-# Note: Only use a user-defined header if you know what you are doing! The
-# following commands have a special meaning inside the header: $title,
-# $datetime, $date, $doxygenversion, $projectname, $projectnumber,
-# $projectbrief, $projectlogo. Doxygen will replace $title with the empty
-# string, for the replacement values of the other commands the user is referred
-# to HTML_HEADER.
+# Note: Only use a user-defined header if you know what you are doing!
+# Note: The header is subject to change so you typically have to regenerate the
+# default header when upgrading to a newer version of doxygen. The following
+# commands have a special meaning inside the header (and footer): For a
+# description of the possible markers and block names see the documentation.
# This tag requires that the tag GENERATE_LATEX is set to YES.
LATEX_HEADER =
-# The LATEX_FOOTER tag can be used to specify a personal LaTeX footer for the
-# generated LaTeX document. The footer should contain everything after the last
-# chapter. If it is left blank doxygen will generate a standard footer. See
+# The LATEX_FOOTER tag can be used to specify a user-defined LaTeX footer for
+# the generated LaTeX document. The footer should contain everything after the
+# last chapter. If it is left blank doxygen will generate a standard footer. See
# LATEX_HEADER for more information on how to generate a default footer and what
-# special commands can be used inside the footer.
-#
-# Note: Only use a user-defined footer if you know what you are doing!
+# special commands can be used inside the footer. See also section "Doxygen
+# usage" for information on how to generate the default footer that doxygen
+# normally uses. Note: Only use a user-defined footer if you know what you are
+# doing!
# This tag requires that the tag GENERATE_LATEX is set to YES.
LATEX_FOOTER =
@@ -1708,9 +1968,11 @@ LATEX_EXTRA_FILES =
PDF_HYPERLINKS = YES
-# If the USE_PDFLATEX tag is set to YES, doxygen will use pdflatex to generate
-# the PDF file directly from the LaTeX files. Set this option to YES, to get a
-# higher quality PDF documentation.
+# If the USE_PDFLATEX tag is set to YES, doxygen will use the engine as
+# specified with LATEX_CMD_NAME to generate the PDF file directly from the LaTeX
+# files. Set this option to YES, to get a higher quality PDF documentation.
+#
+# See also section LATEX_CMD_NAME for selecting the engine.
# The default value is: YES.
# This tag requires that the tag GENERATE_LATEX is set to YES.
@@ -1718,8 +1980,7 @@ USE_PDFLATEX = YES
# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \batchmode
# command to the generated LaTeX files. This will instruct LaTeX to keep running
-# if errors occur, instead of asking the user for help. This option is also used
-# when generating formulas in HTML.
+# if errors occur, instead of asking the user for help.
# The default value is: NO.
# This tag requires that the tag GENERATE_LATEX is set to YES.
@@ -1732,19 +1993,9 @@ LATEX_BATCHMODE = NO
LATEX_HIDE_INDICES = NO
-# If the LATEX_SOURCE_CODE tag is set to YES then doxygen will include source
-# code with syntax highlighting in the LaTeX output.
-#
-# Note that which sources are shown also depends on other settings such as
-# SOURCE_BROWSER.
-# The default value is: NO.
-# This tag requires that the tag GENERATE_LATEX is set to YES.
-
-LATEX_SOURCE_CODE = NO
-
# The LATEX_BIB_STYLE tag can be used to specify the style to use for the
# bibliography, e.g. plainnat, or ieeetr. See
-# http://en.wikipedia.org/wiki/BibTeX and \cite for more info.
+# https://en.wikipedia.org/wiki/BibTeX and \cite for more info.
# The default value is: plain.
# This tag requires that the tag GENERATE_LATEX is set to YES.
@@ -1758,6 +2009,14 @@ LATEX_BIB_STYLE = plain
LATEX_TIMESTAMP = NO
+# The LATEX_EMOJI_DIRECTORY tag is used to specify the (relative or absolute)
+# path from which the emoji images will be read. If a relative path is entered,
+# it will be relative to the LATEX_OUTPUT directory. If left blank the
+# LATEX_OUTPUT directory will be used.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_EMOJI_DIRECTORY =
+
#---------------------------------------------------------------------------
# Configuration options related to the RTF output
#---------------------------------------------------------------------------
@@ -1797,9 +2056,9 @@ COMPACT_RTF = NO
RTF_HYPERLINKS = NO
-# Load stylesheet definitions from file. Syntax is similar to doxygen's config
-# file, i.e. a series of assignments. You only have to provide replacements,
-# missing definitions are set to their default value.
+# Load stylesheet definitions from file. Syntax is similar to doxygen's
+# configuration file, i.e. a series of assignments. You only have to provide
+# replacements, missing definitions are set to their default value.
#
# See also section "Doxygen usage" for information on how to generate the
# default style sheet that doxygen normally uses.
@@ -1808,22 +2067,12 @@ RTF_HYPERLINKS = NO
RTF_STYLESHEET_FILE =
# Set optional variables used in the generation of an RTF document. Syntax is
-# similar to doxygen's config file. A template extensions file can be generated
-# using doxygen -e rtf extensionFile.
+# similar to doxygen's configuration file. A template extensions file can be
+# generated using doxygen -e rtf extensionFile.
# This tag requires that the tag GENERATE_RTF is set to YES.
RTF_EXTENSIONS_FILE =
-# If the RTF_SOURCE_CODE tag is set to YES then doxygen will include source code
-# with syntax highlighting in the RTF output.
-#
-# Note that which sources are shown also depends on other settings such as
-# SOURCE_BROWSER.
-# The default value is: NO.
-# This tag requires that the tag GENERATE_RTF is set to YES.
-
-RTF_SOURCE_CODE = NO
-
#---------------------------------------------------------------------------
# Configuration options related to the man page output
#---------------------------------------------------------------------------
@@ -1895,6 +2144,13 @@ XML_OUTPUT = xml
XML_PROGRAMLISTING = YES
+# If the XML_NS_MEMB_FILE_SCOPE tag is set to YES, doxygen will include
+# namespace members in file scope as well, matching the HTML output.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_XML is set to YES.
+
+XML_NS_MEMB_FILE_SCOPE = NO
+
#---------------------------------------------------------------------------
# Configuration options related to the DOCBOOK output
#---------------------------------------------------------------------------
@@ -1913,23 +2169,14 @@ GENERATE_DOCBOOK = NO
DOCBOOK_OUTPUT = docbook
-# If the DOCBOOK_PROGRAMLISTING tag is set to YES, doxygen will include the
-# program listings (including syntax highlighting and cross-referencing
-# information) to the DOCBOOK output. Note that enabling this will significantly
-# increase the size of the DOCBOOK output.
-# The default value is: NO.
-# This tag requires that the tag GENERATE_DOCBOOK is set to YES.
-
-DOCBOOK_PROGRAMLISTING = NO
-
#---------------------------------------------------------------------------
# Configuration options for the AutoGen Definitions output
#---------------------------------------------------------------------------
# If the GENERATE_AUTOGEN_DEF tag is set to YES, doxygen will generate an
-# AutoGen Definitions (see http://autogen.sf.net) file that captures the
-# structure of the code including all documentation. Note that this feature is
-# still experimental and incomplete at the moment.
+# AutoGen Definitions (see http://autogen.sourceforge.net/) file that captures
+# the structure of the code including all documentation. Note that this feature
+# is still experimental and incomplete at the moment.
# The default value is: NO.
GENERATE_AUTOGEN_DEF = NO
@@ -2008,7 +2255,8 @@ SEARCH_INCLUDES = YES
# The INCLUDE_PATH tag can be used to specify one or more directories that
# contain include files that are not input files but should be processed by the
-# preprocessor.
+# preprocessor. Note that the INCLUDE_PATH is not recursive, so the setting of
+# RECURSIVE has no effect here.
# This tag requires that the tag SEARCH_INCLUDES is set to YES.
INCLUDE_PATH =
@@ -2029,7 +2277,9 @@ INCLUDE_FILE_PATTERNS =
# recursively expanded use the := operator instead of the = operator.
# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
-PREDEFINED = CBOR_CUSTOM_ALLOC CBOR_RESTRICT_POINTER= CBOR_EXPORT
+PREDEFINED = CBOR_RESTRICT_POINTER= \
+ CBOR_EXPORT \
+ _CBOR_NODISCARD=
# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then this
# tag can be used to specify a list of macro names that should be expanded. The
@@ -2096,34 +2346,10 @@ EXTERNAL_GROUPS = YES
EXTERNAL_PAGES = YES
-# The PERL_PATH should be the absolute path and name of the perl script
-# interpreter (i.e. the result of 'which perl').
-# The default file (with absolute path) is: /usr/bin/perl.
-
-PERL_PATH = /usr/bin/perl
-
#---------------------------------------------------------------------------
# Configuration options related to the dot tool
#---------------------------------------------------------------------------
-# If the CLASS_DIAGRAMS tag is set to YES, doxygen will generate a class diagram
-# (in HTML and LaTeX) for classes with base or super classes. Setting the tag to
-# NO turns the diagrams off. Note that this option also works with HAVE_DOT
-# disabled, but it is recommended to install and use dot, since it yields more
-# powerful graphs.
-# The default value is: YES.
-
-CLASS_DIAGRAMS = YES
-
-# You can define message sequence charts within doxygen comments using the \msc
-# command. Doxygen will then run the mscgen tool (see:
-# http://www.mcternan.me.uk/mscgen/)) to produce the chart and insert it in the
-# documentation. The MSCGEN_PATH tag allows you to specify the directory where
-# the mscgen tool resides. If left empty the tool is assumed to be found in the
-# default search path.
-
-MSCGEN_PATH =
-
# You can include diagrams made with dia in doxygen documentation. Doxygen will
# then run dia to produce the diagram and insert it in the documentation. The
# DIA_PATH tag allows you to specify the directory where the dia binary resides.
@@ -2156,35 +2382,50 @@ HAVE_DOT = NO
DOT_NUM_THREADS = 0
-# When you want a differently looking font in the dot files that doxygen
-# generates you can specify the font name using DOT_FONTNAME. You need to make
-# sure dot is able to find the font, which can be done by putting it in a
-# standard location or by setting the DOTFONTPATH environment variable or by
-# setting DOT_FONTPATH to the directory containing the font.
-# The default value is: Helvetica.
+# DOT_COMMON_ATTR is common attributes for nodes, edges and labels of
+# subgraphs. When you want a differently looking font in the dot files that
+# doxygen generates you can specify fontname, fontcolor and fontsize attributes.
+# For details please see <a href=https://graphviz.org/doc/info/attrs.html>Node,
+# Edge and Graph Attributes specification</a> You need to make sure dot is able
+# to find the font, which can be done by putting it in a standard location or by
+# setting the DOTFONTPATH environment variable or by setting DOT_FONTPATH to the
+# directory containing the font. Default graphviz fontsize is 14.
+# The default value is: fontname=Helvetica,fontsize=10.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_COMMON_ATTR = "fontname=Helvetica,fontsize=10"
+
+# DOT_EDGE_ATTR is concatenated with DOT_COMMON_ATTR. For elegant style you can
+# add 'arrowhead=open, arrowtail=open, arrowsize=0.5'. <a
+# href=https://graphviz.org/doc/info/arrows.html>Complete documentation about
+# arrows shapes.</a>
+# The default value is: labelfontname=Helvetica,labelfontsize=10.
# This tag requires that the tag HAVE_DOT is set to YES.
-DOT_FONTNAME = Helvetica
+DOT_EDGE_ATTR = "labelfontname=Helvetica,labelfontsize=10"
-# The DOT_FONTSIZE tag can be used to set the size (in points) of the font of
-# dot graphs.
-# Minimum value: 4, maximum value: 24, default value: 10.
+# DOT_NODE_ATTR is concatenated with DOT_COMMON_ATTR. For view without boxes
+# around nodes set 'shape=plain' or 'shape=plaintext' <a
+# href=https://www.graphviz.org/doc/info/shapes.html>Shapes specification</a>
+# The default value is: shape=box,height=0.2,width=0.4.
# This tag requires that the tag HAVE_DOT is set to YES.
-DOT_FONTSIZE = 10
+DOT_NODE_ATTR = "shape=box,height=0.2,width=0.4"
-# By default doxygen will tell dot to use the default font as specified with
-# DOT_FONTNAME. If you specify a different font using DOT_FONTNAME you can set
-# the path where dot can find it using this tag.
+# You can set the path where dot can find font specified with fontname in
+# DOT_COMMON_ATTR and others dot attributes.
# This tag requires that the tag HAVE_DOT is set to YES.
DOT_FONTPATH =
-# If the CLASS_GRAPH tag is set to YES then doxygen will generate a graph for
-# each documented class showing the direct and indirect inheritance relations.
-# Setting this tag to YES will force the CLASS_DIAGRAMS tag to NO.
+# If the CLASS_GRAPH tag is set to YES (or GRAPH) then doxygen will generate a
+# graph for each documented class showing the direct and indirect inheritance
+# relations. In case HAVE_DOT is set as well dot will be used to draw the graph,
+# otherwise the built-in generator will be used. If the CLASS_GRAPH tag is set
+# to TEXT the direct and indirect inheritance relations will be shown as texts /
+# links.
+# Possible values are: NO, YES, TEXT and GRAPH.
# The default value is: YES.
-# This tag requires that the tag HAVE_DOT is set to YES.
CLASS_GRAPH = YES
@@ -2198,7 +2439,8 @@ CLASS_GRAPH = YES
COLLABORATION_GRAPH = YES
# If the GROUP_GRAPHS tag is set to YES then doxygen will generate a graph for
-# groups, showing the direct groups dependencies.
+# groups, showing the direct groups dependencies. See also the chapter Grouping
+# in the manual.
# The default value is: YES.
# This tag requires that the tag HAVE_DOT is set to YES.
@@ -2221,10 +2463,32 @@ UML_LOOK = NO
# but if the number exceeds 15, the total amount of fields shown is limited to
# 10.
# Minimum value: 0, maximum value: 100, default value: 10.
-# This tag requires that the tag HAVE_DOT is set to YES.
+# This tag requires that the tag UML_LOOK is set to YES.
UML_LIMIT_NUM_FIELDS = 10
+# If the DOT_UML_DETAILS tag is set to NO, doxygen will show attributes and
+# methods without types and arguments in the UML graphs. If the DOT_UML_DETAILS
+# tag is set to YES, doxygen will add type and arguments for attributes and
+# methods in the UML graphs. If the DOT_UML_DETAILS tag is set to NONE, doxygen
+# will not generate fields with class member information in the UML graphs. The
+# class diagrams will look similar to the default class diagrams but using UML
+# notation for the relationships.
+# Possible values are: NO, YES and NONE.
+# The default value is: NO.
+# This tag requires that the tag UML_LOOK is set to YES.
+
+DOT_UML_DETAILS = NO
+
+# The DOT_WRAP_THRESHOLD tag can be used to set the maximum number of characters
+# to display on a single line. If the actual line length exceeds this threshold
+# significantly it will wrapped across multiple lines. Some heuristics are apply
+# to avoid ugly line breaks.
+# Minimum value: 0, maximum value: 1000, default value: 17.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_WRAP_THRESHOLD = 17
+
# If the TEMPLATE_RELATIONS tag is set to YES then the inheritance and
# collaboration graphs will show the relations between templates and their
# instances.
@@ -2291,6 +2555,13 @@ GRAPHICAL_HIERARCHY = YES
DIRECTORY_GRAPH = YES
+# The DIR_GRAPH_MAX_DEPTH tag can be used to limit the maximum number of levels
+# of child directories generated in directory dependency graphs by dot.
+# Minimum value: 1, maximum value: 25, default value: 1.
+# This tag requires that the tag DIRECTORY_GRAPH is set to YES.
+
+DIR_GRAPH_MAX_DEPTH = 1
+
# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images
# generated by dot. For an explanation of the image formats see the section
# output formats in the documentation of the dot tool (Graphviz (see:
@@ -2344,13 +2615,18 @@ MSCFILE_DIRS =
DIAFILE_DIRS =
# When using plantuml, the PLANTUML_JAR_PATH tag should be used to specify the
-# path where java can find the plantuml.jar file. If left blank, it is assumed
-# PlantUML is not used or called during a preprocessing step. Doxygen will
-# generate a warning when it encounters a \startuml command in this case and
-# will not generate output for the diagram.
+# path where java can find the plantuml.jar file or to the filename of jar file
+# to be used. If left blank, it is assumed PlantUML is not used or called during
+# a preprocessing step. Doxygen will generate a warning when it encounters a
+# \startuml command in this case and will not generate output for the diagram.
PLANTUML_JAR_PATH =
+# When using plantuml, the PLANTUML_CFG_FILE tag can be used to specify a
+# configuration file for plantuml.
+
+PLANTUML_CFG_FILE =
+
# When using plantuml, the specified paths are searched for files specified by
# the !include statement in a plantuml block.
@@ -2380,18 +2656,6 @@ DOT_GRAPH_MAX_NODES = 50
MAX_DOT_GRAPH_DEPTH = 0
-# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent
-# background. This is disabled by default, because dot on Windows does not seem
-# to support this out of the box.
-#
-# Warning: Depending on the platform used, enabling this option may lead to
-# badly anti-aliased labels on the edges of a graph (i.e. they become hard to
-# read).
-# The default value is: NO.
-# This tag requires that the tag HAVE_DOT is set to YES.
-
-DOT_TRANSPARENT = NO
-
# Set the DOT_MULTI_TARGETS tag to YES to allow dot to generate multiple output
# files in one run (i.e. multiple -o and -T options on the command line). This
# makes dot run faster, but since only newer versions of dot (>1.8.10) support
@@ -2404,14 +2668,18 @@ DOT_MULTI_TARGETS = YES
# If the GENERATE_LEGEND tag is set to YES doxygen will generate a legend page
# explaining the meaning of the various boxes and arrows in the dot generated
# graphs.
+# Note: This tag requires that UML_LOOK isn't set, i.e. the doxygen internal
+# graphical representation for inheritance and collaboration diagrams is used.
# The default value is: YES.
# This tag requires that the tag HAVE_DOT is set to YES.
GENERATE_LEGEND = YES
-# If the DOT_CLEANUP tag is set to YES, doxygen will remove the intermediate dot
+# If the DOT_CLEANUP tag is set to YES, doxygen will remove the intermediate
# files that are used to generate the various graphs.
+#
+# Note: This setting is not only used for dot files but also for msc temporary
+# files.
# The default value is: YES.
-# This tag requires that the tag HAVE_DOT is set to YES.
DOT_CLEANUP = YES
diff --git a/README.md b/README.md
index cffae9191d01..6d34ba9d4dcb 100644
--- a/README.md
+++ b/README.md
@@ -1,12 +1,12 @@
# [libcbor](https://github.com/PJK/libcbor)
-[![Build Status](https://travis-ci.org/PJK/libcbor.svg?branch=master)](https://travis-ci.org/PJK/libcbor)
+[![CircleCI](https://circleci.com/gh/PJK/libcbor/tree/master.svg?style=svg)](https://circleci.com/gh/PJK/libcbor/tree/master)
[![Build status](https://ci.appveyor.com/api/projects/status/8kkmvmefelsxp5u2?svg=true)](https://ci.appveyor.com/project/PJK/libcbor)
[![Documentation Status](https://readthedocs.org/projects/libcbor/badge/?version=latest)](https://readthedocs.org/projects/libcbor/?badge=latest)
[![latest packaged version(s)](https://repology.org/badge/latest-versions/libcbor.svg)](https://repology.org/project/libcbor/versions)
[![codecov](https://codecov.io/gh/PJK/libcbor/branch/master/graph/badge.svg)](https://codecov.io/gh/PJK/libcbor)
-**libcbor** is a C library for parsing and generating [CBOR](http://tools.ietf.org/html/rfc7049), the general-purpose schema-less binary data format.
+**libcbor** is a C library for parsing and generating [CBOR](https://tools.ietf.org/html/rfc7049), the general-purpose schema-less binary data format.
## Main features
- Complete RFC conformance
@@ -25,7 +25,7 @@
```bash
git clone https://github.com/PJK/libcbor
-cmake -DCMAKE_BUILD_TYPE=Release -DCBOR_CUSTOM_ALLOC=ON libcbor
+cmake -DCMAKE_BUILD_TYPE=Release libcbor
make
make install
```
@@ -63,29 +63,29 @@ yum install libcbor-devel
#include <cbor.h>
#include <stdio.h>
-int main(int argc, char * argv[])
-{
- /* Preallocate the map structure */
- cbor_item_t * root = cbor_new_definite_map(2);
- /* Add the content */
- cbor_map_add(root, (struct cbor_pair) {
- .key = cbor_move(cbor_build_string("Is CBOR awesome?")),
- .value = cbor_move(cbor_build_bool(true))
- });
- cbor_map_add(root, (struct cbor_pair) {
- .key = cbor_move(cbor_build_uint8(42)),
- .value = cbor_move(cbor_build_string("Is the answer"))
- });
- /* Output: `length` bytes of data in the `buffer` */
- unsigned char * buffer;
- size_t buffer_size,
- length = cbor_serialize_alloc(root, &buffer, &buffer_size);
-
- fwrite(buffer, 1, length, stdout);
- free(buffer);
-
- fflush(stdout);
- cbor_decref(&root);
+int main(void) {
+ /* Preallocate the map structure */
+ cbor_item_t* root = cbor_new_definite_map(2);
+ /* Add the content */
+ bool success = cbor_map_add(
+ root, (struct cbor_pair){
+ .key = cbor_move(cbor_build_string("Is CBOR awesome?")),
+ .value = cbor_move(cbor_build_bool(true))});
+ success &= cbor_map_add(
+ root, (struct cbor_pair){
+ .key = cbor_move(cbor_build_uint8(42)),
+ .value = cbor_move(cbor_build_string("Is the answer"))});
+ if (!success) return 1;
+ /* Output: `length` bytes of data in the `buffer` */
+ unsigned char* buffer;
+ size_t buffer_size;
+ cbor_serialize_alloc(root, &buffer, &buffer_size);
+
+ fwrite(buffer, 1, buffer_size, stdout);
+ free(buffer);
+
+ fflush(stdout);
+ cbor_decref(&root);
}
```
@@ -94,7 +94,7 @@ Get the latest documentation at [libcbor.readthedocs.org](http://libcbor.readthe
## Contributions
-All bug reports and contributions are welcome. Please see https://github.com/PJK/libcbor for more info.
+Bug reports and contributions are welcome. Please see [CONTRIBUTING.md](https://github.com/PJK/libcbor/blob/master/CONTRIBUTING.md) for more info.
Kudos to all the [contributors](https://github.com/PJK/libcbor/graphs/contributors)!
diff --git a/appveyor.yml b/appveyor.yml
index 452ced5666b7..6a0cca219b92 100644
--- a/appveyor.yml
+++ b/appveyor.yml
@@ -1,27 +1,14 @@
-image: Visual Studio 2015
+image: Visual Studio 2022
version: '{build}'
-
-branches:
- except:
- - gh-pages
-
platform: x64
-
-environment:
- matrix:
- - CMAKE_GENERATOR: "Visual Studio 14 2015 Win64"
-
-# Via https://github.com/apitrace/apitrace/blob/master/appveyor.yml
+skip_branch_with_pr: true
before_build:
-- cmake -H. -Bbuild -G "%CMAKE_GENERATOR%"
-- C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\bin\x86_amd64\CL.exe /?
+- cmake -H. -Bbuild
build_script:
- if "%APPVEYOR_REPO_TAG%"=="true" (set CONFIGURATION=RelWithDebInfo) else (set CONFIGURATION=Debug)
- cmake --build build --config "%CONFIGURATION%"
# TODO enable CMocka tests, maybe package the binaries
-# TODO add MinGW
-# TODO add older MSVC \ No newline at end of file
diff --git a/clang-format.sh b/clang-format.sh
index e4076500c4f0..311ed4225bc8 100755
--- a/clang-format.sh
+++ b/clang-format.sh
@@ -7,11 +7,4 @@ SOURCES=$(find ${DIRS} -name "*.c")
SOURCES+=" $(find ${DIRS} -name "*.h")"
SOURCES+=" $(find ${DIRS} -name "*.cpp")"
-# TravisCI workaround to use new clang-format while avoiding painful aliasing
-# into the subshell
-if which clang-format-8; then
- clang-format-8 $@ -style=file -i ${SOURCES}
-else
- clang-format $@ -style=file -i ${SOURCES}
-fi
-
+clang-format $@ -style=file -i ${SOURCES}
diff --git a/codecov.yml b/codecov.yml
index e374997dcd15..ede10554c3f5 100644
--- a/codecov.yml
+++ b/codecov.yml
@@ -1,2 +1,9 @@
ignore:
- - "test/stream_expectations.c" # Function pointers are not resolved correctly
+ - "test"
+ - "examples"
+coverage:
+ status:
+ project:
+ default:
+ target: auto
+ threshold: 1% # Don't fail CI on trivial changes and Codecov flakiness
diff --git a/doc/source/api.rst b/doc/source/api.rst
index c25629115060..75b0541cb94e 100644
--- a/doc/source/api.rst
+++ b/doc/source/api.rst
@@ -10,7 +10,7 @@ The data API is centered around :type:`cbor_item_t`, a generic handle for any CB
The single most important thing to keep in mind is: :type:`cbor_item_t` **is an opaque type and should only be manipulated using the appropriate functions!** Think of it as an object.
-The *libcbor* API closely follows the semantics outlined by `CBOR standard <http://tools.ietf.org/html/rfc7049>`_. This part of the documentation provides a short overview of the CBOR constructs, as well as a general introduction to the *libcbor* API. Remaining reference can be found in the following files structured by data types.
+The *libcbor* API closely follows the semantics outlined by `CBOR standard <https://tools.ietf.org/html/rfc7049>`_. This part of the documentation provides a short overview of the CBOR constructs, as well as a general introduction to the *libcbor* API. Remaining reference can be found in the following files structured by data types.
The API is designed to allow both very tight control & flexibility and general convenience with sane defaults. [#]_ For example, client with very specific requirements (constrained environment, custom application protocol built on top of CBOR, etc.) may choose to take full control (and responsibility) of memory and data structures management by interacting directly with the decoder. Other clients might want to take control of specific aspects (streamed collections, hash maps storage), but leave other responsibilities to *libcbor*. More general clients might prefer to be abstracted away from all aforementioned details and only be presented complete data structures.
@@ -28,6 +28,8 @@ The API is designed to allow both very tight control & flexibility and general c
api/item_reference_counting
api/decoding
api/encoding
+ api/streaming_decoding
+ api/streaming_encoding
api/type_0_1
api/type_2
api/type_3
diff --git a/doc/source/api/encoding.rst b/doc/source/api/encoding.rst
index af6bbbe7b9d3..40b47a0cd3db 100644
--- a/doc/source/api/encoding.rst
+++ b/doc/source/api/encoding.rst
@@ -6,6 +6,10 @@ The easiest way to encode data items is using the :func:`cbor_serialize` or :fun
.. doxygenfunction:: cbor_serialize
.. doxygenfunction:: cbor_serialize_alloc
+To determine the number of bytes needed to serialize an item, use :func:`cbor_serialized_size`:
+
+.. doxygenfunction:: cbor_serialized_size
+
Type-specific serializers
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
In case you know the type of the item you want to serialize beforehand, you can use one
diff --git a/doc/source/api/item_reference_counting.rst b/doc/source/api/item_reference_counting.rst
index 0c0fa7257826..70075cb67e5b 100644
--- a/doc/source/api/item_reference_counting.rst
+++ b/doc/source/api/item_reference_counting.rst
@@ -1,24 +1,21 @@
Memory management and reference counting
===============================================
-Due to the nature of its domain, *libcbor* will need to work with heap memory. The stateless decoder and encoder don't allocate any memory.
+Due to the nature of its domain, *libcbor* will need to work with heap memory. The stateless decoder and encoder doesn't allocate any memory.
If you have specific requirements, you should consider rolling your own driver for the stateless API.
Using custom allocator
^^^^^^^^^^^^^^^^^^^^^^^^
-*libcbor* gives you with the ability to provide your own implementations of ``malloc``, ``realloc``, and ``free``. This can be useful if you are using a custom allocator throughout your application, or if you want to implement custom policies (e.g. tighter restrictions on the amount of allocated memory).
+*libcbor* gives you with the ability to provide your own implementations of ``malloc``, ``realloc``, and ``free``.
+This can be useful if you are using a custom allocator throughout your application,
+or if you want to implement custom policies (e.g. tighter restrictions on the amount of allocated memory).
-In order to use this feature, *libcbor* has to be compiled with the :doc:`appropriate flags </getting_started>`. You can verify the configuration using the ``CBOR_CUSTOM_ALLOC`` macro. A simple usage might be as follows:
.. code-block:: c
- #if CBOR_CUSTOM_ALLOC
- cbor_set_allocs(malloc, realloc, free);
- #else
- #error "libcbor built with support for custom allocation is required"
- #endif
+ cbor_set_allocs(malloc, realloc, free);
.. doxygenfunction:: cbor_set_allocs
@@ -26,11 +23,11 @@ In order to use this feature, *libcbor* has to be compiled with the :doc:`approp
Reference counting
^^^^^^^^^^^^^^^^^^^^^
-As CBOR items may require complex cleanups at the end of their lifetime, there is a reference counting mechanism in place. This also enables very simple GC when integrating *libcbor* into managed environment. Every item starts its life (by either explicit creation, or as a result of parsing) with reference count set to 1. When the refcount reaches zero, it will be destroyed.
+As CBOR items may require complex cleanups at the end of their lifetime, there is a reference counting mechanism in place. This also enables a very simple GC when integrating *libcbor* into a managed environment. Every item starts its life (by either explicit creation, or as a result of parsing) with reference count set to 1. When the refcount reaches zero, it will be destroyed.
-Items containing nested items will be destroyed recursively - refcount of every nested item will be decreased by one.
+Items containing nested items will be destroyed recursively - the refcount of every nested item will be decreased by one.
-The destruction is synchronous and renders any pointers to items with refcount zero invalid immediately after calling the :func:`cbor_decref`.
+The destruction is synchronous and renders any pointers to items with refcount zero invalid immediately after calling :func:`cbor_decref`.
.. doxygenfunction:: cbor_incref
diff --git a/doc/source/streaming/decoding.rst b/doc/source/api/streaming_decoding.rst
index 70174aa2715d..d7cea38712a0 100644
--- a/doc/source/streaming/decoding.rst
+++ b/doc/source/api/streaming_decoding.rst
@@ -1,11 +1,12 @@
-Decoding
+Streaming Decoding
=============================
-Another way to decode data using libcbor is to specify a callbacks that will be invoked when upon finding certain items in the input. This API is provided by
+*libcbor* exposes a stateless decoder that reads a stream of input bytes from a buffer and invokes user-provided callbacks as it decodes the input:
.. doxygenfunction:: cbor_stream_decode
-Usage example: https://github.com/PJK/libcbor/blob/master/examples/streaming_parser.c
+For example, when :func:`cbor_stream_decode` encounters a 1B unsigned integer, it will invoke the function pointer stored in ``cbor_callbacks.uint8``.
+Complete usage example: `examples/streaming_parser.c <https://github.com/PJK/libcbor/blob/master/examples/streaming_parser.c>`_
The callbacks are defined by
@@ -16,13 +17,6 @@ When building custom sets of callbacks, feel free to start from
.. doxygenvariable:: cbor_empty_callbacks
-Related structures
-~~~~~~~~~~~~~~~~~~~~~
-
-.. doxygenenum:: cbor_decoder_status
-.. doxygenstruct:: cbor_decoder_result
- :members:
-
Callback types definition
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
diff --git a/doc/source/api/streaming_encoding.rst b/doc/source/api/streaming_encoding.rst
new file mode 100644
index 000000000000..25100da9b5e0
--- /dev/null
+++ b/doc/source/api/streaming_encoding.rst
@@ -0,0 +1,65 @@
+Streaming Encoding
+=============================
+
+`cbor/encoding.h <https://github.com/PJK/libcbor/blob/master/src/cbor/encoding.h>`_
+exposes a low-level encoding API to encode CBOR objects on the fly. Unlike
+:func:`cbor_serialize`, these functions take logical values (integers, floats,
+strings, etc.) instead of :type:`cbor_item_t`. The client is responsible for
+constructing the compound types correctly (e.g. terminating arrays).
+
+Streaming encoding is typically used to create an streaming (indefinite length) CBOR :doc:`strings <type_2>`, :doc:`byte strings <type_3>`, :doc:`arrays <type_4>`, and :doc:`maps <type_5>`. Complete example: `examples/streaming_array.c <https://github.com/PJK/libcbor/blob/master/examples/streaming_array.c>`_
+
+.. doxygenfunction:: cbor_encode_uint8
+
+.. doxygenfunction:: cbor_encode_uint16
+
+.. doxygenfunction:: cbor_encode_uint32
+
+.. doxygenfunction:: cbor_encode_uint64
+
+.. doxygenfunction:: cbor_encode_uint
+
+.. doxygenfunction:: cbor_encode_negint8
+
+.. doxygenfunction:: cbor_encode_negint16
+
+.. doxygenfunction:: cbor_encode_negint32
+
+.. doxygenfunction:: cbor_encode_negint64
+
+.. doxygenfunction:: cbor_encode_negint
+
+.. doxygenfunction:: cbor_encode_bytestring_start
+
+.. doxygenfunction:: cbor_encode_indef_bytestring_start
+
+.. doxygenfunction:: cbor_encode_string_start
+
+.. doxygenfunction:: cbor_encode_indef_string_start
+
+.. doxygenfunction:: cbor_encode_array_start
+
+.. doxygenfunction:: cbor_encode_indef_array_start
+
+.. doxygenfunction:: cbor_encode_map_start
+
+.. doxygenfunction:: cbor_encode_indef_map_start
+
+.. doxygenfunction:: cbor_encode_tag
+
+.. doxygenfunction:: cbor_encode_bool
+
+.. doxygenfunction:: cbor_encode_null
+
+.. doxygenfunction:: cbor_encode_undef
+
+.. doxygenfunction:: cbor_encode_half
+
+.. doxygenfunction:: cbor_encode_single
+
+.. doxygenfunction:: cbor_encode_double
+
+.. doxygenfunction:: cbor_encode_break
+
+.. doxygenfunction:: cbor_encode_ctrl
+
diff --git a/doc/source/api/type_2.rst b/doc/source/api/type_2.rst
index 17df5716ccc2..ff9369a90d67 100644
--- a/doc/source/api/type_2.rst
+++ b/doc/source/api/type_2.rst
@@ -27,11 +27,6 @@ Storage requirements (indefinite) ``sizeof(cbor_item_t) * (1 + chunk_count) +
================================== ======================================================
-Streaming indefinite byte strings
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-Please refer to :doc:`/streaming`.
-
Getting metadata
~~~~~~~~~~~~~~~~~
diff --git a/doc/source/api/type_3.rst b/doc/source/api/type_3.rst
index abec24de40a3..be06fc176566 100644
--- a/doc/source/api/type_3.rst
+++ b/doc/source/api/type_3.rst
@@ -1,7 +1,7 @@
Type 3 – UTF-8 strings
=============================
-CBOR strings work in much the same ways as :doc:`type_2`.
+CBOR strings have the same structure as :doc:`type_2`.
================================== ======================================================
Corresponding :type:`cbor_type` ``CBOR_TYPE_STRING``
@@ -12,10 +12,6 @@ Storage requirements (definite) ``sizeof(cbor_item_t) + length(handle)``
Storage requirements (indefinite) ``sizeof(cbor_item_t) * (1 + chunk_count) + chunks``
================================== ======================================================
-Streaming indefinite strings
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-Please refer to :doc:`/streaming`.
UTF-8 encoding validation
~~~~~~~~~~~~~~~~~~~~~~~~~~~
diff --git a/doc/source/api/type_4.rst b/doc/source/api/type_4.rst
index c3bb88a9cd8a..a76202f4a0fd 100644
--- a/doc/source/api/type_4.rst
+++ b/doc/source/api/type_4.rst
@@ -2,6 +2,11 @@ Type 4 – Arrays
=============================
CBOR arrays, just like :doc:`byte strings <type_2>` and :doc:`strings <type_3>`, can be encoded either as definite, or as indefinite.
+Definite arrays have a fixed size which is stored in the header, whereas indefinite arrays do not and are terminated by a special "break" byte instead.
+
+Arrays are explicitly created or decoded as definite or indefinite and will be encoded using the corresponding wire representation, regardless of whether the actual size is known at the time of encoding.
+
+.. note:: Indefinite arrays can be conveniently used with streaming :doc:`decoding <streaming_decoding>` and :doc:`encoding <streaming_encoding>`.
================================== =====================================================================================
Corresponding :type:`cbor_type` ``CBOR_TYPE_ARRAY``
@@ -28,10 +33,6 @@ Examples
0x20 Unsigned integer 32
... 32 items follow
-Streaming indefinite arrays
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-Please refer to :doc:`/streaming`.
Getting metadata
~~~~~~~~~~~~~~~~~
diff --git a/doc/source/api/type_5.rst b/doc/source/api/type_5.rst
index c9b2e904af6e..7f7be273aba9 100644
--- a/doc/source/api/type_5.rst
+++ b/doc/source/api/type_5.rst
@@ -1,9 +1,18 @@
Type 5 – Maps
=============================
-CBOR maps are the plain old associate hash maps known from JSON and many other formats and languages, with one exception: any CBOR data item can be a key, not just strings. This is somewhat unusual and you, as an application developer, should keep that in mind.
+CBOR maps are the plain old associative maps similar JSON objects or Python dictionaries.
-Maps can be either definite or indefinite, in much the same way as :doc:`type_4`.
+Definite maps have a fixed size which is stored in the header, whereas indefinite maps do not and are terminated by a special "break" byte instead.
+
+Map are explicitly created or decoded as definite or indefinite and will be encoded using the corresponding wire representation, regardless of whether the actual size is known at the time of encoding.
+
+.. note::
+
+ Indefinite maps can be conveniently used with streaming :doc:`decoding <streaming_decoding>` and :doc:`encoding <streaming_encoding>`.
+ Keys and values can simply be output one by one, alternating keys and values.
+
+.. warning:: Any CBOR data item is a legal map key (not just strings).
================================== =====================================================================================
Corresponding :type:`cbor_type` ``CBOR_TYPE_MAP``
@@ -14,10 +23,19 @@ Storage requirements (definite) ``sizeof(cbor_pair) * size + sizeof(cbor_ite
Storage requirements (indefinite) ``<= sizeof(cbor_item_t) + sizeof(cbor_pair) * size * BUFFER_GROWTH``
================================== =====================================================================================
-Streaming maps
+Examples
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-Please refer to :doc:`/streaming`.
+::
+
+ 0xbf Start indefinite map (represents {1: 2})
+ 0x01 Unsigned integer 1 (key)
+ 0x02 Unsigned integer 2 (value)
+ 0xff "Break" control token
+
+::
+
+ 0xa0 Map of size 0
Getting metadata
~~~~~~~~~~~~~~~~~
diff --git a/doc/source/api/type_7.rst b/doc/source/api/type_7.rst
index d2e75c8bf0b3..b105402a08b2 100644
--- a/doc/source/api/type_7.rst
+++ b/doc/source/api/type_7.rst
@@ -65,11 +65,4 @@ Manipulating existing items
Half floats
~~~~~~~~~~~~
CBOR supports two `bytes wide ("half-precision") <https://en.wikipedia.org/wiki/Half-precision_floating-point_format>`_
-floats which are not supported by the C language. *libcbor* represents them using `float <https://en.cppreference.com/w/c/language/type>` values throughout the API, which has important implications when manipulating these values.
-
-In particular, if a user uses some of the manipulation APIs
-(e.g. :func:`cbor_set_float2`, :func:`cbor_new_float2`)
-to introduce a value that doesn't have an exect half-float representation,
-the encoding semantics are given by :func:`cbor_encode_half` as follows:
-
-.. doxygenfunction:: cbor_encode_half
+floats which are not supported by the C language. *libcbor* represents them using `float <https://en.cppreference.com/w/c/language/type>` values throughout the API. Encoding will be performed by :func:`cbor_encode_half`, which will handle any values that cannot be represented as a half-float.
diff --git a/doc/source/conf.py b/doc/source/conf.py
index 3ca95bd6dd1f..585efc8a436f 100644
--- a/doc/source/conf.py
+++ b/doc/source/conf.py
@@ -76,8 +76,8 @@ copyright = '2014 - 2020, Pavel Kalvoda'
# built documents.
#
# The short X.Y version.
-version = '0.8'
-release = '0.8.0'
+version = '0.10'
+release = '0.10.2'
# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
diff --git a/doc/source/getting_started.rst b/doc/source/getting_started.rst
index 3e56f2c84c08..98c5a3956337 100644
--- a/doc/source/getting_started.rst
+++ b/doc/source/getting_started.rst
@@ -50,12 +50,11 @@ Option Meaning
``WITH_TESTS`` Build unit tests (see :doc:`development`) ``OFF`` ``ON``, ``OFF``
======================== ======================================================= ====================== =====================================================================================================================
-The following configuration options will also be defined as macros[#]_ in ``<cbor/common.h>`` and can therefore be used in client code:
+The following configuration options will also be defined as macros [#]_ in ``<cbor/common.h>`` and can therefore be used in client code:
======================== ======================================================= ====================== =====================================================================================================================
Option Meaning Default Possible values
------------------------ ------------------------------------------------------- ---------------------- ---------------------------------------------------------------------------------------------------------------------
-``CBOR_CUSTOM_ALLOC`` Enable custom allocator support ``OFF`` ``ON``, ``OFF``
``CBOR_PRETTY_PRINTER`` Include a pretty-printing routine ``ON`` ``ON``, ``OFF``
``CBOR_BUFFER_GROWTH`` Factor for buffer growth & shrinking ``2`` Decimals > 1
======================== ======================================================= ====================== =====================================================================================================================
@@ -64,6 +63,10 @@ Option Meaning
If you want to pass other custom configuration options, please refer to `<http://www.cmake.org/Wiki/CMake_Useful_Variables>`_.
+.. warning::
+ ``CBOR_CUSTOM_ALLOC`` has been `removed <https://github.com/PJK/libcbor/pull/237>`_.
+ Custom allocators (historically a controlled by a build flag) are always enabled.
+
**Building using make**
CMake will generate a Makefile and other configuration files for the build. As a rule of thumb, you should configure the
diff --git a/doc/source/index.rst b/doc/source/index.rst
index 1922586097e3..79293e798c3b 100644
--- a/doc/source/index.rst
+++ b/doc/source/index.rst
@@ -30,7 +30,6 @@ Contents
getting_started
using
api
- streaming
tests
rfc_conformance
internal
diff --git a/doc/source/requirements.txt b/doc/source/requirements.txt
index 461bb7e804d2..a82e34e58ad2 100644
--- a/doc/source/requirements.txt
+++ b/doc/source/requirements.txt
@@ -1,39 +1,31 @@
alabaster==0.7.12
-argh==0.26.2
-Babel==2.8.0
-breathe==4.14.1
-certifi==2019.11.28
-chardet==3.0.4
-Click==7.0
-docutils==0.16
-Flask==1.1.1
-idna==2.9
-imagesize==1.2.0
-itsdangerous==1.1.0
-Jinja2==2.10.1
-livereload==2.6.1
-MarkupSafe==1.1.1
-packaging==20.3
-pathtools==0.1.2
-port-for==0.3.1
-Pygments==2.6.1
-pyparsing==2.4.6
-pytz==2019.3
-PyYAML==5.3
-requests==2.23.0
-six==1.14.0
-snowballstemmer==2.0.0
-sortedcontainers==2.1.0
-Sphinx==2.4.4
-sphinx-autobuild==0.7.1
-sphinx-rtd-theme==0.4.3
+Babel==2.9.1
+breathe==4.33.1
+certifi==2022.12.7
+charset-normalizer==2.0.12
+colorama==0.4.4
+docutils==0.17.1
+idna==3.3
+imagesize==1.3.0
+importlib-metadata==4.11.3
+Jinja2==3.0.3
+livereload==2.6.3
+MarkupSafe==2.1.1
+packaging==21.3
+Pygments==2.11.2
+pyparsing==3.0.7
+pytz==2021.3
+requests==2.27.1
+snowballstemmer==2.2.0
+Sphinx==4.4.0
+sphinx-autobuild==2021.3.14
+sphinx-rtd-theme==1.0.0
sphinxcontrib-applehelp==1.0.2
sphinxcontrib-devhelp==1.0.2
-sphinxcontrib-htmlhelp==1.0.3
+sphinxcontrib-htmlhelp==2.0.0
sphinxcontrib-jsmath==1.0.1
sphinxcontrib-qthelp==1.0.3
-sphinxcontrib-serializinghtml==1.1.4
-tornado==6.0.4
-urllib3==1.25.8
-watchdog==0.10.2
-Werkzeug==0.15.5
+sphinxcontrib-serializinghtml==1.1.5
+tornado==6.1
+urllib3==1.26.9
+zipp==3.7.0
diff --git a/doc/source/rfc_conformance.rst b/doc/source/rfc_conformance.rst
index 817614835a1f..6848fbacd464 100644
--- a/doc/source/rfc_conformance.rst
+++ b/doc/source/rfc_conformance.rst
@@ -1,13 +1,13 @@
RFC conformance
=========================
-*libcbor* is, generally speaking, very faithful implementation of `RFC 7049 <http://tools.ietf.org/html/rfc7049>`_. There are, however, some limitations imposed by technical constraints.
+*libcbor* is, generally speaking, very faithful implementation of `RFC 7049 <https://tools.ietf.org/html/rfc7049>`_. There are, however, some limitations imposed by technical constraints.
Bytestring length
-------------------
There is no explicit limitation of indefinite length byte strings. [#]_ *libcbor* will not handle byte strings with more chunks than the maximum value of :type:`size_t`. On any sane platform, such string would not fit in the memory anyway. It is, however, possible to process arbitrarily long strings and byte strings using the streaming decoder.
-.. [#] http://tools.ietf.org/html/rfc7049#section-2.2.2
+.. [#] https://tools.ietf.org/html/rfc7049#section-2.2.2
"Half-precision" IEEE 754 floats
---------------------------------
diff --git a/doc/source/streaming.rst b/doc/source/streaming.rst
deleted file mode 100644
index 8e3bb0d9bade..000000000000
--- a/doc/source/streaming.rst
+++ /dev/null
@@ -1,13 +0,0 @@
-Streaming & indefinite items
-=============================
-
-CBOR :doc:`strings <api/type_2>`, :doc:`byte strings <api/type_3>`, :doc:`arrays <api/type_4>`, and :doc:`maps <api/type_5>` can be encoded as *indefinite*, meaning their length or size is not specified. Instead, they are divided into *chunks* (:doc:`strings <api/type_2>`, :doc:`byte strings <api/type_3>`), or explicitly terminated (:doc:`arrays <api/type_4>`, :doc:`maps <api/type_5>`).
-
-This is one of the most important (and due to poor implementations, underutilized) features of CBOR. It enables low-overhead streaming just about anywhere without dealing with channels or pub/sub mechanism. It is, however, important to recognize that CBOR streaming is not a substitute for Websockets [#]_ and similar technologies.
-
-.. [#] :RFC:`6455`
-
-.. toctree::
-
- streaming/decoding
- streaming/encoding
diff --git a/doc/source/streaming/encoding.rst b/doc/source/streaming/encoding.rst
deleted file mode 100644
index 8a56461d3584..000000000000
--- a/doc/source/streaming/encoding.rst
+++ /dev/null
@@ -1,4 +0,0 @@
-Encoding
-=============================
-
-TODO
diff --git a/doc/source/using.rst b/doc/source/using.rst
index dbc09819d46b..ccb7372f23b6 100644
--- a/doc/source/using.rst
+++ b/doc/source/using.rst
@@ -34,10 +34,10 @@ feel free to use just some of the ``cbor/*.h`` headers:
- ``cbor/arrays.h`` - :doc:`api/type_4`
- ``cbor/bytestrings.h`` - :doc:`api/type_2`
- - ``cbor/callbacks.h`` - Callbacks used for :doc:`streaming/decoding`
+ - ``cbor/callbacks.h`` - Callbacks used for :doc:`api/streaming_decoding`
- ``cbor/common.h`` - Common utilities - always transitively included
- ``cbor/data.h`` - Data types definitions - always transitively included
- - ``cbor/encoding.h`` - Streaming encoders for :doc:`streaming/encoding`
+ - ``cbor/encoding.h`` - Streaming encoders for :doc:`api/streaming_encoding`
- ``cbor/floats_ctrls.h`` - :doc:`api/type_7`
- ``cbor/ints.h`` - :doc:`api/type_0_1`
- ``cbor/maps.h`` - :doc:`api/type_5`
@@ -75,11 +75,12 @@ of what is it CBOR does, the examples (located in the ``examples`` directory) sh
.key = cbor_move(cbor_build_uint8(42)),
.value = cbor_move(cbor_build_string("Is the answer"))
});
- /* Output: `length` bytes of data in the `buffer` */
+ /* Output: `buffer_size` bytes of data in the `buffer` */
unsigned char * buffer;
- size_t buffer_size, length = cbor_serialize_alloc(root, &buffer, &buffer_size);
+ size_t buffer_size;
+ cbor_serialize_alloc(root, &buffer, &buffer_size);
- fwrite(buffer, 1, length, stdout);
+ fwrite(buffer, 1, buffer_size, stdout);
free(buffer);
fflush(stdout);
diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt
index d1ddfb17b28a..eaf985ba32cd 100644
--- a/examples/CMakeLists.txt
+++ b/examples/CMakeLists.txt
@@ -7,6 +7,9 @@ target_link_libraries(create_items cbor)
add_executable(streaming_parser streaming_parser.c)
target_link_libraries(streaming_parser cbor)
+add_executable(streaming_array streaming_array.c)
+target_link_libraries(streaming_array cbor)
+
add_executable(sort sort.c)
target_link_libraries(sort cbor)
diff --git a/examples/bazel/README.md b/examples/bazel/README.md
new file mode 100644
index 000000000000..455e2d38d3e5
--- /dev/null
+++ b/examples/bazel/README.md
@@ -0,0 +1,33 @@
+# Bazel Example
+
+This directory shows an example of using LibCbor in a project that builds with Bazel.
+
+## Compile
+
+To build the project:
+
+```shell
+bazel build src:all
+```
+
+## Test
+
+To test the code:
+
+```shell
+bazel test src:all
+```
+
+## Run
+
+To run the demo:
+
+```shell
+bazel run src:hello
+```
+
+or
+
+```shell
+bazel-bin/src/hello
+```
diff --git a/examples/bazel/WORKSPACE b/examples/bazel/WORKSPACE
new file mode 100644
index 000000000000..c7601f3035ff
--- /dev/null
+++ b/examples/bazel/WORKSPACE
@@ -0,0 +1,19 @@
+workspace(name = "libcbor_bazel_example")
+
+load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
+
+# Google Test
+http_archive(
+ name = "gtest",
+ sha256 = "94c634d499558a76fa649edb13721dce6e98fb1e7018dfaeba3cd7a083945e91",
+ strip_prefix = "googletest-release-1.10.0",
+ url = "https://github.com/google/googletest/archive/release-1.10.0.zip",
+)
+
+# libcbor
+new_local_repository(
+ name = "libcbor",
+ build_file = "//third_party:libcbor.BUILD",
+ path = "../../src",
+)
+
diff --git a/examples/bazel/src/BUILD b/examples/bazel/src/BUILD
new file mode 100644
index 000000000000..d3acb578398a
--- /dev/null
+++ b/examples/bazel/src/BUILD
@@ -0,0 +1,46 @@
+load("@rules_cc//cc:defs.bzl", "cc_library")
+load("@rules_cc//cc:defs.bzl", "cc_binary")
+
+cc_library(
+ name = "src",
+ srcs = [
+ "hello.cc",
+ ],
+ hdrs = [
+ "hello.h",
+ ],
+ visibility = [
+ "//src:__pkg__",
+ ],
+ deps = [
+ "@libcbor//:cbor",
+ ],
+)
+
+cc_test(
+ name = "tests",
+ size = "small",
+ srcs = [
+ "hello_test.cc",
+ ],
+ visibility = [
+ "//visibility:private",
+ ],
+ deps = [
+ ":src",
+ "@gtest//:gtest_main",
+ "@libcbor//:cbor",
+ ],
+)
+
+
+cc_binary(
+ name = "hello",
+ srcs = [
+ "main.cc",
+ ],
+ deps = [
+ ":src",
+ ],
+)
+
diff --git a/examples/bazel/src/hello.cc b/examples/bazel/src/hello.cc
new file mode 100644
index 000000000000..5162d26e1b47
--- /dev/null
+++ b/examples/bazel/src/hello.cc
@@ -0,0 +1,7 @@
+#include "src/hello.h"
+
+#include "cbor.h"
+
+void print_cbor_version() {
+ printf("libcbor v%d.%d.%d\n", cbor_major_version, cbor_minor_version, cbor_patch_version);
+}
diff --git a/examples/bazel/src/hello.h b/examples/bazel/src/hello.h
new file mode 100644
index 000000000000..3d50065cfdcf
--- /dev/null
+++ b/examples/bazel/src/hello.h
@@ -0,0 +1,8 @@
+#ifndef HELLO_H_
+#define HELLO_H_
+
+#include <cstdint>
+
+void print_cbor_version(void);
+
+#endif // HELLO_H_
diff --git a/examples/bazel/src/hello_test.cc b/examples/bazel/src/hello_test.cc
new file mode 100644
index 000000000000..68d8633c8772
--- /dev/null
+++ b/examples/bazel/src/hello_test.cc
@@ -0,0 +1,10 @@
+#include "src/hello.h"
+
+#include "gtest/gtest.h"
+
+class HelloTest : public ::testing::Test {};
+
+TEST_F(HelloTest, CborVersion) {
+ EXPECT_EQ(cbor_version(), 0);
+}
+
diff --git a/examples/bazel/src/main.cc b/examples/bazel/src/main.cc
new file mode 100644
index 000000000000..6c1e4f52a03a
--- /dev/null
+++ b/examples/bazel/src/main.cc
@@ -0,0 +1,10 @@
+#include "src/hello.h"
+
+#include <stdio.h>
+
+int main() {
+ print_cbor_version();
+
+ return 0;
+}
+
diff --git a/examples/bazel/third_party/BUILD b/examples/bazel/third_party/BUILD
new file mode 100644
index 000000000000..c4c443f1b562
--- /dev/null
+++ b/examples/bazel/third_party/BUILD
@@ -0,0 +1 @@
+exports_files(["libcbor.BUILD"])
diff --git a/examples/bazel/third_party/libcbor.BUILD b/examples/bazel/third_party/libcbor.BUILD
new file mode 100644
index 000000000000..45f4975b4fc8
--- /dev/null
+++ b/examples/bazel/third_party/libcbor.BUILD
@@ -0,0 +1,21 @@
+cc_library(
+ name = "cbor",
+ srcs = glob([
+ "src/**/*.h",
+ "src/**/*.c",
+ ]),
+ hdrs = [
+ "cbor.h",
+ ] + glob([
+ "cbor/*.h",
+ ]),
+ includes = [
+ "src",
+ "src/cbor",
+ "src/cbor/internal",
+ ],
+ visibility = ["//visibility:public"],
+ deps = [
+ "@libcbor_bazel_example//third_party/libcbor:config",
+ ],
+)
diff --git a/examples/bazel/third_party/libcbor/BUILD b/examples/bazel/third_party/libcbor/BUILD
new file mode 100644
index 000000000000..2ef8702fd308
--- /dev/null
+++ b/examples/bazel/third_party/libcbor/BUILD
@@ -0,0 +1,11 @@
+cc_library(
+ name = "config",
+ hdrs = [
+ "cbor/cbor_export.h",
+ "cbor/configuration.h",
+ ],
+ includes = [
+ "./",
+ ],
+ visibility = ["//visibility:public"],
+)
diff --git a/examples/bazel/third_party/libcbor/cbor/cbor_export.h b/examples/bazel/third_party/libcbor/cbor/cbor_export.h
new file mode 100644
index 000000000000..8bf3dea85c8f
--- /dev/null
+++ b/examples/bazel/third_party/libcbor/cbor/cbor_export.h
@@ -0,0 +1,42 @@
+
+#ifndef CBOR_EXPORT_H
+#define CBOR_EXPORT_H
+
+#ifdef CBOR_STATIC_DEFINE
+#define CBOR_EXPORT
+#define CBOR_NO_EXPORT
+#else
+#ifndef CBOR_EXPORT
+#ifdef cbor_EXPORTS
+/* We are building this library */
+#define CBOR_EXPORT
+#else
+/* We are using this library */
+#define CBOR_EXPORT
+#endif
+#endif
+
+#ifndef CBOR_NO_EXPORT
+#define CBOR_NO_EXPORT
+#endif
+#endif
+
+#ifndef CBOR_DEPRECATED
+#define CBOR_DEPRECATED __attribute__((__deprecated__))
+#endif
+
+#ifndef CBOR_DEPRECATED_EXPORT
+#define CBOR_DEPRECATED_EXPORT CBOR_EXPORT CBOR_DEPRECATED
+#endif
+
+#ifndef CBOR_DEPRECATED_NO_EXPORT
+#define CBOR_DEPRECATED_NO_EXPORT CBOR_NO_EXPORT CBOR_DEPRECATED
+#endif
+
+#if 0 /* DEFINE_NO_DEPRECATED */
+#ifndef CBOR_NO_DEPRECATED
+#define CBOR_NO_DEPRECATED
+#endif
+#endif
+
+#endif /* CBOR_EXPORT_H */
diff --git a/examples/bazel/third_party/libcbor/cbor/configuration.h b/examples/bazel/third_party/libcbor/cbor/configuration.h
new file mode 100644
index 000000000000..3472cf49d8fe
--- /dev/null
+++ b/examples/bazel/third_party/libcbor/cbor/configuration.h
@@ -0,0 +1,15 @@
+#ifndef LIBCBOR_CONFIGURATION_H
+#define LIBCBOR_CONFIGURATION_H
+
+#define CBOR_MAJOR_VERSION 0
+#define CBOR_MINOR_VERSION 10
+#define CBOR_PATCH_VERSION 2
+
+#define CBOR_BUFFER_GROWTH 2
+#define CBOR_MAX_STACK_SIZE 2048
+#define CBOR_PRETTY_PRINTER 1
+
+#define CBOR_RESTRICT_SPECIFIER restrict
+#define CBOR_INLINE_SPECIFIER
+
+#endif // LIBCBOR_CONFIGURATION_H
diff --git a/examples/cjson2cbor.c b/examples/cjson2cbor.c
index 2e3071fb47c5..eae78e1cf7a6 100644
--- a/examples/cjson2cbor.c
+++ b/examples/cjson2cbor.c
@@ -110,7 +110,7 @@ void cjson_cbor_stream_decode(cJSON *source,
}
}
-void usage() {
+void usage(void) {
printf("Usage: cjson [input JSON file]\n");
exit(1);
}
@@ -133,10 +133,10 @@ int main(int argc, char *argv[]) {
/* Print out CBOR bytes */
unsigned char *buffer;
- size_t buffer_size,
- cbor_length = cbor_serialize_alloc(cbor, &buffer, &buffer_size);
+ size_t buffer_size;
+ cbor_serialize_alloc(cbor, &buffer, &buffer_size);
- fwrite(buffer, 1, cbor_length, stdout);
+ fwrite(buffer, 1, buffer_size, stdout);
free(buffer);
fflush(stdout);
diff --git a/examples/create_items.c b/examples/create_items.c
index b875720b5d91..a6e67a9870ef 100644
--- a/examples/create_items.c
+++ b/examples/create_items.c
@@ -8,24 +8,25 @@
#include <stdio.h>
#include "cbor.h"
-int main(int argc, char* argv[]) {
+int main(void) {
/* Preallocate the map structure */
cbor_item_t* root = cbor_new_definite_map(2);
/* Add the content */
- cbor_map_add(root,
- (struct cbor_pair){
- .key = cbor_move(cbor_build_string("Is CBOR awesome?")),
- .value = cbor_move(cbor_build_bool(true))});
- cbor_map_add(root,
- (struct cbor_pair){
- .key = cbor_move(cbor_build_uint8(42)),
- .value = cbor_move(cbor_build_string("Is the answer"))});
+ bool success = cbor_map_add(
+ root, (struct cbor_pair){
+ .key = cbor_move(cbor_build_string("Is CBOR awesome?")),
+ .value = cbor_move(cbor_build_bool(true))});
+ success &= cbor_map_add(
+ root, (struct cbor_pair){
+ .key = cbor_move(cbor_build_uint8(42)),
+ .value = cbor_move(cbor_build_string("Is the answer"))});
+ if (!success) return 1;
/* Output: `length` bytes of data in the `buffer` */
unsigned char* buffer;
- size_t buffer_size,
- length = cbor_serialize_alloc(root, &buffer, &buffer_size);
+ size_t buffer_size;
+ cbor_serialize_alloc(root, &buffer, &buffer_size);
- fwrite(buffer, 1, length, stdout);
+ fwrite(buffer, 1, buffer_size, stdout);
free(buffer);
fflush(stdout);
diff --git a/examples/hello.c b/examples/hello.c
index 275267445dac..788b0ed23138 100644
--- a/examples/hello.c
+++ b/examples/hello.c
@@ -8,9 +8,8 @@
#include <stdio.h>
#include "cbor.h"
-int main(int argc, char* argv[]) {
+int main(void) {
printf("Hello from libcbor %s\n", CBOR_VERSION);
- printf("Custom allocation support: %s\n", CBOR_CUSTOM_ALLOC ? "yes" : "no");
printf("Pretty-printer support: %s\n", CBOR_PRETTY_PRINTER ? "yes" : "no");
printf("Buffer growth factor: %f\n", (float)CBOR_BUFFER_GROWTH);
}
diff --git a/examples/readfile.c b/examples/readfile.c
index 213ee77f0fdd..3f8db6152800 100644
--- a/examples/readfile.c
+++ b/examples/readfile.c
@@ -8,7 +8,7 @@
#include <stdio.h>
#include "cbor.h"
-void usage() {
+void usage(void) {
printf("Usage: readfile [input file]\n");
exit(1);
}
@@ -31,6 +31,7 @@ int main(int argc, char* argv[]) {
/* Assuming `buffer` contains `length` bytes of input data */
struct cbor_load_result result;
cbor_item_t* item = cbor_load(buffer, length, &result);
+ free(buffer);
if (result.error.code != CBOR_ERR_NONE) {
printf(
diff --git a/examples/sort.c b/examples/sort.c
index d5e3aaff9dbe..22f3760b4843 100644
--- a/examples/sort.c
+++ b/examples/sort.c
@@ -14,7 +14,7 @@
* standard library functions.
*/
-int comparUint(const void *a, const void *b) {
+int compareUint(const void *a, const void *b) {
uint8_t av = cbor_get_uint8(*(cbor_item_t **)a),
bv = cbor_get_uint8(*(cbor_item_t **)b);
@@ -26,15 +26,16 @@ int comparUint(const void *a, const void *b) {
return 1;
}
-int main(int argc, char *argv[]) {
+int main(void) {
cbor_item_t *array = cbor_new_definite_array(4);
- cbor_array_push(array, cbor_move(cbor_build_uint8(4)));
- cbor_array_push(array, cbor_move(cbor_build_uint8(3)));
- cbor_array_push(array, cbor_move(cbor_build_uint8(1)));
- cbor_array_push(array, cbor_move(cbor_build_uint8(2)));
+ bool success = cbor_array_push(array, cbor_move(cbor_build_uint8(4)));
+ success &= cbor_array_push(array, cbor_move(cbor_build_uint8(3)));
+ success &= cbor_array_push(array, cbor_move(cbor_build_uint8(1)));
+ success &= cbor_array_push(array, cbor_move(cbor_build_uint8(2)));
+ if (!success) return 1;
qsort(cbor_array_handle(array), cbor_array_size(array), sizeof(cbor_item_t *),
- comparUint);
+ compareUint);
cbor_describe(array, stdout);
fflush(stdout);
diff --git a/examples/streaming_array.c b/examples/streaming_array.c
new file mode 100644
index 000000000000..d165e62b1c9e
--- /dev/null
+++ b/examples/streaming_array.c
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2014-2020 Pavel Kalvoda <me@pavelkalvoda.com>
+ *
+ * libcbor is free software; you can redistribute it and/or modify
+ * it under the terms of the MIT license. See LICENSE for details.
+ */
+
+#include <stdlib.h>
+#include "cbor.h"
+
+void usage(void) {
+ printf("Usage: streaming_array <N>\n");
+ printf("Prints out serialized array [0, ..., N-1]\n");
+ exit(1);
+}
+
+#define BUFFER_SIZE 8
+unsigned char buffer[BUFFER_SIZE];
+FILE* out;
+
+void flush(size_t bytes) {
+ if (bytes == 0) exit(1); // All items should be successfully encoded
+ if (fwrite(buffer, sizeof(unsigned char), bytes, out) != bytes) exit(1);
+ if (fflush(out)) exit(1);
+}
+
+/*
+ * Example of using the streaming encoding API to create an array of integers
+ * on the fly. Notice that a partial output is produced with every element.
+ */
+int main(int argc, char* argv[]) {
+ if (argc != 2) usage();
+ long n = strtol(argv[1], NULL, 10);
+ out = freopen(NULL, "wb", stdout);
+ if (!out) exit(1);
+
+ // Start an indefinite-length array
+ flush(cbor_encode_indef_array_start(buffer, BUFFER_SIZE));
+ // Write the array items one by one
+ for (size_t i = 0; i < n; i++) {
+ flush(cbor_encode_uint32(i, buffer, BUFFER_SIZE));
+ }
+ // Close the array
+ flush(cbor_encode_break(buffer, BUFFER_SIZE));
+
+ if (fclose(out)) exit(1);
+}
diff --git a/examples/streaming_parser.c b/examples/streaming_parser.c
index fe3ab853d978..f5eacb4fb7ac 100644
--- a/examples/streaming_parser.c
+++ b/examples/streaming_parser.c
@@ -9,7 +9,13 @@
#include <string.h>
#include "cbor.h"
-void usage() {
+#ifdef __GNUC__
+#define UNUSED(x) __attribute__((__unused__)) x
+#else
+#define UNUSED(x) x
+#endif
+
+void usage(void) {
printf("Usage: streaming_parser [input file]\n");
exit(1);
}
@@ -24,7 +30,7 @@ void usage() {
const char* key = "a secret key";
bool key_found = false;
-void find_string(void* _ctx, cbor_data buffer, size_t len) {
+void find_string(void* UNUSED(_ctx), cbor_data buffer, uint64_t len) {
if (key_found) {
printf("Found the value: %.*s\n", (int)len, buffer);
key_found = false;
diff --git a/misc/update_version.py b/misc/update_version.py
index eb330215d375..475953021cc4 100755
--- a/misc/update_version.py
+++ b/misc/update_version.py
@@ -1,5 +1,14 @@
import sys, re
from datetime import date
+import logging
+
+logging.basicConfig(level=logging.INFO)
+
+# Update version label in all configuration files
+# Usage: python3 misc/update_version.py X.Y.Z
+
+# When testing, reset local state using:
+# git checkout -- CHANGELOG.md Doxyfile CMakeLists.txt doc/source/conf.py examples/bazel/third_party/libcbor/cbor/configuration.h
version = sys.argv[1]
release_date = date.today().strftime('%Y-%m-%d')
@@ -7,7 +16,10 @@ major, minor, patch = version.split('.')
def replace(file_path, pattern, replacement):
- updated = re.sub(pattern, replacement, open(file_path).read())
+ logging.info(f'Updating {file_path}')
+ original = open(file_path).read()
+ updated = re.sub(pattern, replacement, original)
+ assert updated != original
with open(file_path, 'w') as f:
f.write(updated)
@@ -23,13 +35,22 @@ replace('Doxyfile', DOXY_VERSION + '.*', DOXY_VERSION + version)
# Update CMakeLists.txt
replace('CMakeLists.txt',
- '''SET\\(CBOR_VERSION_MAJOR "0"\\)
-SET\\(CBOR_VERSION_MINOR "7"\\)
-SET\\(CBOR_VERSION_PATCH "0"\\)''',
+ '''SET\\(CBOR_VERSION_MAJOR "\d+"\\)
+SET\\(CBOR_VERSION_MINOR "\d+"\\)
+SET\\(CBOR_VERSION_PATCH "\d+"\\)''',
f'''SET(CBOR_VERSION_MAJOR "{major}")
SET(CBOR_VERSION_MINOR "{minor}")
SET(CBOR_VERSION_PATCH "{patch}")''')
+# Update Basel build example
+replace('examples/bazel/third_party/libcbor/cbor/configuration.h',
+ '''#define CBOR_MAJOR_VERSION \d+
+#define CBOR_MINOR_VERSION \d+
+#define CBOR_PATCH_VERSION \d+''',
+ f'''#define CBOR_MAJOR_VERSION {major}
+#define CBOR_MINOR_VERSION {minor}
+#define CBOR_PATCH_VERSION {patch}''')
+
# Update Sphinx
replace('doc/source/conf.py',
"""version = '.*'
diff --git a/oss-fuzz/build.sh b/oss-fuzz/build.sh
index 4b19b7203f8b..10853a398734 100755
--- a/oss-fuzz/build.sh
+++ b/oss-fuzz/build.sh
@@ -18,7 +18,7 @@
mkdir build
cd build
# We disable libcbor's default sanitizers since we'll be configuring them ourselves via CFLAGS.
-cmake -D CMAKE_BUILD_TYPE=Debug -D CMAKE_INSTALL_PREFIX="$WORK" -D CBOR_CUSTOM_ALLOC=ON -D SANITIZE=OFF ..
+cmake -D CMAKE_BUILD_TYPE=Debug -D CMAKE_INSTALL_PREFIX="$WORK" -D SANITIZE=OFF ..
make "-j$(nproc)"
make install
diff --git a/oss-fuzz/cbor_load_fuzzer.cc b/oss-fuzz/cbor_load_fuzzer.cc
index b32a082bb8a9..0ab04e5a1374 100644
--- a/oss-fuzz/cbor_load_fuzzer.cc
+++ b/oss-fuzz/cbor_load_fuzzer.cc
@@ -1,20 +1,68 @@
#include <cstdint>
#include <cstdio>
+#include <cstdlib>
+#include <unordered_map>
#include "cbor.h"
+static size_t allocated_mem = 0;
+static std::unordered_map<void*, size_t> allocated_len_map;
+static constexpr size_t kMemoryLimit = 1 << 30;
+
void *limited_malloc(size_t size) {
- if (size > 1 << 24) {
+ if (size + allocated_mem > kMemoryLimit) {
+ return nullptr;
+ }
+ if (size == 0) {
return nullptr;
}
- return malloc(size);
+ void* m = malloc(size);
+ if (m != nullptr) {
+ allocated_mem += size;
+ allocated_len_map[m] = size;
+ }
+ return m;
+}
+
+void limited_free(void *ptr) {
+ if (ptr != NULL && allocated_len_map.find(ptr) == allocated_len_map.end()) {
+ abort();
+ }
+ free(ptr);
+ if (ptr != NULL) {
+ allocated_mem -= allocated_len_map[ptr];
+ allocated_len_map.erase(ptr);
+ }
+}
+
+void *limited_realloc(void *ptr, size_t size) {
+ if (ptr != NULL && allocated_len_map.find(ptr) == allocated_len_map.end()) {
+ abort();
+ }
+ if (ptr == NULL) {
+ return limited_malloc(size);
+ }
+ long delta = (long) size - allocated_len_map[ptr];
+ if (delta + allocated_mem > kMemoryLimit) {
+ return nullptr;
+ }
+ void* new_ptr = realloc(ptr, size);
+ if (size > 0 && new_ptr == nullptr) {
+ return nullptr;
+ }
+ allocated_mem += delta;
+ allocated_len_map.erase(ptr);
+ if (size > 0) {
+ allocated_len_map[new_ptr] = size;
+ }
+ return new_ptr;
}
struct State {
FILE* fout;
State() : fout(fopen("/dev/null", "r")) {
- cbor_set_allocs(limited_malloc, realloc, free);
+ cbor_set_allocs(limited_malloc, limited_realloc, limited_free);
}
};
diff --git a/release.sh b/release.sh
index 2fd73d967c22..ec56862883eb 100755
--- a/release.sh
+++ b/release.sh
@@ -22,7 +22,7 @@ cd $DIR
python3 misc/update_version.py "$1"
echo ">>>>> Checking changelog"
-grep -A 5 -F "$1" CHANGELOG.md || true
+grep -A 10 -F "$1" CHANGELOG.md || true
prompt "Is the changelog correct and complete?"
echo ">>>>> Checking Doxyfile"
@@ -33,6 +33,10 @@ echo ">>>>> Checking CMakeLists"
grep -A 2 'SET(CBOR_VERSION_MAJOR' CMakeLists.txt
prompt "Is the CMake version correct?"
+echo ">>>>> Checking Bazel build"
+grep -A 2 'CBOR_MAJOR_VERSION' examples/bazel/third_party/libcbor/cbor/configuration.h
+prompt "Is the version correct?"
+
echo ">>>>> Checking docs"
grep 'version =\|release =' doc/source/conf.py
prompt "Are the versions correct?"
@@ -61,7 +65,9 @@ ctest
popd
prompt "Will proceed to tag the release with $TAG_NAME."
+git commit -a -m "Release $TAG_NAME"
git tag "$TAG_NAME"
+git push --set-upstream origin $(git rev-parse --abbrev-ref HEAD)
git push --tags
set +x
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 2a1492bf6ee3..72a0c901556d 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -1,12 +1,10 @@
-set(SOURCES cbor.c cbor/streaming.c cbor/internal/encoders.c cbor/internal/builder_callbacks.c cbor/internal/loaders.c cbor/internal/memory_utils.c cbor/internal/stack.c cbor/internal/unicode.c cbor/encoding.c cbor/serialization.c cbor/arrays.c cbor/common.c cbor/floats_ctrls.c cbor/bytestrings.c cbor/callbacks.c cbor/strings.c cbor/maps.c cbor/tags.c cbor/ints.c)
+set(SOURCES cbor.c allocators.c cbor/streaming.c cbor/internal/encoders.c cbor/internal/builder_callbacks.c cbor/internal/loaders.c cbor/internal/memory_utils.c cbor/internal/stack.c cbor/internal/unicode.c cbor/encoding.c cbor/serialization.c cbor/arrays.c cbor/common.c cbor/floats_ctrls.c cbor/bytestrings.c cbor/callbacks.c cbor/strings.c cbor/maps.c cbor/tags.c cbor/ints.c)
include(GNUInstallDirs)
+include(JoinPaths)
+include(CheckFunctionExists)
set(CMAKE_SKIP_BUILD_RPATH FALSE)
-if (CBOR_CUSTOM_ALLOC)
- LIST(APPEND SOURCES allocators.c)
-endif(CBOR_CUSTOM_ALLOC)
-
if (NOT DEFINED CMAKE_MACOSX_RPATH)
set(CMAKE_MACOSX_RPATH 0)
endif()
@@ -14,6 +12,12 @@ endif()
add_library(cbor ${SOURCES})
target_include_directories(cbor PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
+# Explicitly link math.h if necessary
+check_function_exists(ldexp LDEXP_AVAILABLE)
+if (NOT LDEXP_AVAILABLE)
+ target_link_libraries(cbor m)
+endif()
+
include(GenerateExportHeader)
generate_export_header(cbor EXPORT_FILE_NAME ${CMAKE_CURRENT_BINARY_DIR}/cbor/cbor_export.h)
target_include_directories(cbor PUBLIC ${CMAKE_CURRENT_BINARY_DIR})
@@ -28,6 +32,8 @@ set_target_properties(cbor PROPERTIES
MACHO_COMPATIBILITY_VERSION ${CBOR_VERSION_MAJOR}.${CBOR_VERSION_MINOR}.0
SOVERSION ${CBOR_VERSION_MAJOR}.${CBOR_VERSION_MINOR})
+join_paths(libdir_for_pc_file "\${prefix}" "${CMAKE_INSTALL_LIBDIR}")
+join_paths(includedir_for_pc_file "\${prefix}" "${CMAKE_INSTALL_INCLUDEDIR}")
configure_file(libcbor.pc.in libcbor.pc @ONLY)
# http://www.cmake.org/Wiki/CMake:Install_Commands
@@ -42,4 +48,4 @@ install(DIRECTORY cbor DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}
install(FILES cbor.h DESTINATION ${CMAKE_INSTALL_INCLUDEDIR})
install(FILES "${CMAKE_CURRENT_BINARY_DIR}/libcbor.pc"
- DESTINATION "${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR}/pkgconfig")
+ DESTINATION "${CMAKE_INSTALL_LIBDIR}/pkgconfig")
diff --git a/src/cbor.c b/src/cbor.c
index 76b892c6b709..626ddddaecfc 100644
--- a/src/cbor.c
+++ b/src/cbor.c
@@ -83,7 +83,7 @@ cbor_item_t *cbor_load(cbor_data source, size_t source_size,
goto error;
}
case CBOR_DECODER_ERROR:
- /* Reserved/malformated item */
+ /* Reserved/malformed item */
{
result->error.code = CBOR_ERR_MALFORMATED;
goto error;
@@ -100,9 +100,7 @@ cbor_item_t *cbor_load(cbor_data source, size_t source_size,
}
} while (stack.size > 0);
- /* Move the result before free */
- cbor_item_t *result_item = context.root;
- return result_item;
+ return context.root;
error:
result->error.position = result->read;
@@ -131,8 +129,6 @@ static cbor_item_t *_cbor_copy_int(cbor_item_t *item, bool negative) {
case CBOR_INT_64:
res = cbor_build_uint64(cbor_get_uint64(item));
break;
- default:
- return NULL;
}
if (negative) cbor_mark_negint(res);
@@ -141,6 +137,7 @@ static cbor_item_t *_cbor_copy_int(cbor_item_t *item, bool negative) {
}
static cbor_item_t *_cbor_copy_float_ctrl(cbor_item_t *item) {
+ // cppcheck-suppress missingReturn
switch (cbor_float_get_width(item)) {
case CBOR_FLOAT_0:
return cbor_build_ctrl(cbor_ctrl_value(item));
@@ -151,11 +148,10 @@ static cbor_item_t *_cbor_copy_float_ctrl(cbor_item_t *item) {
case CBOR_FLOAT_64:
return cbor_build_float8(cbor_float_get_float8(item));
}
-
- return NULL;
}
cbor_item_t *cbor_copy(cbor_item_t *item) {
+ // cppcheck-suppress missingReturn
switch (cbor_typeof(item)) {
case CBOR_TYPE_UINT:
return _cbor_copy_int(item, false);
@@ -167,10 +163,24 @@ cbor_item_t *cbor_copy(cbor_item_t *item) {
cbor_bytestring_length(item));
} else {
cbor_item_t *res = cbor_new_indefinite_bytestring();
- for (size_t i = 0; i < cbor_bytestring_chunk_count(item); i++)
- cbor_bytestring_add_chunk(
- res,
- cbor_move(cbor_copy(cbor_bytestring_chunks_handle(item)[i])));
+ if (res == NULL) {
+ return NULL;
+ }
+
+ for (size_t i = 0; i < cbor_bytestring_chunk_count(item); i++) {
+ cbor_item_t *chunk_copy =
+ cbor_copy(cbor_bytestring_chunks_handle(item)[i]);
+ if (chunk_copy == NULL) {
+ cbor_decref(&res);
+ return NULL;
+ }
+ if (!cbor_bytestring_add_chunk(res, chunk_copy)) {
+ cbor_decref(&chunk_copy);
+ cbor_decref(&res);
+ return NULL;
+ }
+ cbor_decref(&chunk_copy);
+ }
return res;
}
case CBOR_TYPE_STRING:
@@ -179,46 +189,100 @@ cbor_item_t *cbor_copy(cbor_item_t *item) {
cbor_string_length(item));
} else {
cbor_item_t *res = cbor_new_indefinite_string();
- for (size_t i = 0; i < cbor_string_chunk_count(item); i++)
- cbor_string_add_chunk(
- res, cbor_move(cbor_copy(cbor_string_chunks_handle(item)[i])));
+ if (res == NULL) {
+ return NULL;
+ }
+
+ for (size_t i = 0; i < cbor_string_chunk_count(item); i++) {
+ cbor_item_t *chunk_copy =
+ cbor_copy(cbor_string_chunks_handle(item)[i]);
+ if (chunk_copy == NULL) {
+ cbor_decref(&res);
+ return NULL;
+ }
+ if (!cbor_string_add_chunk(res, chunk_copy)) {
+ cbor_decref(&chunk_copy);
+ cbor_decref(&res);
+ return NULL;
+ }
+ cbor_decref(&chunk_copy);
+ }
return res;
}
case CBOR_TYPE_ARRAY: {
cbor_item_t *res;
- if (cbor_array_is_definite(item))
+ if (cbor_array_is_definite(item)) {
res = cbor_new_definite_array(cbor_array_size(item));
- else
+ } else {
res = cbor_new_indefinite_array();
+ }
+ if (res == NULL) {
+ return NULL;
+ }
- for (size_t i = 0; i < cbor_array_size(item); i++)
- cbor_array_push(
- res, cbor_move(cbor_copy(cbor_move(cbor_array_get(item, i)))));
+ for (size_t i = 0; i < cbor_array_size(item); i++) {
+ cbor_item_t *entry_copy = cbor_copy(cbor_move(cbor_array_get(item, i)));
+ if (entry_copy == NULL) {
+ cbor_decref(&res);
+ return NULL;
+ }
+ if (!cbor_array_push(res, entry_copy)) {
+ cbor_decref(&entry_copy);
+ cbor_decref(&res);
+ return NULL;
+ }
+ cbor_decref(&entry_copy);
+ }
return res;
}
case CBOR_TYPE_MAP: {
cbor_item_t *res;
- if (cbor_map_is_definite(item))
+ if (cbor_map_is_definite(item)) {
res = cbor_new_definite_map(cbor_map_size(item));
- else
+ } else {
res = cbor_new_indefinite_map();
+ }
+ if (res == NULL) {
+ return NULL;
+ }
struct cbor_pair *it = cbor_map_handle(item);
- for (size_t i = 0; i < cbor_map_size(item); i++)
- cbor_map_add(res, (struct cbor_pair){
- .key = cbor_move(cbor_copy(it[i].key)),
- .value = cbor_move(cbor_copy(it[i].value))});
+ for (size_t i = 0; i < cbor_map_size(item); i++) {
+ cbor_item_t *key_copy = cbor_copy(it[i].key);
+ if (key_copy == NULL) {
+ cbor_decref(&res);
+ return NULL;
+ }
+ cbor_item_t *value_copy = cbor_copy(it[i].value);
+ if (value_copy == NULL) {
+ cbor_decref(&res);
+ cbor_decref(&key_copy);
+ return NULL;
+ }
+ if (!cbor_map_add(res, (struct cbor_pair){.key = key_copy,
+ .value = value_copy})) {
+ cbor_decref(&res);
+ cbor_decref(&key_copy);
+ cbor_decref(&value_copy);
+ return NULL;
+ }
+ cbor_decref(&key_copy);
+ cbor_decref(&value_copy);
+ }
return res;
}
- case CBOR_TYPE_TAG:
- return cbor_build_tag(
- cbor_tag_value(item),
- cbor_move(cbor_copy(cbor_move(cbor_tag_item(item)))));
+ case CBOR_TYPE_TAG: {
+ cbor_item_t *item_copy = cbor_copy(cbor_move(cbor_tag_item(item)));
+ if (item_copy == NULL) {
+ return NULL;
+ }
+ cbor_item_t *tag = cbor_build_tag(cbor_tag_value(item), item_copy);
+ cbor_decref(&item_copy);
+ return tag;
+ }
case CBOR_TYPE_FLOAT_CTRL:
return _cbor_copy_float_ctrl(item);
}
-
- return NULL;
}
#if CBOR_PRETTY_PRINTER
@@ -245,13 +309,13 @@ static void _cbor_nested_describe(cbor_item_t *item, FILE *out, int indent) {
fprintf(out, "Width: %dB, ", _pow(2, cbor_int_get_width(item)));
fprintf(out, "Value: %" PRIu64 "\n", cbor_get_int(item));
break;
- };
+ }
case CBOR_TYPE_NEGINT: {
fprintf(out, "%*s[CBOR_TYPE_NEGINT] ", indent, " ");
fprintf(out, "Width: %dB, ", _pow(2, cbor_int_get_width(item)));
fprintf(out, "Value: -%" PRIu64 " -1\n", cbor_get_int(item));
break;
- };
+ }
case CBOR_TYPE_BYTESTRING: {
fprintf(out, "%*s[CBOR_TYPE_BYTESTRING] ", indent, " ");
if (cbor_bytestring_is_indefinite(item)) {
@@ -264,7 +328,7 @@ static void _cbor_nested_describe(cbor_item_t *item, FILE *out, int indent) {
fprintf(out, "Definite, length %zuB\n", cbor_bytestring_length(item));
}
break;
- };
+ }
case CBOR_TYPE_STRING: {
fprintf(out, "%*s[CBOR_TYPE_STRING] ", indent, " ");
if (cbor_string_is_indefinite(item)) {
@@ -285,7 +349,7 @@ static void _cbor_nested_describe(cbor_item_t *item, FILE *out, int indent) {
fprintf(out, "\n");
}
break;
- };
+ }
case CBOR_TYPE_ARRAY: {
fprintf(out, "%*s[CBOR_TYPE_ARRAY] ", indent, " ");
if (cbor_array_is_definite(item)) {
@@ -297,7 +361,7 @@ static void _cbor_nested_describe(cbor_item_t *item, FILE *out, int indent) {
for (size_t i = 0; i < cbor_array_size(item); i++)
_cbor_nested_describe(cbor_array_handle(item)[i], out, indent + 4);
break;
- };
+ }
case CBOR_TYPE_MAP: {
fprintf(out, "%*s[CBOR_TYPE_MAP] ", indent, " ");
if (cbor_map_is_definite(item)) {
@@ -311,13 +375,13 @@ static void _cbor_nested_describe(cbor_item_t *item, FILE *out, int indent) {
_cbor_nested_describe(cbor_map_handle(item)[i].value, out, indent + 4);
}
break;
- };
+ }
case CBOR_TYPE_TAG: {
fprintf(out, "%*s[CBOR_TYPE_TAG] ", indent, " ");
fprintf(out, "Value: %" PRIu64 "\n", cbor_tag_value(item));
_cbor_nested_describe(cbor_move(cbor_tag_item(item)), out, indent + 4);
break;
- };
+ }
case CBOR_TYPE_FLOAT_CTRL: {
fprintf(out, "%*s[CBOR_TYPE_FLOAT_CTRL] ", indent, " ");
if (cbor_float_ctrl_is_ctrl(item)) {
@@ -334,7 +398,7 @@ static void _cbor_nested_describe(cbor_item_t *item, FILE *out, int indent) {
fprintf(out, "value: %lf\n", cbor_float_get_float(item));
}
break;
- };
+ }
}
}
diff --git a/src/cbor.h b/src/cbor.h
index d490e6c5862e..46ef8f267ac9 100644
--- a/src/cbor.h
+++ b/src/cbor.h
@@ -39,21 +39,27 @@ extern "C" {
*
* @param source The buffer
* @param source_size
- * @param result[out] Result indicator. #CBOR_ERR_NONE on success
- * @return **new** CBOR item or `NULL` on failure. In that case, \p result
- * contains location and description of the error.
+ * @param[out] result Result indicator. #CBOR_ERR_NONE on success
+ * @return Decoded CBOR item. The item's reference count is initialized to one.
+ * @return `NULL` on failure. In that case, \p result contains the location and
+ * description of the error.
*/
-CBOR_EXPORT cbor_item_t* cbor_load(cbor_data source, size_t source_size,
- struct cbor_load_result* result);
+_CBOR_NODISCARD CBOR_EXPORT cbor_item_t* cbor_load(
+ cbor_data source, size_t source_size, struct cbor_load_result* result);
-/** Deep copy of an item
+/** Take a deep copy of an item
*
- * All the reference counts in the new structure are set to one.
+ * All items this item points to (array and map members, string chunks, tagged
+ * items) will be copied recursively using #cbor_copy. The new item doesn't
+ * alias or point to any items from the original \p item. All the reference
+ * counts in the new structure are set to one.
*
- * @param item[borrow] item to copy
- * @return **new** CBOR deep copy
+ * @param item item to copy
+ * @return Reference to the new item. The item's reference count is initialized
+ * to one.
+ * @return `NULL` if memory allocation fails
*/
-CBOR_EXPORT cbor_item_t* cbor_copy(cbor_item_t* item);
+_CBOR_NODISCARD CBOR_EXPORT cbor_item_t* cbor_copy(cbor_item_t* item);
#if CBOR_PRETTY_PRINTER
#include <stdio.h>
diff --git a/src/cbor/arrays.c b/src/cbor/arrays.c
index c1d01afafee1..a23bbe3cd152 100644
--- a/src/cbor/arrays.c
+++ b/src/cbor/arrays.c
@@ -10,12 +10,12 @@
#include "internal/memory_utils.h"
size_t cbor_array_size(const cbor_item_t *item) {
- assert(cbor_isa_array(item));
+ CBOR_ASSERT(cbor_isa_array(item));
return item->metadata.array_metadata.end_ptr;
}
size_t cbor_array_allocated(const cbor_item_t *item) {
- assert(cbor_isa_array(item));
+ CBOR_ASSERT(cbor_isa_array(item));
return item->metadata.array_metadata.allocated;
}
@@ -31,9 +31,6 @@ bool cbor_array_set(cbor_item_t *item, size_t index, cbor_item_t *value) {
} else {
return false;
}
- // TODO: This is unreachable and the index checking logic above seems
- // suspicious -- out of bounds index is a caller error. Figure out & fix.
- return true;
}
bool cbor_array_replace(cbor_item_t *item, size_t index, cbor_item_t *value) {
@@ -45,7 +42,7 @@ bool cbor_array_replace(cbor_item_t *item, size_t index, cbor_item_t *value) {
}
bool cbor_array_push(cbor_item_t *array, cbor_item_t *pushee) {
- assert(cbor_isa_array(array));
+ CBOR_ASSERT(cbor_isa_array(array));
struct _cbor_array_metadata *metadata =
(struct _cbor_array_metadata *)&array->metadata;
cbor_item_t **data = (cbor_item_t **)array->data;
@@ -59,7 +56,6 @@ bool cbor_array_push(cbor_item_t *array, cbor_item_t *pushee) {
/* Exponential realloc */
if (metadata->end_ptr >= metadata->allocated) {
// Check for overflows first
- // TODO: Explicitly test this
if (!_cbor_safe_to_multiply(CBOR_BUFFER_GROWTH, metadata->allocated)) {
return false;
}
@@ -84,22 +80,22 @@ bool cbor_array_push(cbor_item_t *array, cbor_item_t *pushee) {
}
bool cbor_array_is_definite(const cbor_item_t *item) {
- assert(cbor_isa_array(item));
+ CBOR_ASSERT(cbor_isa_array(item));
return item->metadata.array_metadata.type == _CBOR_METADATA_DEFINITE;
}
bool cbor_array_is_indefinite(const cbor_item_t *item) {
- assert(cbor_isa_array(item));
+ CBOR_ASSERT(cbor_isa_array(item));
return item->metadata.array_metadata.type == _CBOR_METADATA_INDEFINITE;
}
cbor_item_t **cbor_array_handle(const cbor_item_t *item) {
- assert(cbor_isa_array(item));
+ CBOR_ASSERT(cbor_isa_array(item));
return (cbor_item_t **)item->data;
}
cbor_item_t *cbor_new_definite_array(size_t size) {
- cbor_item_t *item = _CBOR_MALLOC(sizeof(cbor_item_t));
+ cbor_item_t *item = _cbor_malloc(sizeof(cbor_item_t));
_CBOR_NOTNULL(item);
cbor_item_t **data = _cbor_alloc_multiple(sizeof(cbor_item_t *), size);
_CBOR_DEPENDENT_NOTNULL(item, data);
@@ -119,8 +115,8 @@ cbor_item_t *cbor_new_definite_array(size_t size) {
return item;
}
-cbor_item_t *cbor_new_indefinite_array() {
- cbor_item_t *item = _CBOR_MALLOC(sizeof(cbor_item_t));
+cbor_item_t *cbor_new_indefinite_array(void) {
+ cbor_item_t *item = _cbor_malloc(sizeof(cbor_item_t));
_CBOR_NOTNULL(item);
*item = (cbor_item_t){
diff --git a/src/cbor/arrays.h b/src/cbor/arrays.h
index 85fe51dcd8dc..db19e59d0624 100644
--- a/src/cbor/arrays.h
+++ b/src/cbor/arrays.h
@@ -17,62 +17,74 @@ extern "C" {
/** Get the number of members
*
- * @param item[borrow] An array
+ * @param item An array
* @return The number of members
*/
+_CBOR_NODISCARD
CBOR_EXPORT size_t cbor_array_size(const cbor_item_t* item);
/** Get the size of the allocated storage
*
- * @param item[borrow] An array
+ * @param item An array
* @return The size of the allocated storage (number of items)
*/
+_CBOR_NODISCARD
CBOR_EXPORT size_t cbor_array_allocated(const cbor_item_t* item);
/** Get item by index
*
- * @param item[borrow] An array
- * @param index The index
- * @return **incref** The item, or `NULL` in case of boundary violation
+ * @param item An array
+ * @param index The index (zero-based)
+ * @return Reference to the item, or `NULL` in case of boundary violation.
+ *
+ * Increases the reference count of the underlying item. The returned reference
+ * must be released using #cbor_decref.
*/
+_CBOR_NODISCARD
CBOR_EXPORT cbor_item_t* cbor_array_get(const cbor_item_t* item, size_t index);
/** Set item by index
*
- * Creating arrays with holes is not possible
+ * If the index is out of bounds, the array is not modified and false is
+ * returned. Creating arrays with holes is not possible.
*
- * @param item[borrow] An array
- * @param value[incref] The item to assign
- * @param index The index, first item is 0.
- * @return true on success, false on allocation failure.
+ * @param item An array
+ * @param value The item to assign
+ * @param index The index (zero-based)
+ * @return `true` on success, `false` on allocation failure.
*/
+_CBOR_NODISCARD
CBOR_EXPORT bool cbor_array_set(cbor_item_t* item, size_t index,
cbor_item_t* value);
/** Replace item at an index
*
- * The item being replace will be #cbor_decref 'ed.
+ * The reference to the item being replaced will be released using #cbor_decref.
*
- * @param item[borrow] An array
- * @param value[incref] The item to assign
- * @param index The index, first item is 0.
+ * @param item An array
+ * @param value The item to assign. Its reference count will be increased by
+ * one.
+ * @param index The index (zero-based)
* @return true on success, false on allocation failure.
*/
+_CBOR_NODISCARD
CBOR_EXPORT bool cbor_array_replace(cbor_item_t* item, size_t index,
cbor_item_t* value);
/** Is the array definite?
*
- * @param item[borrow] An array
+ * @param item An array
* @return Is the array definite?
*/
+_CBOR_NODISCARD
CBOR_EXPORT bool cbor_array_is_definite(const cbor_item_t* item);
/** Is the array indefinite?
*
- * @param item[borrow] An array
+ * @param item An array
* @return Is the array indefinite?
*/
+_CBOR_NODISCARD
CBOR_EXPORT bool cbor_array_is_indefinite(const cbor_item_t* item);
/** Get the array contents
@@ -80,33 +92,42 @@ CBOR_EXPORT bool cbor_array_is_indefinite(const cbor_item_t* item);
* The items may be reordered and modified as long as references remain
* consistent.
*
- * @param item[borrow] An array
- * @return #cbor_array_size items
+ * @param item An array item
+ * @return An array of #cbor_item_t pointers of size #cbor_array_size.
*/
+_CBOR_NODISCARD
CBOR_EXPORT cbor_item_t** cbor_array_handle(const cbor_item_t* item);
/** Create new definite array
*
* @param size Number of slots to preallocate
- * @return **new** array or `NULL` upon malloc failure
+ * @return Reference to the new array item. The item's reference count is
+ * initialized to one.
+ * @return `NULL` if memory allocation fails
*/
+_CBOR_NODISCARD
CBOR_EXPORT cbor_item_t* cbor_new_definite_array(size_t size);
/** Create new indefinite array
*
- * @return **new** array or `NULL` upon malloc failure
+ * @return Reference to the new array item. The item's reference count is
+ * initialized to one.
+ * @return `NULL` if memory allocation fails
*/
-CBOR_EXPORT cbor_item_t* cbor_new_indefinite_array();
+_CBOR_NODISCARD
+CBOR_EXPORT cbor_item_t* cbor_new_indefinite_array(void);
/** Append to the end
*
- * For indefinite items, storage may be realloacted. For definite items, only
+ * For indefinite items, storage may be reallocated. For definite items, only
* the preallocated capacity is available.
*
- * @param array[borrow] An array
- * @param pushee[incref] The item to push
- * @return true on success, false on failure
+ * @param array An array
+ * @param pushee The item to push. Its reference count will be increased by
+ * one.
+ * @return `true` on success, `false` on failure
*/
+_CBOR_NODISCARD
CBOR_EXPORT bool cbor_array_push(cbor_item_t* array, cbor_item_t* pushee);
#ifdef __cplusplus
diff --git a/src/cbor/bytestrings.c b/src/cbor/bytestrings.c
index 75a737bd92ae..528937179aee 100644
--- a/src/cbor/bytestrings.c
+++ b/src/cbor/bytestrings.c
@@ -10,17 +10,17 @@
#include "internal/memory_utils.h"
size_t cbor_bytestring_length(const cbor_item_t *item) {
- assert(cbor_isa_bytestring(item));
+ CBOR_ASSERT(cbor_isa_bytestring(item));
return item->metadata.bytestring_metadata.length;
}
unsigned char *cbor_bytestring_handle(const cbor_item_t *item) {
- assert(cbor_isa_bytestring(item));
+ CBOR_ASSERT(cbor_isa_bytestring(item));
return item->data;
}
bool cbor_bytestring_is_definite(const cbor_item_t *item) {
- assert(cbor_isa_bytestring(item));
+ CBOR_ASSERT(cbor_isa_bytestring(item));
return item->metadata.bytestring_metadata.type == _CBOR_METADATA_DEFINITE;
}
@@ -28,25 +28,26 @@ bool cbor_bytestring_is_indefinite(const cbor_item_t *item) {
return !cbor_bytestring_is_definite(item);
}
-cbor_item_t *cbor_new_definite_bytestring() {
- cbor_item_t *item = _CBOR_MALLOC(sizeof(cbor_item_t));
+cbor_item_t *cbor_new_definite_bytestring(void) {
+ cbor_item_t *item = _cbor_malloc(sizeof(cbor_item_t));
_CBOR_NOTNULL(item);
*item = (cbor_item_t){
.refcount = 1,
.type = CBOR_TYPE_BYTESTRING,
- .metadata = {.bytestring_metadata = {_CBOR_METADATA_DEFINITE, 0}}};
+ .metadata = {.bytestring_metadata = {.type = _CBOR_METADATA_DEFINITE,
+ .length = 0}}};
return item;
}
-cbor_item_t *cbor_new_indefinite_bytestring() {
- cbor_item_t *item = _CBOR_MALLOC(sizeof(cbor_item_t));
+cbor_item_t *cbor_new_indefinite_bytestring(void) {
+ cbor_item_t *item = _cbor_malloc(sizeof(cbor_item_t));
_CBOR_NOTNULL(item);
*item = (cbor_item_t){
.refcount = 1,
.type = CBOR_TYPE_BYTESTRING,
.metadata = {.bytestring_metadata = {.type = _CBOR_METADATA_INDEFINITE,
.length = 0}},
- .data = _CBOR_MALLOC(sizeof(struct cbor_indefinite_string_data))};
+ .data = _cbor_malloc(sizeof(struct cbor_indefinite_string_data))};
_CBOR_DEPENDENT_NOTNULL(item, item->data);
*((struct cbor_indefinite_string_data *)item->data) =
(struct cbor_indefinite_string_data){
@@ -60,7 +61,7 @@ cbor_item_t *cbor_new_indefinite_bytestring() {
cbor_item_t *cbor_build_bytestring(cbor_data handle, size_t length) {
cbor_item_t *item = cbor_new_definite_bytestring();
_CBOR_NOTNULL(item);
- void *content = _CBOR_MALLOC(length);
+ void *content = _cbor_malloc(length);
_CBOR_DEPENDENT_NOTNULL(item, content);
memcpy(content, handle, length);
cbor_bytestring_set_handle(item, content, length);
@@ -70,31 +71,32 @@ cbor_item_t *cbor_build_bytestring(cbor_data handle, size_t length) {
void cbor_bytestring_set_handle(cbor_item_t *item,
cbor_mutable_data CBOR_RESTRICT_POINTER data,
size_t length) {
- assert(cbor_isa_bytestring(item));
- assert(cbor_bytestring_is_definite(item));
+ CBOR_ASSERT(cbor_isa_bytestring(item));
+ CBOR_ASSERT(cbor_bytestring_is_definite(item));
item->data = data;
item->metadata.bytestring_metadata.length = length;
}
cbor_item_t **cbor_bytestring_chunks_handle(const cbor_item_t *item) {
- assert(cbor_isa_bytestring(item));
- assert(cbor_bytestring_is_indefinite(item));
+ CBOR_ASSERT(cbor_isa_bytestring(item));
+ CBOR_ASSERT(cbor_bytestring_is_indefinite(item));
return ((struct cbor_indefinite_string_data *)item->data)->chunks;
}
size_t cbor_bytestring_chunk_count(const cbor_item_t *item) {
- assert(cbor_isa_bytestring(item));
- assert(cbor_bytestring_is_indefinite(item));
+ CBOR_ASSERT(cbor_isa_bytestring(item));
+ CBOR_ASSERT(cbor_bytestring_is_indefinite(item));
return ((struct cbor_indefinite_string_data *)item->data)->chunk_count;
}
bool cbor_bytestring_add_chunk(cbor_item_t *item, cbor_item_t *chunk) {
- assert(cbor_isa_bytestring(item));
- assert(cbor_bytestring_is_indefinite(item));
+ CBOR_ASSERT(cbor_isa_bytestring(item));
+ CBOR_ASSERT(cbor_bytestring_is_indefinite(item));
+ CBOR_ASSERT(cbor_isa_bytestring(chunk));
+ CBOR_ASSERT(cbor_bytestring_is_definite(chunk));
struct cbor_indefinite_string_data *data =
(struct cbor_indefinite_string_data *)item->data;
if (data->chunk_count == data->chunk_capacity) {
- // TODO: Add a test for this
if (!_cbor_safe_to_multiply(CBOR_BUFFER_GROWTH, data->chunk_capacity)) {
return false;
}
diff --git a/src/cbor/bytestrings.h b/src/cbor/bytestrings.h
index 71483f708e26..cacd1adf95f3 100644
--- a/src/cbor/bytestrings.h
+++ b/src/cbor/bytestrings.h
@@ -25,23 +25,26 @@ extern "C" {
*
* For definite byte strings only
*
- * @param item[borrow] a definite bytestring
+ * @param item a definite bytestring
* @return length of the binary data. Zero if no chunk has been attached yet
*/
+_CBOR_NODISCARD
CBOR_EXPORT size_t cbor_bytestring_length(const cbor_item_t *item);
/** Is the byte string definite?
*
- * @param item[borrow] a byte string
+ * @param item a byte string
* @return Is the byte string definite?
*/
+_CBOR_NODISCARD
CBOR_EXPORT bool cbor_bytestring_is_definite(const cbor_item_t *item);
/** Is the byte string indefinite?
*
- * @param item[borrow] a byte string
+ * @param item a byte string
* @return Is the byte string indefinite?
*/
+_CBOR_NODISCARD
CBOR_EXPORT bool cbor_bytestring_is_indefinite(const cbor_item_t *item);
/** Get the handle to the binary data
@@ -49,17 +52,20 @@ CBOR_EXPORT bool cbor_bytestring_is_indefinite(const cbor_item_t *item);
* Definite items only. Modifying the data is allowed. In that case, the caller
* takes responsibility for the effect on items this item might be a part of
*
- * @param item[borrow] A definite byte string
- * @return The address of the binary data. `NULL` if no data have been assigned
+ * @param item A definite byte string
+ * @return The address of the underlying binary data
+ * @return `NULL` if no data have been assigned
* yet.
*/
+_CBOR_NODISCARD
CBOR_EXPORT cbor_mutable_data cbor_bytestring_handle(const cbor_item_t *item);
/** Set the handle to the binary data
*
- * @param item[borrow] A definite byte string
+ * @param item A definite byte string
* @param data The memory block. The caller gives up the ownership of the block.
- * libcbor will deallocate it when appropriate using its free function
+ * libcbor will deallocate it when appropriate using the `free` implementation
+ * configured using #cbor_set_allocs
* @param length Length of the data block
*/
CBOR_EXPORT void cbor_bytestring_set_handle(
@@ -71,17 +77,19 @@ CBOR_EXPORT void cbor_bytestring_set_handle(
* Manipulations with the memory block (e.g. sorting it) are allowed, but the
* validity and the number of chunks must be retained.
*
- * @param item[borrow] A indefinite byte string
+ * @param item A indefinite byte string
* @return array of #cbor_bytestring_chunk_count definite bytestrings
*/
+_CBOR_NODISCARD
CBOR_EXPORT cbor_item_t **cbor_bytestring_chunks_handle(
const cbor_item_t *item);
/** Get the number of chunks this string consist of
*
- * @param item[borrow] A indefinite bytestring
+ * @param item A indefinite bytestring
* @return The chunk count. 0 for freshly created items.
*/
+_CBOR_NODISCARD
CBOR_EXPORT size_t cbor_bytestring_chunk_count(const cbor_item_t *item);
/** Appends a chunk to the bytestring
@@ -90,11 +98,13 @@ CBOR_EXPORT size_t cbor_bytestring_chunk_count(const cbor_item_t *item);
*
* May realloc the chunk storage.
*
- * @param item[borrow] An indefinite byte string
- * @param item[incref] A definite byte string
+ * @param item An indefinite byte string
+ * @param chunk A definite byte string. Its reference count will be be increased
+ * by one.
* @return true on success, false on realloc failure. In that case, the refcount
* of `chunk` is not increased and the `item` is left intact.
*/
+_CBOR_NODISCARD
CBOR_EXPORT bool cbor_bytestring_add_chunk(cbor_item_t *item,
cbor_item_t *chunk);
@@ -102,17 +112,23 @@ CBOR_EXPORT bool cbor_bytestring_add_chunk(cbor_item_t *item,
*
* The handle is initialized to `NULL` and length to 0
*
- * @return **new** definite bytestring. `NULL` on malloc failure.
+ * @return Reference to the new bytestring item. The item's reference count is
+ * initialized to one.
+ * @return `NULL` if memory allocation fails
*/
-CBOR_EXPORT cbor_item_t *cbor_new_definite_bytestring();
+_CBOR_NODISCARD
+CBOR_EXPORT cbor_item_t *cbor_new_definite_bytestring(void);
/** Creates a new indefinite byte string
*
- * The chunks array is initialized to `NULL` and chunkcount to 0
+ * The chunks array is initialized to `NULL` and chunk count to 0
*
- * @return **new** indefinite bytestring. `NULL` on malloc failure.
+ * @return Reference to the new bytestring item. The item's reference count is
+ * initialized to one.
+ * @return `NULL` if memory allocation fails
*/
-CBOR_EXPORT cbor_item_t *cbor_new_indefinite_bytestring();
+_CBOR_NODISCARD
+CBOR_EXPORT cbor_item_t *cbor_new_indefinite_bytestring(void);
/** Creates a new byte string and initializes it
*
@@ -120,9 +136,11 @@ CBOR_EXPORT cbor_item_t *cbor_new_indefinite_bytestring();
*
* @param handle Block of binary data
* @param length Length of `data`
- * @return A **new** byte string with content `handle`. `NULL` on malloc
- * failure.
+ * @return Reference to the new bytestring item. The item's reference count is
+ * initialized to one.
+ * @return `NULL` if memory allocation fails
*/
+_CBOR_NODISCARD
CBOR_EXPORT cbor_item_t *cbor_build_bytestring(cbor_data handle, size_t length);
#ifdef __cplusplus
diff --git a/src/cbor/callbacks.c b/src/cbor/callbacks.c
index 3f1f547a09ef..bdf3f79eee69 100644
--- a/src/cbor/callbacks.c
+++ b/src/cbor/callbacks.c
@@ -7,110 +7,115 @@
#include "callbacks.h"
-#define CBOR_DUMMY_CALLBACK \
- {}
+void cbor_null_uint8_callback(void *_CBOR_UNUSED(_ctx),
+ uint8_t _CBOR_UNUSED(_val)) {}
-void cbor_null_uint8_callback(void *_ctx, uint8_t _val) CBOR_DUMMY_CALLBACK
+void cbor_null_uint16_callback(void *_CBOR_UNUSED(_ctx),
+ uint16_t _CBOR_UNUSED(_val)) {}
- void cbor_null_uint16_callback(void *_ctx,
- uint16_t _val) CBOR_DUMMY_CALLBACK
+void cbor_null_uint32_callback(void *_CBOR_UNUSED(_ctx),
+ uint32_t _CBOR_UNUSED(_val)) {}
- void cbor_null_uint32_callback(void *_ctx,
- uint32_t _val) CBOR_DUMMY_CALLBACK
+void cbor_null_uint64_callback(void *_CBOR_UNUSED(_ctx),
+ uint64_t _CBOR_UNUSED(_val)) {}
- void cbor_null_uint64_callback(void *_ctx,
- uint64_t _val) CBOR_DUMMY_CALLBACK
+void cbor_null_negint8_callback(void *_CBOR_UNUSED(_ctx),
+ uint8_t _CBOR_UNUSED(_val)) {}
- void cbor_null_negint8_callback(void *_ctx,
- uint8_t _val) CBOR_DUMMY_CALLBACK
+void cbor_null_negint16_callback(void *_CBOR_UNUSED(_ctx),
+ uint16_t _CBOR_UNUSED(_val)) {}
- void cbor_null_negint16_callback(void *_ctx,
- uint16_t _val) CBOR_DUMMY_CALLBACK
+void cbor_null_negint32_callback(void *_CBOR_UNUSED(_ctx),
+ uint32_t _CBOR_UNUSED(_val)) {}
- void cbor_null_negint32_callback(void *_ctx,
- uint32_t _val) CBOR_DUMMY_CALLBACK
+void cbor_null_negint64_callback(void *_CBOR_UNUSED(_ctx),
+ uint64_t _CBOR_UNUSED(_val)) {}
- void cbor_null_negint64_callback(void *_ctx,
- uint64_t _val) CBOR_DUMMY_CALLBACK
+void cbor_null_string_callback(void *_CBOR_UNUSED(_ctx),
+ cbor_data _CBOR_UNUSED(_val),
+ uint64_t _CBOR_UNUSED(_val2)) {}
- void cbor_null_string_callback(void *_ctx, cbor_data _val,
- size_t _val2) CBOR_DUMMY_CALLBACK
+void cbor_null_string_start_callback(void *_CBOR_UNUSED(_ctx)) {}
- void cbor_null_string_start_callback(void *_ctx) CBOR_DUMMY_CALLBACK
+void cbor_null_byte_string_callback(void *_CBOR_UNUSED(_ctx),
+ cbor_data _CBOR_UNUSED(_val),
+ uint64_t _CBOR_UNUSED(_val2)) {}
- void cbor_null_byte_string_callback(void *_ctx, cbor_data _val,
- size_t _val2) CBOR_DUMMY_CALLBACK
+void cbor_null_byte_string_start_callback(void *_CBOR_UNUSED(_ctx)) {}
- void cbor_null_byte_string_start_callback(void *_ctx) CBOR_DUMMY_CALLBACK
+void cbor_null_array_start_callback(void *_CBOR_UNUSED(_ctx),
+ uint64_t _CBOR_UNUSED(_val)) {}
- void cbor_null_array_start_callback(void *_ctx,
- size_t _val) CBOR_DUMMY_CALLBACK
+void cbor_null_indef_array_start_callback(void *_CBOR_UNUSED(_ctx)) {}
- void cbor_null_indef_array_start_callback(void *_ctx) CBOR_DUMMY_CALLBACK
+void cbor_null_map_start_callback(void *_CBOR_UNUSED(_ctx),
+ uint64_t _CBOR_UNUSED(_val)) {}
- void cbor_null_map_start_callback(void *_ctx,
- size_t _val) CBOR_DUMMY_CALLBACK
+void cbor_null_indef_map_start_callback(void *_CBOR_UNUSED(_ctx)) {}
- void cbor_null_indef_map_start_callback(void *_ctx) CBOR_DUMMY_CALLBACK
+void cbor_null_tag_callback(void *_CBOR_UNUSED(_ctx),
+ uint64_t _CBOR_UNUSED(_val)) {}
- void cbor_null_tag_callback(void *_ctx, uint64_t _val) CBOR_DUMMY_CALLBACK
+void cbor_null_float2_callback(void *_CBOR_UNUSED(_ctx),
+ float _CBOR_UNUSED(_val)) {}
- void cbor_null_float2_callback(void *_ctx, float _val) CBOR_DUMMY_CALLBACK
+void cbor_null_float4_callback(void *_CBOR_UNUSED(_ctx),
+ float _CBOR_UNUSED(_val)) {}
- void cbor_null_float4_callback(void *_ctx, float _val) CBOR_DUMMY_CALLBACK
+void cbor_null_float8_callback(void *_CBOR_UNUSED(_ctx),
+ double _CBOR_UNUSED(_val)) {}
- void cbor_null_float8_callback(void *_ctx, double _val) CBOR_DUMMY_CALLBACK
+void cbor_null_null_callback(void *_CBOR_UNUSED(_ctx)) {}
- void cbor_null_null_callback(void *_ctx) CBOR_DUMMY_CALLBACK
+void cbor_null_undefined_callback(void *_CBOR_UNUSED(_ctx)) {}
- void cbor_null_undefined_callback(void *_ctx) CBOR_DUMMY_CALLBACK
+void cbor_null_boolean_callback(void *_CBOR_UNUSED(_ctx),
+ bool _CBOR_UNUSED(_val)) {}
- void cbor_null_boolean_callback(void *_ctx, bool _val) CBOR_DUMMY_CALLBACK
+void cbor_null_indef_break_callback(void *_CBOR_UNUSED(_ctx)) {}
- void cbor_null_indef_break_callback(void *_ctx) CBOR_DUMMY_CALLBACK
+CBOR_EXPORT const struct cbor_callbacks cbor_empty_callbacks = {
+ /* Type 0 - Unsigned integers */
+ .uint8 = cbor_null_uint8_callback,
+ .uint16 = cbor_null_uint16_callback,
+ .uint32 = cbor_null_uint32_callback,
+ .uint64 = cbor_null_uint64_callback,
- CBOR_EXPORT const struct cbor_callbacks cbor_empty_callbacks = {
- /* Type 0 - Unsigned integers */
- .uint8 = cbor_null_uint8_callback,
- .uint16 = cbor_null_uint16_callback,
- .uint32 = cbor_null_uint32_callback,
- .uint64 = cbor_null_uint64_callback,
+ /* Type 1 - Negative integers */
+ .negint8 = cbor_null_negint8_callback,
+ .negint16 = cbor_null_negint16_callback,
+ .negint32 = cbor_null_negint32_callback,
+ .negint64 = cbor_null_negint64_callback,
- /* Type 1 - Negative integers */
- .negint8 = cbor_null_negint8_callback,
- .negint16 = cbor_null_negint16_callback,
- .negint32 = cbor_null_negint32_callback,
- .negint64 = cbor_null_negint64_callback,
+ /* Type 2 - Byte strings */
+ .byte_string_start = cbor_null_byte_string_start_callback,
+ .byte_string = cbor_null_byte_string_callback,
- /* Type 2 - Byte strings */
- .byte_string_start = cbor_null_byte_string_start_callback,
- .byte_string = cbor_null_byte_string_callback,
+ /* Type 3 - Strings */
+ .string_start = cbor_null_string_start_callback,
+ .string = cbor_null_string_callback,
- /* Type 3 - Strings */
- .string_start = cbor_null_string_start_callback,
- .string = cbor_null_string_callback,
+ /* Type 4 - Arrays */
+ .indef_array_start = cbor_null_indef_array_start_callback,
+ .array_start = cbor_null_array_start_callback,
- /* Type 4 - Arrays */
- .indef_array_start = cbor_null_indef_array_start_callback,
- .array_start = cbor_null_array_start_callback,
+ /* Type 5 - Maps */
+ .indef_map_start = cbor_null_indef_map_start_callback,
+ .map_start = cbor_null_map_start_callback,
- /* Type 5 - Maps */
- .indef_map_start = cbor_null_indef_map_start_callback,
- .map_start = cbor_null_map_start_callback,
+ /* Type 6 - Tags */
+ .tag = cbor_null_tag_callback,
- /* Type 6 - Tags */
- .tag = cbor_null_tag_callback,
+ /* Type 7 - Floats & misc */
+ /* Type names cannot be member names */
+ .float2 = cbor_null_float2_callback,
+ /* 2B float is not supported in standard C */
+ .float4 = cbor_null_float4_callback,
+ .float8 = cbor_null_float8_callback,
+ .undefined = cbor_null_undefined_callback,
+ .null = cbor_null_null_callback,
+ .boolean = cbor_null_boolean_callback,
- /* Type 7 - Floats & misc */
- /* Type names cannot be member names */
- .float2 = cbor_null_float2_callback,
- /* 2B float is not supported in standard C */
- .float4 = cbor_null_float4_callback,
- .float8 = cbor_null_float8_callback,
- .undefined = cbor_null_undefined_callback,
- .null = cbor_null_null_callback,
- .boolean = cbor_null_boolean_callback,
-
- /* Shared indefinites */
- .indef_break = cbor_null_indef_break_callback,
+ /* Shared indefinites */
+ .indef_break = cbor_null_indef_break_callback,
};
diff --git a/src/cbor/callbacks.h b/src/cbor/callbacks.h
index 9e5965f2d921..c7ae20568dc8 100644
--- a/src/cbor/callbacks.h
+++ b/src/cbor/callbacks.h
@@ -8,6 +8,8 @@
#ifndef LIBCBOR_CALLBACKS_H
#define LIBCBOR_CALLBACKS_H
+#include <stdint.h>
+
#include "cbor/cbor_export.h"
#include "cbor/common.h"
@@ -31,10 +33,10 @@ typedef void (*cbor_int64_callback)(void *, uint64_t);
typedef void (*cbor_simple_callback)(void *);
/** Callback prototype */
-typedef void (*cbor_string_callback)(void *, cbor_data, size_t);
+typedef void (*cbor_string_callback)(void *, cbor_data, uint64_t);
/** Callback prototype */
-typedef void (*cbor_collection_callback)(void *, size_t);
+typedef void (*cbor_collection_callback)(void *, uint64_t);
/** Callback prototype */
typedef void (*cbor_float_callback)(void *, float);
@@ -130,25 +132,25 @@ CBOR_EXPORT void cbor_null_negint32_callback(void *, uint32_t);
CBOR_EXPORT void cbor_null_negint64_callback(void *, uint64_t);
/** Dummy callback implementation - does nothing */
-CBOR_EXPORT void cbor_null_string_callback(void *, cbor_data, size_t);
+CBOR_EXPORT void cbor_null_string_callback(void *, cbor_data, uint64_t);
/** Dummy callback implementation - does nothing */
CBOR_EXPORT void cbor_null_string_start_callback(void *);
/** Dummy callback implementation - does nothing */
-CBOR_EXPORT void cbor_null_byte_string_callback(void *, cbor_data, size_t);
+CBOR_EXPORT void cbor_null_byte_string_callback(void *, cbor_data, uint64_t);
/** Dummy callback implementation - does nothing */
CBOR_EXPORT void cbor_null_byte_string_start_callback(void *);
/** Dummy callback implementation - does nothing */
-CBOR_EXPORT void cbor_null_array_start_callback(void *, size_t);
+CBOR_EXPORT void cbor_null_array_start_callback(void *, uint64_t);
/** Dummy callback implementation - does nothing */
CBOR_EXPORT void cbor_null_indef_array_start_callback(void *);
/** Dummy callback implementation - does nothing */
-CBOR_EXPORT void cbor_null_map_start_callback(void *, size_t);
+CBOR_EXPORT void cbor_null_map_start_callback(void *, uint64_t);
/** Dummy callback implementation - does nothing */
CBOR_EXPORT void cbor_null_indef_map_start_callback(void *);
diff --git a/src/cbor/common.c b/src/cbor/common.c
index 7ccce38ac25b..efbd37ed79d3 100644
--- a/src/cbor/common.c
+++ b/src/cbor/common.c
@@ -15,6 +15,10 @@
#include "strings.h"
#include "tags.h"
+#ifdef DEBUG
+bool _cbor_enable_assert = true;
+#endif
+
bool cbor_isa_uint(const cbor_item_t *item) {
return item->type == CBOR_TYPE_UINT;
}
@@ -78,7 +82,7 @@ cbor_item_t *cbor_incref(cbor_item_t *item) {
void cbor_decref(cbor_item_t **item_ref) {
cbor_item_t *item = *item_ref;
- assert(item->refcount > 0);
+ CBOR_ASSERT(item->refcount > 0);
if (--item->refcount == 0) {
switch (item->type) {
case CBOR_TYPE_UINT:
@@ -88,29 +92,29 @@ void cbor_decref(cbor_item_t **item_ref) {
{ break; }
case CBOR_TYPE_BYTESTRING: {
if (cbor_bytestring_is_definite(item)) {
- _CBOR_FREE(item->data);
+ _cbor_free(item->data);
} else {
/* We need to decref all chunks */
cbor_item_t **handle = cbor_bytestring_chunks_handle(item);
for (size_t i = 0; i < cbor_bytestring_chunk_count(item); i++)
cbor_decref(&handle[i]);
- _CBOR_FREE(
+ _cbor_free(
((struct cbor_indefinite_string_data *)item->data)->chunks);
- _CBOR_FREE(item->data);
+ _cbor_free(item->data);
}
break;
}
case CBOR_TYPE_STRING: {
if (cbor_string_is_definite(item)) {
- _CBOR_FREE(item->data);
+ _cbor_free(item->data);
} else {
/* We need to decref all chunks */
cbor_item_t **handle = cbor_string_chunks_handle(item);
for (size_t i = 0; i < cbor_string_chunk_count(item); i++)
cbor_decref(&handle[i]);
- _CBOR_FREE(
+ _cbor_free(
((struct cbor_indefinite_string_data *)item->data)->chunks);
- _CBOR_FREE(item->data);
+ _cbor_free(item->data);
}
break;
}
@@ -120,7 +124,7 @@ void cbor_decref(cbor_item_t **item_ref) {
size_t size = cbor_array_size(item);
for (size_t i = 0; i < size; i++)
if (handle[i] != NULL) cbor_decref(&handle[i]);
- _CBOR_FREE(item->data);
+ _cbor_free(item->data);
break;
}
case CBOR_TYPE_MAP: {
@@ -130,13 +134,13 @@ void cbor_decref(cbor_item_t **item_ref) {
cbor_decref(&handle->key);
if (handle->value != NULL) cbor_decref(&handle->value);
}
- _CBOR_FREE(item->data);
+ _cbor_free(item->data);
break;
- };
+ }
case CBOR_TYPE_TAG: {
if (item->metadata.tag_metadata.tagged_item != NULL)
cbor_decref(&item->metadata.tag_metadata.tagged_item);
- _CBOR_FREE(item->data);
+ _cbor_free(item->data);
break;
}
case CBOR_TYPE_FLOAT_CTRL: {
@@ -144,8 +148,7 @@ void cbor_decref(cbor_item_t **item_ref) {
break;
}
}
- _CBOR_FREE(item);
- // TODO
+ _cbor_free(item);
*item_ref = NULL;
}
}
diff --git a/src/cbor/common.h b/src/cbor/common.h
index 1f9b79e16d9d..fddaabf3b9cf 100644
--- a/src/cbor/common.h
+++ b/src/cbor/common.h
@@ -13,6 +13,7 @@
#include <stddef.h>
#include <stdint.h>
#include <stdlib.h>
+
#include "cbor/cbor_export.h"
#include "cbor/configuration.h"
#include "data.h"
@@ -21,7 +22,7 @@
extern "C" {
/**
- * C++ is not a subset of C99 -- 'restrict' qualifier is not a part of the
+ * C99 is not a subset of C++ -- 'restrict' qualifier is not a part of the
* language. This is a workaround to keep it in C headers -- compilers allow
* linking non-restrict signatures with restrict implementations.
*
@@ -40,9 +41,9 @@ static const uint8_t cbor_major_version = CBOR_MAJOR_VERSION;
static const uint8_t cbor_minor_version = CBOR_MINOR_VERSION;
static const uint8_t cbor_patch_version = CBOR_PATCH_VERSION;
-#define CBOR_VERSION \
- TO_STR(CBOR_MAJOR_VERSION) \
- "." TO_STR(CBOR_MINOR_VERSION) "." TO_STR(CBOR_PATCH_VERSION)
+#define CBOR_VERSION \
+ _CBOR_TO_STR(CBOR_MAJOR_VERSION) \
+ "." _CBOR_TO_STR(CBOR_MINOR_VERSION) "." _CBOR_TO_STR(CBOR_PATCH_VERSION)
#define CBOR_HEX_VERSION \
((CBOR_MAJOR_VERSION << 16) | (CBOR_MINOR_VERSION << 8) | CBOR_PATCH_VERSION)
@@ -50,20 +51,55 @@ static const uint8_t cbor_patch_version = CBOR_PATCH_VERSION;
*/
#ifdef DEBUG
#include <stdio.h>
-#define debug_print(fmt, ...) \
+#define _cbor_debug_print(fmt, ...) \
do { \
if (DEBUG) \
fprintf(stderr, "%s:%d:%s(): " fmt, __FILE__, __LINE__, __func__, \
__VA_ARGS__); \
} while (0)
+extern bool _cbor_enable_assert;
+// Like `assert`, but can be dynamically disabled in tests to allow testing
+// invalid behaviors.
+#define CBOR_ASSERT(e) assert(!_cbor_enable_assert || (e))
+#define _CBOR_TEST_DISABLE_ASSERT(block) \
+ do { \
+ _cbor_enable_assert = false; \
+ block _cbor_enable_assert = true; \
+ } while (0)
#else
#define debug_print(fmt, ...) \
do { \
} while (0)
+#define CBOR_ASSERT(e)
+#define _CBOR_TEST_DISABLE_ASSERT(block) \
+ do { \
+ block \
+ } while (0)
#endif
-#define TO_STR_(x) #x
-#define TO_STR(x) TO_STR_(x) /* enables proper double expansion */
+#define _CBOR_TO_STR_(x) #x
+#define _CBOR_TO_STR(x) _CBOR_TO_STR_(x) /* enables proper double expansion */
+
+#ifdef __GNUC__
+#define _CBOR_UNUSED(x) __attribute__((__unused__)) x
+// TODO(https://github.com/PJK/libcbor/issues/247): Prefer [[nodiscard]] if
+// available
+#define _CBOR_NODISCARD __attribute__((warn_unused_result))
+#elif defined(_MSC_VER)
+#define _CBOR_UNUSED(x) __pragma(warning(suppress : 4100 4101)) x
+#define _CBOR_NODISCARD
+#else
+#define _CBOR_UNUSED(x) x
+#define _CBOR_NODISCARD
+#endif
+
+typedef void *(*_cbor_malloc_t)(size_t);
+typedef void *(*_cbor_realloc_t)(void *, size_t);
+typedef void (*_cbor_free_t)(void *);
+
+CBOR_EXPORT extern _cbor_malloc_t _cbor_malloc;
+CBOR_EXPORT extern _cbor_realloc_t _cbor_realloc;
+CBOR_EXPORT extern _cbor_free_t _cbor_free;
// Macro to short-circuit builder functions when memory allocation fails
#define _CBOR_NOTNULL(cbor_item) \
@@ -77,24 +113,15 @@ static const uint8_t cbor_patch_version = CBOR_PATCH_VERSION;
#define _CBOR_DEPENDENT_NOTNULL(cbor_item, pointer) \
do { \
if (pointer == NULL) { \
- _CBOR_FREE(cbor_item); \
+ _cbor_free(cbor_item); \
return NULL; \
} \
} while (0)
-#if CBOR_CUSTOM_ALLOC
-
-typedef void *(*_cbor_malloc_t)(size_t);
-typedef void *(*_cbor_realloc_t)(void *, size_t);
-typedef void (*_cbor_free_t)(void *);
-
-CBOR_EXPORT extern _cbor_malloc_t _cbor_malloc;
-CBOR_EXPORT extern _cbor_realloc_t _cbor_realloc;
-CBOR_EXPORT extern _cbor_free_t _cbor_free;
-
/** Sets the memory management routines to use.
*
- * Only available when `CBOR_CUSTOM_ALLOC` is truthy
+ * By default, libcbor will use the standard library `malloc`, `realloc`, and
+ * `free`.
*
* \rst
* .. warning:: This function modifies the global state and should therefore be
@@ -115,18 +142,6 @@ CBOR_EXPORT void cbor_set_allocs(_cbor_malloc_t custom_malloc,
_cbor_realloc_t custom_realloc,
_cbor_free_t custom_free);
-#define _CBOR_MALLOC _cbor_malloc
-#define _CBOR_REALLOC _cbor_realloc
-#define _CBOR_FREE _cbor_free
-
-#else
-
-#define _CBOR_MALLOC malloc
-#define _CBOR_REALLOC realloc
-#define _CBOR_FREE free
-
-#endif
-
/*
* ============================================================================
* Type manipulation
@@ -135,80 +150,92 @@ CBOR_EXPORT void cbor_set_allocs(_cbor_malloc_t custom_malloc,
/** Get the type of the item
*
- * @param item[borrow]
+ * @param item
* @return The type
*/
+_CBOR_NODISCARD
CBOR_EXPORT cbor_type cbor_typeof(
const cbor_item_t *item); /* Will be inlined iff link-time opt is enabled */
/* Standard item types as described by the RFC */
/** Does the item have the appropriate major type?
- * @param item[borrow] the item
+ * @param item the item
* @return Is the item an #CBOR_TYPE_UINT?
*/
+_CBOR_NODISCARD
CBOR_EXPORT bool cbor_isa_uint(const cbor_item_t *item);
/** Does the item have the appropriate major type?
- * @param item[borrow] the item
+ * @param item the item
* @return Is the item a #CBOR_TYPE_NEGINT?
*/
+_CBOR_NODISCARD
CBOR_EXPORT bool cbor_isa_negint(const cbor_item_t *item);
/** Does the item have the appropriate major type?
- * @param item[borrow] the item
+ * @param item the item
* @return Is the item a #CBOR_TYPE_BYTESTRING?
*/
+_CBOR_NODISCARD
CBOR_EXPORT bool cbor_isa_bytestring(const cbor_item_t *item);
/** Does the item have the appropriate major type?
- * @param item[borrow] the item
+ * @param item the item
* @return Is the item a #CBOR_TYPE_STRING?
*/
+_CBOR_NODISCARD
CBOR_EXPORT bool cbor_isa_string(const cbor_item_t *item);
/** Does the item have the appropriate major type?
- * @param item[borrow] the item
+ * @param item the item
* @return Is the item an #CBOR_TYPE_ARRAY?
*/
+_CBOR_NODISCARD
CBOR_EXPORT bool cbor_isa_array(const cbor_item_t *item);
/** Does the item have the appropriate major type?
- * @param item[borrow] the item
+ * @param item the item
* @return Is the item a #CBOR_TYPE_MAP?
*/
+_CBOR_NODISCARD
CBOR_EXPORT bool cbor_isa_map(const cbor_item_t *item);
/** Does the item have the appropriate major type?
- * @param item[borrow] the item
+ * @param item the item
* @return Is the item a #CBOR_TYPE_TAG?
*/
+_CBOR_NODISCARD
CBOR_EXPORT bool cbor_isa_tag(const cbor_item_t *item);
/** Does the item have the appropriate major type?
- * @param item[borrow] the item
+ * @param item the item
* @return Is the item a #CBOR_TYPE_FLOAT_CTRL?
*/
+_CBOR_NODISCARD
CBOR_EXPORT bool cbor_isa_float_ctrl(const cbor_item_t *item);
/* Practical types with respect to their semantics (but not tag values) */
/** Is the item an integer, either positive or negative?
- * @param item[borrow] the item
+ * @param item the item
* @return Is the item an integer, either positive or negative?
*/
+_CBOR_NODISCARD
CBOR_EXPORT bool cbor_is_int(const cbor_item_t *item);
/** Is the item an a floating point number?
- * @param item[borrow] the item
+ * @param item the item
* @return Is the item a floating point number?
*/
+_CBOR_NODISCARD
CBOR_EXPORT bool cbor_is_float(const cbor_item_t *item);
/** Is the item an a boolean?
- * @param item[borrow] the item
+ * @param item the item
* @return Is the item a boolean?
*/
+_CBOR_NODISCARD
CBOR_EXPORT bool cbor_is_bool(const cbor_item_t *item);
/** Does this item represent `null`
@@ -218,9 +245,10 @@ CBOR_EXPORT bool cbor_is_bool(const cbor_item_t *item);
* null pointer will most likely result in a crash.
* \endrst
*
- * @param item[borrow] the item
+ * @param item the item
* @return Is the item (CBOR logical) null?
*/
+_CBOR_NODISCARD
CBOR_EXPORT bool cbor_is_null(const cbor_item_t *item);
/** Does this item represent `undefined`
@@ -230,9 +258,10 @@ CBOR_EXPORT bool cbor_is_null(const cbor_item_t *item);
* C.
* \endrst
*
- * @param item[borrow] the item
+ * @param item the item
* @return Is the item (CBOR logical) undefined?
*/
+_CBOR_NODISCARD
CBOR_EXPORT bool cbor_is_undef(const cbor_item_t *item);
/*
@@ -241,42 +270,48 @@ CBOR_EXPORT bool cbor_is_undef(const cbor_item_t *item);
* ============================================================================
*/
-/** Increases the reference count by one
+/** Increases the item's reference count by one
+ *
+ * Constant complexity; items referring to this one or items being referred to
+ * are not updated.
*
- * No dependent items are affected.
+ * This function can be used to extend reference counting to client code.
*
- * @param item[incref] item the item
- * @return the input reference
+ * @param item Reference to an item
+ * @return The input \p item
*/
CBOR_EXPORT cbor_item_t *cbor_incref(cbor_item_t *item);
-/** Decreases the reference count by one, deallocating the item if needed
+/** Decreases the item's reference count by one, deallocating the item if needed
*
- * In case the item is deallocated, the reference count of any dependent items
- * is adjusted accordingly in a recursive manner.
+ * In case the item is deallocated, the reference count of all items this item
+ * references will also be #cbor_decref 'ed recursively.
*
- * @param item[take] the item. Set to `NULL` if deallocated
+ * @param item Reference to an item. Will be set to `NULL` if deallocated
*/
CBOR_EXPORT void cbor_decref(cbor_item_t **item);
-/** Decreases the reference count by one, deallocating the item if needed
+/** Decreases the item's reference count by one, deallocating the item if needed
*
* Convenience wrapper for #cbor_decref when its set-to-null behavior is not
* needed
*
- * @param item[take] the item
+ * @param item Reference to an item
*/
CBOR_EXPORT void cbor_intermediate_decref(cbor_item_t *item);
-/** Get the reference count
+/** Get the item's reference count
*
* \rst
* .. warning:: This does *not* account for transitive references.
* \endrst
*
- * @param item[borrow] the item
+ * @todo Add some inline examples for reference counting
+ *
+ * @param item the item
* @return the reference count
*/
+_CBOR_NODISCARD
CBOR_EXPORT size_t cbor_refcount(const cbor_item_t *item);
/** Provides CPP-like move construct
@@ -291,9 +326,10 @@ CBOR_EXPORT size_t cbor_refcount(const cbor_item_t *item);
* count afterwards, the memory will be leaked.
* \endrst
*
- * @param item[take] the item
+ * @param item Reference to an item
* @return the item with reference count decreased by one
*/
+_CBOR_NODISCARD
CBOR_EXPORT cbor_item_t *cbor_move(cbor_item_t *item);
#ifdef __cplusplus
diff --git a/src/cbor/configuration.h.in b/src/cbor/configuration.h.in
index 6f65980aa8a2..0052a150489f 100644
--- a/src/cbor/configuration.h.in
+++ b/src/cbor/configuration.h.in
@@ -5,7 +5,6 @@
#define CBOR_MINOR_VERSION ${CBOR_VERSION_MINOR}
#define CBOR_PATCH_VERSION ${CBOR_VERSION_PATCH}
-#cmakedefine01 CBOR_CUSTOM_ALLOC
#define CBOR_BUFFER_GROWTH ${CBOR_BUFFER_GROWTH}
#define CBOR_MAX_STACK_SIZE ${CBOR_MAX_STACK_SIZE}
#cmakedefine01 CBOR_PRETTY_PRINTER
diff --git a/src/cbor/data.h b/src/cbor/data.h
index 982e6a2c9987..a12e92f20c36 100644
--- a/src/cbor/data.h
+++ b/src/cbor/data.h
@@ -45,6 +45,8 @@ typedef enum {
CBOR_ERR_NONE,
CBOR_ERR_NOTENOUGHDATA,
CBOR_ERR_NODATA,
+ // TODO: Should be "malformed" or at least "malformatted". Retained for
+ // backwards compatibility.
CBOR_ERR_MALFORMATED,
CBOR_ERR_MEMERROR /** Memory error - item allocation failed. Is it too big for
your allocator? */
@@ -86,6 +88,11 @@ typedef enum {
CBOR_CTRL_UNDEF = 23
} _cbor_ctrl;
+// Metadata items use size_t (instead of uint64_t) because items in memory take
+// up at least 1B per entry or string byte, so if size_t is narrower than
+// uint64_t, we wouldn't be able to create them in the first place and can save
+// some space.
+
/** Integers specific metadata */
struct _cbor_int_metadata {
cbor_int_width width;
@@ -184,7 +191,7 @@ struct cbor_indefinite_string_data {
/** High-level decoding error */
struct cbor_error {
- /** Aproximate position */
+ /** Approximate position */
size_t position;
/** Description */
cbor_error_code code;
@@ -212,6 +219,8 @@ enum cbor_decoder_status {
*/
CBOR_DECODER_FINISHED,
/** Not enough data to invoke a callback */
+ // TODO: The name is inconsistent with CBOR_ERR_NOTENOUGHDATA. Retained for
+ // backwards compatibility.
CBOR_DECODER_NEDATA,
/** Bad data (reserved MTB, malformed value, etc.) */
CBOR_DECODER_ERROR
diff --git a/src/cbor/encoding.c b/src/cbor/encoding.c
index 19281520edd9..9d931d17570f 100644
--- a/src/cbor/encoding.c
+++ b/src/cbor/encoding.c
@@ -135,17 +135,23 @@ size_t cbor_encode_half(float value, unsigned char *buffer,
val & 0x7FFFFFu; /* 0b0000_0000_0111_1111_1111_1111_1111_1111 */
if (exp == 0xFF) { /* Infinity or NaNs */
if (value != value) {
- res = (uint16_t)0x007e00; /* Not IEEE semantics - required by CBOR
- [s. 3.9] */
+ // We discard information bits in half-float NaNs. This is
+ // not required for the core CBOR protocol (it is only a suggestion in
+ // Section 3.9).
+ // See https://github.com/PJK/libcbor/issues/215
+ res = (uint16_t)0x007e00;
} else {
- res = (uint16_t)((val & 0x80000000u) >> 16u | 0x7C00u |
- (mant ? 1u : 0u) << 15u);
+ // If the mantissa is non-zero, we have a NaN, but those are handled
+ // above. See
+ // https://en.wikipedia.org/wiki/Half-precision_floating-point_format
+ CBOR_ASSERT(mant == 0u);
+ res = (uint16_t)((val & 0x80000000u) >> 16u | 0x7C00u);
}
} else if (exp == 0x00) { /* Zeroes or subnorms */
res = (uint16_t)((val & 0x80000000u) >> 16u | mant >> 13u);
} else { /* Normal numbers */
int8_t logical_exp = (int8_t)(exp - 127);
- assert(logical_exp == exp - 127);
+ CBOR_ASSERT(logical_exp == exp - 127);
// Now we know that 2^exp <= 0 logically
if (logical_exp < -24) {
@@ -158,7 +164,9 @@ size_t cbor_encode_half(float value, unsigned char *buffer,
value is lost. This is an implementation decision that works around the
absence of standard half-float in the language. */
res = (uint16_t)((val & 0x80000000u) >> 16u) | // Extract sign bit
- (uint16_t)(1u << (24u + logical_exp));
+ ((uint16_t)(1u << (24u + logical_exp)) +
+ (uint16_t)(((mant >> (-logical_exp - 2)) + 1) >>
+ 1)); // Round half away from zero for simplicity
} else {
res = (uint16_t)((val & 0x80000000u) >> 16u |
((((uint8_t)logical_exp) + 15u) << 10u) |
diff --git a/src/cbor/encoding.h b/src/cbor/encoding.h
index e4f2102b636a..bcc04f8a98e5 100644
--- a/src/cbor/encoding.h
+++ b/src/cbor/encoding.h
@@ -16,55 +16,87 @@ extern "C" {
#endif
/*
- * ============================================================================
- * Primitives encoding
- * ============================================================================
+ * All cbor_encode_* methods take 2 or 3 arguments:
+ * - a logical `value` to encode (except for trivial items such as NULLs)
+ * - an output `buffer` pointer
+ * - a `buffer_size` specification
+ *
+ * They serialize the `value` into one or more bytes and write the bytes to the
+ * output `buffer` and return either the number of bytes written, or 0 if the
+ * `buffer_size` was too small to small to fit the serialized value (in which
+ * case it is not modified).
*/
-CBOR_EXPORT size_t cbor_encode_uint8(uint8_t, unsigned char *, size_t);
+_CBOR_NODISCARD CBOR_EXPORT size_t cbor_encode_uint8(uint8_t, unsigned char *,
+ size_t);
-CBOR_EXPORT size_t cbor_encode_uint16(uint16_t, unsigned char *, size_t);
+_CBOR_NODISCARD CBOR_EXPORT size_t cbor_encode_uint16(uint16_t, unsigned char *,
+ size_t);
-CBOR_EXPORT size_t cbor_encode_uint32(uint32_t, unsigned char *, size_t);
+_CBOR_NODISCARD CBOR_EXPORT size_t cbor_encode_uint32(uint32_t, unsigned char *,
+ size_t);
-CBOR_EXPORT size_t cbor_encode_uint64(uint64_t, unsigned char *, size_t);
+_CBOR_NODISCARD CBOR_EXPORT size_t cbor_encode_uint64(uint64_t, unsigned char *,
+ size_t);
-CBOR_EXPORT size_t cbor_encode_uint(uint64_t, unsigned char *, size_t);
+_CBOR_NODISCARD CBOR_EXPORT size_t cbor_encode_uint(uint64_t, unsigned char *,
+ size_t);
-CBOR_EXPORT size_t cbor_encode_negint8(uint8_t, unsigned char *, size_t);
+_CBOR_NODISCARD CBOR_EXPORT size_t cbor_encode_negint8(uint8_t, unsigned char *,
+ size_t);
-CBOR_EXPORT size_t cbor_encode_negint16(uint16_t, unsigned char *, size_t);
+_CBOR_NODISCARD CBOR_EXPORT size_t cbor_encode_negint16(uint16_t,
+ unsigned char *,
+ size_t);
-CBOR_EXPORT size_t cbor_encode_negint32(uint32_t, unsigned char *, size_t);
+_CBOR_NODISCARD CBOR_EXPORT size_t cbor_encode_negint32(uint32_t,
+ unsigned char *,
+ size_t);
-CBOR_EXPORT size_t cbor_encode_negint64(uint64_t, unsigned char *, size_t);
+_CBOR_NODISCARD CBOR_EXPORT size_t cbor_encode_negint64(uint64_t,
+ unsigned char *,
+ size_t);
-CBOR_EXPORT size_t cbor_encode_negint(uint64_t, unsigned char *, size_t);
+_CBOR_NODISCARD CBOR_EXPORT size_t cbor_encode_negint(uint64_t, unsigned char *,
+ size_t);
-CBOR_EXPORT size_t cbor_encode_bytestring_start(size_t, unsigned char *,
- size_t);
+_CBOR_NODISCARD CBOR_EXPORT size_t cbor_encode_bytestring_start(size_t,
+ unsigned char *,
+ size_t);
-CBOR_EXPORT size_t cbor_encode_indef_bytestring_start(unsigned char *, size_t);
+_CBOR_NODISCARD CBOR_EXPORT size_t
+cbor_encode_indef_bytestring_start(unsigned char *, size_t);
-CBOR_EXPORT size_t cbor_encode_string_start(size_t, unsigned char *, size_t);
+_CBOR_NODISCARD CBOR_EXPORT size_t cbor_encode_string_start(size_t,
+ unsigned char *,
+ size_t);
-CBOR_EXPORT size_t cbor_encode_indef_string_start(unsigned char *, size_t);
+_CBOR_NODISCARD CBOR_EXPORT size_t
+cbor_encode_indef_string_start(unsigned char *, size_t);
-CBOR_EXPORT size_t cbor_encode_array_start(size_t, unsigned char *, size_t);
+_CBOR_NODISCARD CBOR_EXPORT size_t cbor_encode_array_start(size_t,
+ unsigned char *,
+ size_t);
-CBOR_EXPORT size_t cbor_encode_indef_array_start(unsigned char *, size_t);
+_CBOR_NODISCARD CBOR_EXPORT size_t
+cbor_encode_indef_array_start(unsigned char *, size_t);
-CBOR_EXPORT size_t cbor_encode_map_start(size_t, unsigned char *, size_t);
+_CBOR_NODISCARD CBOR_EXPORT size_t cbor_encode_map_start(size_t,
+ unsigned char *,
+ size_t);
-CBOR_EXPORT size_t cbor_encode_indef_map_start(unsigned char *, size_t);
+_CBOR_NODISCARD CBOR_EXPORT size_t cbor_encode_indef_map_start(unsigned char *,
+ size_t);
-CBOR_EXPORT size_t cbor_encode_tag(uint64_t, unsigned char *, size_t);
+_CBOR_NODISCARD CBOR_EXPORT size_t cbor_encode_tag(uint64_t, unsigned char *,
+ size_t);
-CBOR_EXPORT size_t cbor_encode_bool(bool, unsigned char *, size_t);
+_CBOR_NODISCARD CBOR_EXPORT size_t cbor_encode_bool(bool, unsigned char *,
+ size_t);
-CBOR_EXPORT size_t cbor_encode_null(unsigned char *, size_t);
+_CBOR_NODISCARD CBOR_EXPORT size_t cbor_encode_null(unsigned char *, size_t);
-CBOR_EXPORT size_t cbor_encode_undef(unsigned char *, size_t);
+_CBOR_NODISCARD CBOR_EXPORT size_t cbor_encode_undef(unsigned char *, size_t);
/** Encodes a half-precision float
*
@@ -86,21 +118,20 @@ CBOR_EXPORT size_t cbor_encode_undef(unsigned char *, size_t);
* lost.
* - In all other cases, the sign bit, the exponent, and 10 most significant
* bits of the significand are kept
- *
- * @param value
- * @param buffer Target buffer
- * @param buffer_size Available space in the buffer
- * @return number of bytes written
*/
-CBOR_EXPORT size_t cbor_encode_half(float, unsigned char *, size_t);
+_CBOR_NODISCARD CBOR_EXPORT size_t cbor_encode_half(float, unsigned char *,
+ size_t);
-CBOR_EXPORT size_t cbor_encode_single(float, unsigned char *, size_t);
+_CBOR_NODISCARD CBOR_EXPORT size_t cbor_encode_single(float, unsigned char *,
+ size_t);
-CBOR_EXPORT size_t cbor_encode_double(double, unsigned char *, size_t);
+_CBOR_NODISCARD CBOR_EXPORT size_t cbor_encode_double(double, unsigned char *,
+ size_t);
-CBOR_EXPORT size_t cbor_encode_break(unsigned char *, size_t);
+_CBOR_NODISCARD CBOR_EXPORT size_t cbor_encode_break(unsigned char *, size_t);
-CBOR_EXPORT size_t cbor_encode_ctrl(uint8_t, unsigned char *, size_t);
+_CBOR_NODISCARD CBOR_EXPORT size_t cbor_encode_ctrl(uint8_t, unsigned char *,
+ size_t);
#ifdef __cplusplus
}
diff --git a/src/cbor/floats_ctrls.c b/src/cbor/floats_ctrls.c
index b7e5fcef8530..57bf477d4d3d 100644
--- a/src/cbor/floats_ctrls.c
+++ b/src/cbor/floats_ctrls.c
@@ -10,41 +10,42 @@
#include "assert.h"
cbor_float_width cbor_float_get_width(const cbor_item_t *item) {
- assert(cbor_isa_float_ctrl(item));
+ CBOR_ASSERT(cbor_isa_float_ctrl(item));
return item->metadata.float_ctrl_metadata.width;
}
uint8_t cbor_ctrl_value(const cbor_item_t *item) {
- assert(cbor_isa_float_ctrl(item));
- assert(cbor_float_get_width(item) == CBOR_FLOAT_0);
+ CBOR_ASSERT(cbor_isa_float_ctrl(item));
+ CBOR_ASSERT(cbor_float_get_width(item) == CBOR_FLOAT_0);
return item->metadata.float_ctrl_metadata.ctrl;
}
bool cbor_float_ctrl_is_ctrl(const cbor_item_t *item) {
- assert(cbor_isa_float_ctrl(item));
+ CBOR_ASSERT(cbor_isa_float_ctrl(item));
return cbor_float_get_width(item) == CBOR_FLOAT_0;
}
float cbor_float_get_float2(const cbor_item_t *item) {
- assert(cbor_is_float(item));
- assert(cbor_float_get_width(item) == CBOR_FLOAT_16);
+ CBOR_ASSERT(cbor_is_float(item));
+ CBOR_ASSERT(cbor_float_get_width(item) == CBOR_FLOAT_16);
return *(float *)item->data;
}
float cbor_float_get_float4(const cbor_item_t *item) {
- assert(cbor_is_float(item));
- assert(cbor_float_get_width(item) == CBOR_FLOAT_32);
+ CBOR_ASSERT(cbor_is_float(item));
+ CBOR_ASSERT(cbor_float_get_width(item) == CBOR_FLOAT_32);
return *(float *)item->data;
}
double cbor_float_get_float8(const cbor_item_t *item) {
- assert(cbor_is_float(item));
- assert(cbor_float_get_width(item) == CBOR_FLOAT_64);
+ CBOR_ASSERT(cbor_is_float(item));
+ CBOR_ASSERT(cbor_float_get_width(item) == CBOR_FLOAT_64);
return *(double *)item->data;
}
double cbor_float_get_float(const cbor_item_t *item) {
- assert(cbor_is_float(item));
+ CBOR_ASSERT(cbor_is_float(item));
+ // cppcheck-suppress missingReturn
switch (cbor_float_get_width(item)) {
case CBOR_FLOAT_0:
return NAN;
@@ -55,46 +56,45 @@ double cbor_float_get_float(const cbor_item_t *item) {
case CBOR_FLOAT_64:
return cbor_float_get_float8(item);
}
- return NAN; /* Compiler complaints */
}
bool cbor_get_bool(const cbor_item_t *item) {
- assert(cbor_is_bool(item));
+ CBOR_ASSERT(cbor_is_bool(item));
return item->metadata.float_ctrl_metadata.ctrl == CBOR_CTRL_TRUE;
}
void cbor_set_float2(cbor_item_t *item, float value) {
- assert(cbor_is_float(item));
- assert(cbor_float_get_width(item) == CBOR_FLOAT_16);
+ CBOR_ASSERT(cbor_is_float(item));
+ CBOR_ASSERT(cbor_float_get_width(item) == CBOR_FLOAT_16);
*((float *)item->data) = value;
}
void cbor_set_float4(cbor_item_t *item, float value) {
- assert(cbor_is_float(item));
- assert(cbor_float_get_width(item) == CBOR_FLOAT_32);
+ CBOR_ASSERT(cbor_is_float(item));
+ CBOR_ASSERT(cbor_float_get_width(item) == CBOR_FLOAT_32);
*((float *)item->data) = value;
}
void cbor_set_float8(cbor_item_t *item, double value) {
- assert(cbor_is_float(item));
- assert(cbor_float_get_width(item) == CBOR_FLOAT_64);
+ CBOR_ASSERT(cbor_is_float(item));
+ CBOR_ASSERT(cbor_float_get_width(item) == CBOR_FLOAT_64);
*((double *)item->data) = value;
}
void cbor_set_ctrl(cbor_item_t *item, uint8_t value) {
- assert(cbor_isa_float_ctrl(item));
- assert(cbor_float_get_width(item) == CBOR_FLOAT_0);
+ CBOR_ASSERT(cbor_isa_float_ctrl(item));
+ CBOR_ASSERT(cbor_float_get_width(item) == CBOR_FLOAT_0);
item->metadata.float_ctrl_metadata.ctrl = value;
}
void cbor_set_bool(cbor_item_t *item, bool value) {
- assert(cbor_is_bool(item));
+ CBOR_ASSERT(cbor_is_bool(item));
item->metadata.float_ctrl_metadata.ctrl =
value ? CBOR_CTRL_TRUE : CBOR_CTRL_FALSE;
}
-cbor_item_t *cbor_new_ctrl() {
- cbor_item_t *item = _CBOR_MALLOC(sizeof(cbor_item_t));
+cbor_item_t *cbor_new_ctrl(void) {
+ cbor_item_t *item = _cbor_malloc(sizeof(cbor_item_t));
_CBOR_NOTNULL(item);
*item = (cbor_item_t){
@@ -106,8 +106,8 @@ cbor_item_t *cbor_new_ctrl() {
return item;
}
-cbor_item_t *cbor_new_float2() {
- cbor_item_t *item = _CBOR_MALLOC(sizeof(cbor_item_t) + 4);
+cbor_item_t *cbor_new_float2(void) {
+ cbor_item_t *item = _cbor_malloc(sizeof(cbor_item_t) + 4);
_CBOR_NOTNULL(item);
*item = (cbor_item_t){
@@ -118,8 +118,8 @@ cbor_item_t *cbor_new_float2() {
return item;
}
-cbor_item_t *cbor_new_float4() {
- cbor_item_t *item = _CBOR_MALLOC(sizeof(cbor_item_t) + 4);
+cbor_item_t *cbor_new_float4(void) {
+ cbor_item_t *item = _cbor_malloc(sizeof(cbor_item_t) + 4);
_CBOR_NOTNULL(item);
*item = (cbor_item_t){
@@ -130,8 +130,8 @@ cbor_item_t *cbor_new_float4() {
return item;
}
-cbor_item_t *cbor_new_float8() {
- cbor_item_t *item = _CBOR_MALLOC(sizeof(cbor_item_t) + 8);
+cbor_item_t *cbor_new_float8(void) {
+ cbor_item_t *item = _cbor_malloc(sizeof(cbor_item_t) + 8);
_CBOR_NOTNULL(item);
*item = (cbor_item_t){
@@ -142,14 +142,14 @@ cbor_item_t *cbor_new_float8() {
return item;
}
-cbor_item_t *cbor_new_null() {
+cbor_item_t *cbor_new_null(void) {
cbor_item_t *item = cbor_new_ctrl();
_CBOR_NOTNULL(item);
cbor_set_ctrl(item, CBOR_CTRL_NULL);
return item;
}
-cbor_item_t *cbor_new_undef() {
+cbor_item_t *cbor_new_undef(void) {
cbor_item_t *item = cbor_new_ctrl();
_CBOR_NOTNULL(item);
cbor_set_ctrl(item, CBOR_CTRL_UNDEF);
diff --git a/src/cbor/floats_ctrls.h b/src/cbor/floats_ctrls.h
index 92eb8bc3eaa3..335eab8328be 100644
--- a/src/cbor/floats_ctrls.h
+++ b/src/cbor/floats_ctrls.h
@@ -23,111 +23,131 @@ extern "C" {
/** Is this a ctrl value?
*
- * @param item[borrow] A float or ctrl item
+ * @param item A float or ctrl item
* @return Is this a ctrl value?
*/
-CBOR_EXPORT bool cbor_float_ctrl_is_ctrl(const cbor_item_t *item);
+_CBOR_NODISCARD CBOR_EXPORT bool cbor_float_ctrl_is_ctrl(
+ const cbor_item_t *item);
/** Get the float width
*
- * @param item[borrow] A float or ctrl item
+ * @param item A float or ctrl item
* @return The width.
*/
-CBOR_EXPORT cbor_float_width cbor_float_get_width(const cbor_item_t *item);
+_CBOR_NODISCARD CBOR_EXPORT cbor_float_width
+cbor_float_get_width(const cbor_item_t *item);
/** Get a half precision float
*
* The item must have the corresponding width
*
- * @param[borrow] A half precision float
+ * @param item A half precision float
* @return half precision value
*/
-CBOR_EXPORT float cbor_float_get_float2(const cbor_item_t *item);
+_CBOR_NODISCARD CBOR_EXPORT float cbor_float_get_float2(
+ const cbor_item_t *item);
/** Get a single precision float
*
* The item must have the corresponding width
*
- * @param[borrow] A signle precision float
+ * @param item A single precision float
* @return single precision value
*/
-CBOR_EXPORT float cbor_float_get_float4(const cbor_item_t *item);
+_CBOR_NODISCARD CBOR_EXPORT float cbor_float_get_float4(
+ const cbor_item_t *item);
/** Get a double precision float
*
* The item must have the corresponding width
*
- * @param[borrow] A double precision float
+ * @param item A double precision float
* @return double precision value
*/
-CBOR_EXPORT double cbor_float_get_float8(const cbor_item_t *item);
+_CBOR_NODISCARD CBOR_EXPORT double cbor_float_get_float8(
+ const cbor_item_t *item);
/** Get the float value represented as double
*
* Can be used regardless of the width.
*
- * @param[borrow] Any float
+ * @param item Any float
* @return double precision value
*/
-CBOR_EXPORT double cbor_float_get_float(const cbor_item_t *item);
+_CBOR_NODISCARD CBOR_EXPORT double cbor_float_get_float(
+ const cbor_item_t *item);
/** Get value from a boolean ctrl item
*
- * @param item[borrow] A ctrl item
+ * @param item A ctrl item
* @return boolean value
*/
-CBOR_EXPORT bool cbor_get_bool(const cbor_item_t *item);
+_CBOR_NODISCARD CBOR_EXPORT bool cbor_get_bool(const cbor_item_t *item);
/** Constructs a new ctrl item
*
* The width cannot be changed once the item is created
*
- * @return **new** 1B ctrl or `NULL` upon memory allocation failure
+ * @return Reference to the new ctrl item. The item's reference count is
+ * initialized to one.
+ * @return `NULL` if memory allocation fails
*/
-CBOR_EXPORT cbor_item_t *cbor_new_ctrl();
+_CBOR_NODISCARD CBOR_EXPORT cbor_item_t *cbor_new_ctrl(void);
/** Constructs a new float item
*
* The width cannot be changed once the item is created
*
- * @return **new** 2B float or `NULL` upon memory allocation failure
+ * @return Reference to the new float item. The item's reference count is
+ * initialized to one.
+ * @return `NULL` if memory allocation fails
*/
-CBOR_EXPORT cbor_item_t *cbor_new_float2();
+_CBOR_NODISCARD CBOR_EXPORT cbor_item_t *cbor_new_float2(void);
/** Constructs a new float item
*
* The width cannot be changed once the item is created
*
- * @return **new** 4B float or `NULL` upon memory allocation failure
+ * @return Reference to the new float item. The item's reference count is
+ * initialized to one.
+ * @return `NULL` if memory allocation fails
*/
-CBOR_EXPORT cbor_item_t *cbor_new_float4();
+_CBOR_NODISCARD CBOR_EXPORT cbor_item_t *cbor_new_float4(void);
/** Constructs a new float item
*
* The width cannot be changed once the item is created
*
- * @return **new** 8B float or `NULL` upon memory allocation failure
+ * @return Reference to the new float item. The item's reference count is
+ * initialized to one.
+ * @return `NULL` if memory allocation fails
*/
-CBOR_EXPORT cbor_item_t *cbor_new_float8();
+_CBOR_NODISCARD CBOR_EXPORT cbor_item_t *cbor_new_float8(void);
/** Constructs new null ctrl item
*
- * @return **new** null ctrl item or `NULL` upon memory allocation failure
+ * @return Reference to the new null item. The item's reference count is
+ * initialized to one.
+ * @return `NULL` if memory allocation fails
*/
-CBOR_EXPORT cbor_item_t *cbor_new_null();
+_CBOR_NODISCARD CBOR_EXPORT cbor_item_t *cbor_new_null(void);
/** Constructs new undef ctrl item
*
- * @return **new** undef ctrl item or `NULL` upon memory allocation failure
+ * @return Reference to the new undef item. The item's reference count is
+ * initialized to one.
+ * @return `NULL` if memory allocation fails
*/
-CBOR_EXPORT cbor_item_t *cbor_new_undef();
+_CBOR_NODISCARD CBOR_EXPORT cbor_item_t *cbor_new_undef(void);
/** Constructs new boolean ctrl item
*
* @param value The value to use
- * @return **new** boolen ctrl item or `NULL` upon memory allocation failure
+ * @return Reference to the new boolean item. The item's reference count is
+ * initialized to one.
+ * @return `NULL` if memory allocation fails
*/
-CBOR_EXPORT cbor_item_t *cbor_build_bool(bool value);
+_CBOR_NODISCARD CBOR_EXPORT cbor_item_t *cbor_build_bool(bool value);
/** Assign a control value
*
@@ -136,7 +156,7 @@ CBOR_EXPORT cbor_item_t *cbor_build_bool(bool value);
* invalid value using this mechanism. Please consult the standard before use.
* \endrst
*
- * @param item[borrow] A ctrl item
+ * @param item A ctrl item
* @param value The simple value to assign. Please consult the standard for
* allowed values
*/
@@ -144,66 +164,74 @@ CBOR_EXPORT void cbor_set_ctrl(cbor_item_t *item, uint8_t value);
/** Assign a boolean value to a boolean ctrl item
*
- * @param item[borrow] A ctrl item
+ * @param item A ctrl item
* @param value The simple value to assign.
*/
CBOR_EXPORT void cbor_set_bool(cbor_item_t *item, bool value);
/** Assigns a float value
*
- * @param item[borrow] A half precision float
+ * @param item A half precision float
* @param value The value to assign
*/
CBOR_EXPORT void cbor_set_float2(cbor_item_t *item, float value);
/** Assigns a float value
*
- * @param item[borrow] A single precision float
+ * @param item A single precision float
* @param value The value to assign
*/
CBOR_EXPORT void cbor_set_float4(cbor_item_t *item, float value);
/** Assigns a float value
*
- * @param item[borrow] A double precision float
+ * @param item A double precision float
* @param value The value to assign
*/
CBOR_EXPORT void cbor_set_float8(cbor_item_t *item, double value);
/** Reads the control value
*
- * @param item[borrow] A ctrl item
+ * @param item A ctrl item
* @return the simple value
*/
-CBOR_EXPORT uint8_t cbor_ctrl_value(const cbor_item_t *item);
+_CBOR_NODISCARD CBOR_EXPORT uint8_t cbor_ctrl_value(const cbor_item_t *item);
/** Constructs a new float
*
* @param value the value to use
- * @return **new** float
+ * @return Reference to the new float item. The item's reference count is
+ * initialized to one.
+ * @return `NULL` if memory allocation fails
*/
-CBOR_EXPORT cbor_item_t *cbor_build_float2(float value);
+_CBOR_NODISCARD CBOR_EXPORT cbor_item_t *cbor_build_float2(float value);
/** Constructs a new float
*
* @param value the value to use
- * @return **new** float or `NULL` upon memory allocation failure
+ * @return Reference to the new float item. The item's reference count is
+ * initialized to one.
+ * @return `NULL` if memory allocation fails
*/
-CBOR_EXPORT cbor_item_t *cbor_build_float4(float value);
+_CBOR_NODISCARD CBOR_EXPORT cbor_item_t *cbor_build_float4(float value);
/** Constructs a new float
*
* @param value the value to use
- * @return **new** float or `NULL` upon memory allocation failure
+ * @return Reference to the new float item. The item's reference count is
+ * initialized to one.
+ * @return `NULL` if memory allocation fails
*/
-CBOR_EXPORT cbor_item_t *cbor_build_float8(double value);
+_CBOR_NODISCARD CBOR_EXPORT cbor_item_t *cbor_build_float8(double value);
/** Constructs a ctrl item
*
* @param value the value to use
- * @return **new** ctrl item or `NULL` upon memory allocation failure
+ * @return Reference to the new ctrl item. The item's reference count is
+ * initialized to one.
+ * @return `NULL` if memory allocation fails
*/
-CBOR_EXPORT cbor_item_t *cbor_build_ctrl(uint8_t value);
+_CBOR_NODISCARD CBOR_EXPORT cbor_item_t *cbor_build_ctrl(uint8_t value);
#ifdef __cplusplus
}
diff --git a/src/cbor/internal/builder_callbacks.c b/src/cbor/internal/builder_callbacks.c
index f6c571136162..78277f050c2b 100644
--- a/src/cbor/internal/builder_callbacks.c
+++ b/src/cbor/internal/builder_callbacks.c
@@ -6,9 +6,12 @@
*/
#include "builder_callbacks.h"
+
#include <string.h>
+
#include "../arrays.h"
#include "../bytestrings.h"
+#include "../common.h"
#include "../floats_ctrls.h"
#include "../ints.h"
#include "../maps.h"
@@ -16,73 +19,96 @@
#include "../tags.h"
#include "unicode.h"
+// `_cbor_builder_append` takes ownership of `item`. If adding the item to
+// parent container fails, `item` will be deallocated to prevent memory.
void _cbor_builder_append(cbor_item_t *item,
struct _cbor_decoder_context *ctx) {
if (ctx->stack->size == 0) {
/* Top level item */
ctx->root = item;
- } else {
- /* Part of a bigger structure */
- switch (ctx->stack->top->item->type) {
- case CBOR_TYPE_ARRAY: {
- if (cbor_array_is_definite(ctx->stack->top->item)) {
- /*
- * We don't need an explicit check for whether the item still belongs
- * into this array because if there are extra items, they will cause a
- * syntax error when decoded.
- */
- assert(ctx->stack->top->subitems > 0);
- cbor_array_push(ctx->stack->top->item, item);
- ctx->stack->top->subitems--;
- if (ctx->stack->top->subitems == 0) {
- cbor_item_t *item = ctx->stack->top->item;
- _cbor_stack_pop(ctx->stack);
- _cbor_builder_append(item, ctx);
- }
- cbor_decref(&item);
- } else {
- /* Indefinite array, don't bother with subitems */
- cbor_array_push(ctx->stack->top->item, item);
+ return;
+ }
+ /* Part of a bigger structure */
+ switch (ctx->stack->top->item->type) {
+ // Handle Arrays and Maps since they can contain subitems of any type.
+ // Byte/string construction from chunks is handled in the respective chunk
+ // handlers.
+ case CBOR_TYPE_ARRAY: {
+ if (cbor_array_is_definite(ctx->stack->top->item)) {
+ // We don't need an explicit check for whether the item still belongs
+ // into this array because if there are extra items, they will cause a
+ // syntax error when decoded.
+ CBOR_ASSERT(ctx->stack->top->subitems > 0);
+ // This should never happen since the definite array should be
+ // preallocated for the expected number of items.
+ if (!cbor_array_push(ctx->stack->top->item, item)) {
+ ctx->creation_failed = true;
cbor_decref(&item);
+ break;
}
- break;
- }
- case CBOR_TYPE_MAP: {
- /* We use 0 and 1 subitems to distinguish between keys and values in
- * indefinite items */
- if (ctx->stack->top->subitems % 2) {
- /* Odd record, this is a value */
- _cbor_map_add_value(ctx->stack->top->item, cbor_move(item));
- } else {
- /* Even record, this is a key */
- _cbor_map_add_key(ctx->stack->top->item, cbor_move(item));
+ cbor_decref(&item);
+ ctx->stack->top->subitems--;
+ if (ctx->stack->top->subitems == 0) {
+ cbor_item_t *stack_item = ctx->stack->top->item;
+ _cbor_stack_pop(ctx->stack);
+ _cbor_builder_append(stack_item, ctx);
}
- if (cbor_map_is_definite(ctx->stack->top->item)) {
- ctx->stack->top->subitems--;
- if (ctx->stack->top->subitems == 0) {
- cbor_item_t *item = ctx->stack->top->item;
- _cbor_stack_pop(ctx->stack);
- _cbor_builder_append(item, ctx);
- }
- } else {
- ctx->stack->top->subitems ^=
- 1; /* Flip the indicator for indefinite items */
+ } else {
+ /* Indefinite array, don't bother with subitems */
+ if (!cbor_array_push(ctx->stack->top->item, item)) {
+ ctx->creation_failed = true;
}
- break;
+ cbor_decref(&item);
}
- case CBOR_TYPE_TAG: {
- assert(ctx->stack->top->subitems == 1);
- cbor_tag_set_item(ctx->stack->top->item, item);
- cbor_decref(&item); /* Give up on our reference */
- cbor_item_t *item = ctx->stack->top->item;
- _cbor_stack_pop(ctx->stack);
- _cbor_builder_append(item, ctx);
- break;
+ break;
+ }
+ case CBOR_TYPE_MAP: {
+ // Handle both definite and indefinite maps the same initially.
+ // Note: We use 0 and 1 subitems to distinguish between keys and values in
+ // indefinite items
+ if (ctx->stack->top->subitems % 2) {
+ /* Odd record, this is a value */
+ if (!_cbor_map_add_value(ctx->stack->top->item, item)) {
+ ctx->creation_failed = true;
+ cbor_decref(&item);
+ break;
+ }
+ } else {
+ /* Even record, this is a key */
+ if (!_cbor_map_add_key(ctx->stack->top->item, item)) {
+ ctx->creation_failed = true;
+ cbor_decref(&item);
+ break;
+ }
}
- default: {
- cbor_decref(&item);
- ctx->syntax_error = true;
+ cbor_decref(&item);
+ if (cbor_map_is_definite(ctx->stack->top->item)) {
+ CBOR_ASSERT(ctx->stack->top->subitems > 0);
+ ctx->stack->top->subitems--;
+ if (ctx->stack->top->subitems == 0) {
+ cbor_item_t *map_entry = ctx->stack->top->item;
+ _cbor_stack_pop(ctx->stack);
+ _cbor_builder_append(map_entry, ctx);
+ }
+ } else {
+ ctx->stack->top->subitems ^=
+ 1; /* Flip the indicator for indefinite items */
}
+ break;
+ }
+ case CBOR_TYPE_TAG: {
+ CBOR_ASSERT(ctx->stack->top->subitems == 1);
+ cbor_tag_set_item(ctx->stack->top->item, item);
+ cbor_decref(&item); /* Give up on our reference */
+ cbor_item_t *tagged_item = ctx->stack->top->item;
+ _cbor_stack_pop(ctx->stack);
+ _cbor_builder_append(tagged_item, ctx);
+ break;
+ }
+ // We have an item to append but nothing to append it to.
+ default: {
+ cbor_decref(&item);
+ ctx->syntax_error = true;
}
}
}
@@ -95,6 +121,16 @@ void _cbor_builder_append(cbor_item_t *item,
} \
} while (0)
+// Check that the length fits into size_t. If not, we cannot possibly allocate
+// the required memory and should fail fast.
+#define CHECK_LENGTH(ctx, length) \
+ do { \
+ if (length > SIZE_MAX) { \
+ ctx->creation_failed = true; \
+ return; \
+ } \
+ } while (0)
+
#define PUSH_CTX_STACK(ctx, res, subitems) \
do { \
if (_cbor_stack_push(ctx->stack, res, subitems) == NULL) { \
@@ -151,6 +187,7 @@ void cbor_builder_negint8_callback(void *context, uint8_t value) {
void cbor_builder_negint16_callback(void *context, uint16_t value) {
struct _cbor_decoder_context *ctx = context;
cbor_item_t *res = cbor_new_int16();
+ CHECK_RES(ctx, res);
cbor_mark_negint(res);
cbor_set_uint16(res, value);
_cbor_builder_append(res, ctx);
@@ -175,34 +212,36 @@ void cbor_builder_negint64_callback(void *context, uint64_t value) {
}
void cbor_builder_byte_string_callback(void *context, cbor_data data,
- size_t length) {
+ uint64_t length) {
struct _cbor_decoder_context *ctx = context;
- unsigned char *new_handle = _CBOR_MALLOC(length);
+ CHECK_LENGTH(ctx, length);
+ unsigned char *new_handle = _cbor_malloc(length);
if (new_handle == NULL) {
ctx->creation_failed = true;
return;
}
memcpy(new_handle, data, length);
- cbor_item_t *res = cbor_new_definite_bytestring();
+ cbor_item_t *new_chunk = cbor_new_definite_bytestring();
- if (res == NULL) {
- _CBOR_FREE(new_handle);
+ if (new_chunk == NULL) {
+ _cbor_free(new_handle);
ctx->creation_failed = true;
return;
}
- cbor_bytestring_set_handle(res, new_handle, length);
+ cbor_bytestring_set_handle(new_chunk, new_handle, length);
- if (ctx->stack->size > 0 && cbor_isa_bytestring(ctx->stack->top->item)) {
- if (cbor_bytestring_is_indefinite(ctx->stack->top->item)) {
- cbor_bytestring_add_chunk(ctx->stack->top->item, cbor_move(res));
- } else {
- cbor_decref(&res);
- ctx->syntax_error = true;
+ // If an indef bytestring is on the stack, extend it (if it were closed, it
+ // would have been popped). Handle any syntax errors upstream.
+ if (ctx->stack->size > 0 && cbor_isa_bytestring(ctx->stack->top->item) &&
+ cbor_bytestring_is_indefinite(ctx->stack->top->item)) {
+ if (!cbor_bytestring_add_chunk(ctx->stack->top->item, new_chunk)) {
+ ctx->creation_failed = true;
}
+ cbor_decref(&new_chunk);
} else {
- _cbor_builder_append(res, ctx);
+ _cbor_builder_append(new_chunk, ctx);
}
}
@@ -214,19 +253,20 @@ void cbor_builder_byte_string_start_callback(void *context) {
}
void cbor_builder_string_callback(void *context, cbor_data data,
- size_t length) {
+ uint64_t length) {
struct _cbor_decoder_context *ctx = context;
+ CHECK_LENGTH(ctx, length);
struct _cbor_unicode_status unicode_status;
-
- size_t codepoint_count =
+ uint64_t codepoint_count =
_cbor_unicode_codepoint_count(data, length, &unicode_status);
- if (unicode_status.status == _CBOR_UNICODE_BADCP) {
+ if (unicode_status.status != _CBOR_UNICODE_OK) {
ctx->syntax_error = true;
return;
}
+ CBOR_ASSERT(codepoint_count <= length);
- unsigned char *new_handle = _CBOR_MALLOC(length);
+ unsigned char *new_handle = _cbor_malloc(length);
if (new_handle == NULL) {
ctx->creation_failed = true;
@@ -234,25 +274,25 @@ void cbor_builder_string_callback(void *context, cbor_data data,
}
memcpy(new_handle, data, length);
- cbor_item_t *res = cbor_new_definite_string();
- if (res == NULL) {
- _CBOR_FREE(new_handle);
+ cbor_item_t *new_chunk = cbor_new_definite_string();
+ if (new_chunk == NULL) {
+ _cbor_free(new_handle);
ctx->creation_failed = true;
return;
}
- cbor_string_set_handle(res, new_handle, length);
- res->metadata.string_metadata.codepoint_count = codepoint_count;
-
- /* Careful here: order matters */
- if (ctx->stack->size > 0 && cbor_isa_string(ctx->stack->top->item)) {
- if (cbor_string_is_indefinite(ctx->stack->top->item)) {
- cbor_string_add_chunk(ctx->stack->top->item, cbor_move(res));
- } else {
- cbor_decref(&res);
- ctx->syntax_error = true;
+ cbor_string_set_handle(new_chunk, new_handle, length);
+ new_chunk->metadata.string_metadata.codepoint_count = codepoint_count;
+
+ // If an indef string is on the stack, extend it (if it were closed, it would
+ // have been popped). Handle any syntax errors upstream.
+ if (ctx->stack->size > 0 && cbor_isa_string(ctx->stack->top->item) &&
+ cbor_string_is_indefinite(ctx->stack->top->item)) {
+ if (!cbor_string_add_chunk(ctx->stack->top->item, new_chunk)) {
+ ctx->creation_failed = true;
}
+ cbor_decref(&new_chunk);
} else {
- _cbor_builder_append(res, ctx);
+ _cbor_builder_append(new_chunk, ctx);
}
}
@@ -263,8 +303,9 @@ void cbor_builder_string_start_callback(void *context) {
PUSH_CTX_STACK(ctx, res, 0);
}
-void cbor_builder_array_start_callback(void *context, size_t size) {
+void cbor_builder_array_start_callback(void *context, uint64_t size) {
struct _cbor_decoder_context *ctx = context;
+ CHECK_LENGTH(ctx, size);
cbor_item_t *res = cbor_new_definite_array(size);
CHECK_RES(ctx, res);
if (size > 0) {
@@ -288,8 +329,9 @@ void cbor_builder_indef_map_start_callback(void *context) {
PUSH_CTX_STACK(ctx, res, 0);
}
-void cbor_builder_map_start_callback(void *context, size_t size) {
+void cbor_builder_map_start_callback(void *context, uint64_t size) {
struct _cbor_decoder_context *ctx = context;
+ CHECK_LENGTH(ctx, size);
cbor_item_t *res = cbor_new_definite_map(size);
CHECK_RES(ctx, res);
if (size > 0) {
@@ -305,14 +347,13 @@ void cbor_builder_map_start_callback(void *context, size_t size) {
bool _cbor_is_indefinite(cbor_item_t *item) {
switch (item->type) {
case CBOR_TYPE_BYTESTRING:
- return item->metadata.bytestring_metadata.type ==
- _CBOR_METADATA_INDEFINITE;
+ return cbor_bytestring_is_indefinite(item);
case CBOR_TYPE_STRING:
- return item->metadata.string_metadata.type == _CBOR_METADATA_INDEFINITE;
+ return cbor_string_is_indefinite(item);
case CBOR_TYPE_ARRAY:
- return item->metadata.array_metadata.type == _CBOR_METADATA_INDEFINITE;
+ return cbor_array_is_indefinite(item);
case CBOR_TYPE_MAP:
- return item->metadata.map_metadata.type == _CBOR_METADATA_INDEFINITE;
+ return cbor_map_is_indefinite(item);
default:
return false;
}
@@ -340,6 +381,7 @@ void cbor_builder_indef_break_callback(void *context) {
void cbor_builder_float2_callback(void *context, float value) {
struct _cbor_decoder_context *ctx = context;
cbor_item_t *res = cbor_new_float2();
+ CHECK_RES(ctx, res);
cbor_set_float2(res, value);
_cbor_builder_append(res, ctx);
}
diff --git a/src/cbor/internal/builder_callbacks.h b/src/cbor/internal/builder_callbacks.h
index a93afb1ca8f8..7893960e4131 100644
--- a/src/cbor/internal/builder_callbacks.h
+++ b/src/cbor/internal/builder_callbacks.h
@@ -26,6 +26,10 @@ struct _cbor_decoder_context {
struct _cbor_stack *stack;
};
+/** Internal helper: Append item to the top of the stack while handling errors.
+ */
+void _cbor_builder_append(cbor_item_t *item, struct _cbor_decoder_context *ctx);
+
void cbor_builder_uint8_callback(void *, uint8_t);
void cbor_builder_uint16_callback(void *, uint16_t);
@@ -42,19 +46,19 @@ void cbor_builder_negint32_callback(void *, uint32_t);
void cbor_builder_negint64_callback(void *, uint64_t);
-void cbor_builder_string_callback(void *, cbor_data, size_t);
+void cbor_builder_string_callback(void *, cbor_data, uint64_t);
void cbor_builder_string_start_callback(void *);
-void cbor_builder_byte_string_callback(void *, cbor_data, size_t);
+void cbor_builder_byte_string_callback(void *, cbor_data, uint64_t);
void cbor_builder_byte_string_start_callback(void *);
-void cbor_builder_array_start_callback(void *, size_t);
+void cbor_builder_array_start_callback(void *, uint64_t);
void cbor_builder_indef_array_start_callback(void *);
-void cbor_builder_map_start_callback(void *, size_t);
+void cbor_builder_map_start_callback(void *, uint64_t);
void cbor_builder_indef_map_start_callback(void *);
diff --git a/src/cbor/internal/encoders.c b/src/cbor/internal/encoders.c
index 657e25c3987a..49d4d7f33d2b 100644
--- a/src/cbor/internal/encoders.c
+++ b/src/cbor/internal/encoders.c
@@ -33,8 +33,8 @@ size_t _cbor_encode_uint16(uint16_t value, unsigned char *buffer,
#ifdef IS_BIG_ENDIAN
memcpy(buffer + 1, &value, 2);
#else
- buffer[1] = value >> 8;
- buffer[2] = value;
+ buffer[1] = (unsigned char)(value >> 8);
+ buffer[2] = (unsigned char)value;
#endif
return 3;
@@ -50,10 +50,10 @@ size_t _cbor_encode_uint32(uint32_t value, unsigned char *buffer,
#ifdef IS_BIG_ENDIAN
memcpy(buffer + 1, &value, 4);
#else
- buffer[1] = value >> 24;
- buffer[2] = value >> 16;
- buffer[3] = value >> 8;
- buffer[4] = value;
+ buffer[1] = (unsigned char)(value >> 24);
+ buffer[2] = (unsigned char)(value >> 16);
+ buffer[3] = (unsigned char)(value >> 8);
+ buffer[4] = (unsigned char)value;
#endif
return 5;
@@ -69,14 +69,14 @@ size_t _cbor_encode_uint64(uint64_t value, unsigned char *buffer,
#ifdef IS_BIG_ENDIAN
memcpy(buffer + 1, &value, 8);
#else
- buffer[1] = value >> 56;
- buffer[2] = value >> 48;
- buffer[3] = value >> 40;
- buffer[4] = value >> 32;
- buffer[5] = value >> 24;
- buffer[6] = value >> 16;
- buffer[7] = value >> 8;
- buffer[8] = value;
+ buffer[1] = (unsigned char)(value >> 56);
+ buffer[2] = (unsigned char)(value >> 48);
+ buffer[3] = (unsigned char)(value >> 40);
+ buffer[4] = (unsigned char)(value >> 32);
+ buffer[5] = (unsigned char)(value >> 24);
+ buffer[6] = (unsigned char)(value >> 16);
+ buffer[7] = (unsigned char)(value >> 8);
+ buffer[8] = (unsigned char)value;
#endif
return 9;
diff --git a/src/cbor/internal/encoders.h b/src/cbor/internal/encoders.h
index 14ad5015cb5a..7eadb7121646 100644
--- a/src/cbor/internal/encoders.h
+++ b/src/cbor/internal/encoders.h
@@ -14,18 +14,23 @@
extern "C" {
#endif
+_CBOR_NODISCARD
size_t _cbor_encode_uint8(uint8_t value, unsigned char *buffer,
size_t buffer_size, uint8_t offset);
+_CBOR_NODISCARD
size_t _cbor_encode_uint16(uint16_t value, unsigned char *buffer,
size_t buffer_size, uint8_t offset);
+_CBOR_NODISCARD
size_t _cbor_encode_uint32(uint32_t value, unsigned char *buffer,
size_t buffer_size, uint8_t offset);
+_CBOR_NODISCARD
size_t _cbor_encode_uint64(uint64_t value, unsigned char *buffer,
size_t buffer_size, uint8_t offset);
+_CBOR_NODISCARD
size_t _cbor_encode_uint(uint64_t value, unsigned char *buffer,
size_t buffer_size, uint8_t offset);
diff --git a/src/cbor/internal/loaders.c b/src/cbor/internal/loaders.c
index af00f135527f..c25c63358318 100644
--- a/src/cbor/internal/loaders.c
+++ b/src/cbor/internal/loaders.c
@@ -64,7 +64,7 @@ float _cbor_decode_half(unsigned char *halfp) {
return (float)(half & 0x8000 ? -val : val);
}
-double _cbor_load_half(cbor_data source) {
+float _cbor_load_half(cbor_data source) {
/* Discard const */
return _cbor_decode_half((unsigned char *)source);
}
diff --git a/src/cbor/internal/loaders.h b/src/cbor/internal/loaders.h
index a4c82b209f55..ce37563a3d80 100644
--- a/src/cbor/internal/loaders.h
+++ b/src/cbor/internal/loaders.h
@@ -15,18 +15,25 @@ extern "C" {
#endif
/* Read the given uint from the given location, no questions asked */
+_CBOR_NODISCARD
uint8_t _cbor_load_uint8(const unsigned char *source);
+_CBOR_NODISCARD
uint16_t _cbor_load_uint16(const unsigned char *source);
+_CBOR_NODISCARD
uint32_t _cbor_load_uint32(const unsigned char *source);
+_CBOR_NODISCARD
uint64_t _cbor_load_uint64(const unsigned char *source);
-double _cbor_load_half(cbor_data source);
+_CBOR_NODISCARD
+float _cbor_load_half(cbor_data source);
+_CBOR_NODISCARD
float _cbor_load_float(cbor_data source);
+_CBOR_NODISCARD
double _cbor_load_double(cbor_data source);
#ifdef __cplusplus
diff --git a/src/cbor/internal/memory_utils.c b/src/cbor/internal/memory_utils.c
index 918b708e3313..bbea63cb9f06 100644
--- a/src/cbor/internal/memory_utils.c
+++ b/src/cbor/internal/memory_utils.c
@@ -23,12 +23,25 @@ size_t _cbor_highest_bit(size_t number) {
}
bool _cbor_safe_to_multiply(size_t a, size_t b) {
+ if (a <= 1 || b <= 1) return true;
return _cbor_highest_bit(a) + _cbor_highest_bit(b) <= sizeof(size_t) * 8;
}
+bool _cbor_safe_to_add(size_t a, size_t b) {
+ // Unsigned integer overflow doesn't constitute UB
+ size_t sum = a + b;
+ return sum >= a && sum >= b;
+}
+
+size_t _cbor_safe_signaling_add(size_t a, size_t b) {
+ if (a == 0 || b == 0) return 0;
+ if (_cbor_safe_to_add(a, b)) return a + b;
+ return 0;
+}
+
void* _cbor_alloc_multiple(size_t item_size, size_t item_count) {
if (_cbor_safe_to_multiply(item_size, item_count)) {
- return _CBOR_MALLOC(item_size * item_count);
+ return _cbor_malloc(item_size * item_count);
} else {
return NULL;
}
@@ -37,7 +50,7 @@ void* _cbor_alloc_multiple(size_t item_size, size_t item_count) {
void* _cbor_realloc_multiple(void* pointer, size_t item_size,
size_t item_count) {
if (_cbor_safe_to_multiply(item_size, item_count)) {
- return _CBOR_REALLOC(pointer, item_size * item_count);
+ return _cbor_realloc(pointer, item_size * item_count);
} else {
return NULL;
}
diff --git a/src/cbor/internal/memory_utils.h b/src/cbor/internal/memory_utils.h
index c41ace67948f..14843c8c56f6 100644
--- a/src/cbor/internal/memory_utils.h
+++ b/src/cbor/internal/memory_utils.h
@@ -11,9 +11,20 @@
#include <stdbool.h>
#include <string.h>
-/** Can a and b be multiplied without overflowing size_t? */
+#include "cbor/common.h"
+
+/** Can `a` and `b` be multiplied without overflowing size_t? */
+_CBOR_NODISCARD
bool _cbor_safe_to_multiply(size_t a, size_t b);
+/** Can `a` and `b` be added without overflowing size_t? */
+_CBOR_NODISCARD
+bool _cbor_safe_to_add(size_t a, size_t b);
+
+/** Adds `a` and `b`, propagating zeros and returing 0 on overflow. */
+_CBOR_NODISCARD
+size_t _cbor_safe_signaling_add(size_t a, size_t b);
+
/** Overflow-proof contiguous array allocation
*
* @param item_size
diff --git a/src/cbor/internal/stack.c b/src/cbor/internal/stack.c
index 79c9e5e5297e..2db03cbbf081 100644
--- a/src/cbor/internal/stack.c
+++ b/src/cbor/internal/stack.c
@@ -7,14 +7,14 @@
#include "stack.h"
-struct _cbor_stack _cbor_stack_init() {
+struct _cbor_stack _cbor_stack_init(void) {
return (struct _cbor_stack){.top = NULL, .size = 0};
}
void _cbor_stack_pop(struct _cbor_stack *stack) {
struct _cbor_stack_record *top = stack->top;
stack->top = stack->top->lower;
- _CBOR_FREE(top);
+ _cbor_free(top);
stack->size--;
}
@@ -23,7 +23,7 @@ struct _cbor_stack_record *_cbor_stack_push(struct _cbor_stack *stack,
size_t subitems) {
if (stack->size == CBOR_MAX_STACK_SIZE) return NULL;
struct _cbor_stack_record *new_top =
- _CBOR_MALLOC(sizeof(struct _cbor_stack_record));
+ _cbor_malloc(sizeof(struct _cbor_stack_record));
if (new_top == NULL) return NULL;
*new_top = (struct _cbor_stack_record){stack->top, item, subitems};
diff --git a/src/cbor/internal/stack.h b/src/cbor/internal/stack.h
index 42ed04429c7e..cf2206b40e58 100644
--- a/src/cbor/internal/stack.h
+++ b/src/cbor/internal/stack.h
@@ -16,8 +16,18 @@ extern "C" {
/** Simple stack record for the parser */
struct _cbor_stack_record {
+ /** Pointer to the parent stack frame */
struct _cbor_stack_record *lower;
+ /** Item under construction */
cbor_item_t *item;
+ /**
+ * How many outstanding subitems are expected.
+ *
+ * For example, when we see a new definite array, `subitems` is initialized to
+ * the array length. With every item added, the counter is decreased. When it
+ * reaches zero, the stack is popped and the complete item is propagated
+ * upwards.
+ */
size_t subitems;
};
@@ -27,10 +37,12 @@ struct _cbor_stack {
size_t size;
};
-struct _cbor_stack _cbor_stack_init();
+_CBOR_NODISCARD
+struct _cbor_stack _cbor_stack_init(void);
void _cbor_stack_pop(struct _cbor_stack *);
+_CBOR_NODISCARD
struct _cbor_stack_record *_cbor_stack_push(struct _cbor_stack *, cbor_item_t *,
size_t);
diff --git a/src/cbor/internal/unicode.c b/src/cbor/internal/unicode.c
index 98b49728989e..1831c8e62057 100644
--- a/src/cbor/internal/unicode.c
+++ b/src/cbor/internal/unicode.c
@@ -6,6 +6,7 @@
*/
#include "unicode.h"
+#include <stdint.h>
#define UTF8_ACCEPT 0
#define UTF8_REJECT 1
@@ -65,12 +66,12 @@ uint32_t _cbor_unicode_decode(uint32_t* state, uint32_t* codep, uint32_t byte) {
return *state;
}
-size_t _cbor_unicode_codepoint_count(cbor_data source, size_t source_length,
- struct _cbor_unicode_status* status) {
+uint64_t _cbor_unicode_codepoint_count(cbor_data source, uint64_t source_length,
+ struct _cbor_unicode_status* status) {
*status =
(struct _cbor_unicode_status){.location = 0, .status = _CBOR_UNICODE_OK};
uint32_t codepoint, state = UTF8_ACCEPT, res;
- size_t pos = 0, count = 0;
+ uint64_t pos = 0, count = 0;
for (; pos < source_length; pos++) {
res = _cbor_unicode_decode(&state, &codepoint, source[pos]);
@@ -90,5 +91,5 @@ size_t _cbor_unicode_codepoint_count(cbor_data source, size_t source_length,
error:
*status = (struct _cbor_unicode_status){.location = pos,
.status = _CBOR_UNICODE_BADCP};
- return -1;
+ return 0;
}
diff --git a/src/cbor/internal/unicode.h b/src/cbor/internal/unicode.h
index 5f6456029306..af32cc7ff027 100644
--- a/src/cbor/internal/unicode.h
+++ b/src/cbor/internal/unicode.h
@@ -19,11 +19,12 @@ enum _cbor_unicode_status_error { _CBOR_UNICODE_OK, _CBOR_UNICODE_BADCP };
/** Signals unicode validation error and possibly its location */
struct _cbor_unicode_status {
enum _cbor_unicode_status_error status;
- size_t location;
+ uint64_t location;
};
-size_t _cbor_unicode_codepoint_count(cbor_data source, size_t source_length,
- struct _cbor_unicode_status* status);
+_CBOR_NODISCARD
+uint64_t _cbor_unicode_codepoint_count(cbor_data source, uint64_t source_length,
+ struct _cbor_unicode_status* status);
#ifdef __cplusplus
}
diff --git a/src/cbor/ints.c b/src/cbor/ints.c
index 880982e5a3e5..b4d035a1897e 100644
--- a/src/cbor/ints.c
+++ b/src/cbor/ints.c
@@ -8,36 +8,37 @@
#include "ints.h"
cbor_int_width cbor_int_get_width(const cbor_item_t *item) {
- assert(cbor_is_int(item));
+ CBOR_ASSERT(cbor_is_int(item));
return item->metadata.int_metadata.width;
}
uint8_t cbor_get_uint8(const cbor_item_t *item) {
- assert(cbor_is_int(item));
- assert(cbor_int_get_width(item) == CBOR_INT_8);
+ CBOR_ASSERT(cbor_is_int(item));
+ CBOR_ASSERT(cbor_int_get_width(item) == CBOR_INT_8);
return *item->data;
}
uint16_t cbor_get_uint16(const cbor_item_t *item) {
- assert(cbor_is_int(item));
- assert(cbor_int_get_width(item) == CBOR_INT_16);
+ CBOR_ASSERT(cbor_is_int(item));
+ CBOR_ASSERT(cbor_int_get_width(item) == CBOR_INT_16);
return *(uint16_t *)item->data;
}
uint32_t cbor_get_uint32(const cbor_item_t *item) {
- assert(cbor_is_int(item));
- assert(cbor_int_get_width(item) == CBOR_INT_32);
+ CBOR_ASSERT(cbor_is_int(item));
+ CBOR_ASSERT(cbor_int_get_width(item) == CBOR_INT_32);
return *(uint32_t *)item->data;
}
uint64_t cbor_get_uint64(const cbor_item_t *item) {
- assert(cbor_is_int(item));
- assert(cbor_int_get_width(item) == CBOR_INT_64);
+ CBOR_ASSERT(cbor_is_int(item));
+ CBOR_ASSERT(cbor_int_get_width(item) == CBOR_INT_64);
return *(uint64_t *)item->data;
}
uint64_t cbor_get_int(const cbor_item_t *item) {
- assert(cbor_is_int(item));
+ CBOR_ASSERT(cbor_is_int(item));
+ // cppcheck-suppress missingReturn
switch (cbor_int_get_width(item)) {
case CBOR_INT_8:
return cbor_get_uint8(item);
@@ -48,46 +49,44 @@ uint64_t cbor_get_int(const cbor_item_t *item) {
case CBOR_INT_64:
return cbor_get_uint64(item);
}
- // TODO: This should be handled in a default branch
- return 0xDEADBEEF; /* Compiler complaints */
}
void cbor_set_uint8(cbor_item_t *item, uint8_t value) {
- assert(cbor_is_int(item));
- assert(cbor_int_get_width(item) == CBOR_INT_8);
+ CBOR_ASSERT(cbor_is_int(item));
+ CBOR_ASSERT(cbor_int_get_width(item) == CBOR_INT_8);
*item->data = value;
}
void cbor_set_uint16(cbor_item_t *item, uint16_t value) {
- assert(cbor_is_int(item));
- assert(cbor_int_get_width(item) == CBOR_INT_16);
+ CBOR_ASSERT(cbor_is_int(item));
+ CBOR_ASSERT(cbor_int_get_width(item) == CBOR_INT_16);
*(uint16_t *)item->data = value;
}
void cbor_set_uint32(cbor_item_t *item, uint32_t value) {
- assert(cbor_is_int(item));
- assert(cbor_int_get_width(item) == CBOR_INT_32);
+ CBOR_ASSERT(cbor_is_int(item));
+ CBOR_ASSERT(cbor_int_get_width(item) == CBOR_INT_32);
*(uint32_t *)item->data = value;
}
void cbor_set_uint64(cbor_item_t *item, uint64_t value) {
- assert(cbor_is_int(item));
- assert(cbor_int_get_width(item) == CBOR_INT_64);
+ CBOR_ASSERT(cbor_is_int(item));
+ CBOR_ASSERT(cbor_int_get_width(item) == CBOR_INT_64);
*(uint64_t *)item->data = value;
}
void cbor_mark_uint(cbor_item_t *item) {
- assert(cbor_is_int(item));
+ CBOR_ASSERT(cbor_is_int(item));
item->type = CBOR_TYPE_UINT;
}
void cbor_mark_negint(cbor_item_t *item) {
- assert(cbor_is_int(item));
+ CBOR_ASSERT(cbor_is_int(item));
item->type = CBOR_TYPE_NEGINT;
}
-cbor_item_t *cbor_new_int8() {
- cbor_item_t *item = _CBOR_MALLOC(sizeof(cbor_item_t) + 1);
+cbor_item_t *cbor_new_int8(void) {
+ cbor_item_t *item = _cbor_malloc(sizeof(cbor_item_t) + 1);
_CBOR_NOTNULL(item);
*item = (cbor_item_t){.data = (unsigned char *)item + sizeof(cbor_item_t),
.refcount = 1,
@@ -96,8 +95,8 @@ cbor_item_t *cbor_new_int8() {
return item;
}
-cbor_item_t *cbor_new_int16() {
- cbor_item_t *item = _CBOR_MALLOC(sizeof(cbor_item_t) + 2);
+cbor_item_t *cbor_new_int16(void) {
+ cbor_item_t *item = _cbor_malloc(sizeof(cbor_item_t) + 2);
_CBOR_NOTNULL(item);
*item = (cbor_item_t){.data = (unsigned char *)item + sizeof(cbor_item_t),
.refcount = 1,
@@ -106,8 +105,8 @@ cbor_item_t *cbor_new_int16() {
return item;
}
-cbor_item_t *cbor_new_int32() {
- cbor_item_t *item = _CBOR_MALLOC(sizeof(cbor_item_t) + 4);
+cbor_item_t *cbor_new_int32(void) {
+ cbor_item_t *item = _cbor_malloc(sizeof(cbor_item_t) + 4);
_CBOR_NOTNULL(item);
*item = (cbor_item_t){.data = (unsigned char *)item + sizeof(cbor_item_t),
.refcount = 1,
@@ -116,8 +115,8 @@ cbor_item_t *cbor_new_int32() {
return item;
}
-cbor_item_t *cbor_new_int64() {
- cbor_item_t *item = _CBOR_MALLOC(sizeof(cbor_item_t) + 8);
+cbor_item_t *cbor_new_int64(void) {
+ cbor_item_t *item = _cbor_malloc(sizeof(cbor_item_t) + 8);
_CBOR_NOTNULL(item);
*item = (cbor_item_t){.data = (unsigned char *)item + sizeof(cbor_item_t),
.refcount = 1,
diff --git a/src/cbor/ints.h b/src/cbor/ints.h
index fc7de600102e..006aa428e0a5 100644
--- a/src/cbor/ints.h
+++ b/src/cbor/ints.h
@@ -23,42 +23,42 @@ extern "C" {
/** Extracts the integer value
*
- * @param item[borrow] positive or negative integer
+ * @param item positive or negative integer
* @return the value
*/
-CBOR_EXPORT uint8_t cbor_get_uint8(const cbor_item_t *item);
+_CBOR_NODISCARD CBOR_EXPORT uint8_t cbor_get_uint8(const cbor_item_t *item);
/** Extracts the integer value
*
- * @param item[borrow] positive or negative integer
+ * @param item positive or negative integer
* @return the value
*/
-CBOR_EXPORT uint16_t cbor_get_uint16(const cbor_item_t *item);
+_CBOR_NODISCARD CBOR_EXPORT uint16_t cbor_get_uint16(const cbor_item_t *item);
/** Extracts the integer value
*
- * @param item[borrow] positive or negative integer
+ * @param item positive or negative integer
* @return the value
*/
-CBOR_EXPORT uint32_t cbor_get_uint32(const cbor_item_t *item);
+_CBOR_NODISCARD CBOR_EXPORT uint32_t cbor_get_uint32(const cbor_item_t *item);
/** Extracts the integer value
*
- * @param item[borrow] positive or negative integer
+ * @param item positive or negative integer
* @return the value
*/
-CBOR_EXPORT uint64_t cbor_get_uint64(const cbor_item_t *item);
+_CBOR_NODISCARD CBOR_EXPORT uint64_t cbor_get_uint64(const cbor_item_t *item);
/** Extracts the integer value
*
- * @param item[borrow] positive or negative integer
+ * @param item positive or negative integer
* @return the value, extended to `uint64_t`
*/
-CBOR_EXPORT uint64_t cbor_get_int(const cbor_item_t *item);
+_CBOR_NODISCARD CBOR_EXPORT uint64_t cbor_get_int(const cbor_item_t *item);
/** Assigns the integer value
*
- * @param item[borrow] positive or negative integer item
+ * @param item positive or negative integer item
* @param value the value to assign. For negative integer, the logical value is
* `-value - 1`
*/
@@ -66,7 +66,7 @@ CBOR_EXPORT void cbor_set_uint8(cbor_item_t *item, uint8_t value);
/** Assigns the integer value
*
- * @param item[borrow] positive or negative integer item
+ * @param item positive or negative integer item
* @param value the value to assign. For negative integer, the logical value is
* `-value - 1`
*/
@@ -74,7 +74,7 @@ CBOR_EXPORT void cbor_set_uint16(cbor_item_t *item, uint16_t value);
/** Assigns the integer value
*
- * @param item[borrow] positive or negative integer item
+ * @param item positive or negative integer item
* @param value the value to assign. For negative integer, the logical value is
* `-value - 1`
*/
@@ -82,7 +82,7 @@ CBOR_EXPORT void cbor_set_uint32(cbor_item_t *item, uint32_t value);
/** Assigns the integer value
*
- * @param item[borrow] positive or negative integer item
+ * @param item positive or negative integer item
* @param value the value to assign. For negative integer, the logical value is
* `-value - 1`
*/
@@ -90,16 +90,17 @@ CBOR_EXPORT void cbor_set_uint64(cbor_item_t *item, uint64_t value);
/** Queries the integer width
*
- * @param item[borrow] positive or negative integer item
+ * @param item positive or negative integer item
* @return the width
*/
-CBOR_EXPORT cbor_int_width cbor_int_get_width(const cbor_item_t *item);
+_CBOR_NODISCARD CBOR_EXPORT cbor_int_width
+cbor_int_get_width(const cbor_item_t *item);
/** Marks the integer item as a positive integer
*
* The data value is not changed
*
- * @param item[borrow] positive or negative integer item
+ * @param item positive or negative integer item
*/
CBOR_EXPORT void cbor_mark_uint(cbor_item_t *item);
@@ -107,7 +108,7 @@ CBOR_EXPORT void cbor_mark_uint(cbor_item_t *item);
*
* The data value is not changed
*
- * @param item[borrow] positive or negative integer item
+ * @param item positive or negative integer item
*/
CBOR_EXPORT void cbor_mark_negint(cbor_item_t *item);
@@ -118,7 +119,7 @@ CBOR_EXPORT void cbor_mark_negint(cbor_item_t *item);
* @return **new** positive integer or `NULL` on memory allocation failure. The
* value is not initialized
*/
-CBOR_EXPORT cbor_item_t *cbor_new_int8();
+_CBOR_NODISCARD CBOR_EXPORT cbor_item_t *cbor_new_int8(void);
/** Allocates new integer with 2B width
*
@@ -127,7 +128,7 @@ CBOR_EXPORT cbor_item_t *cbor_new_int8();
* @return **new** positive integer or `NULL` on memory allocation failure. The
* value is not initialized
*/
-CBOR_EXPORT cbor_item_t *cbor_new_int16();
+_CBOR_NODISCARD CBOR_EXPORT cbor_item_t *cbor_new_int16(void);
/** Allocates new integer with 4B width
*
@@ -136,7 +137,7 @@ CBOR_EXPORT cbor_item_t *cbor_new_int16();
* @return **new** positive integer or `NULL` on memory allocation failure. The
* value is not initialized
*/
-CBOR_EXPORT cbor_item_t *cbor_new_int32();
+_CBOR_NODISCARD CBOR_EXPORT cbor_item_t *cbor_new_int32(void);
/** Allocates new integer with 8B width
*
@@ -145,63 +146,63 @@ CBOR_EXPORT cbor_item_t *cbor_new_int32();
* @return **new** positive integer or `NULL` on memory allocation failure. The
* value is not initialized
*/
-CBOR_EXPORT cbor_item_t *cbor_new_int64();
+_CBOR_NODISCARD CBOR_EXPORT cbor_item_t *cbor_new_int64(void);
/** Constructs a new positive integer
*
* @param value the value to use
* @return **new** positive integer or `NULL` on memory allocation failure
*/
-CBOR_EXPORT cbor_item_t *cbor_build_uint8(uint8_t value);
+_CBOR_NODISCARD CBOR_EXPORT cbor_item_t *cbor_build_uint8(uint8_t value);
/** Constructs a new positive integer
*
* @param value the value to use
* @return **new** positive integer or `NULL` on memory allocation failure
*/
-CBOR_EXPORT cbor_item_t *cbor_build_uint16(uint16_t value);
+_CBOR_NODISCARD CBOR_EXPORT cbor_item_t *cbor_build_uint16(uint16_t value);
/** Constructs a new positive integer
*
* @param value the value to use
* @return **new** positive integer or `NULL` on memory allocation failure
*/
-CBOR_EXPORT cbor_item_t *cbor_build_uint32(uint32_t value);
+_CBOR_NODISCARD CBOR_EXPORT cbor_item_t *cbor_build_uint32(uint32_t value);
/** Constructs a new positive integer
*
* @param value the value to use
* @return **new** positive integer or `NULL` on memory allocation failure
*/
-CBOR_EXPORT cbor_item_t *cbor_build_uint64(uint64_t value);
+_CBOR_NODISCARD CBOR_EXPORT cbor_item_t *cbor_build_uint64(uint64_t value);
/** Constructs a new negative integer
*
* @param value the value to use
* @return **new** negative integer or `NULL` on memory allocation failure
*/
-CBOR_EXPORT cbor_item_t *cbor_build_negint8(uint8_t value);
+_CBOR_NODISCARD CBOR_EXPORT cbor_item_t *cbor_build_negint8(uint8_t value);
/** Constructs a new negative integer
*
* @param value the value to use
* @return **new** negative integer or `NULL` on memory allocation failure
*/
-CBOR_EXPORT cbor_item_t *cbor_build_negint16(uint16_t value);
+_CBOR_NODISCARD CBOR_EXPORT cbor_item_t *cbor_build_negint16(uint16_t value);
/** Constructs a new negative integer
*
* @param value the value to use
* @return **new** negative integer or `NULL` on memory allocation failure
*/
-CBOR_EXPORT cbor_item_t *cbor_build_negint32(uint32_t value);
+_CBOR_NODISCARD CBOR_EXPORT cbor_item_t *cbor_build_negint32(uint32_t value);
/** Constructs a new negative integer
*
* @param value the value to use
* @return **new** negative integer or `NULL` on memory allocation failure
*/
-CBOR_EXPORT cbor_item_t *cbor_build_negint64(uint64_t value);
+_CBOR_NODISCARD CBOR_EXPORT cbor_item_t *cbor_build_negint64(uint64_t value);
#ifdef __cplusplus
}
diff --git a/src/cbor/maps.c b/src/cbor/maps.c
index 45140e2cfa2b..8711e57acb70 100644
--- a/src/cbor/maps.c
+++ b/src/cbor/maps.c
@@ -9,17 +9,17 @@
#include "internal/memory_utils.h"
size_t cbor_map_size(const cbor_item_t *item) {
- assert(cbor_isa_map(item));
+ CBOR_ASSERT(cbor_isa_map(item));
return item->metadata.map_metadata.end_ptr;
}
size_t cbor_map_allocated(const cbor_item_t *item) {
- assert(cbor_isa_map(item));
+ CBOR_ASSERT(cbor_isa_map(item));
return item->metadata.map_metadata.allocated;
}
cbor_item_t *cbor_new_definite_map(size_t size) {
- cbor_item_t *item = _CBOR_MALLOC(sizeof(cbor_item_t));
+ cbor_item_t *item = _cbor_malloc(sizeof(cbor_item_t));
_CBOR_NOTNULL(item);
*item = (cbor_item_t){
@@ -34,8 +34,8 @@ cbor_item_t *cbor_new_definite_map(size_t size) {
return item;
}
-cbor_item_t *cbor_new_indefinite_map() {
- cbor_item_t *item = _CBOR_MALLOC(sizeof(cbor_item_t));
+cbor_item_t *cbor_new_indefinite_map(void) {
+ cbor_item_t *item = _cbor_malloc(sizeof(cbor_item_t));
_CBOR_NOTNULL(item);
*item = (cbor_item_t){
@@ -50,7 +50,7 @@ cbor_item_t *cbor_new_indefinite_map() {
}
bool _cbor_map_add_key(cbor_item_t *item, cbor_item_t *key) {
- assert(cbor_isa_map(item));
+ CBOR_ASSERT(cbor_isa_map(item));
struct _cbor_map_metadata *metadata =
(struct _cbor_map_metadata *)&item->metadata;
if (cbor_map_is_definite(item)) {
@@ -66,7 +66,6 @@ bool _cbor_map_add_key(cbor_item_t *item, cbor_item_t *key) {
if (metadata->end_ptr >= metadata->allocated) {
/* Exponential realloc */
// Check for overflows first
- // TODO: Explicitly test this
if (!_cbor_safe_to_multiply(CBOR_BUFFER_GROWTH, metadata->allocated)) {
return false;
}
@@ -94,7 +93,7 @@ bool _cbor_map_add_key(cbor_item_t *item, cbor_item_t *key) {
}
bool _cbor_map_add_value(cbor_item_t *item, cbor_item_t *value) {
- assert(cbor_isa_map(item));
+ CBOR_ASSERT(cbor_isa_map(item));
cbor_incref(value);
cbor_map_handle(item)[
/* Move one back since we are assuming _add_key (which increased the ptr)
@@ -105,13 +104,13 @@ bool _cbor_map_add_value(cbor_item_t *item, cbor_item_t *value) {
}
bool cbor_map_add(cbor_item_t *item, struct cbor_pair pair) {
- assert(cbor_isa_map(item));
+ CBOR_ASSERT(cbor_isa_map(item));
if (!_cbor_map_add_key(item, pair.key)) return false;
return _cbor_map_add_value(item, pair.value);
}
bool cbor_map_is_definite(const cbor_item_t *item) {
- assert(cbor_isa_map(item));
+ CBOR_ASSERT(cbor_isa_map(item));
return item->metadata.map_metadata.type == _CBOR_METADATA_DEFINITE;
}
@@ -120,6 +119,6 @@ bool cbor_map_is_indefinite(const cbor_item_t *item) {
}
struct cbor_pair *cbor_map_handle(const cbor_item_t *item) {
- assert(cbor_isa_map(item));
+ CBOR_ASSERT(cbor_isa_map(item));
return (struct cbor_pair *)item->data;
}
diff --git a/src/cbor/maps.h b/src/cbor/maps.h
index 370c6fcd4336..5c05b542bd84 100644
--- a/src/cbor/maps.h
+++ b/src/cbor/maps.h
@@ -23,87 +23,96 @@ extern "C" {
/** Get the number of pairs
*
- * @param item[borrow] A map
+ * @param item A map
* @return The number of pairs
*/
-CBOR_EXPORT size_t cbor_map_size(const cbor_item_t *item);
+_CBOR_NODISCARD CBOR_EXPORT size_t cbor_map_size(const cbor_item_t *item);
/** Get the size of the allocated storage
*
- * @param item[borrow] A map
+ * @param item A map
* @return Allocated storage size (as the number of #cbor_pair items)
*/
-CBOR_EXPORT size_t cbor_map_allocated(const cbor_item_t *item);
+_CBOR_NODISCARD CBOR_EXPORT size_t cbor_map_allocated(const cbor_item_t *item);
/** Create a new definite map
*
* @param size The number of slots to preallocate
- * @return **new** definite map. `NULL` on malloc failure.
+ * @return Reference to the new map item. The item's reference count is
+ * initialized to one.
+ * @return `NULL` if memory allocation fails
*/
-CBOR_EXPORT cbor_item_t *cbor_new_definite_map(size_t size);
+_CBOR_NODISCARD CBOR_EXPORT cbor_item_t *cbor_new_definite_map(size_t size);
/** Create a new indefinite map
*
- * @param size The number of slots to preallocate
- * @return **new** definite map. `NULL` on malloc failure.
+ * @return Reference to the new map item. The item's reference count is
+ * initialized to one.
+ * @return `NULL` if memory allocation fails
*/
-CBOR_EXPORT cbor_item_t *cbor_new_indefinite_map();
+_CBOR_NODISCARD CBOR_EXPORT cbor_item_t *cbor_new_indefinite_map(void);
/** Add a pair to the map
*
* For definite maps, items can only be added to the preallocated space. For
* indefinite maps, the storage will be expanded as needed
*
- * @param item[borrow] A map
- * @param pair[incref] The key-value pair to add (incref is member-wise)
- * @return `true` on success, `false` if either reallocation failed or the
- * preallcoated storage is full
+ * @param item A map
+ * @param pair The key-value pair to add. Reference count of the #cbor_pair.key
+ * and #cbor_pair.value will be increased by one.
+ * @return `true` on success, `false` if memory allocation failed (indefinite
+ * maps) or the preallocated storage is full (definite maps)
*/
-CBOR_EXPORT bool cbor_map_add(cbor_item_t *item, struct cbor_pair pair);
+_CBOR_NODISCARD CBOR_EXPORT bool cbor_map_add(cbor_item_t *item,
+ struct cbor_pair pair);
/** Add a key to the map
*
* Sets the value to `NULL`. Internal API.
*
- * @param item[borrow] A map
- * @param key[incref] The key
+ * @param item A map
+ * @param key The key, Its reference count will be be increased by one.
* @return `true` on success, `false` if either reallocation failed or the
- * preallcoated storage is full
+ * preallocated storage is full
*/
-CBOR_EXPORT bool _cbor_map_add_key(cbor_item_t *item, cbor_item_t *key);
+_CBOR_NODISCARD CBOR_EXPORT bool _cbor_map_add_key(cbor_item_t *item,
+ cbor_item_t *key);
/** Add a value to the map
*
* Assumes that #_cbor_map_add_key has been called. Internal API.
*
- * @param item[borrow] A map
- * @param key[incref] The value
+ * @param item A map
+ * @param value The value. Its reference count will be be increased by one.
* @return `true` on success, `false` if either reallocation failed or the
- * preallcoated storage is full
+ * preallocated storage is full
*/
-CBOR_EXPORT bool _cbor_map_add_value(cbor_item_t *item, cbor_item_t *value);
+_CBOR_NODISCARD CBOR_EXPORT bool _cbor_map_add_value(cbor_item_t *item,
+ cbor_item_t *value);
/** Is this map definite?
*
- * @param item[borrow] A map
+ * @param item A map
* @return Is this map definite?
*/
-CBOR_EXPORT bool cbor_map_is_definite(const cbor_item_t *item);
+_CBOR_NODISCARD CBOR_EXPORT bool cbor_map_is_definite(const cbor_item_t *item);
/** Is this map indefinite?
*
- * @param item[borrow] A map
+ * @param item A map
* @return Is this map indefinite?
*/
-CBOR_EXPORT bool cbor_map_is_indefinite(const cbor_item_t *item);
+_CBOR_NODISCARD CBOR_EXPORT bool cbor_map_is_indefinite(
+ const cbor_item_t *item);
/** Get the pairs storage
*
- * @param item[borrow] A map
+ * @param item A map
* @return Array of #cbor_map_size pairs. Manipulation is possible as long as
* references remain valid.
*/
-CBOR_EXPORT struct cbor_pair *cbor_map_handle(const cbor_item_t *item);
+_CBOR_NODISCARD CBOR_EXPORT struct cbor_pair *cbor_map_handle(
+ const cbor_item_t *item);
#ifdef __cplusplus
}
diff --git a/src/cbor/serialization.c b/src/cbor/serialization.c
index 56a48176aab4..40f4c531d575 100644
--- a/src/cbor/serialization.c
+++ b/src/cbor/serialization.c
@@ -19,6 +19,7 @@
size_t cbor_serialize(const cbor_item_t *item, unsigned char *buffer,
size_t buffer_size) {
+ // cppcheck-suppress missingReturn
switch (cbor_typeof(item)) {
case CBOR_TYPE_UINT:
return cbor_serialize_uint(item, buffer, buffer_size);
@@ -36,44 +37,144 @@ size_t cbor_serialize(const cbor_item_t *item, unsigned char *buffer,
return cbor_serialize_tag(item, buffer, buffer_size);
case CBOR_TYPE_FLOAT_CTRL:
return cbor_serialize_float_ctrl(item, buffer, buffer_size);
- default:
- return 0;
}
}
-size_t cbor_serialize_alloc(const cbor_item_t *item, unsigned char **buffer,
- size_t *buffer_size) {
- size_t bfr_size = 32;
- unsigned char *bfr = _CBOR_MALLOC(bfr_size), *tmp_bfr;
- if (bfr == NULL) {
- return 0;
- }
+/** Largest integer that can be encoded as embedded in the item leading byte. */
+const uint64_t kMaxEmbeddedInt = 23;
- size_t written;
+/** How many bytes will a tag for a nested item of a given `size` take when
+ * encoded.*/
+size_t _cbor_encoded_header_size(uint64_t size) {
+ if (size <= kMaxEmbeddedInt)
+ return 1;
+ else if (size <= UINT8_MAX)
+ return 2;
+ else if (size <= UINT16_MAX)
+ return 3;
+ else if (size <= UINT32_MAX)
+ return 5;
+ else
+ return 9;
+}
- /* This is waaay too optimistic - figure out something smarter (eventually) */
- while ((written = cbor_serialize(item, bfr, bfr_size)) == 0) {
- if (!_cbor_safe_to_multiply(CBOR_BUFFER_GROWTH, bfr_size)) {
- _CBOR_FREE(bfr);
- return 0;
+size_t cbor_serialized_size(const cbor_item_t *item) {
+ // cppcheck-suppress missingReturn
+ switch (cbor_typeof(item)) {
+ case CBOR_TYPE_UINT:
+ case CBOR_TYPE_NEGINT:
+ switch (cbor_int_get_width(item)) {
+ case CBOR_INT_8:
+ if (cbor_get_uint8(item) <= kMaxEmbeddedInt) return 1;
+ return 2;
+ case CBOR_INT_16:
+ return 3;
+ case CBOR_INT_32:
+ return 5;
+ case CBOR_INT_64:
+ return 9;
+ }
+ // Note: We do not _cbor_safe_signaling_add zero-length definite strings,
+ // they would cause zeroes to propagate. All other items are at least one
+ // byte.
+ case CBOR_TYPE_BYTESTRING: {
+ if (cbor_bytestring_is_definite(item)) {
+ size_t header_size =
+ _cbor_encoded_header_size(cbor_bytestring_length(item));
+ if (cbor_bytestring_length(item) == 0) return header_size;
+ return _cbor_safe_signaling_add(header_size,
+ cbor_bytestring_length(item));
+ }
+ size_t indef_bytestring_size = 2; // Leading byte + break
+ cbor_item_t **chunks = cbor_bytestring_chunks_handle(item);
+ for (size_t i = 0; i < cbor_bytestring_chunk_count(item); i++) {
+ indef_bytestring_size = _cbor_safe_signaling_add(
+ indef_bytestring_size, cbor_serialized_size(chunks[i]));
+ }
+ return indef_bytestring_size;
}
-
- tmp_bfr = _CBOR_REALLOC(bfr, bfr_size *= 2);
-
- if (tmp_bfr == NULL) {
- _CBOR_FREE(bfr);
- return 0;
+ case CBOR_TYPE_STRING: {
+ if (cbor_string_is_definite(item)) {
+ size_t header_size =
+ _cbor_encoded_header_size(cbor_string_length(item));
+ if (cbor_string_length(item) == 0) return header_size;
+ return _cbor_safe_signaling_add(header_size, cbor_string_length(item));
+ }
+ size_t indef_string_size = 2; // Leading byte + break
+ cbor_item_t **chunks = cbor_string_chunks_handle(item);
+ for (size_t i = 0; i < cbor_string_chunk_count(item); i++) {
+ indef_string_size = _cbor_safe_signaling_add(
+ indef_string_size, cbor_serialized_size(chunks[i]));
+ }
+ return indef_string_size;
+ }
+ case CBOR_TYPE_ARRAY: {
+ size_t array_size = cbor_array_is_definite(item)
+ ? _cbor_encoded_header_size(cbor_array_size(item))
+ : 2; // Leading byte + break
+ cbor_item_t **items = cbor_array_handle(item);
+ for (size_t i = 0; i < cbor_array_size(item); i++) {
+ array_size = _cbor_safe_signaling_add(array_size,
+ cbor_serialized_size(items[i]));
+ }
+ return array_size;
+ }
+ case CBOR_TYPE_MAP: {
+ size_t map_size = cbor_map_is_definite(item)
+ ? _cbor_encoded_header_size(cbor_map_size(item))
+ : 2; // Leading byte + break
+ struct cbor_pair *items = cbor_map_handle(item);
+ for (size_t i = 0; i < cbor_map_size(item); i++) {
+ map_size = _cbor_safe_signaling_add(
+ map_size,
+ _cbor_safe_signaling_add(cbor_serialized_size(items[i].key),
+ cbor_serialized_size(items[i].value)));
+ }
+ return map_size;
}
- bfr = tmp_bfr;
+ case CBOR_TYPE_TAG: {
+ return _cbor_safe_signaling_add(
+ _cbor_encoded_header_size(cbor_tag_value(item)),
+ cbor_serialized_size(cbor_move(cbor_tag_item(item))));
+ }
+ case CBOR_TYPE_FLOAT_CTRL:
+ switch (cbor_float_get_width(item)) {
+ case CBOR_FLOAT_0:
+ return _cbor_encoded_header_size(cbor_ctrl_value(item));
+ case CBOR_FLOAT_16:
+ return 3;
+ case CBOR_FLOAT_32:
+ return 5;
+ case CBOR_FLOAT_64:
+ return 9;
+ }
+ }
+}
+
+size_t cbor_serialize_alloc(const cbor_item_t *item, unsigned char **buffer,
+ size_t *buffer_size) {
+ *buffer = NULL;
+ size_t serialized_size = cbor_serialized_size(item);
+ if (serialized_size == 0) {
+ if (buffer_size != NULL) *buffer_size = 0;
+ return 0;
+ }
+ *buffer = _cbor_malloc(serialized_size);
+ if (*buffer == NULL) {
+ if (buffer_size != NULL) *buffer_size = 0;
+ return 0;
}
- *buffer = bfr;
- *buffer_size = bfr_size;
+
+ size_t written = cbor_serialize(item, *buffer, serialized_size);
+ CBOR_ASSERT(written == serialized_size);
+ if (buffer_size != NULL) *buffer_size = serialized_size;
return written;
}
size_t cbor_serialize_uint(const cbor_item_t *item, unsigned char *buffer,
size_t buffer_size) {
- assert(cbor_isa_uint(item));
+ CBOR_ASSERT(cbor_isa_uint(item));
+ // cppcheck-suppress missingReturn
switch (cbor_int_get_width(item)) {
case CBOR_INT_8:
return cbor_encode_uint8(cbor_get_uint8(item), buffer, buffer_size);
@@ -83,14 +184,13 @@ size_t cbor_serialize_uint(const cbor_item_t *item, unsigned char *buffer,
return cbor_encode_uint32(cbor_get_uint32(item), buffer, buffer_size);
case CBOR_INT_64:
return cbor_encode_uint64(cbor_get_uint64(item), buffer, buffer_size);
- default:
- return 0;
}
}
size_t cbor_serialize_negint(const cbor_item_t *item, unsigned char *buffer,
size_t buffer_size) {
- assert(cbor_isa_negint(item));
+ CBOR_ASSERT(cbor_isa_negint(item));
+ // cppcheck-suppress missingReturn
switch (cbor_int_get_width(item)) {
case CBOR_INT_8:
return cbor_encode_negint8(cbor_get_uint8(item), buffer, buffer_size);
@@ -100,173 +200,158 @@ size_t cbor_serialize_negint(const cbor_item_t *item, unsigned char *buffer,
return cbor_encode_negint32(cbor_get_uint32(item), buffer, buffer_size);
case CBOR_INT_64:
return cbor_encode_negint64(cbor_get_uint64(item), buffer, buffer_size);
- default:
- return 0;
}
}
size_t cbor_serialize_bytestring(const cbor_item_t *item, unsigned char *buffer,
size_t buffer_size) {
- assert(cbor_isa_bytestring(item));
+ CBOR_ASSERT(cbor_isa_bytestring(item));
if (cbor_bytestring_is_definite(item)) {
size_t length = cbor_bytestring_length(item);
size_t written = cbor_encode_bytestring_start(length, buffer, buffer_size);
- if (written && (buffer_size - written >= length)) {
+ if (written > 0 && (buffer_size - written >= length)) {
memcpy(buffer + written, cbor_bytestring_handle(item), length);
return written + length;
- } else
- return 0;
+ }
+ return 0;
} else {
- assert(cbor_bytestring_is_indefinite(item));
+ CBOR_ASSERT(cbor_bytestring_is_indefinite(item));
size_t chunk_count = cbor_bytestring_chunk_count(item);
size_t written = cbor_encode_indef_bytestring_start(buffer, buffer_size);
-
if (written == 0) return 0;
cbor_item_t **chunks = cbor_bytestring_chunks_handle(item);
for (size_t i = 0; i < chunk_count; i++) {
size_t chunk_written = cbor_serialize_bytestring(
chunks[i], buffer + written, buffer_size - written);
- if (chunk_written == 0)
- return 0;
- else
- written += chunk_written;
+ if (chunk_written == 0) return 0;
+ written += chunk_written;
}
- if (cbor_encode_break(buffer + written, buffer_size - written) > 0)
- return written + 1;
- else
- return 0;
+
+ size_t break_written =
+ cbor_encode_break(buffer + written, buffer_size - written);
+ if (break_written == 0) return 0;
+ return written + break_written;
}
}
size_t cbor_serialize_string(const cbor_item_t *item, unsigned char *buffer,
size_t buffer_size) {
- assert(cbor_isa_string(item));
+ CBOR_ASSERT(cbor_isa_string(item));
if (cbor_string_is_definite(item)) {
size_t length = cbor_string_length(item);
size_t written = cbor_encode_string_start(length, buffer, buffer_size);
if (written && (buffer_size - written >= length)) {
memcpy(buffer + written, cbor_string_handle(item), length);
return written + length;
- } else
- return 0;
+ }
+ return 0;
} else {
- assert(cbor_string_is_indefinite(item));
+ CBOR_ASSERT(cbor_string_is_indefinite(item));
size_t chunk_count = cbor_string_chunk_count(item);
size_t written = cbor_encode_indef_string_start(buffer, buffer_size);
-
if (written == 0) return 0;
cbor_item_t **chunks = cbor_string_chunks_handle(item);
for (size_t i = 0; i < chunk_count; i++) {
size_t chunk_written = cbor_serialize_string(chunks[i], buffer + written,
buffer_size - written);
- if (chunk_written == 0)
- return 0;
- else
- written += chunk_written;
+ if (chunk_written == 0) return 0;
+ written += chunk_written;
}
- if (cbor_encode_break(buffer + written, buffer_size - written) > 0)
- return written + 1;
- else
- return 0;
+
+ size_t break_written =
+ cbor_encode_break(buffer + written, buffer_size - written);
+ if (break_written == 0) return 0;
+ return written + break_written;
}
}
size_t cbor_serialize_array(const cbor_item_t *item, unsigned char *buffer,
size_t buffer_size) {
- assert(cbor_isa_array(item));
+ CBOR_ASSERT(cbor_isa_array(item));
size_t size = cbor_array_size(item), written = 0;
cbor_item_t **handle = cbor_array_handle(item);
if (cbor_array_is_definite(item)) {
written = cbor_encode_array_start(size, buffer, buffer_size);
} else {
- assert(cbor_array_is_indefinite(item));
+ CBOR_ASSERT(cbor_array_is_indefinite(item));
written = cbor_encode_indef_array_start(buffer, buffer_size);
}
if (written == 0) return 0;
- size_t item_written;
for (size_t i = 0; i < size; i++) {
- item_written =
+ size_t item_written =
cbor_serialize(*(handle++), buffer + written, buffer_size - written);
- if (item_written == 0)
- return 0;
- else
- written += item_written;
+ if (item_written == 0) return 0;
+ written += item_written;
}
if (cbor_array_is_definite(item)) {
return written;
} else {
- assert(cbor_array_is_indefinite(item));
- item_written = cbor_encode_break(buffer + written, buffer_size - written);
- if (item_written == 0)
- return 0;
- else
- return written + 1;
+ CBOR_ASSERT(cbor_array_is_indefinite(item));
+ size_t break_written =
+ cbor_encode_break(buffer + written, buffer_size - written);
+ if (break_written == 0) return 0;
+ return written + break_written;
}
}
size_t cbor_serialize_map(const cbor_item_t *item, unsigned char *buffer,
size_t buffer_size) {
- assert(cbor_isa_map(item));
+ CBOR_ASSERT(cbor_isa_map(item));
size_t size = cbor_map_size(item), written = 0;
struct cbor_pair *handle = cbor_map_handle(item);
if (cbor_map_is_definite(item)) {
written = cbor_encode_map_start(size, buffer, buffer_size);
} else {
- assert(cbor_map_is_indefinite(item));
+ CBOR_ASSERT(cbor_map_is_indefinite(item));
written = cbor_encode_indef_map_start(buffer, buffer_size);
}
if (written == 0) return 0;
- size_t item_written;
for (size_t i = 0; i < size; i++) {
- item_written =
+ size_t item_written =
cbor_serialize(handle->key, buffer + written, buffer_size - written);
- if (item_written == 0)
+ if (item_written == 0) {
return 0;
- else
- written += item_written;
+ }
+ written += item_written;
item_written = cbor_serialize((handle++)->value, buffer + written,
buffer_size - written);
- if (item_written == 0)
- return 0;
- else
- written += item_written;
+ if (item_written == 0) return 0;
+ written += item_written;
}
if (cbor_map_is_definite(item)) {
return written;
} else {
- assert(cbor_map_is_indefinite(item));
- item_written = cbor_encode_break(buffer + written, buffer_size - written);
- if (item_written == 0)
- return 0;
- else
- return written + 1;
+ CBOR_ASSERT(cbor_map_is_indefinite(item));
+ size_t break_written =
+ cbor_encode_break(buffer + written, buffer_size - written);
+ if (break_written == 0) return 0;
+ return written + break_written;
}
}
size_t cbor_serialize_tag(const cbor_item_t *item, unsigned char *buffer,
size_t buffer_size) {
- assert(cbor_isa_tag(item));
+ CBOR_ASSERT(cbor_isa_tag(item));
size_t written = cbor_encode_tag(cbor_tag_value(item), buffer, buffer_size);
if (written == 0) return 0;
size_t item_written = cbor_serialize(cbor_move(cbor_tag_item(item)),
buffer + written, buffer_size - written);
- if (item_written == 0)
- return 0;
- else
- return written + item_written;
+ if (item_written == 0) return 0;
+ return written + item_written;
}
size_t cbor_serialize_float_ctrl(const cbor_item_t *item, unsigned char *buffer,
size_t buffer_size) {
- assert(cbor_isa_float_ctrl(item));
+ CBOR_ASSERT(cbor_isa_float_ctrl(item));
+ // cppcheck-suppress missingReturn
switch (cbor_float_get_width(item)) {
case CBOR_FLOAT_0:
/* CTRL - special treatment */
@@ -280,7 +365,4 @@ size_t cbor_serialize_float_ctrl(const cbor_item_t *item, unsigned char *buffer,
return cbor_encode_double(cbor_float_get_float8(item), buffer,
buffer_size);
}
-
- /* Should never happen - make the compiler happy */
- return 0;
}
diff --git a/src/cbor/serialization.h b/src/cbor/serialization.h
index 3f7707afca61..228ae75d6011 100644
--- a/src/cbor/serialization.h
+++ b/src/cbor/serialization.h
@@ -23,110 +23,143 @@ extern "C" {
/** Serialize the given item
*
- * @param item[borrow] A data item
+ * @param item A data item
* @param buffer Buffer to serialize to
* @param buffer_size Size of the \p buffer
* @return Length of the result. 0 on failure.
*/
-CBOR_EXPORT size_t cbor_serialize(const cbor_item_t *item,
- cbor_mutable_data buffer, size_t buffer_size);
+_CBOR_NODISCARD CBOR_EXPORT size_t cbor_serialize(const cbor_item_t *item,
+ cbor_mutable_data buffer,
+ size_t buffer_size);
+
+/** Compute the length (in bytes) of the item when serialized using
+ * `cbor_serialize`.
+ *
+ * Time complexity is proportional to the number of nested items.
+ *
+ * @param item A data item
+ * @return Length (>= 1) of the item when serialized. 0 if the length overflows
+ * `size_t`.
+ */
+_CBOR_NODISCARD CBOR_EXPORT size_t
+cbor_serialized_size(const cbor_item_t *item);
/** Serialize the given item, allocating buffers as needed
*
+ * Since libcbor v0.10, the return value is always the same as `buffer_size` (if
+ * provided, see https://github.com/PJK/libcbor/pull/251/). New clients should
+ * ignore the return value.
+ *
* \rst
- * .. warning:: It is your responsibility to free the buffer using an
+ * .. warning:: It is the caller's responsibility to free the buffer using an
* appropriate ``free`` implementation.
* \endrst
*
- * @param item[borrow] A data item
- * @param buffer[out] Buffer containing the result
- * @param buffer_size[out] Size of the \p buffer
- * @return Length of the result. 0 on failure, in which case \p buffer is
- * ``NULL``.
+ * @param item A data item
+ * @param[out] buffer Buffer containing the result
+ * @param[out] buffer_size Size of the \p buffer, or 0 on memory allocation
+ * failure.
+ * @return Length of the result in bytes
+ * @return 0 on memory allocation failure, in which case \p buffer is `NULL`.
*/
CBOR_EXPORT size_t cbor_serialize_alloc(const cbor_item_t *item,
- cbor_mutable_data *buffer,
+ unsigned char **buffer,
size_t *buffer_size);
/** Serialize an uint
*
- * @param item[borrow] A uint
- * @param buffer Buffer to serialize to
+ * @param item A uint
+ * @param[out] buffer Buffer to serialize to
* @param buffer_size Size of the \p buffer
- * @return Length of the result. 0 on failure.
+ * @return Length of the result
+ * @return 0 if the \p buffer_size doesn't fit the result
*/
-CBOR_EXPORT size_t cbor_serialize_uint(const cbor_item_t *, cbor_mutable_data,
- size_t);
+_CBOR_NODISCARD CBOR_EXPORT size_t cbor_serialize_uint(const cbor_item_t *item,
+ cbor_mutable_data buffer,
+ size_t buffer_size);
/** Serialize a negint
*
- * @param item[borrow] A neging
- * @param buffer Buffer to serialize to
+ * @param item A negint
+ * @param[out] buffer Buffer to serialize to
* @param buffer_size Size of the \p buffer
- * @return Length of the result. 0 on failure.
+ * @return Length of the result
+ * @return 0 if the \p buffer_size doesn't fit the result
*/
-CBOR_EXPORT size_t cbor_serialize_negint(const cbor_item_t *, cbor_mutable_data,
- size_t);
+_CBOR_NODISCARD CBOR_EXPORT size_t cbor_serialize_negint(
+ const cbor_item_t *item, cbor_mutable_data buffer, size_t buffer_size);
/** Serialize a bytestring
*
- * @param item[borrow] A bytestring
- * @param buffer Buffer to serialize to
+ * @param item A bytestring
+ * @param[out] buffer Buffer to serialize to
* @param buffer_size Size of the \p buffer
- * @return Length of the result. 0 on failure.
+ * @return Length of the result
+ * @return 0 if the \p buffer_size doesn't fit the result. The \p buffer may
+ * still be modified
*/
-CBOR_EXPORT size_t cbor_serialize_bytestring(const cbor_item_t *,
- cbor_mutable_data, size_t);
+_CBOR_NODISCARD CBOR_EXPORT size_t cbor_serialize_bytestring(
+ const cbor_item_t *item, cbor_mutable_data buffer, size_t buffer_size);
/** Serialize a string
*
- * @param item[borrow] A string
- * @param buffer Buffer to serialize to
+ * @param item A string
+ * @param[out] buffer Buffer to serialize to
* @param buffer_size Size of the \p buffer
- * @return Length of the result. 0 on failure.
+ * @return Length of the result
+ * @return 0 if the \p buffer_size doesn't fit the result. The \p buffer may
+ * still be modified
*/
-CBOR_EXPORT size_t cbor_serialize_string(const cbor_item_t *, cbor_mutable_data,
- size_t);
-
+_CBOR_NODISCARD CBOR_EXPORT size_t cbor_serialize_string(
+ const cbor_item_t *item, cbor_mutable_data buffer, size_t buffer_size);
/** Serialize an array
*
- * @param item[borrow] An array
- * @param buffer Buffer to serialize to
+ * @param item An array
+ * @param[out] buffer Buffer to serialize to
* @param buffer_size Size of the \p buffer
- * @return Length of the result. 0 on failure.
+ * @return Length of the result
+ * @return 0 if the \p buffer_size doesn't fit the result. The \p buffer may
+ * still be modified
*/
-CBOR_EXPORT size_t cbor_serialize_array(const cbor_item_t *, cbor_mutable_data,
- size_t);
+_CBOR_NODISCARD CBOR_EXPORT size_t cbor_serialize_array(
+ const cbor_item_t *item, cbor_mutable_data buffer, size_t buffer_size);
/** Serialize a map
*
- * @param item[borrow] A map
- * @param buffer Buffer to serialize to
+ * @param item A map
+ * @param[out] buffer Buffer to serialize to
* @param buffer_size Size of the \p buffer
- * @return Length of the result. 0 on failure.
+ * @return Length of the result
+ * @return 0 if the \p buffer_size doesn't fit the result. The \p buffer may
+ * still be modified
*/
-CBOR_EXPORT size_t cbor_serialize_map(const cbor_item_t *, cbor_mutable_data,
- size_t);
+_CBOR_NODISCARD CBOR_EXPORT size_t cbor_serialize_map(const cbor_item_t *item,
+ cbor_mutable_data buffer,
+ size_t buffer_size);
/** Serialize a tag
*
- * @param item[borrow] A tag
- * @param buffer Buffer to serialize to
+ * @param item A tag
+ * @param[out] buffer Buffer to serialize to
* @param buffer_size Size of the \p buffer
- * @return Length of the result. 0 on failure.
+ * @return Length of the result
+ * @return 0 if the \p buffer_size doesn't fit the result. The \p buffer may
+ * still be modified
*/
-CBOR_EXPORT size_t cbor_serialize_tag(const cbor_item_t *, cbor_mutable_data,
- size_t);
+_CBOR_NODISCARD CBOR_EXPORT size_t cbor_serialize_tag(const cbor_item_t *item,
+ cbor_mutable_data buffer,
+ size_t buffer_size);
/** Serialize a
*
- * @param item[borrow] A float or ctrl
- * @param buffer Buffer to serialize to
+ * @param item A float or ctrl
+ * @param[out] buffer Buffer to serialize to
* @param buffer_size Size of the \p buffer
- * @return Length of the result. 0 on failure.
+ * @return Length of the result
+ * @return 0 if the \p buffer_size doesn't fit the result
*/
-CBOR_EXPORT size_t cbor_serialize_float_ctrl(const cbor_item_t *,
- cbor_mutable_data, size_t);
+_CBOR_NODISCARD CBOR_EXPORT size_t cbor_serialize_float_ctrl(
+ const cbor_item_t *item, cbor_mutable_data buffer, size_t buffer_size);
#ifdef __cplusplus
}
diff --git a/src/cbor/streaming.c b/src/cbor/streaming.c
index aa58abb3eaba..922a71d8e6b0 100644
--- a/src/cbor/streaming.c
+++ b/src/cbor/streaming.c
@@ -8,7 +8,7 @@
#include "streaming.h"
#include "internal/loaders.h"
-bool static claim_bytes(size_t required, size_t provided,
+static bool claim_bytes(size_t required, size_t provided,
struct cbor_decoder_result *result) {
if (required > (provided - result->read)) {
result->required = required + result->read;
@@ -22,6 +22,24 @@ bool static claim_bytes(size_t required, size_t provided,
}
}
+// Use implicit capture as an exception to avoid the super long parameter list
+#define CLAIM_BYTES_AND_INVOKE(callback_name, length, source_extra_offset) \
+ do { \
+ if (claim_bytes(length, source_size, &result)) { \
+ callbacks->callback_name(context, source + 1 + source_extra_offset, \
+ length); \
+ } \
+ } while (0)
+
+#define READ_CLAIM_INVOKE(callback_name, length_reader, length_bytes) \
+ do { \
+ if (claim_bytes(length_bytes, source_size, &result)) { \
+ uint64_t length = length_reader(source + 1); \
+ CLAIM_BYTES_AND_INVOKE(callback_name, length, length_bytes); \
+ } \
+ return result; \
+ } while (0)
+
struct cbor_decoder_result cbor_stream_decode(
cbor_data source, size_t source_size,
const struct cbor_callbacks *callbacks, void *context) {
@@ -98,7 +116,7 @@ struct cbor_decoder_result cbor_stream_decode(
case 0x1E: /* Fallthrough */
case 0x1F:
/* Reserved */
- { return (struct cbor_decoder_result){0, CBOR_DECODER_ERROR}; }
+ { return (struct cbor_decoder_result){.status = CBOR_DECODER_ERROR}; }
case 0x20: /* Fallthrough */
case 0x21: /* Fallthrough */
case 0x22: /* Fallthrough */
@@ -166,7 +184,7 @@ struct cbor_decoder_result cbor_stream_decode(
case 0x3E: /* Fallthrough */
case 0x3F:
/* Reserved */
- { return (struct cbor_decoder_result){0, CBOR_DECODER_ERROR}; }
+ { return (struct cbor_decoder_result){.status = CBOR_DECODER_ERROR}; }
case 0x40: /* Fallthrough */
case 0x41: /* Fallthrough */
case 0x42: /* Fallthrough */
@@ -193,63 +211,27 @@ struct cbor_decoder_result cbor_stream_decode(
case 0x57:
/* Embedded length byte string */
{
- size_t length =
- (size_t)_cbor_load_uint8(source) - 0x40; /* 0x40 offset */
- if (claim_bytes(length, source_size, &result)) {
- callbacks->byte_string(context, source + 1, length);
- }
+ uint64_t length = _cbor_load_uint8(source) - 0x40; /* 0x40 offset */
+ CLAIM_BYTES_AND_INVOKE(byte_string, length, 0);
return result;
}
case 0x58:
/* One byte length byte string */
- // TODO template this?
- {
- if (claim_bytes(1, source_size, &result)) {
- size_t length = (size_t)_cbor_load_uint8(source + 1);
- if (claim_bytes(length, source_size, &result)) {
- callbacks->byte_string(context, source + 1 + 1, length);
- }
- }
- return result;
- }
+ READ_CLAIM_INVOKE(byte_string, _cbor_load_uint8, 1);
case 0x59:
/* Two bytes length byte string */
- {
- if (claim_bytes(2, source_size, &result)) {
- size_t length = (size_t)_cbor_load_uint16(source + 1);
- if (claim_bytes(length, source_size, &result)) {
- callbacks->byte_string(context, source + 1 + 2, length);
- }
- }
- return result;
- }
+ READ_CLAIM_INVOKE(byte_string, _cbor_load_uint16, 2);
case 0x5A:
/* Four bytes length byte string */
- {
- if (claim_bytes(4, source_size, &result)) {
- size_t length = (size_t)_cbor_load_uint32(source + 1);
- if (claim_bytes(length, source_size, &result)) {
- callbacks->byte_string(context, source + 1 + 4, length);
- }
- }
- return result;
- }
+ READ_CLAIM_INVOKE(byte_string, _cbor_load_uint32, 4);
case 0x5B:
/* Eight bytes length byte string */
- {
- if (claim_bytes(8, source_size, &result)) {
- size_t length = (size_t)_cbor_load_uint64(source + 1);
- if (claim_bytes(length, source_size, &result)) {
- callbacks->byte_string(context, source + 1 + 8, length);
- }
- }
- return result;
- }
+ READ_CLAIM_INVOKE(byte_string, _cbor_load_uint64, 8);
case 0x5C: /* Fallthrough */
case 0x5D: /* Fallthrough */
case 0x5E:
/* Reserved */
- { return (struct cbor_decoder_result){0, CBOR_DECODER_ERROR}; }
+ { return (struct cbor_decoder_result){.status = CBOR_DECODER_ERROR}; }
case 0x5F:
/* Indefinite byte string */
{
@@ -282,62 +264,27 @@ struct cbor_decoder_result cbor_stream_decode(
case 0x77:
/* Embedded one byte length string */
{
- size_t length =
- (size_t)_cbor_load_uint8(source) - 0x60; /* 0x60 offset */
- if (claim_bytes(length, source_size, &result)) {
- callbacks->string(context, source + 1, length);
- }
+ uint64_t length = _cbor_load_uint8(source) - 0x60; /* 0x60 offset */
+ CLAIM_BYTES_AND_INVOKE(string, length, 0);
return result;
}
case 0x78:
/* One byte length string */
- {
- if (claim_bytes(1, source_size, &result)) {
- size_t length = (size_t)_cbor_load_uint8(source + 1);
- if (claim_bytes(length, source_size, &result)) {
- callbacks->string(context, source + 1 + 1, length);
- }
- }
- return result;
- }
+ READ_CLAIM_INVOKE(string, _cbor_load_uint8, 1);
case 0x79:
/* Two bytes length string */
- {
- if (claim_bytes(2, source_size, &result)) {
- size_t length = (size_t)_cbor_load_uint16(source + 1);
- if (claim_bytes(length, source_size, &result)) {
- callbacks->string(context, source + 1 + 2, length);
- }
- }
- return result;
- }
+ READ_CLAIM_INVOKE(string, _cbor_load_uint16, 2);
case 0x7A:
/* Four bytes length string */
- {
- if (claim_bytes(4, source_size, &result)) {
- size_t length = (size_t)_cbor_load_uint32(source + 1);
- if (claim_bytes(length, source_size, &result)) {
- callbacks->string(context, source + 1 + 4, length);
- }
- }
- return result;
- }
+ READ_CLAIM_INVOKE(string, _cbor_load_uint32, 4);
case 0x7B:
/* Eight bytes length string */
- {
- if (claim_bytes(8, source_size, &result)) {
- size_t length = (size_t)_cbor_load_uint64(source + 1);
- if (claim_bytes(length, source_size, &result)) {
- callbacks->string(context, source + 1 + 8, length);
- }
- }
- return result;
- }
+ READ_CLAIM_INVOKE(string, _cbor_load_uint64, 8);
case 0x7C: /* Fallthrough */
case 0x7D: /* Fallthrough */
case 0x7E:
/* Reserved */
- { return (struct cbor_decoder_result){0, CBOR_DECODER_ERROR}; }
+ { return (struct cbor_decoder_result){.status = CBOR_DECODER_ERROR}; }
case 0x7F:
/* Indefinite length string */
{
@@ -371,14 +318,14 @@ struct cbor_decoder_result cbor_stream_decode(
/* Embedded one byte length array */
{
callbacks->array_start(
- context, (size_t)_cbor_load_uint8(source) - 0x80); /* 0x40 offset */
+ context, _cbor_load_uint8(source) - 0x80); /* 0x40 offset */
return result;
}
case 0x98:
/* One byte length array */
{
if (claim_bytes(1, source_size, &result)) {
- callbacks->array_start(context, (size_t)_cbor_load_uint8(source + 1));
+ callbacks->array_start(context, _cbor_load_uint8(source + 1));
}
return result;
}
@@ -386,8 +333,7 @@ struct cbor_decoder_result cbor_stream_decode(
/* Two bytes length array */
{
if (claim_bytes(2, source_size, &result)) {
- callbacks->array_start(context,
- (size_t)_cbor_load_uint16(source + 1));
+ callbacks->array_start(context, _cbor_load_uint16(source + 1));
}
return result;
}
@@ -395,8 +341,7 @@ struct cbor_decoder_result cbor_stream_decode(
/* Four bytes length array */
{
if (claim_bytes(4, source_size, &result)) {
- callbacks->array_start(context,
- (size_t)_cbor_load_uint32(source + 1));
+ callbacks->array_start(context, _cbor_load_uint32(source + 1));
}
return result;
}
@@ -404,8 +349,7 @@ struct cbor_decoder_result cbor_stream_decode(
/* Eight bytes length array */
{
if (claim_bytes(8, source_size, &result)) {
- callbacks->array_start(context,
- (size_t)_cbor_load_uint64(source + 1));
+ callbacks->array_start(context, _cbor_load_uint64(source + 1));
}
return result;
}
@@ -413,7 +357,7 @@ struct cbor_decoder_result cbor_stream_decode(
case 0x9D: /* Fallthrough */
case 0x9E:
/* Reserved */
- { return (struct cbor_decoder_result){0, CBOR_DECODER_ERROR}; }
+ { return (struct cbor_decoder_result){.status = CBOR_DECODER_ERROR}; }
case 0x9F:
/* Indefinite length array */
{
@@ -446,15 +390,15 @@ struct cbor_decoder_result cbor_stream_decode(
case 0xB7:
/* Embedded one byte length map */
{
- callbacks->map_start(
- context, (size_t)_cbor_load_uint8(source) - 0xA0); /* 0xA0 offset */
+ callbacks->map_start(context,
+ _cbor_load_uint8(source) - 0xA0); /* 0xA0 offset */
return result;
}
case 0xB8:
/* One byte length map */
{
if (claim_bytes(1, source_size, &result)) {
- callbacks->map_start(context, (size_t)_cbor_load_uint8(source + 1));
+ callbacks->map_start(context, _cbor_load_uint8(source + 1));
}
return result;
}
@@ -462,7 +406,7 @@ struct cbor_decoder_result cbor_stream_decode(
/* Two bytes length map */
{
if (claim_bytes(2, source_size, &result)) {
- callbacks->map_start(context, (size_t)_cbor_load_uint16(source + 1));
+ callbacks->map_start(context, _cbor_load_uint16(source + 1));
}
return result;
}
@@ -470,7 +414,7 @@ struct cbor_decoder_result cbor_stream_decode(
/* Four bytes length map */
{
if (claim_bytes(4, source_size, &result)) {
- callbacks->map_start(context, (size_t)_cbor_load_uint32(source + 1));
+ callbacks->map_start(context, _cbor_load_uint32(source + 1));
}
return result;
}
@@ -478,7 +422,7 @@ struct cbor_decoder_result cbor_stream_decode(
/* Eight bytes length map */
{
if (claim_bytes(8, source_size, &result)) {
- callbacks->map_start(context, (size_t)_cbor_load_uint64(source + 1));
+ callbacks->map_start(context, _cbor_load_uint64(source + 1));
}
return result;
}
@@ -486,7 +430,7 @@ struct cbor_decoder_result cbor_stream_decode(
case 0xBD: /* Fallthrough */
case 0xBE:
/* Reserved */
- { return (struct cbor_decoder_result){0, CBOR_DECODER_ERROR}; }
+ { return (struct cbor_decoder_result){.status = CBOR_DECODER_ERROR}; }
case 0xBF:
/* Indefinite length map */
{
@@ -506,8 +450,8 @@ struct cbor_decoder_result cbor_stream_decode(
case 0xC5:
/* Big float */
{
- callbacks->tag(context,
- _cbor_load_uint8(source) - 0xC0); /* 0xC0 offset */
+ callbacks->tag(context, (uint64_t)(_cbor_load_uint8(source) -
+ 0xC0)); /* 0xC0 offset */
return result;
}
case 0xC6: /* Fallthrough */
@@ -526,14 +470,14 @@ struct cbor_decoder_result cbor_stream_decode(
case 0xD3: /* Fallthrough */
case 0xD4: /* Unassigned tag value */
{
- return (struct cbor_decoder_result){0, CBOR_DECODER_ERROR};
+ return (struct cbor_decoder_result){.status = CBOR_DECODER_ERROR};
}
case 0xD5: /* Expected b64url conversion tag - fallthrough */
case 0xD6: /* Expected b64 conversion tag - fallthrough */
case 0xD7: /* Expected b16 conversion tag */
{
- callbacks->tag(context,
- _cbor_load_uint8(source) - 0xC0); /* 0xC0 offset */
+ callbacks->tag(context, (uint64_t)(_cbor_load_uint8(source) -
+ 0xC0)); /* 0xC0 offset */
return result;
}
case 0xD8: /* 1B tag */
@@ -569,7 +513,7 @@ struct cbor_decoder_result cbor_stream_decode(
case 0xDE: /* Fallthrough */
case 0xDF: /* Reserved */
{
- return (struct cbor_decoder_result){0, CBOR_DECODER_ERROR};
+ return (struct cbor_decoder_result){.status = CBOR_DECODER_ERROR};
}
case 0xE0: /* Fallthrough */
case 0xE1: /* Fallthrough */
@@ -592,7 +536,7 @@ struct cbor_decoder_result cbor_stream_decode(
case 0xF2: /* Fallthrough */
case 0xF3: /* Simple value - unassigned */
{
- return (struct cbor_decoder_result){0, CBOR_DECODER_ERROR};
+ return (struct cbor_decoder_result){.status = CBOR_DECODER_ERROR};
}
case 0xF4:
/* False */
@@ -620,7 +564,7 @@ struct cbor_decoder_result cbor_stream_decode(
}
case 0xF8:
/* 1B simple value, unassigned */
- { return (struct cbor_decoder_result){0, CBOR_DECODER_ERROR}; }
+ { return (struct cbor_decoder_result){.status = CBOR_DECODER_ERROR}; }
case 0xF9:
/* 2B float */
{
@@ -649,16 +593,13 @@ struct cbor_decoder_result cbor_stream_decode(
case 0xFD: /* Fallthrough */
case 0xFE:
/* Reserved */
- { return (struct cbor_decoder_result){0, CBOR_DECODER_ERROR}; }
+ { return (struct cbor_decoder_result){.status = CBOR_DECODER_ERROR}; }
case 0xFF:
/* Break */
- {
- callbacks->indef_break(context);
- return result;
- }
- default: /* Never happens - this shuts up the compiler */
- {
+ callbacks->indef_break(context);
+ // Never happens, the switch statement is exhaustive on the 1B range; make
+ // compiler happy
+ default:
return result;
- }
}
}
diff --git a/src/cbor/streaming.h b/src/cbor/streaming.h
index 532d959b8b2e..cb908e17e9c9 100644
--- a/src/cbor/streaming.h
+++ b/src/cbor/streaming.h
@@ -18,16 +18,16 @@ extern "C" {
/** Stateless decoder
*
- * Will try parsing the \p buffer and will invoke the appropriate callback on
+ * Will try parsing the \p source and will invoke the appropriate callback on
* success. Decodes one item at a time. No memory allocations occur.
*
- * @param buffer Input buffer
- * @param buffer_size Length of the buffer
+ * @param source Input buffer
+ * @param source_size Length of the buffer
* @param callbacks The callback bundle
* @param context An arbitrary pointer to allow for maintaining context.
*/
-CBOR_EXPORT struct cbor_decoder_result cbor_stream_decode(
- cbor_data buffer, size_t buffer_size,
+_CBOR_NODISCARD CBOR_EXPORT struct cbor_decoder_result cbor_stream_decode(
+ cbor_data source, size_t source_size,
const struct cbor_callbacks* callbacks, void* context);
#ifdef __cplusplus
diff --git a/src/cbor/strings.c b/src/cbor/strings.c
index 209886b5f8c3..de2d1024bb4c 100644
--- a/src/cbor/strings.c
+++ b/src/cbor/strings.c
@@ -9,8 +9,8 @@
#include <string.h>
#include "internal/memory_utils.h"
-cbor_item_t *cbor_new_definite_string() {
- cbor_item_t *item = _CBOR_MALLOC(sizeof(cbor_item_t));
+cbor_item_t *cbor_new_definite_string(void) {
+ cbor_item_t *item = _cbor_malloc(sizeof(cbor_item_t));
_CBOR_NOTNULL(item);
*item = (cbor_item_t){
.refcount = 1,
@@ -19,15 +19,15 @@ cbor_item_t *cbor_new_definite_string() {
return item;
}
-cbor_item_t *cbor_new_indefinite_string() {
- cbor_item_t *item = _CBOR_MALLOC(sizeof(cbor_item_t));
+cbor_item_t *cbor_new_indefinite_string(void) {
+ cbor_item_t *item = _cbor_malloc(sizeof(cbor_item_t));
_CBOR_NOTNULL(item);
*item = (cbor_item_t){
.refcount = 1,
.type = CBOR_TYPE_STRING,
.metadata = {.string_metadata = {.type = _CBOR_METADATA_INDEFINITE,
.length = 0}},
- .data = _CBOR_MALLOC(sizeof(struct cbor_indefinite_string_data))};
+ .data = _cbor_malloc(sizeof(struct cbor_indefinite_string_data))};
_CBOR_DEPENDENT_NOTNULL(item, item->data);
*((struct cbor_indefinite_string_data *)item->data) =
(struct cbor_indefinite_string_data){
@@ -42,7 +42,7 @@ cbor_item_t *cbor_build_string(const char *val) {
cbor_item_t *item = cbor_new_definite_string();
_CBOR_NOTNULL(item);
size_t len = strlen(val);
- unsigned char *handle = _CBOR_MALLOC(len);
+ unsigned char *handle = _cbor_malloc(len);
_CBOR_DEPENDENT_NOTNULL(item, handle);
memcpy(handle, val, len);
cbor_string_set_handle(item, handle, len);
@@ -52,7 +52,7 @@ cbor_item_t *cbor_build_string(const char *val) {
cbor_item_t *cbor_build_stringn(const char *val, size_t length) {
cbor_item_t *item = cbor_new_definite_string();
_CBOR_NOTNULL(item);
- unsigned char *handle = _CBOR_MALLOC(length);
+ unsigned char *handle = _cbor_malloc(length);
_CBOR_DEPENDENT_NOTNULL(item, handle);
memcpy(handle, val, length);
cbor_string_set_handle(item, handle, length);
@@ -62,31 +62,30 @@ cbor_item_t *cbor_build_stringn(const char *val, size_t length) {
void cbor_string_set_handle(cbor_item_t *item,
cbor_mutable_data CBOR_RESTRICT_POINTER data,
size_t length) {
- assert(cbor_isa_string(item));
- assert(cbor_string_is_definite(item));
+ CBOR_ASSERT(cbor_isa_string(item));
+ CBOR_ASSERT(cbor_string_is_definite(item));
item->data = data;
item->metadata.string_metadata.length = length;
}
cbor_item_t **cbor_string_chunks_handle(const cbor_item_t *item) {
- assert(cbor_isa_string(item));
- assert(cbor_string_is_indefinite(item));
+ CBOR_ASSERT(cbor_isa_string(item));
+ CBOR_ASSERT(cbor_string_is_indefinite(item));
return ((struct cbor_indefinite_string_data *)item->data)->chunks;
}
size_t cbor_string_chunk_count(const cbor_item_t *item) {
- assert(cbor_isa_string(item));
- assert(cbor_string_is_indefinite(item));
+ CBOR_ASSERT(cbor_isa_string(item));
+ CBOR_ASSERT(cbor_string_is_indefinite(item));
return ((struct cbor_indefinite_string_data *)item->data)->chunk_count;
}
bool cbor_string_add_chunk(cbor_item_t *item, cbor_item_t *chunk) {
- assert(cbor_isa_string(item));
- assert(cbor_string_is_indefinite(item));
+ CBOR_ASSERT(cbor_isa_string(item));
+ CBOR_ASSERT(cbor_string_is_indefinite(item));
struct cbor_indefinite_string_data *data =
(struct cbor_indefinite_string_data *)item->data;
if (data->chunk_count == data->chunk_capacity) {
- // TODO: Add a test for this
if (!_cbor_safe_to_multiply(CBOR_BUFFER_GROWTH, data->chunk_capacity)) {
return false;
}
@@ -109,22 +108,22 @@ bool cbor_string_add_chunk(cbor_item_t *item, cbor_item_t *chunk) {
}
size_t cbor_string_length(const cbor_item_t *item) {
- assert(cbor_isa_string(item));
+ CBOR_ASSERT(cbor_isa_string(item));
return item->metadata.string_metadata.length;
}
unsigned char *cbor_string_handle(const cbor_item_t *item) {
- assert(cbor_isa_string(item));
+ CBOR_ASSERT(cbor_isa_string(item));
return item->data;
}
size_t cbor_string_codepoint_count(const cbor_item_t *item) {
- assert(cbor_isa_string(item));
+ CBOR_ASSERT(cbor_isa_string(item));
return item->metadata.string_metadata.codepoint_count;
}
bool cbor_string_is_definite(const cbor_item_t *item) {
- assert(cbor_isa_string(item));
+ CBOR_ASSERT(cbor_isa_string(item));
return item->metadata.string_metadata.type == _CBOR_METADATA_DEFINITE;
}
diff --git a/src/cbor/strings.h b/src/cbor/strings.h
index 49398af842a0..7a18f95e29fa 100644
--- a/src/cbor/strings.h
+++ b/src/cbor/strings.h
@@ -21,48 +21,53 @@ extern "C" {
* ============================================================================
*/
-/** Returns the length of the underlying string
+/** Returns the length of the underlying string in bytes
*
- * For definite strings only
+ * There can be fewer unicode character than bytes (see
+ * `cbor_string_codepoint_count`). For definite strings only.
*
- * @param item[borrow] a definite string
+ * @param item a definite string
* @return length of the string. Zero if no chunk has been attached yet
*/
-CBOR_EXPORT size_t cbor_string_length(const cbor_item_t *item);
+_CBOR_NODISCARD CBOR_EXPORT size_t cbor_string_length(const cbor_item_t *item);
/** The number of codepoints in this string
*
* Might differ from length if there are multibyte ones
*
- * @param item[borrow] A string
+ * @param item A string
* @return The number of codepoints in this string
*/
-CBOR_EXPORT size_t cbor_string_codepoint_count(const cbor_item_t *item);
+_CBOR_NODISCARD CBOR_EXPORT size_t
+cbor_string_codepoint_count(const cbor_item_t *item);
/** Is the string definite?
*
- * @param item[borrow] a string
+ * @param item a string
* @return Is the string definite?
*/
-CBOR_EXPORT bool cbor_string_is_definite(const cbor_item_t *item);
+_CBOR_NODISCARD CBOR_EXPORT bool cbor_string_is_definite(
+ const cbor_item_t *item);
/** Is the string indefinite?
*
- * @param item[borrow] a string
+ * @param item a string
* @return Is the string indefinite?
*/
-CBOR_EXPORT bool cbor_string_is_indefinite(const cbor_item_t *item);
+_CBOR_NODISCARD CBOR_EXPORT bool cbor_string_is_indefinite(
+ const cbor_item_t *item);
/** Get the handle to the underlying string
*
* Definite items only. Modifying the data is allowed. In that case, the caller
* takes responsibility for the effect on items this item might be a part of
*
- * @param item[borrow] A definite string
- * @return The address of the underlying string. `NULL` if no data have been
- * assigned yet.
+ * @param item A definite string
+ * @return The address of the underlying string.
+ * @return `NULL` if no data have been assigned yet.
*/
-CBOR_EXPORT cbor_mutable_data cbor_string_handle(const cbor_item_t *item);
+_CBOR_NODISCARD CBOR_EXPORT cbor_mutable_data
+cbor_string_handle(const cbor_item_t *item);
/** Set the handle to the underlying string
*
@@ -73,7 +78,7 @@ CBOR_EXPORT cbor_mutable_data cbor_string_handle(const cbor_item_t *item);
* the CBOR item will be left inconsistent.
* \endrst
*
- * @param item[borrow] A definite string
+ * @param item A definite string
* @param data The memory block. The caller gives up the ownership of the block.
* libcbor will deallocate it when appropriate using its free function
* @param length Length of the data block
@@ -87,17 +92,19 @@ CBOR_EXPORT void cbor_string_set_handle(
* Manipulations with the memory block (e.g. sorting it) are allowed, but the
* validity and the number of chunks must be retained.
*
- * @param item[borrow] A indefinite string
+ * @param item A indefinite string
* @return array of #cbor_string_chunk_count definite strings
*/
-CBOR_EXPORT cbor_item_t **cbor_string_chunks_handle(const cbor_item_t *item);
+_CBOR_NODISCARD CBOR_EXPORT cbor_item_t **cbor_string_chunks_handle(
+ const cbor_item_t *item);
/** Get the number of chunks this string consist of
*
- * @param item[borrow] A indefinite string
+ * @param item A indefinite string
* @return The chunk count. 0 for freshly created items.
*/
-CBOR_EXPORT size_t cbor_string_chunk_count(const cbor_item_t *item);
+_CBOR_NODISCARD CBOR_EXPORT size_t
+cbor_string_chunk_count(const cbor_item_t *item);
/** Appends a chunk to the string
*
@@ -105,46 +112,60 @@ CBOR_EXPORT size_t cbor_string_chunk_count(const cbor_item_t *item);
*
* May realloc the chunk storage.
*
- * @param item[borrow] An indefinite string
- * @param item[incref] A definite string
- * @return true on success. false on realloc failure. In that case, the refcount
- * of `chunk` is not increased and the `item` is left intact.
+ * @param item An indefinite string
+ * @param chunk A definite string item. Its reference count will be increased
+ * by one.
+ * @return `true` on success. `false` on memory allocation failure. In that
+ * case, the refcount of @p `chunk` is not increased and the @p `item` is left
+ * intact.
*/
-CBOR_EXPORT bool cbor_string_add_chunk(cbor_item_t *item, cbor_item_t *chunk);
+_CBOR_NODISCARD CBOR_EXPORT bool cbor_string_add_chunk(cbor_item_t *item,
+ cbor_item_t *chunk);
/** Creates a new definite string
*
* The handle is initialized to `NULL` and length to 0
*
- * @return **new** definite string. `NULL` on malloc failure.
+ * @return Reference to the new string item. The item's reference count is
+ * initialized to one.
+ * @return `NULL` if memory allocation fails
*/
-CBOR_EXPORT cbor_item_t *cbor_new_definite_string();
+_CBOR_NODISCARD CBOR_EXPORT cbor_item_t *cbor_new_definite_string(void);
/** Creates a new indefinite string
*
* The chunks array is initialized to `NULL` and chunkcount to 0
*
- * @return **new** indefinite string. `NULL` on malloc failure.
+ * @return Reference to the new string item. The item's reference count is
+ * initialized to one.
+ * @return `NULL` if memory allocation fails
*/
-CBOR_EXPORT cbor_item_t *cbor_new_indefinite_string();
+_CBOR_NODISCARD CBOR_EXPORT cbor_item_t *cbor_new_indefinite_string(void);
/** Creates a new string and initializes it
*
* The `val` will be copied to a newly allocated block
*
* @param val A null-terminated UTF-8 string
- * @return A **new** string with content `handle`. `NULL` on malloc failure.
+ * @return Reference to the new string item. The item's reference count is
+ * initialized to one.
+ * @return `NULL` if memory allocation fails
*/
-CBOR_EXPORT cbor_item_t *cbor_build_string(const char *val);
+_CBOR_NODISCARD CBOR_EXPORT cbor_item_t *cbor_build_string(const char *val);
/** Creates a new string and initializes it
*
* The `handle` will be copied to a newly allocated block
*
- * @param val A UTF-8 string, at least \p length long (excluding the null byte)
- * @return A **new** string with content `handle`. `NULL` on malloc failure.
+ * @param val A UTF-8 string, at least @p `length` long (excluding the null
+ * byte)
+ * @param length Length (in bytes) of the string passed in @p `val`.
+ * @return Reference to the new string item. The item's reference count is
+ * initialized to one.
+ * @return `NULL` if memory allocation fails
*/
-CBOR_EXPORT cbor_item_t *cbor_build_stringn(const char *val, size_t length);
+_CBOR_NODISCARD CBOR_EXPORT cbor_item_t *cbor_build_stringn(const char *val,
+ size_t length);
#ifdef __cplusplus
}
diff --git a/src/cbor/tags.c b/src/cbor/tags.c
index 60b3e69eacd4..3f3edb0b0e1d 100644
--- a/src/cbor/tags.c
+++ b/src/cbor/tags.c
@@ -8,7 +8,7 @@
#include "tags.h"
cbor_item_t *cbor_new_tag(uint64_t value) {
- cbor_item_t *item = _CBOR_MALLOC(sizeof(cbor_item_t));
+ cbor_item_t *item = _cbor_malloc(sizeof(cbor_item_t));
_CBOR_NOTNULL(item);
*item = (cbor_item_t){
@@ -21,23 +21,26 @@ cbor_item_t *cbor_new_tag(uint64_t value) {
}
cbor_item_t *cbor_tag_item(const cbor_item_t *item) {
- assert(cbor_isa_tag(item));
+ CBOR_ASSERT(cbor_isa_tag(item));
return cbor_incref(item->metadata.tag_metadata.tagged_item);
}
uint64_t cbor_tag_value(const cbor_item_t *item) {
- assert(cbor_isa_tag(item));
+ CBOR_ASSERT(cbor_isa_tag(item));
return item->metadata.tag_metadata.value;
}
void cbor_tag_set_item(cbor_item_t *item, cbor_item_t *tagged_item) {
- assert(cbor_isa_tag(item));
+ CBOR_ASSERT(cbor_isa_tag(item));
cbor_incref(tagged_item);
item->metadata.tag_metadata.tagged_item = tagged_item;
}
cbor_item_t *cbor_build_tag(uint64_t value, cbor_item_t *item) {
cbor_item_t *res = cbor_new_tag(value);
+ if (res == NULL) {
+ return NULL;
+ }
cbor_tag_set_item(res, item);
return res;
}
diff --git a/src/cbor/tags.h b/src/cbor/tags.h
index f4b8028f7951..a7365df10208 100644
--- a/src/cbor/tags.h
+++ b/src/cbor/tags.h
@@ -24,39 +24,48 @@ extern "C" {
/** Create a new tag
*
* @param value The tag value. Please consult the tag repository
- * @return **new** tag. Item reference is `NULL`. Returns `NULL` upon
- * memory allocation failure
+ * @return Reference to the new tag item. The item's reference count is
+ * initialized to one.
+ * @return `NULL` if memory allocation fails
*/
-CBOR_EXPORT cbor_item_t *cbor_new_tag(uint64_t value);
+_CBOR_NODISCARD CBOR_EXPORT cbor_item_t *cbor_new_tag(uint64_t value);
/** Get the tagged item
*
- * @param item[borrow] A tag
- * @return **incref** the tagged item
+ * @param item A tag
+ * @return Reference to the tagged item
+ *
+ * Increases the reference count of the underlying item. The returned reference
+ * must be released using #cbor_decref.
*/
-CBOR_EXPORT cbor_item_t *cbor_tag_item(const cbor_item_t *item);
+_CBOR_NODISCARD CBOR_EXPORT cbor_item_t *cbor_tag_item(const cbor_item_t *item);
/** Get tag value
*
- * @param item[borrow] A tag
+ * @param item A tag
* @return The tag value. Please consult the tag repository
*/
-CBOR_EXPORT uint64_t cbor_tag_value(const cbor_item_t *item);
+_CBOR_NODISCARD CBOR_EXPORT uint64_t cbor_tag_value(const cbor_item_t *item);
/** Set the tagged item
*
- * @param item[borrow] A tag
- * @param tagged_item[incref] The item to tag
+ * @param item A tag
+ * @param tagged_item The item to tag. Its reference count will be increased
+ * by one.
*/
CBOR_EXPORT void cbor_tag_set_item(cbor_item_t *item, cbor_item_t *tagged_item);
/** Build a new tag
*
- * @param item[incref] The tagee
+ * @param item The item to tag. Its reference count will be increased by
+ * one.
* @param value Tag value
- * @return **new** tag item
+ * @return Reference to the new tag item. The item's reference count is
+ * initialized to one.
+ * @return `NULL` if memory allocation fails
*/
-CBOR_EXPORT cbor_item_t *cbor_build_tag(uint64_t value, cbor_item_t *item);
+_CBOR_NODISCARD CBOR_EXPORT cbor_item_t *cbor_build_tag(uint64_t value,
+ cbor_item_t *item);
#ifdef __cplusplus
}
diff --git a/src/libcbor.pc.in b/src/libcbor.pc.in
index f144bda33bc6..b37af08434f9 100644
--- a/src/libcbor.pc.in
+++ b/src/libcbor.pc.in
@@ -1,7 +1,7 @@
prefix=@CMAKE_INSTALL_PREFIX@
exec_prefix=${prefix}
-libdir=${prefix}/@CMAKE_INSTALL_LIBDIR@
-includedir=${prefix}/include
+libdir=@libdir_for_pc_file@
+includedir=@includedir_for_pc_file@
Name: @PROJECT_NAME@
Description: @PROJECT_NAME@ - CBOR protocol implementation
diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt
index 67ea13dfc44c..9721fd03a166 100644
--- a/test/CMakeLists.txt
+++ b/test/CMakeLists.txt
@@ -1,20 +1,22 @@
file(GLOB TESTS "*_test.c")
-if(NOT CBOR_CUSTOM_ALLOC)
- # Memory allocation test requires custom allocator support to instrument it.
- list(REMOVE_ITEM TESTS ${CMAKE_CURRENT_SOURCE_DIR}/memory_allocation_test.c)
-endif(NOT CBOR_CUSTOM_ALLOC)
-
find_package(CMocka REQUIRED)
message(STATUS "CMocka vars: ${CMOCKA_LIBRARIES} ${CMOCKA_INCLUDE_DIR}")
+find_library(MATH_LIBRARY m)
+
+CHECK_INCLUDE_FILE("execinfo.h" HAS_EXECINFO)
+
foreach (TEST ${TESTS})
string(REGEX REPLACE ".*/([^/]+).c" "\\1" NAME ${TEST})
message("Adding test ${NAME}")
- add_executable(${NAME} "${NAME}.c" assertions.c stream_expectations.c)
+ add_executable(${NAME} "${NAME}.c" assertions.c stream_expectations.c test_allocator.c)
target_link_libraries(${NAME} ${CMOCKA_LIBRARIES})
target_link_libraries(${NAME} cbor)
+ if(MATH_LIBRARY)
+ target_link_libraries(${NAME} ${MATH_LIBRARY})
+ endif()
target_include_directories(${NAME} PUBLIC ${CMOCKA_INCLUDE_DIR})
# See https://stackoverflow.com/a/10824578/499521
ADD_TEST(ctest_build_test_${NAME}
diff --git a/test/type_4_encoders_test.c b/test/array_encoders_test.c
index fbd036bbf6d6..54a28bd94c6b 100644
--- a/test/type_4_encoders_test.c
+++ b/test/array_encoders_test.c
@@ -5,41 +5,38 @@
* it under the terms of the MIT license. See LICENSE for details.
*/
-#include <setjmp.h>
-#include <stdarg.h>
-#include <stddef.h>
-
-#include <cmocka.h>
-
+#include "assertions.h"
#include "cbor.h"
unsigned char buffer[512];
-static void test_embedded_array_start(void **state) {
- assert_int_equal(1, cbor_encode_array_start(1, buffer, 512));
+static void test_embedded_array_start(void **_CBOR_UNUSED(_state)) {
+ assert_size_equal(1, cbor_encode_array_start(1, buffer, 512));
assert_memory_equal(buffer, ((unsigned char[]){0x81}), 1);
}
-static void test_array_start(void **state) {
- assert_int_equal(5, cbor_encode_array_start(1000000, buffer, 512));
+static void test_array_start(void **_CBOR_UNUSED(_state)) {
+ assert_size_equal(5, cbor_encode_array_start(1000000, buffer, 512));
assert_memory_equal(buffer, ((unsigned char[]){0x9A, 0x00, 0x0F, 0x42, 0x40}),
5);
}
-static void test_indef_array_start(void **state) {
- assert_int_equal(1, cbor_encode_indef_array_start(buffer, 512));
- assert_int_equal(0, cbor_encode_indef_array_start(buffer, 0));
+static void test_indef_array_start(void **_CBOR_UNUSED(_state)) {
+ assert_size_equal(1, cbor_encode_indef_array_start(buffer, 512));
+ assert_size_equal(0, cbor_encode_indef_array_start(buffer, 0));
assert_memory_equal(buffer, ((unsigned char[]){0x9F}), 1);
}
-static void test_indef_array_encoding(void **state) {
+static void test_indef_array_encoding(void **_CBOR_UNUSED(_state)) {
cbor_item_t *array = cbor_new_indefinite_array();
cbor_item_t *one = cbor_build_uint8(1);
cbor_item_t *two = cbor_build_uint8(2);
- cbor_array_push(array, one);
- cbor_array_push(array, two);
- assert_int_equal(4, cbor_serialize_array(array, buffer, 512));
+ assert_true(cbor_array_push(array, one));
+ assert_true(cbor_array_push(array, two));
+
+ assert_size_equal(4, cbor_serialize_array(array, buffer, 512));
assert_memory_equal(buffer, ((unsigned char[]){0x9F, 0x01, 0x02, 0xFF}), 4);
+
cbor_decref(&array);
cbor_decref(&one);
cbor_decref(&two);
diff --git a/test/array_test.c b/test/array_test.c
new file mode 100644
index 000000000000..1a241c051f2c
--- /dev/null
+++ b/test/array_test.c
@@ -0,0 +1,222 @@
+/*
+ * Copyright (c) 2014-2020 Pavel Kalvoda <me@pavelkalvoda.com>
+ *
+ * libcbor is free software; you can redistribute it and/or modify
+ * it under the terms of the MIT license. See LICENSE for details.
+ */
+
+#include "assertions.h"
+#include "cbor.h"
+#include "test_allocator.h"
+
+cbor_item_t *arr;
+struct cbor_load_result res;
+
+unsigned char data1[] = {0x80, 0xFF};
+
+static void test_empty_array(void **_CBOR_UNUSED(_state)) {
+ arr = cbor_load(data1, 2, &res);
+ assert_non_null(arr);
+ assert_true(cbor_typeof(arr) == CBOR_TYPE_ARRAY);
+ assert_true(cbor_isa_array(arr));
+ assert_true(cbor_array_size(arr) == 0);
+ assert_true(res.read == 1);
+ cbor_decref(&arr);
+ assert_null(arr);
+}
+
+unsigned char data2[] = {0x81, 0x01, 0xFF};
+
+static void test_simple_array(void **_CBOR_UNUSED(_state)) {
+ arr = cbor_load(data2, 3, &res);
+ assert_non_null(arr);
+ assert_true(cbor_typeof(arr) == CBOR_TYPE_ARRAY);
+ assert_true(cbor_isa_array(arr));
+ assert_size_equal(cbor_array_size(arr), 1);
+ assert_true(res.read == 2);
+ assert_size_equal(cbor_array_allocated(arr), 1);
+ /* Check the values */
+ assert_uint8(cbor_array_handle(arr)[0], 1);
+ cbor_item_t *intermediate = cbor_array_get(arr, 0);
+ assert_uint8(intermediate, 1);
+
+ cbor_item_t *new_val = cbor_build_uint8(10);
+ assert_false(cbor_array_set(arr, 1, new_val));
+ assert_false(cbor_array_set(arr, 3, new_val));
+ cbor_decref(&new_val);
+
+ cbor_decref(&arr);
+ cbor_decref(&intermediate);
+ assert_null(arr);
+ assert_null(intermediate);
+}
+
+unsigned char data3[] = {0x82, 0x01, 0x81, 0x01, 0xFF};
+
+static void test_nested_arrays(void **_CBOR_UNUSED(_state)) {
+ arr = cbor_load(data3, 5, &res);
+ assert_non_null(arr);
+ assert_true(cbor_typeof(arr) == CBOR_TYPE_ARRAY);
+ assert_true(cbor_isa_array(arr));
+ assert_true(cbor_array_size(arr) == 2);
+ assert_true(res.read == 4);
+ /* Check the values */
+ assert_uint8(cbor_array_handle(arr)[0], 1);
+
+ cbor_item_t *nested = cbor_array_handle(arr)[1];
+ assert_true(cbor_isa_array(nested));
+ assert_true(cbor_array_size(nested) == 1);
+ assert_uint8(cbor_array_handle(nested)[0], 1);
+
+ cbor_decref(&arr);
+ assert_null(arr);
+}
+
+unsigned char test_indef_arrays_data[] = {0x9f, 0x01, 0x02, 0xFF};
+
+static void test_indef_arrays(void **_CBOR_UNUSED(_state)) {
+ arr = cbor_load(test_indef_arrays_data, 4, &res);
+ assert_non_null(arr);
+ assert_true(cbor_typeof(arr) == CBOR_TYPE_ARRAY);
+ assert_true(cbor_isa_array(arr));
+ assert_true(cbor_array_size(arr) == 2);
+ assert_true(res.read == 4);
+ /* Check the values */
+ assert_uint8(cbor_array_handle(arr)[0], 1);
+ assert_uint8(cbor_array_handle(arr)[1], 2);
+
+ assert_true(cbor_array_set(arr, 1, cbor_move(cbor_build_uint8(10))));
+
+ cbor_decref(&arr);
+ assert_null(arr);
+}
+
+unsigned char test_nested_indef_arrays_data[] = {0x9f, 0x01, 0x9f, 0x02,
+ 0xFF, 0x03, 0xFF};
+
+static void test_nested_indef_arrays(void **_CBOR_UNUSED(_state)) {
+ arr = cbor_load(test_nested_indef_arrays_data, 7, &res);
+ assert_non_null(arr);
+ assert_true(cbor_typeof(arr) == CBOR_TYPE_ARRAY);
+ assert_true(cbor_isa_array(arr));
+ assert_size_equal(cbor_array_size(arr), 3);
+ assert_true(res.read == 7);
+ /* Check the values */
+ assert_uint8(cbor_array_handle(arr)[0], 1);
+
+ cbor_item_t *nested = cbor_array_handle(arr)[1];
+ assert_true(cbor_isa_array(nested));
+ assert_true(cbor_array_size(nested) == 1);
+ assert_uint8(cbor_array_handle(nested)[0], 2);
+
+ cbor_decref(&arr);
+ assert_null(arr);
+}
+
+static void test_array_replace(void **_CBOR_UNUSED(_state)) {
+ cbor_item_t *array = cbor_new_definite_array(2);
+ assert_size_equal(cbor_array_size(array), 0);
+ cbor_item_t *one = cbor_build_uint8(1);
+ cbor_item_t *three = cbor_build_uint8(3);
+ assert_size_equal(cbor_refcount(one), 1);
+ assert_size_equal(cbor_refcount(three), 1);
+
+ // No item to replace
+ assert_false(cbor_array_replace(array, 0, three));
+ assert_size_equal(cbor_refcount(three), 1);
+
+ // Add items [1, 2]
+ assert_true(cbor_array_push(array, one));
+ assert_true(cbor_array_push(array, cbor_move(cbor_build_uint8(2))));
+ assert_size_equal(cbor_refcount(one), 2);
+ assert_size_equal(cbor_array_size(array), 2);
+
+ // Array has only two items
+ assert_false(cbor_array_replace(array, 2, three));
+ assert_size_equal(cbor_refcount(three), 1);
+
+ // Change [1, 2] to [3, 2]
+ assert_true(cbor_array_replace(array, 0, three));
+ assert_size_equal(cbor_refcount(one), 1);
+ assert_size_equal(cbor_refcount(three), 2);
+ assert_uint8(cbor_move(cbor_array_get(array, 0)), 3);
+ assert_uint8(cbor_move(cbor_array_get(array, 1)), 2);
+
+ cbor_decref(&one);
+ cbor_decref(&three);
+ cbor_decref(&array);
+}
+
+static void test_array_push_overflow(void **_CBOR_UNUSED(_state)) {
+ cbor_item_t *array = cbor_new_indefinite_array();
+ cbor_item_t *one = cbor_build_uint8(1);
+ struct _cbor_array_metadata *metadata =
+ (struct _cbor_array_metadata *)&array->metadata;
+ // Pretend we already have a huge block allocated
+ metadata->allocated = SIZE_MAX;
+ metadata->end_ptr = SIZE_MAX;
+
+ assert_false(cbor_array_push(array, one));
+ assert_size_equal(cbor_refcount(one), 1);
+
+ cbor_decref(&one);
+ metadata->allocated = 0;
+ metadata->end_ptr = 0;
+ cbor_decref(&array);
+}
+
+static void test_array_creation(void **_CBOR_UNUSED(_state)) {
+ WITH_FAILING_MALLOC({ assert_null(cbor_new_definite_array(42)); });
+ WITH_MOCK_MALLOC({ assert_null(cbor_new_definite_array(42)); }, 2, MALLOC,
+ MALLOC_FAIL);
+
+ WITH_FAILING_MALLOC({ assert_null(cbor_new_indefinite_array()); });
+}
+
+static void test_array_push(void **_CBOR_UNUSED(_state)) {
+ WITH_MOCK_MALLOC(
+ {
+ cbor_item_t *array = cbor_new_indefinite_array();
+ cbor_item_t *string = cbor_build_string("Hello!");
+
+ assert_false(cbor_array_push(array, string));
+ assert_size_equal(cbor_array_allocated(array), 0);
+ assert_null(array->data);
+ assert_size_equal(array->metadata.array_metadata.end_ptr, 0);
+
+ cbor_decref(&string);
+ cbor_decref(&array);
+ },
+ 4, MALLOC, MALLOC, MALLOC, REALLOC_FAIL);
+}
+
+static unsigned char simple_indef_array[] = {0x9F, 0x01, 0x02, 0xFF};
+static void test_indef_array_decode(void **_CBOR_UNUSED(_state)) {
+ WITH_MOCK_MALLOC(
+ {
+ cbor_item_t *array;
+ struct cbor_load_result res;
+ array = cbor_load(simple_indef_array, 4, &res);
+
+ assert_null(array);
+ assert_size_equal(res.error.code, CBOR_ERR_MEMERROR);
+ },
+ 4, MALLOC, MALLOC, MALLOC, REALLOC_FAIL);
+}
+
+int main(void) {
+ const struct CMUnitTest tests[] = {
+ cmocka_unit_test(test_empty_array),
+ cmocka_unit_test(test_simple_array),
+ cmocka_unit_test(test_nested_arrays),
+ cmocka_unit_test(test_indef_arrays),
+ cmocka_unit_test(test_nested_indef_arrays),
+ cmocka_unit_test(test_array_replace),
+ cmocka_unit_test(test_array_push_overflow),
+ cmocka_unit_test(test_array_creation),
+ cmocka_unit_test(test_array_push),
+ cmocka_unit_test(test_indef_array_decode),
+ };
+
+ return cmocka_run_group_tests(tests, NULL, NULL);
+}
diff --git a/test/assertions.c b/test/assertions.c
index 16fb4cdaaaeb..197e829d489d 100644
--- a/test/assertions.c
+++ b/test/assertions.c
@@ -32,18 +32,19 @@ void assert_uint64(cbor_item_t* item, uint64_t num) {
assert_true(cbor_get_uint64(item) == num);
}
-void assert_decoder_result(size_t read, enum cbor_decoder_status status,
- struct cbor_decoder_result result) {
- assert_true(read == result.read);
- assert_true(status == result.status);
- assert_true(0 == result.required);
+void assert_decoder_result(size_t expected_bytes_read,
+ enum cbor_decoder_status expected_status,
+ struct cbor_decoder_result actual_result) {
+ assert_true(actual_result.read == expected_bytes_read);
+ assert_true(actual_result.status == expected_status);
+ assert_true(actual_result.required == 0);
}
-void assert_decoder_result_nedata(size_t required,
- struct cbor_decoder_result result) {
- assert_true(0 == result.read);
- assert_true(CBOR_DECODER_NEDATA == result.status);
- assert_int_equal((int)required, (int)result.required);
+void assert_decoder_result_nedata(size_t expected_bytes_required,
+ struct cbor_decoder_result actual_result) {
+ assert_true(actual_result.read == 0);
+ assert_true(actual_result.status == CBOR_DECODER_NEDATA);
+ assert_true(actual_result.required == expected_bytes_required);
}
void assert_minimum_input_size(size_t expected, cbor_data data) {
@@ -51,3 +52,14 @@ void assert_minimum_input_size(size_t expected, cbor_data data) {
assert_decoder_result_nedata(expected, decode(data, 1));
}
}
+
+void _assert_size_equal(size_t actual, size_t expected, const char* src_file,
+ int src_line) {
+ if (actual == expected) return;
+ // Not using `fail_msg` since it mishandles variadic macro arguments, which
+ // causes compiler warnings/
+ // TODO file bug
+ printf("(%s:%d) assert_size_equal: Expected %zu to equal %zu\n", src_file,
+ src_line, actual, expected);
+ fail();
+}
diff --git a/test/assertions.h b/test/assertions.h
index 7a36a4c5933a..13e8d6f12137 100644
--- a/test/assertions.h
+++ b/test/assertions.h
@@ -1,6 +1,8 @@
+// Headers needed by cmocka -- must be imported first
#include <setjmp.h>
#include <stdarg.h>
#include <stddef.h>
+#include <stdint.h>
#include <cmocka.h>
@@ -14,16 +16,18 @@ void assert_uint16(cbor_item_t* item, uint16_t num);
void assert_uint32(cbor_item_t* item, uint32_t num);
void assert_uint64(cbor_item_t* item, uint64_t num);
-/** Assert that result `status` and `read` are equal. */
-void assert_decoder_result(size_t read, enum cbor_decoder_status status,
- struct cbor_decoder_result result);
+// TODO: Fix "Yoda" parameter ordering of asserts
+/** Verify the `actual_result.status` and `actual_result.status`. */
+void assert_decoder_result(size_t expected_bytes_read,
+ enum cbor_decoder_status expected_status,
+ struct cbor_decoder_result actual_result);
/**
* Assert that the result is set to CBOR_DECODER_NEDATA with the given
* `cbor_decoder_result.required` value.
*/
-void assert_decoder_result_nedata(size_t required,
- struct cbor_decoder_result result);
+void assert_decoder_result_nedata(size_t expected_bytes_required,
+ struct cbor_decoder_result actual_result);
/**
* Check that the streaming decoder returns a correct CBOR_DECODER_NEDATA
@@ -31,4 +35,10 @@ void assert_decoder_result_nedata(size_t required,
*/
void assert_minimum_input_size(size_t expected, cbor_data data);
+/** Check the equality of two `size_t`s. */
+void _assert_size_equal(size_t actual, size_t expected, const char* src_file,
+ int src_line);
+#define assert_size_equal(actual, expected) \
+ _assert_size_equal(actual, expected, __FILE__, __LINE__)
+
#endif
diff --git a/test/bad_inputs_test.c b/test/bad_inputs_test.c
index 6ca5270aa248..de7bdab95231 100644
--- a/test/bad_inputs_test.c
+++ b/test/bad_inputs_test.c
@@ -5,12 +5,7 @@
* it under the terms of the MIT license. See LICENSE for details.
*/
-#include <setjmp.h>
-#include <stdarg.h>
-#include <stddef.h>
-
-#include <cmocka.h>
-
+#include "assertions.h"
#include "cbor.h"
/* These tests verify behavior on interesting randomly generated inputs from the
@@ -21,54 +16,54 @@ struct cbor_load_result res;
/* Map start + array with embedded length */
unsigned char data1[] = {0xA9, 0x85};
-static void test_1(void **state) {
+static void test_1(void **_CBOR_UNUSED(_state)) {
item = cbor_load(data1, 2, &res);
assert_null(item);
assert_true(res.error.code == CBOR_ERR_NOTENOUGHDATA);
- assert_int_equal(res.error.position, 2);
+ assert_size_equal(res.error.position, 2);
}
unsigned char data2[] = {0x9D};
-static void test_2(void **state) {
+static void test_2(void **_CBOR_UNUSED(_state)) {
item = cbor_load(data2, 1, &res);
assert_null(item);
assert_true(res.error.code == CBOR_ERR_MALFORMATED);
- assert_int_equal(res.error.position, 0);
+ assert_size_equal(res.error.position, 0);
}
unsigned char data3[] = {0xD6};
-static void test_3(void **state) {
+static void test_3(void **_CBOR_UNUSED(_state)) {
item = cbor_load(data3, 1, &res);
assert_null(item);
assert_true(res.error.code == CBOR_ERR_NOTENOUGHDATA);
- assert_int_equal(res.error.position, 1);
+ assert_size_equal(res.error.position, 1);
}
#ifdef SANE_MALLOC
unsigned char data4[] = {0xBA, 0xC1, 0xE8, 0x3E, 0xE7, 0x20, 0xA8};
-static void test_4(void **state) {
+static void test_4(void **_CBOR_UNUSED(_state)) {
item = cbor_load(data4, 7, &res);
assert_null(item);
assert_true(res.error.code == CBOR_ERR_MEMERROR);
- assert_int_equal(res.error.position, 5);
+ assert_size_equal(res.error.position, 5);
}
unsigned char data5[] = {0x9A, 0xDA, 0x3A, 0xB2, 0x7F, 0x29};
-static void test_5(void **state) {
+static void test_5(void **_CBOR_UNUSED(_state)) {
assert_true(res.error.code == CBOR_ERR_MEMERROR);
item = cbor_load(data5, 6, &res);
assert_null(item);
- assert_int_equal(res.error.position, 5);
+ assert_size_equal(res.error.position, 5);
/* Indef string expectation mismatch */
}
#endif
unsigned char data6[] = {0x7F, 0x21, 0x4C, 0x02, 0x40};
-static void test_6(void **state) {
+static void test_6(void **_CBOR_UNUSED(_state)) {
item = cbor_load(data6, 5, &res);
assert_null(item);
assert_true(res.error.code == CBOR_ERR_SYNTAXERROR);
- assert_int_equal(res.error.position, 2);
+ assert_size_equal(res.error.position, 2);
}
#ifdef EIGHT_BYTE_SIZE_T
@@ -76,11 +71,11 @@ static void test_6(void **state) {
* works with 64b sizes */
unsigned char data7[] = {0xA2, 0x9B, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
-static void test_7(void **state) {
+static void test_7(void **_CBOR_UNUSED(_state)) {
item = cbor_load(data7, 16, &res);
assert_null(item);
assert_true(res.error.code == CBOR_ERR_MEMERROR);
- assert_int_equal(res.error.position, 10);
+ assert_size_equal(res.error.position, 10);
}
#endif
@@ -89,19 +84,19 @@ unsigned char data8[] = {0xA3, 0x64, 0x68, 0x61, 0x6C, 0x66, 0xFF, 0x00,
0xFA, 0x7F, 0x7F, 0xFF, 0xFF, 0x6D, 0x73, 0x69,
0x6D, 0x70, 0x6C, 0x65, 0x20, 0x76, 0x61, 0x6C,
0x75, 0x65, 0x73, 0x83, 0xF5, 0xF4, 0xF6};
-static void test_8(void **state) {
+static void test_8(void **_CBOR_UNUSED(_state)) {
item = cbor_load(data8, 39, &res);
assert_null(item);
assert_true(res.error.code == CBOR_ERR_SYNTAXERROR);
- assert_int_equal(res.error.position, 7);
+ assert_size_equal(res.error.position, 7);
}
unsigned char data9[] = {0xBF, 0x05, 0xFF, 0x00, 0x00, 0x00, 0x10, 0x04};
-static void test_9(void **state) {
+static void test_9(void **_CBOR_UNUSED(_state)) {
item = cbor_load(data9, 8, &res);
assert_null(item);
assert_true(res.error.code == CBOR_ERR_SYNTAXERROR);
- assert_int_equal(res.error.position, 3);
+ assert_size_equal(res.error.position, 3);
}
int main(void) {
diff --git a/test/type_2_encoders_test.c b/test/bytestring_encoders_test.c
index 563fbe1b1261..8e2fbe694055 100644
--- a/test/type_2_encoders_test.c
+++ b/test/bytestring_encoders_test.c
@@ -5,30 +5,26 @@
* it under the terms of the MIT license. See LICENSE for details.
*/
-#include <setjmp.h>
-#include <stdarg.h>
-#include <stddef.h>
-
-#include <cmocka.h>
+#include "assertions.h"
#include "cbor.h"
unsigned char buffer[512];
-static void test_embedded_bytestring_start(void **state) {
- assert_int_equal(1, cbor_encode_bytestring_start(1, buffer, 512));
+static void test_embedded_bytestring_start(void **_CBOR_UNUSED(_state)) {
+ assert_size_equal(1, cbor_encode_bytestring_start(1, buffer, 512));
assert_memory_equal(buffer, ((unsigned char[]){0x41}), 1);
}
-static void test_bytestring_start(void **state) {
- assert_int_equal(5, cbor_encode_bytestring_start(1000000, buffer, 512));
+static void test_bytestring_start(void **_CBOR_UNUSED(_state)) {
+ assert_size_equal(5, cbor_encode_bytestring_start(1000000, buffer, 512));
assert_memory_equal(buffer, ((unsigned char[]){0x5A, 0x00, 0x0F, 0x42, 0x40}),
5);
}
-static void test_indef_bytestring_start(void **state) {
- assert_int_equal(0, cbor_encode_indef_bytestring_start(buffer, 0));
- assert_int_equal(1, cbor_encode_indef_bytestring_start(buffer, 512));
+static void test_indef_bytestring_start(void **_CBOR_UNUSED(_state)) {
+ assert_size_equal(0, cbor_encode_indef_bytestring_start(buffer, 0));
+ assert_size_equal(1, cbor_encode_indef_bytestring_start(buffer, 512));
assert_memory_equal(buffer, ((unsigned char[]){0x5F}), 1);
}
diff --git a/test/type_2_test.c b/test/bytestring_test.c
index d29b9f4c0fa9..08968a13e98e 100644
--- a/test/type_2_test.c
+++ b/test/bytestring_test.c
@@ -5,13 +5,9 @@
* it under the terms of the MIT license. See LICENSE for details.
*/
-#include <setjmp.h>
-#include <stdarg.h>
-#include <stddef.h>
-
-#include <cmocka.h>
-
+#include "assertions.h"
#include "cbor.h"
+#include "test_allocator.h"
cbor_item_t *bs;
struct cbor_load_result res;
@@ -137,18 +133,18 @@ unsigned char data8[] = {
0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD,
0xFE, 0xFF};
-static void test_empty_bs(void **state) {
+static void test_empty_bs(void **_CBOR_UNUSED(_state)) {
bs = cbor_load(data1, 2, &res);
assert_non_null(bs);
assert_true(cbor_typeof(bs) == CBOR_TYPE_BYTESTRING);
assert_true(cbor_isa_bytestring(bs));
- assert_int_equal(cbor_bytestring_length(bs), 0);
+ assert_size_equal(cbor_bytestring_length(bs), 0);
assert_true(res.read == 1);
cbor_decref(&bs);
assert_null(bs);
}
-static void test_embedded_bs(void **state) {
+static void test_embedded_bs(void **_CBOR_UNUSED(_state)) {
bs = cbor_load(data2, 2, &res);
assert_non_null(bs);
assert_true(cbor_typeof(bs) == CBOR_TYPE_BYTESTRING);
@@ -161,13 +157,13 @@ static void test_embedded_bs(void **state) {
assert_null(bs);
}
-static void test_notenough_data(void **state) {
+static void test_notenough_data(void **_CBOR_UNUSED(_state)) {
bs = cbor_load(data3, 2, &res);
assert_null(bs);
assert_true(res.error.code == CBOR_ERR_NOTENOUGHDATA);
}
-static void test_short_bs1(void **state) {
+static void test_short_bs1(void **_CBOR_UNUSED(_state)) {
bs = cbor_load(data3, 4, &res);
assert_non_null(bs);
assert_true(cbor_typeof(bs) == CBOR_TYPE_BYTESTRING);
@@ -180,7 +176,7 @@ static void test_short_bs1(void **state) {
assert_null(bs);
}
-static void test_short_bs2(void **state) {
+static void test_short_bs2(void **_CBOR_UNUSED(_state)) {
bs = cbor_load(data4, 259, &res);
assert_non_null(bs);
assert_true(cbor_typeof(bs) == CBOR_TYPE_BYTESTRING);
@@ -192,7 +188,7 @@ static void test_short_bs2(void **state) {
assert_null(bs);
}
-static void test_half_bs(void **state) {
+static void test_half_bs(void **_CBOR_UNUSED(_state)) {
bs = cbor_load(data5, 259, &res);
assert_non_null(bs);
assert_true(cbor_typeof(bs) == CBOR_TYPE_BYTESTRING);
@@ -204,7 +200,7 @@ static void test_half_bs(void **state) {
assert_null(bs);
}
-static void test_int_bs(void **state) {
+static void test_int_bs(void **_CBOR_UNUSED(_state)) {
bs = cbor_load(data6, 261, &res);
assert_non_null(bs);
assert_true(cbor_typeof(bs) == CBOR_TYPE_BYTESTRING);
@@ -216,7 +212,7 @@ static void test_int_bs(void **state) {
assert_null(bs);
}
-static void test_long_bs(void **state) {
+static void test_long_bs(void **_CBOR_UNUSED(_state)) {
bs = cbor_load(data7, 265, &res);
assert_non_null(bs);
assert_true(cbor_typeof(bs) == CBOR_TYPE_BYTESTRING);
@@ -230,7 +226,7 @@ static void test_long_bs(void **state) {
unsigned char data9[] = {0x5F, 0xFF};
-static void test_zero_indef(void **state) {
+static void test_zero_indef(void **_CBOR_UNUSED(_state)) {
bs = cbor_load(data9, 2, &res);
assert_non_null(bs);
assert_true(cbor_typeof(bs) == CBOR_TYPE_BYTESTRING);
@@ -246,7 +242,7 @@ unsigned char data10[] = {0x5F, 0x58, 0x01, 0xA1, 0xFF, 0xFF};
/* start | bstring | break| extra */
-static void test_short_indef(void **state) {
+static void test_short_indef(void **_CBOR_UNUSED(_state)) {
bs = cbor_load(data10, 6, &res);
assert_non_null(bs);
assert_true(cbor_typeof(bs) == CBOR_TYPE_BYTESTRING);
@@ -269,10 +265,10 @@ unsigned char data11[] = {0x5F, 0x58, 0x01, 0xA1, 0x58, 0x01, 0xA2, 0xFF, 0xFF};
/* start | bstring | bstring | break|
* extra */
-static void test_two_indef(void **state) {
+static void test_two_indef(void **_CBOR_UNUSED(_state)) {
bs = cbor_load(data11, 9, &res);
assert_non_null(bs);
- assert_int_equal(1, cbor_refcount(bs));
+ assert_size_equal(1, cbor_refcount(bs));
assert_true(cbor_typeof(bs) == CBOR_TYPE_BYTESTRING);
assert_true(cbor_isa_bytestring(bs));
assert_true(cbor_bytestring_length(bs) == 0);
@@ -297,31 +293,89 @@ unsigned char data12[] = {0x5F, 0x58, 0x01};
/* start | bstring - too short */
-static void test_missing_indef(void **state) {
+static void test_missing_indef(void **_CBOR_UNUSED(_state)) {
bs = cbor_load(data12, 3, &res);
assert_true(res.error.code == CBOR_ERR_NOTENOUGHDATA);
assert_null(bs);
}
-static void test_inline_creation(void **state) {
+static void test_inline_creation(void **_CBOR_UNUSED(_state)) {
bs = cbor_build_bytestring((cbor_data) "Hello!", 6);
assert_memory_equal(cbor_bytestring_handle(bs), "Hello!", 6);
cbor_decref(&bs);
}
+static void test_add_chunk_reallocation_overflow(void **_CBOR_UNUSED(_state)) {
+ bs = cbor_new_indefinite_bytestring();
+ cbor_item_t *chunk = cbor_build_bytestring((cbor_data) "Hello!", 6);
+ struct cbor_indefinite_string_data *metadata =
+ (struct cbor_indefinite_string_data *)bs->data;
+ // Pretend we already have many chunks allocated
+ metadata->chunk_count = SIZE_MAX;
+ metadata->chunk_capacity = SIZE_MAX;
+
+ assert_false(cbor_bytestring_add_chunk(bs, chunk));
+ assert_size_equal(cbor_refcount(chunk), 1);
+
+ metadata->chunk_count = 0;
+ metadata->chunk_capacity = 0;
+ cbor_decref(&chunk);
+ cbor_decref(&bs);
+}
+
+static void test_bytestring_creation(void **_CBOR_UNUSED(_state)) {
+ WITH_FAILING_MALLOC({ assert_null(cbor_new_definite_bytestring()); });
+
+ WITH_FAILING_MALLOC({ assert_null(cbor_new_indefinite_bytestring()); });
+ WITH_MOCK_MALLOC({ assert_null(cbor_new_indefinite_bytestring()); }, 2,
+ MALLOC, MALLOC_FAIL);
+
+ unsigned char bytes[] = {0, 0, 0xFF, 0xAB};
+
+ WITH_FAILING_MALLOC({ assert_null(cbor_build_bytestring(bytes, 4)); });
+ WITH_MOCK_MALLOC({ assert_null(cbor_build_bytestring(bytes, 4)); }, 2, MALLOC,
+ MALLOC_FAIL);
+}
+
+static void test_bytestring_add_chunk(void **_CBOR_UNUSED(_state)) {
+ unsigned char bytes[] = {0, 0, 0xFF, 0xAB};
+ WITH_MOCK_MALLOC(
+ {
+ cbor_item_t *bytestring = cbor_new_indefinite_bytestring();
+ cbor_item_t *chunk = cbor_build_bytestring(bytes, 4);
+
+ assert_false(cbor_bytestring_add_chunk(bytestring, chunk));
+
+ assert_size_equal(cbor_bytestring_chunk_count(bytestring), 0);
+ assert_size_equal(
+ ((struct cbor_indefinite_string_data *)bytestring->data)
+ ->chunk_capacity,
+ 0);
+
+ cbor_decref(&chunk);
+ cbor_decref(&bytestring);
+ },
+ 5, MALLOC, MALLOC, MALLOC, MALLOC, REALLOC_FAIL);
+}
+
int main(void) {
- const struct CMUnitTest tests[] = {cmocka_unit_test(test_empty_bs),
- cmocka_unit_test(test_embedded_bs),
- cmocka_unit_test(test_notenough_data),
- cmocka_unit_test(test_short_bs1),
- cmocka_unit_test(test_short_bs2),
- cmocka_unit_test(test_half_bs),
- cmocka_unit_test(test_int_bs),
- cmocka_unit_test(test_long_bs),
- cmocka_unit_test(test_zero_indef),
- cmocka_unit_test(test_short_indef),
- cmocka_unit_test(test_two_indef),
- cmocka_unit_test(test_missing_indef),
- cmocka_unit_test(test_inline_creation)};
+ const struct CMUnitTest tests[] = {
+ cmocka_unit_test(test_empty_bs),
+ cmocka_unit_test(test_embedded_bs),
+ cmocka_unit_test(test_notenough_data),
+ cmocka_unit_test(test_short_bs1),
+ cmocka_unit_test(test_short_bs2),
+ cmocka_unit_test(test_half_bs),
+ cmocka_unit_test(test_int_bs),
+ cmocka_unit_test(test_long_bs),
+ cmocka_unit_test(test_zero_indef),
+ cmocka_unit_test(test_short_indef),
+ cmocka_unit_test(test_two_indef),
+ cmocka_unit_test(test_missing_indef),
+ cmocka_unit_test(test_inline_creation),
+ cmocka_unit_test(test_add_chunk_reallocation_overflow),
+ cmocka_unit_test(test_bytestring_creation),
+ cmocka_unit_test(test_bytestring_add_chunk),
+ };
return cmocka_run_group_tests(tests, NULL, NULL);
}
diff --git a/test/callbacks_test.c b/test/callbacks_test.c
index 6bb5d692bb12..d9e90195c819 100644
--- a/test/callbacks_test.c
+++ b/test/callbacks_test.c
@@ -4,14 +4,11 @@
* libcbor is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
*/
-
-#include <setjmp.h>
-#include <stdarg.h>
-#include <stddef.h>
-
-#include <cmocka.h>
-
+#include "assertions.h"
#include "cbor.h"
+#include "cbor/internal/builder_callbacks.h"
+#include "cbor/internal/stack.h"
+#include "test_allocator.h"
unsigned char data[] = {
0x93, 0x01, 0x19, 0x01, 0x01, 0x1A, 0x00, 0x01, 0x05, 0xB8, 0x1B, 0x00,
@@ -23,7 +20,7 @@ unsigned char data[] = {
0x88, 0x00, 0x75, 0x9C, 0xF6, 0xF7, 0xF5};
/* Exercise the default callbacks */
-static void test_default_callbacks(void **state) {
+static void test_default_callbacks(void** _CBOR_UNUSED(_state)) {
size_t read = 0;
while (read < 79) {
struct cbor_decoder_result result =
@@ -32,9 +29,366 @@ static void test_default_callbacks(void **state) {
}
}
+unsigned char bytestring_data[] = {0x01, 0x02, 0x03};
+static void test_builder_byte_string_callback_append(
+ void** _CBOR_UNUSED(_state)) {
+ struct _cbor_stack stack = _cbor_stack_init();
+ assert_non_null(
+ _cbor_stack_push(&stack, cbor_new_indefinite_bytestring(), 0));
+ struct _cbor_decoder_context context = {
+ .creation_failed = false,
+ .syntax_error = false,
+ .root = NULL,
+ .stack = &stack,
+ };
+
+ cbor_builder_byte_string_callback(&context, bytestring_data, 3);
+
+ assert_false(context.creation_failed);
+ assert_false(context.syntax_error);
+ assert_size_equal(context.stack->size, 1);
+
+ cbor_item_t* bytestring = stack.top->item;
+ assert_size_equal(cbor_refcount(bytestring), 1);
+ assert_true(cbor_typeof(bytestring) == CBOR_TYPE_BYTESTRING);
+ assert_true(cbor_isa_bytestring(bytestring));
+ assert_size_equal(cbor_bytestring_length(bytestring), 0);
+ assert_true(cbor_bytestring_is_indefinite(bytestring));
+ assert_size_equal(cbor_bytestring_chunk_count(bytestring), 1);
+
+ cbor_item_t* chunk = cbor_bytestring_chunks_handle(bytestring)[0];
+ assert_size_equal(cbor_refcount(chunk), 1);
+ assert_true(cbor_typeof(bytestring) == CBOR_TYPE_BYTESTRING);
+ assert_true(cbor_isa_bytestring(chunk));
+ assert_true(cbor_bytestring_is_definite(chunk));
+ assert_size_equal(cbor_bytestring_length(chunk), 3);
+ assert_memory_equal(cbor_bytestring_handle(chunk), bytestring_data, 3);
+ // Data is copied
+ assert_ptr_not_equal(cbor_bytestring_handle(chunk), bytestring_data);
+
+ cbor_decref(&bytestring);
+ _cbor_stack_pop(&stack);
+}
+
+static void test_builder_byte_string_callback_append_alloc_failure(
+ void** _CBOR_UNUSED(_state)) {
+ struct _cbor_stack stack = _cbor_stack_init();
+ assert_non_null(
+ _cbor_stack_push(&stack, cbor_new_indefinite_bytestring(), 0));
+ struct _cbor_decoder_context context = {
+ .creation_failed = false,
+ .syntax_error = false,
+ .root = NULL,
+ .stack = &stack,
+ };
+
+ WITH_FAILING_MALLOC(
+ { cbor_builder_byte_string_callback(&context, bytestring_data, 3); });
+
+ assert_true(context.creation_failed);
+ assert_false(context.syntax_error);
+ assert_size_equal(context.stack->size, 1);
+
+ // The stack remains unchanged
+ cbor_item_t* bytestring = stack.top->item;
+ assert_size_equal(cbor_refcount(bytestring), 1);
+ assert_true(cbor_typeof(bytestring) == CBOR_TYPE_BYTESTRING);
+ assert_true(cbor_isa_bytestring(bytestring));
+ assert_size_equal(cbor_bytestring_length(bytestring), 0);
+ assert_true(cbor_bytestring_is_indefinite(bytestring));
+ assert_size_equal(cbor_bytestring_chunk_count(bytestring), 0);
+
+ cbor_decref(&bytestring);
+ _cbor_stack_pop(&stack);
+}
+
+static void test_builder_byte_string_callback_append_item_alloc_failure(
+ void** _CBOR_UNUSED(_state)) {
+ struct _cbor_stack stack = _cbor_stack_init();
+ assert_non_null(
+ _cbor_stack_push(&stack, cbor_new_indefinite_bytestring(), 0));
+ struct _cbor_decoder_context context = {
+ .creation_failed = false,
+ .syntax_error = false,
+ .root = NULL,
+ .stack = &stack,
+ };
+
+ // Allocate new data block, but fail to allocate a new item with it
+ WITH_MOCK_MALLOC(
+ { cbor_builder_byte_string_callback(&context, bytestring_data, 3); }, 2,
+ MALLOC, MALLOC_FAIL);
+
+ assert_true(context.creation_failed);
+ assert_false(context.syntax_error);
+ assert_size_equal(context.stack->size, 1);
+
+ // The stack remains unchanged
+ cbor_item_t* bytestring = stack.top->item;
+ assert_size_equal(cbor_refcount(bytestring), 1);
+ assert_true(cbor_typeof(bytestring) == CBOR_TYPE_BYTESTRING);
+ assert_true(cbor_isa_bytestring(bytestring));
+ assert_size_equal(cbor_bytestring_length(bytestring), 0);
+ assert_true(cbor_bytestring_is_indefinite(bytestring));
+ assert_size_equal(cbor_bytestring_chunk_count(bytestring), 0);
+
+ cbor_decref(&bytestring);
+ _cbor_stack_pop(&stack);
+}
+
+static void test_builder_byte_string_callback_append_parent_alloc_failure(
+ void** _CBOR_UNUSED(_state)) {
+ struct _cbor_stack stack = _cbor_stack_init();
+ assert_non_null(
+ _cbor_stack_push(&stack, cbor_new_indefinite_bytestring(), 0));
+ struct _cbor_decoder_context context = {
+ .creation_failed = false,
+ .syntax_error = false,
+ .root = NULL,
+ .stack = &stack,
+ };
+
+ // Allocate new item, but fail to push it into the parent on the stack
+ WITH_MOCK_MALLOC(
+ { cbor_builder_byte_string_callback(&context, bytestring_data, 3); }, 3,
+ MALLOC, MALLOC, REALLOC_FAIL);
+
+ assert_true(context.creation_failed);
+ assert_false(context.syntax_error);
+ assert_size_equal(context.stack->size, 1);
+
+ // The stack remains unchanged
+ cbor_item_t* bytestring = stack.top->item;
+ assert_size_equal(cbor_refcount(bytestring), 1);
+ assert_true(cbor_typeof(bytestring) == CBOR_TYPE_BYTESTRING);
+ assert_true(cbor_isa_bytestring(bytestring));
+ assert_size_equal(cbor_bytestring_length(bytestring), 0);
+ assert_true(cbor_bytestring_is_indefinite(bytestring));
+ assert_size_equal(cbor_bytestring_chunk_count(bytestring), 0);
+
+ cbor_decref(&bytestring);
+ _cbor_stack_pop(&stack);
+}
+
+unsigned char string_data[] = {0x61, 0x62, 0x63};
+static void test_builder_string_callback_append(void** _CBOR_UNUSED(_state)) {
+ struct _cbor_stack stack = _cbor_stack_init();
+ assert_non_null(_cbor_stack_push(&stack, cbor_new_indefinite_string(), 0));
+ struct _cbor_decoder_context context = {
+ .creation_failed = false,
+ .syntax_error = false,
+ .root = NULL,
+ .stack = &stack,
+ };
+
+ cbor_builder_string_callback(&context, string_data, 3);
+
+ assert_false(context.creation_failed);
+ assert_false(context.syntax_error);
+ assert_size_equal(context.stack->size, 1);
+
+ cbor_item_t* string = stack.top->item;
+ assert_size_equal(cbor_refcount(string), 1);
+ assert_true(cbor_isa_string(string));
+ assert_size_equal(cbor_string_length(string), 0);
+ assert_true(cbor_string_is_indefinite(string));
+ assert_size_equal(cbor_string_chunk_count(string), 1);
+
+ cbor_item_t* chunk = cbor_string_chunks_handle(string)[0];
+ assert_size_equal(cbor_refcount(chunk), 1);
+ assert_true(cbor_isa_string(chunk));
+ assert_true(cbor_string_is_definite(chunk));
+ assert_size_equal(cbor_string_length(chunk), 3);
+ assert_memory_equal(cbor_string_handle(chunk), "abc", 3);
+ // Data is copied
+ assert_ptr_not_equal(cbor_string_handle(chunk), string_data);
+
+ cbor_decref(&string);
+ _cbor_stack_pop(&stack);
+}
+
+static void test_builder_string_callback_append_alloc_failure(
+ void** _CBOR_UNUSED(_state)) {
+ struct _cbor_stack stack = _cbor_stack_init();
+ assert_non_null(_cbor_stack_push(&stack, cbor_new_indefinite_string(), 0));
+ struct _cbor_decoder_context context = {
+ .creation_failed = false,
+ .syntax_error = false,
+ .root = NULL,
+ .stack = &stack,
+ };
+
+ WITH_FAILING_MALLOC(
+ { cbor_builder_string_callback(&context, string_data, 3); });
+
+ assert_true(context.creation_failed);
+ assert_false(context.syntax_error);
+ assert_size_equal(context.stack->size, 1);
+
+ // The stack remains unchanged
+ cbor_item_t* string = stack.top->item;
+ assert_size_equal(cbor_refcount(string), 1);
+ assert_true(cbor_typeof(string) == CBOR_TYPE_STRING);
+ assert_true(cbor_isa_string(string));
+ assert_size_equal(cbor_string_length(string), 0);
+ assert_true(cbor_string_is_indefinite(string));
+ assert_size_equal(cbor_string_chunk_count(string), 0);
+
+ cbor_decref(&string);
+ _cbor_stack_pop(&stack);
+}
+
+static void test_builder_string_callback_append_item_alloc_failure(
+ void** _CBOR_UNUSED(_state)) {
+ struct _cbor_stack stack = _cbor_stack_init();
+ assert_non_null(_cbor_stack_push(&stack, cbor_new_indefinite_string(), 0));
+ struct _cbor_decoder_context context = {
+ .creation_failed = false,
+ .syntax_error = false,
+ .root = NULL,
+ .stack = &stack,
+ };
+
+ // Allocate new data block, but fail to allocate a new item with it
+ WITH_MOCK_MALLOC({ cbor_builder_string_callback(&context, string_data, 3); },
+ 2, MALLOC, MALLOC_FAIL);
+
+ assert_true(context.creation_failed);
+ assert_false(context.syntax_error);
+ assert_size_equal(context.stack->size, 1);
+
+ // The stack remains unchanged
+ cbor_item_t* string = stack.top->item;
+ assert_size_equal(cbor_refcount(string), 1);
+ assert_true(cbor_typeof(string) == CBOR_TYPE_STRING);
+ assert_true(cbor_isa_string(string));
+ assert_size_equal(cbor_string_length(string), 0);
+ assert_true(cbor_string_is_indefinite(string));
+ assert_size_equal(cbor_string_chunk_count(string), 0);
+
+ cbor_decref(&string);
+ _cbor_stack_pop(&stack);
+}
+
+static void test_builder_string_callback_append_parent_alloc_failure(
+ void** _CBOR_UNUSED(_state)) {
+ struct _cbor_stack stack = _cbor_stack_init();
+ assert_non_null(_cbor_stack_push(&stack, cbor_new_indefinite_string(), 0));
+ struct _cbor_decoder_context context = {
+ .creation_failed = false,
+ .syntax_error = false,
+ .root = NULL,
+ .stack = &stack,
+ };
+
+ // Allocate new item, but fail to push it into the parent on the stack
+ WITH_MOCK_MALLOC({ cbor_builder_string_callback(&context, string_data, 3); },
+ 3, MALLOC, MALLOC, REALLOC_FAIL);
+
+ assert_true(context.creation_failed);
+ assert_false(context.syntax_error);
+ assert_size_equal(context.stack->size, 1);
+
+ // The stack remains unchanged
+ cbor_item_t* string = stack.top->item;
+ assert_size_equal(cbor_refcount(string), 1);
+ assert_true(cbor_typeof(string) == CBOR_TYPE_STRING);
+ assert_true(cbor_isa_string(string));
+ assert_size_equal(cbor_string_length(string), 0);
+ assert_true(cbor_string_is_indefinite(string));
+ assert_size_equal(cbor_string_chunk_count(string), 0);
+
+ cbor_decref(&string);
+ _cbor_stack_pop(&stack);
+}
+
+static void test_append_array_failure(void** _CBOR_UNUSED(_state)) {
+ struct _cbor_stack stack = _cbor_stack_init();
+ assert_non_null(_cbor_stack_push(&stack, cbor_new_definite_array(0), 0));
+ stack.top->subitems = 1;
+ struct _cbor_decoder_context context = {
+ .creation_failed = false,
+ .syntax_error = false,
+ .root = NULL,
+ .stack = &stack,
+ };
+ cbor_item_t* item = cbor_build_uint8(42);
+
+ _cbor_builder_append(item, &context);
+
+ assert_true(context.creation_failed);
+ assert_false(context.syntax_error);
+ assert_size_equal(context.stack->size, 1);
+
+ // The stack remains unchanged
+ cbor_item_t* array = stack.top->item;
+ assert_size_equal(cbor_refcount(array), 1);
+ assert_true(cbor_isa_array(array));
+ assert_size_equal(cbor_array_size(array), 0);
+
+ // item free'd by _cbor_builder_append
+ cbor_decref(&array);
+ _cbor_stack_pop(&stack);
+}
+
+static void test_append_map_failure(void** _CBOR_UNUSED(_state)) {
+ struct _cbor_stack stack = _cbor_stack_init();
+ assert_non_null(
+ _cbor_stack_push(&stack, cbor_new_indefinite_map(), /*subitems=*/0));
+ struct _cbor_decoder_context context = {
+ .creation_failed = false,
+ .syntax_error = false,
+ .root = NULL,
+ .stack = &stack,
+ };
+ cbor_item_t* item = cbor_build_uint8(42);
+
+ WITH_MOCK_MALLOC({ _cbor_builder_append(item, &context); }, 1, REALLOC_FAIL);
+
+ assert_true(context.creation_failed);
+ assert_false(context.syntax_error);
+ assert_size_equal(context.stack->size, 1);
+
+ // The stack remains unchanged
+ cbor_item_t* map = stack.top->item;
+ assert_size_equal(cbor_refcount(map), 1);
+ assert_true(cbor_isa_map(map));
+ assert_size_equal(cbor_map_size(map), 0);
+
+ // item free'd by _cbor_builder_append
+ cbor_decref(&map);
+ _cbor_stack_pop(&stack);
+}
+
+// Size 1 array start, but we get an indef break
+unsigned char invalid_indef_break_data[] = {0x81, 0xFF};
+static void test_invalid_indef_break(void** _CBOR_UNUSED(_state)) {
+ struct cbor_load_result res;
+ cbor_item_t* item = cbor_load(invalid_indef_break_data, 2, &res);
+
+ assert_null(item);
+ assert_size_equal(res.read, 2);
+ assert_true(res.error.code == CBOR_ERR_SYNTAXERROR);
+}
+
int main(void) {
const struct CMUnitTest tests[] = {
+ cmocka_unit_test(test_default_callbacks),
+ cmocka_unit_test(test_builder_byte_string_callback_append),
+ cmocka_unit_test(test_builder_byte_string_callback_append_alloc_failure),
+ cmocka_unit_test(
+ test_builder_byte_string_callback_append_item_alloc_failure),
+ cmocka_unit_test(
+ test_builder_byte_string_callback_append_parent_alloc_failure),
+ cmocka_unit_test(test_builder_string_callback_append),
+ cmocka_unit_test(test_builder_string_callback_append_alloc_failure),
+ cmocka_unit_test(test_builder_string_callback_append_item_alloc_failure),
+ cmocka_unit_test(
+ test_builder_string_callback_append_parent_alloc_failure),
+ cmocka_unit_test(test_append_array_failure),
+ cmocka_unit_test(test_append_map_failure),
+ cmocka_unit_test(test_invalid_indef_break),
+ };
- cmocka_unit_test(test_default_callbacks)};
- return cmocka_run_group_tests(tests, NULL, NULL);
+ cmocka_run_group_tests(tests, NULL, NULL);
}
diff --git a/test/cbor_serialize_test.c b/test/cbor_serialize_test.c
index cd1f6d74ed6f..d549c37217cc 100644
--- a/test/cbor_serialize_test.c
+++ b/test/cbor_serialize_test.c
@@ -5,140 +5,220 @@
* it under the terms of the MIT license. See LICENSE for details.
*/
+// cbor_serialize_alloc
+#pragma clang diagnostic ignored "-Wdeprecated-declarations"
+#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
+
+#include <math.h>
#include <setjmp.h>
#include <stdarg.h>
#include <stddef.h>
+#include <stdint.h>
+#include <string.h>
#include <cmocka.h>
-#include <math.h>
-#include <stdarg.h>
-#include <string.h>
-#include <strings.h>
+#include "assertions.h"
#include "cbor.h"
+#include "test_allocator.h"
unsigned char buffer[512];
-static void test_serialize_uint8(void **state) {
+static void test_serialize_uint8_embed(void **_CBOR_UNUSED(_state)) {
cbor_item_t *item = cbor_new_int8();
cbor_set_uint8(item, 0);
- assert_int_equal(1, cbor_serialize(item, buffer, 512));
+ assert_size_equal(1, cbor_serialize(item, buffer, 512));
assert_memory_equal(buffer, (unsigned char[]){0x00}, 1);
+ assert_size_equal(cbor_serialized_size(item), 1);
+ cbor_decref(&item);
+}
+
+static void test_serialize_uint8(void **_CBOR_UNUSED(_state)) {
+ cbor_item_t *item = cbor_new_int8();
+ cbor_set_uint8(item, 42);
+ assert_size_equal(2, cbor_serialize(item, buffer, 512));
+ assert_memory_equal(buffer, ((unsigned char[]){0x18, 0x2a}), 2);
+ assert_size_equal(cbor_serialized_size(item), 2);
cbor_decref(&item);
}
-static void test_serialize_uint16(void **state) {
+static void test_serialize_uint16(void **_CBOR_UNUSED(_state)) {
cbor_item_t *item = cbor_new_int16();
cbor_set_uint16(item, 1000);
- assert_int_equal(3, cbor_serialize(item, buffer, 512));
+ assert_size_equal(3, cbor_serialize(item, buffer, 512));
assert_memory_equal(buffer, ((unsigned char[]){0x19, 0x03, 0xE8}), 3);
+ assert_size_equal(cbor_serialized_size(item), 3);
cbor_decref(&item);
}
-static void test_serialize_uint32(void **state) {
+static void test_serialize_uint32(void **_CBOR_UNUSED(_state)) {
cbor_item_t *item = cbor_new_int32();
cbor_set_uint32(item, 1000000);
- assert_int_equal(5, cbor_serialize(item, buffer, 512));
+ assert_size_equal(5, cbor_serialize(item, buffer, 512));
assert_memory_equal(buffer, ((unsigned char[]){0x1A, 0x00, 0x0F, 0x42, 0x40}),
5);
+ assert_size_equal(cbor_serialized_size(item), 5);
cbor_decref(&item);
}
-static void test_serialize_uint64(void **state) {
+static void test_serialize_uint64(void **_CBOR_UNUSED(_state)) {
cbor_item_t *item = cbor_new_int64();
cbor_set_uint64(item, 1000000000000);
- assert_int_equal(9, cbor_serialize(item, buffer, 512));
+ assert_size_equal(9, cbor_serialize(item, buffer, 512));
assert_memory_equal(
buffer,
((unsigned char[]){0x1B, 0x00, 0x00, 0x00, 0xE8, 0xD4, 0xA5, 0x10, 0x00}),
9);
+ assert_size_equal(cbor_serialized_size(item), 9);
cbor_decref(&item);
}
-static void test_serialize_negint8(void **state) {
+static void test_serialize_negint8_embed(void **_CBOR_UNUSED(_state)) {
cbor_item_t *item = cbor_new_int8();
cbor_set_uint8(item, 0);
cbor_mark_negint(item);
- assert_int_equal(1, cbor_serialize(item, buffer, 512));
+ assert_size_equal(1, cbor_serialize(item, buffer, 512));
assert_memory_equal(buffer, (unsigned char[]){0x20}, 1);
+ assert_size_equal(cbor_serialized_size(item), 1);
cbor_decref(&item);
}
-static void test_serialize_negint16(void **state) {
+static void test_serialize_negint8(void **_CBOR_UNUSED(_state)) {
+ cbor_item_t *item = cbor_new_int8();
+ cbor_set_uint8(item, 42);
+ cbor_mark_negint(item);
+ assert_size_equal(2, cbor_serialize(item, buffer, 512));
+ assert_memory_equal(buffer, ((unsigned char[]){0x38, 0x2a}), 2);
+ assert_size_equal(cbor_serialized_size(item), 2);
+ cbor_decref(&item);
+}
+
+static void test_serialize_negint16(void **_CBOR_UNUSED(_state)) {
cbor_item_t *item = cbor_new_int16();
cbor_set_uint16(item, 1000);
cbor_mark_negint(item);
- assert_int_equal(3, cbor_serialize(item, buffer, 512));
+ assert_size_equal(3, cbor_serialize(item, buffer, 512));
assert_memory_equal(buffer, ((unsigned char[]){0x39, 0x03, 0xE8}), 3);
+ assert_size_equal(cbor_serialized_size(item), 3);
cbor_decref(&item);
}
-static void test_serialize_negint32(void **state) {
+static void test_serialize_negint32(void **_CBOR_UNUSED(_state)) {
cbor_item_t *item = cbor_new_int32();
cbor_set_uint32(item, 1000000);
cbor_mark_negint(item);
- assert_int_equal(5, cbor_serialize(item, buffer, 512));
+ assert_size_equal(5, cbor_serialize(item, buffer, 512));
assert_memory_equal(buffer, ((unsigned char[]){0x3A, 0x00, 0x0F, 0x42, 0x40}),
5);
+ assert_size_equal(cbor_serialized_size(item), 5);
cbor_decref(&item);
}
-static void test_serialize_negint64(void **state) {
+static void test_serialize_negint64(void **_CBOR_UNUSED(_state)) {
cbor_item_t *item = cbor_new_int64();
cbor_set_uint64(item, 1000000000000);
cbor_mark_negint(item);
- assert_int_equal(9, cbor_serialize(item, buffer, 512));
+ assert_size_equal(9, cbor_serialize(item, buffer, 512));
assert_memory_equal(
buffer,
((unsigned char[]){0x3B, 0x00, 0x00, 0x00, 0xE8, 0xD4, 0xA5, 0x10, 0x00}),
9);
+ assert_size_equal(cbor_serialized_size(item), 9);
cbor_decref(&item);
}
-static void test_serialize_definite_bytestring(void **state) {
+static void test_serialize_definite_bytestring(void **_CBOR_UNUSED(_state)) {
cbor_item_t *item = cbor_new_definite_bytestring();
unsigned char *data = malloc(256);
- bzero(data, 256); /* Prevent undefined behavior in comparison */
cbor_bytestring_set_handle(item, data, 256);
- assert_int_equal(256 + 3, cbor_serialize(item, buffer, 512));
+ memset(data, 0, 256); /* Prevent undefined behavior in comparison */
+ assert_size_equal(256 + 3, cbor_serialize(item, buffer, 512));
assert_memory_equal(buffer, ((unsigned char[]){0x59, 0x01, 0x00}), 3);
assert_memory_equal(buffer + 3, data, 256);
+ assert_size_equal(cbor_serialized_size(item), 259);
cbor_decref(&item);
}
-static void test_serialize_indefinite_bytestring(void **state) {
+static void test_serialize_indefinite_bytestring(void **_CBOR_UNUSED(_state)) {
cbor_item_t *item = cbor_new_indefinite_bytestring();
cbor_item_t *chunk = cbor_new_definite_bytestring();
unsigned char *data = malloc(256);
- bzero(data, 256); /* Prevent undefined behavior in comparison */
+ memset(data, 0, 256); /* Prevent undefined behavior in comparison */
cbor_bytestring_set_handle(chunk, data, 256);
- cbor_bytestring_add_chunk(item, cbor_move(chunk));
- assert_int_equal(cbor_bytestring_chunk_count(item), 1);
+ assert_true(cbor_bytestring_add_chunk(item, cbor_move(chunk)));
+ assert_size_equal(cbor_bytestring_chunk_count(item), 1);
- assert_int_equal(1 + 3 + 256 + 1, cbor_serialize(item, buffer, 512));
+ assert_size_equal(1 + 3 + 256 + 1, cbor_serialize(item, buffer, 512));
assert_memory_equal(buffer, ((unsigned char[]){0x5F, 0x59, 0x01, 0x00}), 4);
assert_memory_equal(buffer + 4, data, 256);
assert_memory_equal(buffer + 4 + 256, ((unsigned char[]){0xFF}), 1);
+ assert_size_equal(cbor_serialized_size(item), 261);
+ cbor_decref(&item);
+}
+
+static void test_serialize_bytestring_size_overflow(
+ void **_CBOR_UNUSED(_state)) {
+ cbor_item_t *item = cbor_new_definite_bytestring();
+
+ // Fake having a huge chunk of data
+ unsigned char *data = malloc(1);
+ cbor_bytestring_set_handle(item, data, SIZE_MAX);
+
+ // Would require 1 + 8 + SIZE_MAX bytes, which overflows size_t
+ assert_size_equal(cbor_serialize(item, buffer, 512), 0);
+ assert_size_equal(cbor_serialized_size(item), 0);
+ cbor_decref(&item);
+}
+
+static void test_serialize_bytestring_no_space(void **_CBOR_UNUSED(_state)) {
+ cbor_item_t *item = cbor_new_definite_bytestring();
+ unsigned char *data = malloc(12);
+ cbor_bytestring_set_handle(item, data, 12);
+
+ assert_size_equal(cbor_serialize(item, buffer, 1), 0);
+
+ cbor_decref(&item);
+}
+
+static void test_serialize_indefinite_bytestring_no_space(
+ void **_CBOR_UNUSED(_state)) {
+ cbor_item_t *item = cbor_new_indefinite_bytestring();
+ cbor_item_t *chunk = cbor_new_definite_bytestring();
+ unsigned char *data = malloc(256);
+ cbor_bytestring_set_handle(chunk, data, 256);
+ assert_true(cbor_bytestring_add_chunk(item, cbor_move(chunk)));
+
+ // Not enough space for the leading byte
+ assert_size_equal(cbor_serialize(item, buffer, 0), 0);
+
+ // Not enough space for the chunk
+ assert_size_equal(cbor_serialize(item, buffer, 30), 0);
+
+ // Not enough space for the indef break
+ assert_size_equal(
+ cbor_serialize(item, buffer, 1 + cbor_serialized_size(chunk)), 0);
+
cbor_decref(&item);
}
-static void test_serialize_definite_string(void **state) {
+static void test_serialize_definite_string(void **_CBOR_UNUSED(_state)) {
cbor_item_t *item = cbor_new_definite_string();
unsigned char *data = malloc(12);
strncpy((char *)data, "Hello world!", 12);
cbor_string_set_handle(item, data, 12);
- assert_int_equal(1 + 12, cbor_serialize(item, buffer, 512));
+ assert_size_equal(1 + 12, cbor_serialize(item, buffer, 512));
assert_memory_equal(
buffer,
((unsigned char[]){0x6C, 0x48, 0x65, 0x6C, 0x6C, 0x6F, 0x20, 0x77, 0x6F,
0x72, 0x6C, 0x64, 0x21}),
13);
+ assert_size_equal(cbor_serialized_size(item), 13);
cbor_decref(&item);
}
-static void test_serialize_indefinite_string(void **state) {
+static void test_serialize_indefinite_string(void **_CBOR_UNUSED(_state)) {
cbor_item_t *item = cbor_new_indefinite_string();
cbor_item_t *chunk = cbor_new_definite_string();
@@ -147,177 +227,445 @@ static void test_serialize_indefinite_string(void **state) {
cbor_string_set_handle(chunk, data, 12);
assert_true(cbor_string_add_chunk(item, cbor_move(chunk)));
- assert_int_equal(cbor_string_chunk_count(item), 1);
+ assert_size_equal(cbor_string_chunk_count(item), 1);
- assert_int_equal(15, cbor_serialize(item, buffer, 512));
+ assert_size_equal(15, cbor_serialize(item, buffer, 512));
assert_memory_equal(
buffer,
((unsigned char[]){0x7F, 0x6C, 0x48, 0x65, 0x6C, 0x6C, 0x6F, 0x20, 0x77,
0x6F, 0x72, 0x6C, 0x64, 0x21, 0xFF}),
15);
+ assert_size_equal(cbor_serialized_size(item), 15);
+ cbor_decref(&item);
+}
+
+static void test_serialize_string_no_space(void **_CBOR_UNUSED(_state)) {
+ cbor_item_t *item = cbor_new_definite_string();
+ unsigned char *data = malloc(12);
+ cbor_string_set_handle(item, data, 12);
+
+ assert_size_equal(cbor_serialize(item, buffer, 1), 0);
+
+ cbor_decref(&item);
+}
+
+static void test_serialize_indefinite_string_no_space(
+ void **_CBOR_UNUSED(_state)) {
+ cbor_item_t *item = cbor_new_indefinite_string();
+ cbor_item_t *chunk = cbor_new_definite_string();
+ unsigned char *data = malloc(256);
+ cbor_string_set_handle(chunk, data, 256);
+ assert_true(cbor_string_add_chunk(item, cbor_move(chunk)));
+
+ // Not enough space for the leading byte
+ assert_size_equal(cbor_serialize(item, buffer, 0), 0);
+
+ // Not enough space for the chunk
+ assert_size_equal(cbor_serialize(item, buffer, 30), 0);
+
+ // Not enough space for the indef break
+ assert_size_equal(
+ cbor_serialize(item, buffer, 1 + cbor_serialized_size(chunk)), 0);
+
cbor_decref(&item);
}
-static void test_serialize_definite_array(void **state) {
+static void test_serialize_definite_array(void **_CBOR_UNUSED(_state)) {
cbor_item_t *item = cbor_new_definite_array(2);
cbor_item_t *one = cbor_build_uint8(1);
cbor_item_t *two = cbor_build_uint8(2);
- cbor_array_push(item, one);
- cbor_array_set(item, 1, two);
- cbor_array_replace(item, 0, one);
+ assert_true(cbor_array_push(item, one));
+ assert_true(cbor_array_set(item, 1, two));
+ assert_true(cbor_array_replace(item, 0, one));
- assert_int_equal(3, cbor_serialize(item, buffer, 512));
+ assert_size_equal(3, cbor_serialize(item, buffer, 512));
assert_memory_equal(buffer, ((unsigned char[]){0x82, 0x01, 0x02}), 3);
+ assert_size_equal(cbor_serialized_size(item), 3);
cbor_decref(&item);
cbor_decref(&one);
cbor_decref(&two);
}
-static void test_serialize_indefinite_array(void **state) {
+static void test_serialize_array_no_space(void **_CBOR_UNUSED(_state)) {
+ cbor_item_t *item = cbor_new_indefinite_array();
+ cbor_item_t *one = cbor_build_uint8(1);
+ assert_true(cbor_array_push(item, one));
+ assert_size_equal(cbor_serialized_size(item), 3);
+
+ // Not enough space for the leading byte
+ assert_size_equal(0, cbor_serialize(item, buffer, 0));
+
+ // Not enough space for the item
+ assert_size_equal(0, cbor_serialize(item, buffer, 1));
+
+ // Not enough space for the indef break
+ assert_size_equal(0, cbor_serialize(item, buffer, 2));
+
+ cbor_decref(&item);
+ cbor_decref(&one);
+}
+
+static void test_serialize_indefinite_array(void **_CBOR_UNUSED(_state)) {
cbor_item_t *item = cbor_new_indefinite_array();
cbor_item_t *one = cbor_build_uint8(1);
cbor_item_t *two = cbor_build_uint8(2);
- cbor_array_push(item, one);
- cbor_array_push(item, two);
+ assert_true(cbor_array_push(item, one));
+ assert_true(cbor_array_push(item, two));
- assert_int_equal(4, cbor_serialize(item, buffer, 512));
+ assert_size_equal(4, cbor_serialize(item, buffer, 512));
assert_memory_equal(buffer, ((unsigned char[]){0x9F, 0x01, 0x02, 0xFF}), 4);
+ assert_size_equal(cbor_serialized_size(item), 4);
cbor_decref(&item);
cbor_decref(&one);
cbor_decref(&two);
}
-static void test_serialize_definite_map(void **state) {
+static void test_serialize_definite_map(void **_CBOR_UNUSED(_state)) {
cbor_item_t *item = cbor_new_definite_map(2);
cbor_item_t *one = cbor_build_uint8(1);
cbor_item_t *two = cbor_build_uint8(2);
- cbor_map_add(item, (struct cbor_pair){.key = one, .value = two});
- cbor_map_add(item, (struct cbor_pair){.key = two, .value = one});
+ assert_true(cbor_map_add(item, (struct cbor_pair){.key = one, .value = two}));
+ assert_true(cbor_map_add(item, (struct cbor_pair){.key = two, .value = one}));
- assert_int_equal(5, cbor_serialize(item, buffer, 512));
+ assert_size_equal(5, cbor_serialize(item, buffer, 512));
assert_memory_equal(buffer, ((unsigned char[]){0xA2, 0x01, 0x02, 0x02, 0x01}),
5);
+ assert_size_equal(cbor_serialized_size(item), 5);
cbor_decref(&item);
cbor_decref(&one);
cbor_decref(&two);
}
-static void test_serialize_indefinite_map(void **state) {
- cbor_item_t *item = cbor_new_indefinite_map(2);
+static void test_serialize_indefinite_map(void **_CBOR_UNUSED(_state)) {
+ cbor_item_t *item = cbor_new_indefinite_map();
cbor_item_t *one = cbor_build_uint8(1);
cbor_item_t *two = cbor_build_uint8(2);
assert_true(cbor_map_add(item, (struct cbor_pair){.key = one, .value = two}));
assert_true(cbor_map_add(item, (struct cbor_pair){.key = two, .value = one}));
- assert_int_equal(6, cbor_serialize(item, buffer, 512));
+ assert_size_equal(6, cbor_serialize(item, buffer, 512));
assert_memory_equal(
buffer, ((unsigned char[]){0xBF, 0x01, 0x02, 0x02, 0x01, 0xFF}), 6);
+ assert_size_equal(cbor_serialized_size(item), 6);
cbor_decref(&item);
cbor_decref(&one);
cbor_decref(&two);
}
-static void test_serialize_tags(void **state) {
+static void test_serialize_map_no_space(void **_CBOR_UNUSED(_state)) {
+ cbor_item_t *item = cbor_new_indefinite_map();
+ cbor_item_t *one = cbor_build_uint8(1);
+ cbor_item_t *two = cbor_build_uint8(2);
+ assert_true(cbor_map_add(item, (struct cbor_pair){.key = one, .value = two}));
+ assert_size_equal(cbor_serialized_size(item), 4);
+
+ // Not enough space for the leading byte
+ assert_size_equal(cbor_serialize(item, buffer, 0), 0);
+
+ // Not enough space for the key
+ assert_size_equal(cbor_serialize(item, buffer, 1), 0);
+
+ // Not enough space for the value
+ assert_size_equal(cbor_serialize(item, buffer, 2), 0);
+
+ // Not enough space for the indef break
+ assert_size_equal(cbor_serialize(item, buffer, 3), 0);
+
+ cbor_decref(&item);
+ cbor_decref(&one);
+ cbor_decref(&two);
+}
+
+static void test_serialize_tags(void **_CBOR_UNUSED(_state)) {
cbor_item_t *item = cbor_new_tag(21);
cbor_item_t *one = cbor_build_uint8(1);
cbor_tag_set_item(item, one);
- assert_int_equal(2, cbor_serialize(item, buffer, 512));
+ assert_size_equal(2, cbor_serialize(item, buffer, 512));
assert_memory_equal(buffer, ((unsigned char[]){0xD5, 0x01}), 2);
+ assert_size_equal(cbor_serialized_size(item), 2);
+ cbor_decref(&item);
+ cbor_decref(&one);
+}
+
+static void test_serialize_tags_no_space(void **_CBOR_UNUSED(_state)) {
+ cbor_item_t *item = cbor_new_tag(21);
+ cbor_item_t *one = cbor_build_uint8(1);
+ cbor_tag_set_item(item, one);
+ assert_size_equal(cbor_serialized_size(item), 2);
+
+ // Not enough space for the leading byte
+ assert_size_equal(cbor_serialize(item, buffer, 0), 0);
+
+ // Not enough space for the item
+ assert_size_equal(cbor_serialize(item, buffer, 1), 0);
+
cbor_decref(&item);
cbor_decref(&one);
}
-static void test_serialize_half(void **state) {
+static void test_serialize_half(void **_CBOR_UNUSED(_state)) {
cbor_item_t *item = cbor_new_float2();
cbor_set_float2(item, NAN);
- assert_int_equal(3, cbor_serialize(item, buffer, 512));
+ assert_size_equal(3, cbor_serialize(item, buffer, 512));
assert_memory_equal(buffer, ((unsigned char[]){0xF9, 0x7E, 0x00}), 3);
+ assert_size_equal(cbor_serialized_size(item), 3);
cbor_decref(&item);
}
-static void test_serialize_single(void **state) {
+static void test_serialize_single(void **_CBOR_UNUSED(_state)) {
cbor_item_t *item = cbor_new_float4();
cbor_set_float4(item, 100000.0f);
- assert_int_equal(5, cbor_serialize(item, buffer, 512));
+ assert_size_equal(5, cbor_serialize(item, buffer, 512));
assert_memory_equal(buffer, ((unsigned char[]){0xFA, 0x47, 0xC3, 0x50, 0x00}),
5);
+ assert_size_equal(cbor_serialized_size(item), 5);
cbor_decref(&item);
}
-static void test_serialize_double(void **state) {
+static void test_serialize_double(void **_CBOR_UNUSED(_state)) {
cbor_item_t *item = cbor_new_float8();
cbor_set_float8(item, -4.1);
- assert_int_equal(9, cbor_serialize(item, buffer, 512));
+ assert_size_equal(9, cbor_serialize(item, buffer, 512));
assert_memory_equal(
buffer,
((unsigned char[]){0xFB, 0xC0, 0x10, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66}),
9);
+ assert_size_equal(cbor_serialized_size(item), 9);
cbor_decref(&item);
}
-static void test_serialize_ctrl(void **state) {
+static void test_serialize_ctrl(void **_CBOR_UNUSED(_state)) {
cbor_item_t *item = cbor_new_undef();
- assert_int_equal(1, cbor_serialize(item, buffer, 512));
+ assert_size_equal(1, cbor_serialize(item, buffer, 512));
assert_memory_equal(buffer, ((unsigned char[]){0xF7}), 1);
+ assert_size_equal(cbor_serialized_size(item), 1);
cbor_decref(&item);
}
-static void test_serialize_long_ctrl(void **state) {
+static void test_serialize_long_ctrl(void **_CBOR_UNUSED(_state)) {
cbor_item_t *item = cbor_new_ctrl();
cbor_set_ctrl(item, 254);
- assert_int_equal(2, cbor_serialize(item, buffer, 512));
+ assert_size_equal(2, cbor_serialize(item, buffer, 512));
assert_memory_equal(buffer, ((unsigned char[]){0xF8, 0xFE}), 2);
+ assert_size_equal(cbor_serialized_size(item), 2);
cbor_decref(&item);
}
-static void test_auto_serialize(void **state) {
+static void test_auto_serialize(void **_CBOR_UNUSED(_state)) {
cbor_item_t *item = cbor_new_definite_array(4);
- for (size_t i = 0; i < 4; i++)
- cbor_array_push(item, cbor_move(cbor_build_uint64(0)));
+ for (size_t i = 0; i < 4; i++) {
+ assert_true(cbor_array_push(item, cbor_move(cbor_build_uint64(0))));
+ }
+
+ unsigned char *output;
+ size_t output_size;
+ assert_size_equal(cbor_serialize_alloc(item, &output, &output_size), 37);
+ assert_size_equal(output_size, 37);
+ assert_size_equal(cbor_serialized_size(item), 37);
+ assert_memory_equal(output, ((unsigned char[]){0x84, 0x1B}), 2);
+ cbor_decref(&item);
+ _cbor_free(output);
+}
+
+static void test_auto_serialize_no_size(void **_CBOR_UNUSED(_state)) {
+ cbor_item_t *item = cbor_build_uint8(1);
+
+ unsigned char *output;
+ assert_size_equal(cbor_serialize_alloc(item, &output, NULL), 1);
+ assert_memory_equal(output, ((unsigned char[]){0x01}), 1);
+ assert_size_equal(cbor_serialized_size(item), 1);
+ cbor_decref(&item);
+ _cbor_free(output);
+}
+
+static void test_auto_serialize_too_large(void **_CBOR_UNUSED(_state)) {
+ cbor_item_t *item = cbor_new_indefinite_string();
+ cbor_item_t *chunk = cbor_new_definite_string();
+ assert_true(cbor_string_add_chunk(item, chunk));
+
+ // Pretend the chunk is huge
+ chunk->metadata.string_metadata.length = SIZE_MAX;
+ assert_true(SIZE_MAX + 2 == 1);
+ assert_size_equal(cbor_serialized_size(item), 0);
+ unsigned char *output;
+ size_t output_size;
+ assert_size_equal(cbor_serialize_alloc(item, &output, &output_size), 0);
+ assert_size_equal(output_size, 0);
+ assert_null(output);
+
+ chunk->metadata.string_metadata.length = 0;
+ cbor_decref(&chunk);
+ cbor_decref(&item);
+}
+
+static void test_auto_serialize_alloc_fail(void **_CBOR_UNUSED(_state)) {
+ cbor_item_t *item = cbor_build_uint8(42);
+
+ WITH_FAILING_MALLOC({
+ unsigned char *output;
+ size_t output_size;
+ assert_size_equal(cbor_serialize_alloc(item, &output, &output_size), 0);
+ assert_size_equal(output_size, 0);
+ assert_null(output);
+ });
+
+ cbor_decref(&item);
+}
+
+static void test_auto_serialize_zero_len_bytestring(
+ void **_CBOR_UNUSED(_state)) {
+ cbor_item_t *item = cbor_build_bytestring((cbor_data) "", 0);
+
+ unsigned char *output;
+ assert_size_equal(cbor_serialize_alloc(item, &output, NULL), 1);
+ assert_memory_equal(output, ((unsigned char[]){0x40}), 1);
+ assert_size_equal(cbor_serialized_size(item), 1);
+ cbor_decref(&item);
+ _cbor_free(output);
+}
+
+static void test_auto_serialize_zero_len_string(void **_CBOR_UNUSED(_state)) {
+ cbor_item_t *item = cbor_build_string("");
+
+ unsigned char *output;
+ assert_size_equal(cbor_serialize_alloc(item, &output, NULL), 1);
+ assert_memory_equal(output, ((unsigned char[]){0x60}), 1);
+ assert_size_equal(cbor_serialized_size(item), 1);
+ cbor_decref(&item);
+ _cbor_free(output);
+}
+
+static void test_auto_serialize_zero_len_bytestring_chunk(
+ void **_CBOR_UNUSED(_state)) {
+ cbor_item_t *item = cbor_new_indefinite_bytestring();
+
+ assert_true(cbor_bytestring_add_chunk(
+ item, cbor_move(cbor_build_bytestring((cbor_data) "", 0))));
+
+ unsigned char *output;
+ assert_size_equal(cbor_serialize_alloc(item, &output, NULL), 3);
+ assert_memory_equal(output, ((unsigned char[]){0x5f, 0x40, 0xff}), 3);
+ assert_size_equal(cbor_serialized_size(item), 3);
+ cbor_decref(&item);
+ _cbor_free(output);
+}
+
+static void test_auto_serialize_zero_len_string_chunk(
+ void **_CBOR_UNUSED(_state)) {
+ cbor_item_t *item = cbor_new_indefinite_string();
+
+ assert_true(cbor_string_add_chunk(item, cbor_move(cbor_build_string(""))));
+
+ unsigned char *output;
+ assert_size_equal(cbor_serialize_alloc(item, &output, NULL), 3);
+ assert_memory_equal(output, ((unsigned char[]){0x7f, 0x60, 0xff}), 3);
+ assert_size_equal(cbor_serialized_size(item), 3);
+ cbor_decref(&item);
+ _cbor_free(output);
+}
+
+static void test_auto_serialize_zero_len_array(void **_CBOR_UNUSED(_state)) {
+ cbor_item_t *item = cbor_new_definite_array(0);
+
+ unsigned char *output;
+ assert_size_equal(cbor_serialize_alloc(item, &output, NULL), 1);
+ assert_memory_equal(output, ((unsigned char[]){0x80}), 1);
+ assert_size_equal(cbor_serialized_size(item), 1);
+ cbor_decref(&item);
+ _cbor_free(output);
+}
+
+static void test_auto_serialize_zero_len_indef_array(
+ void **_CBOR_UNUSED(_state)) {
+ cbor_item_t *item = cbor_new_indefinite_array();
+
+ unsigned char *output;
+ assert_size_equal(cbor_serialize_alloc(item, &output, NULL), 2);
+ assert_memory_equal(output, ((unsigned char[]){0x9f, 0xff}), 2);
+ assert_size_equal(cbor_serialized_size(item), 2);
+ cbor_decref(&item);
+ _cbor_free(output);
+}
+
+static void test_auto_serialize_zero_len_map(void **_CBOR_UNUSED(_state)) {
+ cbor_item_t *item = cbor_new_definite_map(0);
+
+ unsigned char *output;
+ assert_size_equal(cbor_serialize_alloc(item, &output, NULL), 1);
+ assert_memory_equal(output, ((unsigned char[]){0xa0}), 1);
+ assert_size_equal(cbor_serialized_size(item), 1);
+ cbor_decref(&item);
+ _cbor_free(output);
+}
+
+static void test_auto_serialize_zero_len_indef_map(
+ void **_CBOR_UNUSED(_state)) {
+ cbor_item_t *item = cbor_new_indefinite_map();
- unsigned char *buffer;
- size_t buffer_size;
- assert_int_equal(37, cbor_serialize_alloc(item, &buffer, &buffer_size));
- assert_int_equal(64, buffer_size);
- assert_memory_equal(buffer, ((unsigned char[]){0x84, 0x1B}), 2);
+ unsigned char *output;
+ assert_size_equal(cbor_serialize_alloc(item, &output, NULL), 2);
+ assert_memory_equal(output, ((unsigned char[]){0xbf, 0xff}), 2);
+ assert_size_equal(cbor_serialized_size(item), 2);
cbor_decref(&item);
- _CBOR_FREE(buffer);
+ _cbor_free(output);
}
int main(void) {
const struct CMUnitTest tests[] = {
+ cmocka_unit_test(test_serialize_uint8_embed),
cmocka_unit_test(test_serialize_uint8),
cmocka_unit_test(test_serialize_uint16),
cmocka_unit_test(test_serialize_uint32),
cmocka_unit_test(test_serialize_uint64),
+ cmocka_unit_test(test_serialize_negint8_embed),
cmocka_unit_test(test_serialize_negint8),
cmocka_unit_test(test_serialize_negint16),
cmocka_unit_test(test_serialize_negint32),
cmocka_unit_test(test_serialize_negint64),
cmocka_unit_test(test_serialize_definite_bytestring),
cmocka_unit_test(test_serialize_indefinite_bytestring),
+ cmocka_unit_test(test_serialize_bytestring_size_overflow),
+ cmocka_unit_test(test_serialize_bytestring_no_space),
+ cmocka_unit_test(test_serialize_indefinite_bytestring_no_space),
cmocka_unit_test(test_serialize_definite_string),
cmocka_unit_test(test_serialize_indefinite_string),
+ cmocka_unit_test(test_serialize_string_no_space),
+ cmocka_unit_test(test_serialize_indefinite_string_no_space),
cmocka_unit_test(test_serialize_definite_array),
cmocka_unit_test(test_serialize_indefinite_array),
+ cmocka_unit_test(test_serialize_array_no_space),
cmocka_unit_test(test_serialize_definite_map),
cmocka_unit_test(test_serialize_indefinite_map),
+ cmocka_unit_test(test_serialize_map_no_space),
cmocka_unit_test(test_serialize_tags),
+ cmocka_unit_test(test_serialize_tags_no_space),
cmocka_unit_test(test_serialize_half),
cmocka_unit_test(test_serialize_single),
cmocka_unit_test(test_serialize_double),
cmocka_unit_test(test_serialize_ctrl),
cmocka_unit_test(test_serialize_long_ctrl),
- cmocka_unit_test(test_auto_serialize)};
+ cmocka_unit_test(test_auto_serialize),
+ cmocka_unit_test(test_auto_serialize_no_size),
+ cmocka_unit_test(test_auto_serialize_too_large),
+ cmocka_unit_test(test_auto_serialize_alloc_fail),
+ cmocka_unit_test(test_auto_serialize_zero_len_bytestring),
+ cmocka_unit_test(test_auto_serialize_zero_len_string),
+ cmocka_unit_test(test_auto_serialize_zero_len_bytestring_chunk),
+ cmocka_unit_test(test_auto_serialize_zero_len_string_chunk),
+ cmocka_unit_test(test_auto_serialize_zero_len_array),
+ cmocka_unit_test(test_auto_serialize_zero_len_indef_array),
+ cmocka_unit_test(test_auto_serialize_zero_len_map),
+ cmocka_unit_test(test_auto_serialize_zero_len_indef_map),
+ };
return cmocka_run_group_tests(tests, NULL, NULL);
}
diff --git a/test/cbor_stream_decode_test.c b/test/cbor_stream_decode_test.c
index 1d90bc7fdd76..1b8caf47765d 100644
--- a/test/cbor_stream_decode_test.c
+++ b/test/cbor_stream_decode_test.c
@@ -5,22 +5,16 @@
* it under the terms of the MIT license. See LICENSE for details.
*/
-#include <setjmp.h>
-#include <stdarg.h>
-#include <stddef.h>
-
-#include <cmocka.h>
-
#include "assertions.h"
#include "cbor.h"
#include "stream_expectations.h"
-static void test_no_data(void **state) {
+static void test_no_data(void **_CBOR_UNUSED(_state)) {
assert_decoder_result_nedata(1, decode(NULL, 0));
}
unsigned char embedded_uint8_data[] = {0x00, 0x01, 0x05, 0x17};
-static void test_uint8_embedded_decoding(void **state) {
+static void test_uint8_embedded_decoding(void **_CBOR_UNUSED(_state)) {
assert_uint8_eq(0);
assert_decoder_result(1, CBOR_DECODER_FINISHED,
decode(embedded_uint8_data, 1));
@@ -39,7 +33,7 @@ static void test_uint8_embedded_decoding(void **state) {
}
unsigned char uint8_data[] = {0x18, 0x83, 0x18, 0xFF};
-static void test_uint8_decoding(void **state) {
+static void test_uint8_decoding(void **_CBOR_UNUSED(_state)) {
assert_uint8_eq(0x83);
assert_decoder_result(2, CBOR_DECODER_FINISHED, decode(uint8_data, 2));
@@ -50,7 +44,7 @@ static void test_uint8_decoding(void **state) {
}
unsigned char uint16_data[] = {0x19, 0x01, 0xf4};
-static void test_uint16_decoding(void **state) {
+static void test_uint16_decoding(void **_CBOR_UNUSED(_state)) {
assert_uint16_eq(500);
assert_decoder_result(3, CBOR_DECODER_FINISHED, decode(uint16_data, 3));
@@ -58,7 +52,7 @@ static void test_uint16_decoding(void **state) {
}
unsigned char uint32_data[] = {0x1a, 0xa5, 0xf7, 0x02, 0xb3};
-static void test_uint32_decoding(void **state) {
+static void test_uint32_decoding(void **_CBOR_UNUSED(_state)) {
assert_uint32_eq((uint32_t)2784428723UL);
assert_decoder_result(5, CBOR_DECODER_FINISHED, decode(uint32_data, 5));
@@ -67,7 +61,7 @@ static void test_uint32_decoding(void **state) {
unsigned char uint64_data[] = {0x1b, 0xa5, 0xf7, 0x02, 0xb3,
0xa5, 0xf7, 0x02, 0xb3};
-static void test_uint64_decoding(void **state) {
+static void test_uint64_decoding(void **_CBOR_UNUSED(_state)) {
assert_uint64_eq(11959030306112471731ULL);
assert_decoder_result(9, CBOR_DECODER_FINISHED, decode(uint64_data, 9));
@@ -75,7 +69,7 @@ static void test_uint64_decoding(void **state) {
}
unsigned char embedded_negint8_data[] = {0x20, 0x21, 0x25, 0x37};
-static void test_negint8_embedded_decoding(void **state) {
+static void test_negint8_embedded_decoding(void **_CBOR_UNUSED(_state)) {
assert_negint8_eq(0);
assert_decoder_result(1, CBOR_DECODER_FINISHED,
decode(embedded_negint8_data, 1));
@@ -94,7 +88,7 @@ static void test_negint8_embedded_decoding(void **state) {
}
unsigned char negint8_data[] = {0x38, 0x83, 0x38, 0xFF};
-static void test_negint8_decoding(void **state) {
+static void test_negint8_decoding(void **_CBOR_UNUSED(_state)) {
assert_negint8_eq(0x83);
assert_decoder_result(2, CBOR_DECODER_FINISHED, decode(negint8_data, 2));
@@ -105,7 +99,7 @@ static void test_negint8_decoding(void **state) {
}
unsigned char negint16_data[] = {0x39, 0x01, 0xf4};
-static void test_negint16_decoding(void **state) {
+static void test_negint16_decoding(void **_CBOR_UNUSED(_state)) {
assert_negint16_eq(500);
assert_decoder_result(3, CBOR_DECODER_FINISHED, decode(negint16_data, 3));
@@ -113,7 +107,7 @@ static void test_negint16_decoding(void **state) {
}
unsigned char negint32_data[] = {0x3a, 0xa5, 0xf7, 0x02, 0xb3};
-static void test_negint32_decoding(void **state) {
+static void test_negint32_decoding(void **_CBOR_UNUSED(_state)) {
assert_negint32_eq((uint32_t)2784428723UL);
assert_decoder_result(5, CBOR_DECODER_FINISHED, decode(negint32_data, 5));
@@ -122,7 +116,7 @@ static void test_negint32_decoding(void **state) {
unsigned char negint64_data[] = {0x3b, 0xa5, 0xf7, 0x02, 0xb3,
0xa5, 0xf7, 0x02, 0xb3};
-static void test_negint64_decoding(void **state) {
+static void test_negint64_decoding(void **_CBOR_UNUSED(_state)) {
assert_negint64_eq(11959030306112471731ULL);
assert_decoder_result(9, CBOR_DECODER_FINISHED, decode(negint64_data, 9));
@@ -130,7 +124,7 @@ static void test_negint64_decoding(void **state) {
}
unsigned char bstring_embedded_int8_data[] = {0x41, 0xFF};
-static void test_bstring_embedded_int8_decoding(void **state) {
+static void test_bstring_embedded_int8_decoding(void **_CBOR_UNUSED(_state)) {
assert_bstring_mem_eq(bstring_embedded_int8_data + 1, 1);
assert_decoder_result(2, CBOR_DECODER_FINISHED,
decode(bstring_embedded_int8_data, 2));
@@ -138,54 +132,69 @@ static void test_bstring_embedded_int8_decoding(void **state) {
assert_minimum_input_size(2, bstring_embedded_int8_data);
}
-// TODO: Add tests with actual bstring/string chunks
-
-unsigned char bstring_int8_data[] = {0x58, 0x00};
-static void test_bstring_int8_decoding(void **state) {
- assert_bstring_mem_eq(bstring_int8_data + 2, 0);
- assert_decoder_result(2, CBOR_DECODER_FINISHED, decode(bstring_int8_data, 2));
+// The callback returns a *pointer* to the the start of the data segment (after
+// the second byte of input); the data is never read, so we never run into
+// memory issues despite not allocating and initializing all the data.
+unsigned char bstring_int8_data[] = {0x58, 0x02 /*, [2 bytes] */};
+static void test_bstring_int8_decoding(void **_CBOR_UNUSED(_state)) {
+ assert_bstring_mem_eq(bstring_int8_data + 2, 2);
+ assert_decoder_result(4, CBOR_DECODER_FINISHED, decode(bstring_int8_data, 4));
assert_minimum_input_size(2, bstring_int8_data);
+ assert_decoder_result_nedata(/* expected_bytes_required= */ 2 + 2,
+ decode(bstring_int8_data, 2));
+}
+
+unsigned char bstring_int8_empty_data[] = {0x58, 0x00};
+static void test_bstring_int8_empty_decoding(void **_CBOR_UNUSED(_state)) {
+ assert_bstring_mem_eq(bstring_int8_empty_data + 2, 0);
+ assert_decoder_result(2, CBOR_DECODER_FINISHED,
+ decode(bstring_int8_empty_data, 2));
+
+ assert_minimum_input_size(2, bstring_int8_empty_data);
}
unsigned char bstring_int16_data[] = {0x59, 0x01, 0x5C /*, [348 bytes] */};
-static void test_bstring_int16_decoding(void **state) {
+static void test_bstring_int16_decoding(void **_CBOR_UNUSED(_state)) {
assert_bstring_mem_eq(bstring_int16_data + 3, 348);
assert_decoder_result(3 + 348, CBOR_DECODER_FINISHED,
decode(bstring_int16_data, 3 + 348));
assert_minimum_input_size(3, bstring_int16_data);
- assert_decoder_result_nedata(3 + 348, decode(bstring_int16_data, 3));
+ assert_decoder_result_nedata(/* expected_bytes_required= */ 3 + 348,
+ decode(bstring_int16_data, 3));
}
unsigned char bstring_int32_data[] = {0x5A, 0x00, 0x10, 0x10,
0x10 /*, [1052688 bytes] */};
-static void test_bstring_int32_decoding(void **state) {
+static void test_bstring_int32_decoding(void **_CBOR_UNUSED(_state)) {
assert_bstring_mem_eq(bstring_int32_data + 5, 1052688);
assert_decoder_result(5 + 1052688, CBOR_DECODER_FINISHED,
decode(bstring_int32_data, 5 + 1052688));
assert_minimum_input_size(5, bstring_int32_data);
- assert_decoder_result_nedata(5 + 1052688, decode(bstring_int32_data, 5));
+ assert_decoder_result_nedata(/* expected_bytes_required= */ 5 + 1052688,
+ decode(bstring_int32_data, 5));
}
#ifdef EIGHT_BYTE_SIZE_T
unsigned char bstring_int64_data[] = {
0x5B, 0x00, 0x00, 0x00, 0x01,
0x00, 0x00, 0x00, 0x00 /*, [4294967296 bytes] */};
-static void test_bstring_int64_decoding(void **state) {
+static void test_bstring_int64_decoding(void **_CBOR_UNUSED(_state)) {
assert_bstring_mem_eq(bstring_int64_data + 9, 4294967296);
assert_decoder_result(9 + 4294967296, CBOR_DECODER_FINISHED,
decode(bstring_int64_data, 9 + 4294967296));
assert_minimum_input_size(9, bstring_int64_data);
- assert_decoder_result_nedata(9 + 4294967296, decode(bstring_int64_data, 9));
+ assert_decoder_result_nedata(/* expected_bytes_required= */ 9 + 4294967296,
+ decode(bstring_int64_data, 9));
}
#endif
unsigned char bstring_indef_1_data[] = {0x5F, 0x40 /* Empty byte string */,
0xFF};
-static void test_bstring_indef_decoding_1(void **state) {
+static void test_bstring_indef_decoding_1(void **_CBOR_UNUSED(_state)) {
assert_bstring_indef_start();
assert_decoder_result(1, CBOR_DECODER_FINISHED,
decode(bstring_indef_1_data, 3));
@@ -200,7 +209,7 @@ static void test_bstring_indef_decoding_1(void **state) {
}
unsigned char bstring_indef_2_data[] = {0x5F, 0xFF};
-static void test_bstring_indef_decoding_2(void **state) {
+static void test_bstring_indef_decoding_2(void **_CBOR_UNUSED(_state)) {
assert_bstring_indef_start();
assert_decoder_result(1, CBOR_DECODER_FINISHED,
decode(bstring_indef_2_data, 2));
@@ -210,11 +219,14 @@ static void test_bstring_indef_decoding_2(void **state) {
decode(bstring_indef_2_data + 1, 1));
}
-// TODO: Comment formatting seems weird
-unsigned char bstring_indef_3_data[] = {
- 0x5F, 0x40 /* Empty byte string */, 0x58,
- 0x01, 0xFF /* 1B 1 char bytes string */, 0xFF};
-static void test_bstring_indef_decoding_3(void **state) {
+unsigned char bstring_indef_3_data[] = {0x5F,
+ // Empty byte string
+ 0x40,
+ // 1B, 1 character byte string
+ 0x58, 0x01, 0x00,
+ // Break
+ 0xFF};
+static void test_bstring_indef_decoding_3(void **_CBOR_UNUSED(_state)) {
assert_bstring_indef_start();
assert_decoder_result(1, CBOR_DECODER_FINISHED,
decode(bstring_indef_3_data, 6));
@@ -232,15 +244,135 @@ static void test_bstring_indef_decoding_3(void **state) {
decode(bstring_indef_3_data + 5, 1));
}
+unsigned char string_embedded_int8_data[] = {0x61, 0xFF};
+static void test_string_embedded_int8_decoding(void **_CBOR_UNUSED(_state)) {
+ assert_string_mem_eq(string_embedded_int8_data + 1, 1);
+ assert_decoder_result(2, CBOR_DECODER_FINISHED,
+ decode(string_embedded_int8_data, 2));
+
+ assert_minimum_input_size(2, string_embedded_int8_data);
+}
+
+// The callback returns a *pointer* to the the start of the data segment (after
+// the second byte of input); the data is never read, so we never run into
+// memory issues despite not allocating and initializing all the data.
+unsigned char string_int8_data[] = {0x78, 0x02 /*, [2 bytes] */};
+static void test_string_int8_decoding(void **_CBOR_UNUSED(_state)) {
+ assert_string_mem_eq(string_int8_data + 2, 2);
+ assert_decoder_result(4, CBOR_DECODER_FINISHED, decode(string_int8_data, 4));
+
+ assert_minimum_input_size(2, string_int8_data);
+ assert_decoder_result_nedata(/* expected_bytes_required= */ 2 + 2,
+ decode(string_int8_data, 2));
+}
+
+unsigned char string_int8_empty_data[] = {0x78, 0x00};
+static void test_string_int8_empty_decoding(void **_CBOR_UNUSED(_state)) {
+ assert_string_mem_eq(string_int8_empty_data + 2, 0);
+ assert_decoder_result(2, CBOR_DECODER_FINISHED,
+ decode(string_int8_empty_data, 2));
+
+ assert_minimum_input_size(2, string_int8_empty_data);
+}
+
+unsigned char string_int16_data[] = {0x79, 0x01, 0x5C /*, [348 bytes] */};
+static void test_string_int16_decoding(void **_CBOR_UNUSED(_state)) {
+ assert_string_mem_eq(string_int16_data + 3, 348);
+ assert_decoder_result(3 + 348, CBOR_DECODER_FINISHED,
+ decode(string_int16_data, 3 + 348));
+
+ assert_minimum_input_size(3, string_int16_data);
+ assert_decoder_result_nedata(/* expected_bytes_required= */ 3 + 348,
+ decode(string_int16_data, 3));
+}
+
+unsigned char string_int32_data[] = {0x7A, 0x00, 0x10, 0x10,
+ 0x10 /*, [1052688 bytes] */};
+static void test_string_int32_decoding(void **_CBOR_UNUSED(_state)) {
+ assert_string_mem_eq(string_int32_data + 5, 1052688);
+ assert_decoder_result(5 + 1052688, CBOR_DECODER_FINISHED,
+ decode(string_int32_data, 5 + 1052688));
+
+ assert_minimum_input_size(5, string_int32_data);
+ assert_decoder_result_nedata(/* expected_bytes_required= */ 5 + 1052688,
+ decode(string_int32_data, 5));
+}
+
+#ifdef EIGHT_BYTE_SIZE_T
+unsigned char string_int64_data[] = {
+ 0x7B, 0x00, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x00, 0x00 /*, [4294967296 bytes] */};
+static void test_string_int64_decoding(void **_CBOR_UNUSED(_state)) {
+ assert_string_mem_eq(string_int64_data + 9, 4294967296);
+ assert_decoder_result(9 + 4294967296, CBOR_DECODER_FINISHED,
+ decode(string_int64_data, 9 + 4294967296));
+
+ assert_minimum_input_size(9, string_int64_data);
+ assert_decoder_result_nedata(/* expected_bytes_required= */ 9 + 4294967296,
+ decode(string_int64_data, 9));
+}
+#endif
+
+unsigned char string_indef_1_data[] = {0x7F, 0x60 /* Empty string */, 0xFF};
+static void test_string_indef_decoding_1(void **_CBOR_UNUSED(_state)) {
+ assert_string_indef_start();
+ assert_decoder_result(1, CBOR_DECODER_FINISHED,
+ decode(string_indef_1_data, 3));
+
+ assert_string_mem_eq(string_indef_1_data + 2, 0);
+ assert_decoder_result(1, CBOR_DECODER_FINISHED,
+ decode(string_indef_1_data + 1, 2));
+
+ assert_indef_break();
+ assert_decoder_result(1, CBOR_DECODER_FINISHED,
+ decode(string_indef_1_data + 2, 1));
+}
+
+unsigned char string_indef_2_data[] = {0x7F, 0xFF};
+static void test_string_indef_decoding_2(void **_CBOR_UNUSED(_state)) {
+ assert_string_indef_start();
+ assert_decoder_result(1, CBOR_DECODER_FINISHED,
+ decode(string_indef_2_data, 2));
+
+ assert_indef_break();
+ assert_decoder_result(1, CBOR_DECODER_FINISHED,
+ decode(string_indef_2_data + 1, 1));
+}
+
+unsigned char string_indef_3_data[] = {0x7F,
+ // Empty string
+ 0x60,
+ // 1B, 1 character byte string
+ 0x78, 0x01, 0x00,
+ // Break
+ 0xFF};
+static void test_string_indef_decoding_3(void **_CBOR_UNUSED(_state)) {
+ assert_string_indef_start();
+ assert_decoder_result(1, CBOR_DECODER_FINISHED,
+ decode(string_indef_3_data, 6));
+
+ assert_string_mem_eq(string_indef_3_data + 2, 0);
+ assert_decoder_result(1, CBOR_DECODER_FINISHED,
+ decode(string_indef_3_data + 1, 5));
+
+ assert_string_mem_eq(string_indef_3_data + 4, 1);
+ assert_decoder_result(3, CBOR_DECODER_FINISHED,
+ decode(string_indef_3_data + 2, 4));
+
+ assert_indef_break();
+ assert_decoder_result(1, CBOR_DECODER_FINISHED,
+ decode(string_indef_3_data + 5, 1));
+}
+
unsigned char array_embedded_int8_data[] = {0x80};
-static void test_array_embedded_int8_decoding(void **state) {
+static void test_array_embedded_int8_decoding(void **_CBOR_UNUSED(_state)) {
assert_array_start(0);
assert_decoder_result(1, CBOR_DECODER_FINISHED,
decode(array_embedded_int8_data, 1));
}
unsigned char array_int8_data[] = {0x98, 0x02, 0x00, 0x01};
-static void test_array_int8_decoding(void **state) {
+static void test_array_int8_decoding(void **_CBOR_UNUSED(_state)) {
assert_array_start(2);
assert_decoder_result(2, CBOR_DECODER_FINISHED, decode(array_int8_data, 4));
@@ -256,7 +388,7 @@ static void test_array_int8_decoding(void **state) {
}
unsigned char array_int16_data[] = {0x99, 0x00, 0x02, 0x00, 0x01};
-static void test_array_int16_decoding(void **state) {
+static void test_array_int16_decoding(void **_CBOR_UNUSED(_state)) {
assert_array_start(2);
assert_decoder_result(3, CBOR_DECODER_FINISHED, decode(array_int16_data, 5));
@@ -272,7 +404,7 @@ static void test_array_int16_decoding(void **state) {
}
unsigned char array_int32_data[] = {0x9A, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01};
-static void test_array_int32_decoding(void **state) {
+static void test_array_int32_decoding(void **_CBOR_UNUSED(_state)) {
assert_array_start(2);
assert_decoder_result(5, CBOR_DECODER_FINISHED, decode(array_int32_data, 7));
@@ -289,7 +421,7 @@ static void test_array_int32_decoding(void **state) {
unsigned char array_int64_data[] = {0x9B, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x02, 0x00, 0x01};
-static void test_array_int64_decoding(void **state) {
+static void test_array_int64_decoding(void **_CBOR_UNUSED(_state)) {
assert_array_start(2);
assert_decoder_result(9, CBOR_DECODER_FINISHED, decode(array_int64_data, 11));
@@ -305,7 +437,7 @@ static void test_array_int64_decoding(void **state) {
}
unsigned char array_of_arrays_data[] = {0x82, 0x80, 0x80};
-static void test_array_of_arrays_decoding(void **state) {
+static void test_array_of_arrays_decoding(void **_CBOR_UNUSED(_state)) {
assert_array_start(2);
assert_decoder_result(1, CBOR_DECODER_FINISHED,
decode(array_of_arrays_data, 3));
@@ -320,7 +452,7 @@ static void test_array_of_arrays_decoding(void **state) {
}
unsigned char indef_array_data_1[] = {0x9F, 0x00, 0x18, 0xFF, 0x9F, 0xFF, 0xFF};
-static void test_indef_array_decoding_1(void **state) {
+static void test_indef_array_decoding_1(void **_CBOR_UNUSED(_state)) {
assert_indef_array_start();
assert_decoder_result(1, CBOR_DECODER_FINISHED,
decode(indef_array_data_1, 7));
@@ -347,7 +479,7 @@ static void test_indef_array_decoding_1(void **state) {
}
unsigned char map_embedded_int8_data[] = {0xa1, 0x01, 0x00};
-static void test_map_embedded_int8_decoding(void **state) {
+static void test_map_embedded_int8_decoding(void **_CBOR_UNUSED(_state)) {
assert_map_start(1);
assert_decoder_result(1, CBOR_DECODER_FINISHED,
decode(map_embedded_int8_data, 3));
@@ -362,7 +494,7 @@ static void test_map_embedded_int8_decoding(void **state) {
}
unsigned char map_int8_data[] = {0xB8, 0x01, 0x00, 0x01};
-static void test_map_int8_decoding(void **state) {
+static void test_map_int8_decoding(void **_CBOR_UNUSED(_state)) {
assert_map_start(1);
assert_decoder_result(2, CBOR_DECODER_FINISHED, decode(map_int8_data, 4));
@@ -376,7 +508,7 @@ static void test_map_int8_decoding(void **state) {
}
unsigned char map_int16_data[] = {0xB9, 0x00, 0x01, 0x00, 0x01};
-static void test_map_int16_decoding(void **state) {
+static void test_map_int16_decoding(void **_CBOR_UNUSED(_state)) {
assert_map_start(1);
assert_decoder_result(3, CBOR_DECODER_FINISHED, decode(map_int16_data, 5));
@@ -392,7 +524,7 @@ static void test_map_int16_decoding(void **state) {
}
unsigned char map_int32_data[] = {0xBA, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01};
-static void test_map_int32_decoding(void **state) {
+static void test_map_int32_decoding(void **_CBOR_UNUSED(_state)) {
assert_map_start(1);
assert_decoder_result(5, CBOR_DECODER_FINISHED, decode(map_int32_data, 7));
@@ -409,7 +541,7 @@ static void test_map_int32_decoding(void **state) {
unsigned char map_int64_data[] = {0xBB, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x01, 0x00, 0x01};
-static void test_map_int64_decoding(void **state) {
+static void test_map_int64_decoding(void **_CBOR_UNUSED(_state)) {
assert_map_start(1);
assert_decoder_result(9, CBOR_DECODER_FINISHED, decode(map_int64_data, 11));
@@ -425,7 +557,7 @@ static void test_map_int64_decoding(void **state) {
}
unsigned char indef_map_data_1[] = {0xBF, 0x00, 0x18, 0xFF, 0xFF};
-static void test_indef_map_decoding_1(void **state) {
+static void test_indef_map_decoding_1(void **_CBOR_UNUSED(_state)) {
assert_indef_map_start();
assert_decoder_result(1, CBOR_DECODER_FINISHED, decode(indef_map_data_1, 5));
@@ -443,13 +575,13 @@ static void test_indef_map_decoding_1(void **state) {
}
unsigned char embedded_tag_data[] = {0xC1};
-static void test_embedded_tag_decoding(void **state) {
+static void test_embedded_tag_decoding(void **_CBOR_UNUSED(_state)) {
assert_tag_eq(1);
assert_decoder_result(1, CBOR_DECODER_FINISHED, decode(embedded_tag_data, 1));
}
unsigned char int8_tag_data[] = {0xD8, 0xFE};
-static void test_int8_tag_decoding(void **state) {
+static void test_int8_tag_decoding(void **_CBOR_UNUSED(_state)) {
assert_tag_eq(254);
assert_decoder_result(2, CBOR_DECODER_FINISHED, decode(int8_tag_data, 2));
@@ -457,7 +589,7 @@ static void test_int8_tag_decoding(void **state) {
}
unsigned char int16_tag_data[] = {0xD9, 0xFE, 0xFD};
-static void test_int16_tag_decoding(void **state) {
+static void test_int16_tag_decoding(void **_CBOR_UNUSED(_state)) {
assert_tag_eq(65277);
assert_decoder_result(3, CBOR_DECODER_FINISHED, decode(int16_tag_data, 3));
@@ -465,7 +597,7 @@ static void test_int16_tag_decoding(void **state) {
}
unsigned char int32_tag_data[] = {0xDA, 0xFE, 0xFD, 0xFC, 0xFB};
-static void test_int32_tag_decoding(void **state) {
+static void test_int32_tag_decoding(void **_CBOR_UNUSED(_state)) {
assert_tag_eq(4278058235ULL);
assert_decoder_result(5, CBOR_DECODER_FINISHED, decode(int32_tag_data, 5));
@@ -474,7 +606,7 @@ static void test_int32_tag_decoding(void **state) {
unsigned char int64_tag_data[] = {0xDB, 0xFE, 0xFD, 0xFC, 0xFB,
0xFA, 0xF9, 0xF8, 0xF7};
-static void test_int64_tag_decoding(void **state) {
+static void test_int64_tag_decoding(void **_CBOR_UNUSED(_state)) {
assert_tag_eq(18374120213919168759ULL);
assert_decoder_result(9, CBOR_DECODER_FINISHED, decode(int64_tag_data, 9));
@@ -482,12 +614,12 @@ static void test_int64_tag_decoding(void **state) {
}
unsigned char bad_tag_data[] = {0xC6};
-static void test_bad_tag_decoding(void **state) {
+static void test_bad_tag_decoding(void **_CBOR_UNUSED(_state)) {
assert_decoder_result(0, CBOR_DECODER_ERROR, decode(bad_tag_data, 1));
}
unsigned char float2_data[] = {0xF9, 0x7B, 0xFF};
-static void test_float2_decoding(void **state) {
+static void test_float2_decoding(void **_CBOR_UNUSED(_state)) {
assert_half(65504.0f);
assert_decoder_result(3, CBOR_DECODER_FINISHED, decode(float2_data, 3));
@@ -495,7 +627,7 @@ static void test_float2_decoding(void **state) {
}
unsigned char float4_data[] = {0xFA, 0x47, 0xC3, 0x50, 0x00};
-static void test_float4_decoding(void **state) {
+static void test_float4_decoding(void **_CBOR_UNUSED(_state)) {
assert_float(100000.0f);
assert_decoder_result(5, CBOR_DECODER_FINISHED, decode(float4_data, 5));
@@ -504,7 +636,7 @@ static void test_float4_decoding(void **state) {
unsigned char float8_data[] = {0xFB, 0xC0, 0x10, 0x66, 0x66,
0x66, 0x66, 0x66, 0x66};
-static void test_float8_decoding(void **state) {
+static void test_float8_decoding(void **_CBOR_UNUSED(_state)) {
assert_double(-4.1);
assert_decoder_result(9, CBOR_DECODER_FINISHED, decode(float8_data, 9));
@@ -512,33 +644,32 @@ static void test_float8_decoding(void **state) {
}
unsigned char false_data[] = {0xF4};
-static void test_false_decoding(void **state) {
+static void test_false_decoding(void **_CBOR_UNUSED(_state)) {
assert_bool(false);
assert_decoder_result(1, CBOR_DECODER_FINISHED, decode(false_data, 1));
}
unsigned char true_data[] = {0xF5};
-static void test_true_decoding(void **state) {
+static void test_true_decoding(void **_CBOR_UNUSED(_state)) {
assert_bool(true);
assert_decoder_result(1, CBOR_DECODER_FINISHED, decode(true_data, 1));
}
unsigned char null_data[] = {0xF6};
-static void test_null_decoding(void **state) {
+static void test_null_decoding(void **_CBOR_UNUSED(_state)) {
assert_nil();
assert_decoder_result(1, CBOR_DECODER_FINISHED, decode(null_data, 1));
}
unsigned char undef_data[] = {0xF7};
-static void test_undef_decoding(void **state) {
+static void test_undef_decoding(void **_CBOR_UNUSED(_state)) {
assert_undef();
assert_decoder_result(1, CBOR_DECODER_FINISHED, decode(undef_data, 1));
}
-#define stream_test(f) cmocka_unit_test_teardown(f, clear_stream_assertions)
+#define stream_test(f) cmocka_unit_test_teardown(f, clean_up_stream_assertions)
int main(void) {
- set_decoder(&cbor_stream_decode);
const struct CMUnitTest tests[] = {
stream_test(test_no_data),
@@ -556,6 +687,7 @@ int main(void) {
stream_test(test_bstring_embedded_int8_decoding),
stream_test(test_bstring_int8_decoding),
+ stream_test(test_bstring_int8_empty_decoding),
stream_test(test_bstring_int16_decoding),
stream_test(test_bstring_int32_decoding),
#ifdef EIGHT_BYTE_SIZE_T
@@ -565,6 +697,18 @@ int main(void) {
stream_test(test_bstring_indef_decoding_2),
stream_test(test_bstring_indef_decoding_3),
+ stream_test(test_string_embedded_int8_decoding),
+ stream_test(test_string_int8_decoding),
+ stream_test(test_string_int8_empty_decoding),
+ stream_test(test_string_int16_decoding),
+ stream_test(test_string_int32_decoding),
+#ifdef EIGHT_BYTE_SIZE_T
+ stream_test(test_string_int64_decoding),
+#endif
+ stream_test(test_string_indef_decoding_1),
+ stream_test(test_string_indef_decoding_2),
+ stream_test(test_string_indef_decoding_3),
+
stream_test(test_array_embedded_int8_decoding),
stream_test(test_array_int8_decoding),
stream_test(test_array_int16_decoding),
diff --git a/test/copy_test.c b/test/copy_test.c
index 91651390aebb..92e210a6a600 100644
--- a/test/copy_test.c
+++ b/test/copy_test.c
@@ -5,18 +5,13 @@
* it under the terms of the MIT license. See LICENSE for details.
*/
-#include <setjmp.h>
-#include <stdarg.h>
-#include <stddef.h>
-
-#include <cmocka.h>
-
#include "assertions.h"
#include "cbor.h"
+#include "test_allocator.h"
cbor_item_t *item, *copy, *tmp;
-static void test_uints(void **state) {
+static void test_uints(void **_CBOR_UNUSED(_state)) {
item = cbor_build_uint8(10);
assert_uint8(copy = cbor_copy(item), 10);
cbor_decref(&item);
@@ -38,7 +33,7 @@ static void test_uints(void **state) {
cbor_decref(&copy);
}
-static void test_negints(void **state) {
+static void test_negints(void **_CBOR_UNUSED(_state)) {
item = cbor_build_negint8(10);
assert_true(cbor_get_uint8(copy = cbor_copy(item)) == 10);
cbor_decref(&item);
@@ -60,7 +55,7 @@ static void test_negints(void **state) {
cbor_decref(&copy);
}
-static void test_def_bytestring(void **state) {
+static void test_def_bytestring(void **_CBOR_UNUSED(_state)) {
item = cbor_build_bytestring((cbor_data) "abc", 3);
assert_memory_equal(cbor_bytestring_handle(copy = cbor_copy(item)),
cbor_bytestring_handle(item), 3);
@@ -68,14 +63,14 @@ static void test_def_bytestring(void **state) {
cbor_decref(&copy);
}
-static void test_indef_bytestring(void **state) {
+static void test_indef_bytestring(void **_CBOR_UNUSED(_state)) {
item = cbor_new_indefinite_bytestring();
- cbor_bytestring_add_chunk(
- item, cbor_move(cbor_build_bytestring((cbor_data) "abc", 3)));
+ assert_true(cbor_bytestring_add_chunk(
+ item, cbor_move(cbor_build_bytestring((cbor_data) "abc", 3))));
copy = cbor_copy(item);
- assert_int_equal(cbor_bytestring_chunk_count(item),
- cbor_bytestring_chunk_count(copy));
+ assert_size_equal(cbor_bytestring_chunk_count(item),
+ cbor_bytestring_chunk_count(copy));
assert_memory_equal(
cbor_bytestring_handle(cbor_bytestring_chunks_handle(copy)[0]), "abc", 3);
@@ -83,7 +78,7 @@ static void test_indef_bytestring(void **state) {
cbor_decref(&copy);
}
-static void test_def_string(void **state) {
+static void test_def_string(void **_CBOR_UNUSED(_state)) {
item = cbor_build_string("abc");
assert_memory_equal(cbor_string_handle(copy = cbor_copy(item)),
cbor_string_handle(item), 3);
@@ -91,13 +86,13 @@ static void test_def_string(void **state) {
cbor_decref(&copy);
}
-static void test_indef_string(void **state) {
+static void test_indef_string(void **_CBOR_UNUSED(_state)) {
item = cbor_new_indefinite_string();
- cbor_string_add_chunk(item, cbor_move(cbor_build_string("abc")));
+ assert_true(cbor_string_add_chunk(item, cbor_move(cbor_build_string("abc"))));
copy = cbor_copy(item);
- assert_int_equal(cbor_string_chunk_count(item),
- cbor_string_chunk_count(copy));
+ assert_size_equal(cbor_string_chunk_count(item),
+ cbor_string_chunk_count(copy));
assert_memory_equal(cbor_string_handle(cbor_string_chunks_handle(copy)[0]),
"abc", 3);
@@ -105,9 +100,9 @@ static void test_indef_string(void **state) {
cbor_decref(&copy);
}
-static void test_def_array(void **state) {
+static void test_def_array(void **_CBOR_UNUSED(_state)) {
item = cbor_new_definite_array(1);
- cbor_array_push(item, cbor_move(cbor_build_uint8(42)));
+ assert_true(cbor_array_push(item, cbor_move(cbor_build_uint8(42))));
assert_uint8(tmp = cbor_array_get(copy = cbor_copy(item), 0), 42);
cbor_decref(&item);
@@ -115,9 +110,9 @@ static void test_def_array(void **state) {
cbor_decref(&tmp);
}
-static void test_indef_array(void **state) {
+static void test_indef_array(void **_CBOR_UNUSED(_state)) {
item = cbor_new_indefinite_array();
- cbor_array_push(item, cbor_move(cbor_build_uint8(42)));
+ assert_true(cbor_array_push(item, cbor_move(cbor_build_uint8(42))));
assert_uint8(tmp = cbor_array_get(copy = cbor_copy(item), 0), 42);
cbor_decref(&item);
@@ -125,12 +120,12 @@ static void test_indef_array(void **state) {
cbor_decref(&tmp);
}
-static void test_def_map(void **state) {
+static void test_def_map(void **_CBOR_UNUSED(_state)) {
item = cbor_new_definite_map(1);
- cbor_map_add(item, (struct cbor_pair){
- .key = cbor_move(cbor_build_uint8(42)),
- .value = cbor_move(cbor_build_uint8(43)),
- });
+ assert_true(cbor_map_add(item, (struct cbor_pair){
+ .key = cbor_move(cbor_build_uint8(42)),
+ .value = cbor_move(cbor_build_uint8(43)),
+ }));
assert_uint8(cbor_map_handle(copy = cbor_copy(item))[0].key, 42);
@@ -138,12 +133,12 @@ static void test_def_map(void **state) {
cbor_decref(&copy);
}
-static void test_indef_map(void **state) {
- item = cbor_new_indefinite_map(1);
- cbor_map_add(item, (struct cbor_pair){
- .key = cbor_move(cbor_build_uint8(42)),
- .value = cbor_move(cbor_build_uint8(43)),
- });
+static void test_indef_map(void **_CBOR_UNUSED(_state)) {
+ item = cbor_new_indefinite_map();
+ assert_true(cbor_map_add(item, (struct cbor_pair){
+ .key = cbor_move(cbor_build_uint8(42)),
+ .value = cbor_move(cbor_build_uint8(43)),
+ }));
assert_uint8(cbor_map_handle(copy = cbor_copy(item))[0].key, 42);
@@ -151,7 +146,7 @@ static void test_indef_map(void **state) {
cbor_decref(&copy);
}
-static void test_tag(void **state) {
+static void test_tag(void **_CBOR_UNUSED(_state)) {
item = cbor_build_tag(10, cbor_move(cbor_build_uint8(42)));
assert_uint8(cbor_move(cbor_tag_item(copy = cbor_copy(item))), 42);
@@ -160,14 +155,14 @@ static void test_tag(void **state) {
cbor_decref(&copy);
}
-static void test_ctrls(void **state) {
+static void test_ctrls(void **_CBOR_UNUSED(_state)) {
item = cbor_new_null();
assert_true(cbor_is_null(copy = cbor_copy(item)));
cbor_decref(&item);
cbor_decref(&copy);
}
-static void test_floats(void **state) {
+static void test_floats(void **_CBOR_UNUSED(_state)) {
item = cbor_build_float2(3.14f);
assert_true(cbor_float_get_float2(copy = cbor_copy(item)) ==
cbor_float_get_float2(item));
@@ -187,9 +182,261 @@ static void test_floats(void **state) {
cbor_decref(&copy);
}
+static void test_alloc_failure_simple(void **_CBOR_UNUSED(_state)) {
+ item = cbor_build_uint8(10);
+
+ WITH_FAILING_MALLOC({ assert_null(cbor_copy(item)); });
+ assert_size_equal(cbor_refcount(item), 1);
+
+ cbor_decref(&item);
+}
+
+static void test_bytestring_alloc_failure(void **_CBOR_UNUSED(_state)) {
+ item = cbor_new_indefinite_bytestring();
+ assert_true(cbor_bytestring_add_chunk(
+ item, cbor_move(cbor_build_bytestring((cbor_data) "abc", 3))));
+
+ WITH_FAILING_MALLOC({ assert_null(cbor_copy(item)); });
+ assert_size_equal(cbor_refcount(item), 1);
+
+ cbor_decref(&item);
+}
+
+static void test_bytestring_chunk_alloc_failure(void **_CBOR_UNUSED(_state)) {
+ item = cbor_new_indefinite_bytestring();
+ assert_true(cbor_bytestring_add_chunk(
+ item, cbor_move(cbor_build_bytestring((cbor_data) "abc", 3))));
+
+ WITH_MOCK_MALLOC({ assert_null(cbor_copy(item)); }, 2, MALLOC, MALLOC_FAIL);
+ assert_size_equal(cbor_refcount(item), 1);
+
+ cbor_decref(&item);
+}
+
+static void test_bytestring_chunk_append_failure(void **_CBOR_UNUSED(_state)) {
+ item = cbor_new_indefinite_bytestring();
+ assert_true(cbor_bytestring_add_chunk(
+ item, cbor_move(cbor_build_bytestring((cbor_data) "abc", 3))));
+
+ WITH_MOCK_MALLOC({ assert_null(cbor_copy(item)); }, 5,
+ // New indef string, cbor_indefinite_string_data, chunk item,
+ // chunk data, extend cbor_indefinite_string_data.chunks
+ MALLOC, MALLOC, MALLOC, MALLOC, REALLOC_FAIL);
+ assert_size_equal(cbor_refcount(item), 1);
+
+ cbor_decref(&item);
+}
+
+static void test_bytestring_second_chunk_alloc_failure(
+ void **_CBOR_UNUSED(_state)) {
+ item = cbor_new_indefinite_bytestring();
+ assert_true(cbor_bytestring_add_chunk(
+ item, cbor_move(cbor_build_bytestring((cbor_data) "abc", 3))));
+ assert_true(cbor_bytestring_add_chunk(
+ item, cbor_move(cbor_build_bytestring((cbor_data) "def", 3))));
+
+ WITH_MOCK_MALLOC({ assert_null(cbor_copy(item)); }, 6,
+ // New indef string, cbor_indefinite_string_data, chunk item,
+ // chunk data, extend cbor_indefinite_string_data.chunks,
+ // second chunk item
+ MALLOC, MALLOC, MALLOC, MALLOC, REALLOC, MALLOC_FAIL);
+ assert_size_equal(cbor_refcount(item), 1);
+
+ cbor_decref(&item);
+}
+
+static void test_string_alloc_failure(void **_CBOR_UNUSED(_state)) {
+ item = cbor_new_indefinite_string();
+ assert_true(cbor_string_add_chunk(item, cbor_move(cbor_build_string("abc"))));
+
+ WITH_FAILING_MALLOC({ assert_null(cbor_copy(item)); });
+ assert_size_equal(cbor_refcount(item), 1);
+
+ cbor_decref(&item);
+}
+
+static void test_string_chunk_alloc_failure(void **_CBOR_UNUSED(_state)) {
+ item = cbor_new_indefinite_string();
+ assert_true(cbor_string_add_chunk(item, cbor_move(cbor_build_string("abc"))));
+
+ WITH_MOCK_MALLOC({ assert_null(cbor_copy(item)); }, 2, MALLOC, MALLOC_FAIL);
+ assert_size_equal(cbor_refcount(item), 1);
+
+ cbor_decref(&item);
+}
+
+static void test_string_chunk_append_failure(void **_CBOR_UNUSED(_state)) {
+ item = cbor_new_indefinite_string();
+ assert_true(cbor_string_add_chunk(item, cbor_move(cbor_build_string("abc"))));
+
+ WITH_MOCK_MALLOC({ assert_null(cbor_copy(item)); }, 5,
+ // New indef string, cbor_indefinite_string_data, chunk item,
+ // chunk data, extend cbor_indefinite_string_data.chunks
+ MALLOC, MALLOC, MALLOC, MALLOC, REALLOC_FAIL);
+ assert_size_equal(cbor_refcount(item), 1);
+
+ cbor_decref(&item);
+}
+
+static void test_string_second_chunk_alloc_failure(
+ void **_CBOR_UNUSED(_state)) {
+ item = cbor_new_indefinite_string();
+ assert_true(cbor_string_add_chunk(item, cbor_move(cbor_build_string("abc"))));
+ assert_true(cbor_string_add_chunk(item, cbor_move(cbor_build_string("def"))));
+
+ WITH_MOCK_MALLOC({ assert_null(cbor_copy(item)); }, 6,
+ // New indef string, cbor_indefinite_string_data, chunk item,
+ // chunk data, extend cbor_indefinite_string_data.chunks,
+ // second chunk item
+ MALLOC, MALLOC, MALLOC, MALLOC, REALLOC, MALLOC_FAIL);
+ assert_size_equal(cbor_refcount(item), 1);
+
+ cbor_decref(&item);
+}
+
+static void test_array_alloc_failure(void **_CBOR_UNUSED(_state)) {
+ item = cbor_new_indefinite_array();
+ assert_true(cbor_array_push(item, cbor_move(cbor_build_uint8(42))));
+
+ WITH_FAILING_MALLOC({ assert_null(cbor_copy(item)); });
+ assert_size_equal(cbor_refcount(item), 1);
+
+ cbor_decref(&item);
+}
+
+static void test_array_item_alloc_failure(void **_CBOR_UNUSED(_state)) {
+ item = cbor_new_indefinite_array();
+ assert_true(cbor_array_push(item, cbor_move(cbor_build_uint8(42))));
+
+ WITH_MOCK_MALLOC({ assert_null(cbor_copy(item)); }, 2,
+ // New array, item copy
+ MALLOC, MALLOC_FAIL);
+
+ assert_size_equal(cbor_refcount(item), 1);
+
+ cbor_decref(&item);
+}
+
+static void test_array_push_failure(void **_CBOR_UNUSED(_state)) {
+ item = cbor_new_indefinite_array();
+ assert_true(cbor_array_push(item, cbor_move(cbor_build_uint8(42))));
+
+ WITH_MOCK_MALLOC({ assert_null(cbor_copy(item)); }, 3,
+ // New array, item copy, array reallocation
+ MALLOC, MALLOC, REALLOC_FAIL);
+
+ assert_size_equal(cbor_refcount(item), 1);
+
+ cbor_decref(&item);
+}
+
+static void test_array_second_item_alloc_failure(void **_CBOR_UNUSED(_state)) {
+ item = cbor_new_indefinite_array();
+ assert_true(cbor_array_push(item, cbor_move(cbor_build_uint8(42))));
+ assert_true(cbor_array_push(item, cbor_move(cbor_build_uint8(43))));
+
+ WITH_MOCK_MALLOC({ assert_null(cbor_copy(item)); }, 4,
+ // New array, item copy, array reallocation, second item copy
+ MALLOC, MALLOC, REALLOC, MALLOC_FAIL);
+
+ assert_size_equal(cbor_refcount(item), 1);
+
+ cbor_decref(&item);
+}
+
+static void test_map_alloc_failure(void **_CBOR_UNUSED(_state)) {
+ item = cbor_new_indefinite_map();
+ assert_true(
+ cbor_map_add(item, (struct cbor_pair){cbor_move(cbor_build_uint8(42)),
+ cbor_move(cbor_build_bool(true))}));
+
+ WITH_FAILING_MALLOC({ assert_null(cbor_copy(item)); });
+ assert_size_equal(cbor_refcount(item), 1);
+
+ cbor_decref(&item);
+}
+
+static void test_map_key_alloc_failure(void **_CBOR_UNUSED(_state)) {
+ item = cbor_new_indefinite_map();
+ assert_true(
+ cbor_map_add(item, (struct cbor_pair){cbor_move(cbor_build_uint8(42)),
+ cbor_move(cbor_build_bool(true))}));
+
+ WITH_MOCK_MALLOC({ assert_null(cbor_copy(item)); }, 2,
+ // New map, key copy
+ MALLOC, MALLOC_FAIL);
+ assert_size_equal(cbor_refcount(item), 1);
+
+ cbor_decref(&item);
+}
+
+static void test_map_value_alloc_failure(void **_CBOR_UNUSED(_state)) {
+ item = cbor_new_indefinite_map();
+ assert_true(
+ cbor_map_add(item, (struct cbor_pair){cbor_move(cbor_build_uint8(42)),
+ cbor_move(cbor_build_bool(true))}));
+
+ WITH_MOCK_MALLOC({ assert_null(cbor_copy(item)); }, 3,
+ // New map, key copy, value copy
+ MALLOC, MALLOC, MALLOC_FAIL);
+ assert_size_equal(cbor_refcount(item), 1);
+
+ cbor_decref(&item);
+}
+
+static void test_map_add_failure(void **_CBOR_UNUSED(_state)) {
+ item = cbor_new_indefinite_map();
+ assert_true(
+ cbor_map_add(item, (struct cbor_pair){cbor_move(cbor_build_uint8(42)),
+ cbor_move(cbor_build_bool(true))}));
+
+ WITH_MOCK_MALLOC({ assert_null(cbor_copy(item)); }, 4,
+ // New map, key copy, value copy, add
+ MALLOC, MALLOC, MALLOC, REALLOC_FAIL);
+ assert_size_equal(cbor_refcount(item), 1);
+
+ cbor_decref(&item);
+}
+
+static void test_map_second_key_failure(void **_CBOR_UNUSED(_state)) {
+ item = cbor_new_indefinite_map();
+ assert_true(
+ cbor_map_add(item, (struct cbor_pair){cbor_move(cbor_build_uint8(42)),
+ cbor_move(cbor_build_bool(true))}));
+ assert_true(cbor_map_add(
+ item, (struct cbor_pair){cbor_move(cbor_build_uint8(43)),
+ cbor_move(cbor_build_bool(false))}));
+
+ WITH_MOCK_MALLOC({ assert_null(cbor_copy(item)); }, 5,
+ // New map, key copy, value copy, add, second key copy
+ MALLOC, MALLOC, MALLOC, REALLOC, MALLOC_FAIL);
+ assert_size_equal(cbor_refcount(item), 1);
+
+ cbor_decref(&item);
+}
+
+static void test_tag_item_alloc_failure(void **_CBOR_UNUSED(_state)) {
+ item = cbor_build_tag(1, cbor_move(cbor_build_uint8(42)));
+
+ WITH_FAILING_MALLOC({ assert_null(cbor_copy(item)); });
+ assert_size_equal(cbor_refcount(item), 1);
+
+ cbor_decref(&item);
+}
+
+static void test_tag_alloc_failure(void **_CBOR_UNUSED(_state)) {
+ item = cbor_build_tag(1, cbor_move(cbor_build_uint8(42)));
+
+ WITH_MOCK_MALLOC({ assert_null(cbor_copy(item)); }, 2,
+ // Item copy, tag
+ MALLOC, MALLOC_FAIL);
+ assert_size_equal(cbor_refcount(item), 1);
+
+ cbor_decref(&item);
+}
+
int main(void) {
const struct CMUnitTest tests[] = {
-
cmocka_unit_test(test_uints),
cmocka_unit_test(test_negints),
cmocka_unit_test(test_def_bytestring),
@@ -202,6 +449,27 @@ int main(void) {
cmocka_unit_test(test_indef_map),
cmocka_unit_test(test_tag),
cmocka_unit_test(test_ctrls),
- cmocka_unit_test(test_floats)};
+ cmocka_unit_test(test_floats),
+ cmocka_unit_test(test_alloc_failure_simple),
+ cmocka_unit_test(test_bytestring_alloc_failure),
+ cmocka_unit_test(test_bytestring_chunk_alloc_failure),
+ cmocka_unit_test(test_bytestring_chunk_append_failure),
+ cmocka_unit_test(test_bytestring_second_chunk_alloc_failure),
+ cmocka_unit_test(test_string_alloc_failure),
+ cmocka_unit_test(test_string_chunk_alloc_failure),
+ cmocka_unit_test(test_string_chunk_append_failure),
+ cmocka_unit_test(test_string_second_chunk_alloc_failure),
+ cmocka_unit_test(test_array_alloc_failure),
+ cmocka_unit_test(test_array_item_alloc_failure),
+ cmocka_unit_test(test_array_push_failure),
+ cmocka_unit_test(test_array_second_item_alloc_failure),
+ cmocka_unit_test(test_map_alloc_failure),
+ cmocka_unit_test(test_map_key_alloc_failure),
+ cmocka_unit_test(test_map_value_alloc_failure),
+ cmocka_unit_test(test_map_add_failure),
+ cmocka_unit_test(test_map_second_key_failure),
+ cmocka_unit_test(test_tag_item_alloc_failure),
+ cmocka_unit_test(test_tag_alloc_failure),
+ };
return cmocka_run_group_tests(tests, NULL, NULL);
}
diff --git a/test/float_ctrl_encoders_test.c b/test/float_ctrl_encoders_test.c
new file mode 100644
index 000000000000..8940106d91d3
--- /dev/null
+++ b/test/float_ctrl_encoders_test.c
@@ -0,0 +1,213 @@
+/*
+ * Copyright (c) 2014-2020 Pavel Kalvoda <me@pavelkalvoda.com>
+ *
+ * libcbor is free software; you can redistribute it and/or modify
+ * it under the terms of the MIT license. See LICENSE for details.
+ */
+
+#include <math.h>
+#include "assertions.h"
+#include "cbor.h"
+
+unsigned char buffer[512];
+
+static void test_bools(void **_CBOR_UNUSED(_state)) {
+ assert_size_equal(1, cbor_encode_bool(false, buffer, 512));
+ assert_memory_equal(buffer, ((unsigned char[]){0xF4}), 1);
+ assert_size_equal(1, cbor_encode_bool(true, buffer, 512));
+ assert_memory_equal(buffer, ((unsigned char[]){0xF5}), 1);
+}
+
+static void test_null(void **_CBOR_UNUSED(_state)) {
+ assert_size_equal(1, cbor_encode_null(buffer, 512));
+ assert_memory_equal(buffer, ((unsigned char[]){0xF6}), 1);
+}
+
+static void test_undef(void **_CBOR_UNUSED(_state)) {
+ assert_size_equal(1, cbor_encode_undef(buffer, 512));
+ assert_memory_equal(buffer, ((unsigned char[]){0xF7}), 1);
+}
+
+static void test_break(void **_CBOR_UNUSED(_state)) {
+ assert_size_equal(1, cbor_encode_break(buffer, 512));
+ assert_memory_equal(buffer, ((unsigned char[]){0xFF}), 1);
+}
+
+/* Check that encode(decode(buffer)) = buffer for a valid half-float in the
+ * buffer.*/
+static void assert_half_float_codec_identity(void) {
+ unsigned char secondary_buffer[3];
+ struct cbor_load_result res;
+ // Load and check data in buffer
+ cbor_item_t *half_float = cbor_load(buffer, 3, &res);
+ assert_size_equal(res.error.code, CBOR_ERR_NONE);
+ assert_true(cbor_isa_float_ctrl(half_float));
+ assert_true(cbor_is_float(half_float));
+ assert_size_equal(cbor_float_get_width(half_float), CBOR_FLOAT_16);
+ // Encode again and check equality
+ assert_size_equal(3, cbor_encode_half(cbor_float_get_float2(half_float),
+ secondary_buffer, 3));
+ assert_memory_equal(buffer, secondary_buffer, 3);
+ cbor_decref(&half_float);
+}
+
+static void test_half(void **_CBOR_UNUSED(_state)) {
+ assert_size_equal(3, cbor_encode_half(1.5f, buffer, 512));
+ assert_memory_equal(buffer, ((unsigned char[]){0xF9, 0x3E, 0x00}), 3);
+ assert_half_float_codec_identity();
+
+ assert_size_equal(3, cbor_encode_half(-0.0f, buffer, 512));
+ assert_memory_equal(buffer, ((unsigned char[]){0xF9, 0x80, 0x00}), 3);
+ assert_half_float_codec_identity();
+
+ assert_size_equal(3, cbor_encode_half(0.0f, buffer, 512));
+ assert_memory_equal(buffer, ((unsigned char[]){0xF9, 0x00, 0x00}), 3);
+ assert_half_float_codec_identity();
+
+ assert_size_equal(3, cbor_encode_half(65504.0f, buffer, 512));
+ assert_memory_equal(buffer, ((unsigned char[]){0xF9, 0x7B, 0xFF}), 3);
+ assert_half_float_codec_identity();
+
+ assert_size_equal(3, cbor_encode_half(0.00006103515625f, buffer, 512));
+ assert_memory_equal(buffer, ((unsigned char[]){0xF9, 0x04, 0x00}), 3);
+ assert_half_float_codec_identity();
+
+ assert_size_equal(3, cbor_encode_half(-4.0f, buffer, 512));
+ assert_memory_equal(buffer, ((unsigned char[]){0xF9, 0xC4, 0x00}), 3);
+ assert_half_float_codec_identity();
+
+ /* Smallest representable value */
+ assert_size_equal(3, cbor_encode_half(5.960464477539063e-8f, buffer, 512));
+ assert_memory_equal(buffer, ((unsigned char[]){0xF9, 0x00, 0x01}), 3);
+ assert_half_float_codec_identity();
+
+ /* Smaller than the smallest, approximate magnitude representation */
+ assert_size_equal(3, cbor_encode_half(5.960464477539062e-8f, buffer, 512));
+ assert_memory_equal(buffer, ((unsigned char[]){0xF9, 0x00, 0x01}), 3);
+ assert_half_float_codec_identity();
+
+ assert_size_equal(3, cbor_encode_half(4.172325134277344e-7f, buffer, 512));
+ assert_memory_equal(buffer, ((unsigned char[]){0xF9, 0x00, 0x07}), 3);
+ assert_half_float_codec_identity();
+
+ assert_size_equal(3, cbor_encode_half(6.097555160522461e-5f, buffer, 512));
+ assert_memory_equal(buffer, ((unsigned char[]){0xF9, 0x03, 0xff}), 3);
+ assert_half_float_codec_identity();
+
+ assert_size_equal(3, cbor_encode_half(6.100535392761231e-5f, buffer, 512));
+ assert_memory_equal(buffer, ((unsigned char[]){0xF9, 0x04, 0x00}), 3);
+ assert_half_float_codec_identity();
+
+ /* Smaller than the smallest and even the magnitude cannot be represented,
+ round off to zero */
+ assert_size_equal(3, cbor_encode_half(1e-25f, buffer, 512));
+ assert_memory_equal(buffer, ((unsigned char[]){0xF9, 0x00, 0x00}), 3);
+ assert_half_float_codec_identity();
+
+ assert_size_equal(3, cbor_encode_half(1.1920928955078125e-7, buffer, 512));
+ assert_memory_equal(buffer, ((unsigned char[]){0xF9, 0x00, 0x02}), 3);
+ assert_half_float_codec_identity();
+
+ assert_size_equal(3, cbor_encode_half(-1.1920928955078124e-7, buffer, 512));
+ assert_memory_equal(buffer, ((unsigned char[]){0xF9, 0x80, 0x02}), 3);
+ assert_half_float_codec_identity();
+
+ assert_size_equal(3, cbor_encode_half(INFINITY, buffer, 512));
+ assert_memory_equal(buffer, ((unsigned char[]){0xF9, 0x7C, 0x00}), 3);
+ assert_half_float_codec_identity();
+}
+
+static void test_half_special(void **_CBOR_UNUSED(_state)) {
+ assert_size_equal(3, cbor_encode_half(NAN, buffer, 512));
+ assert_memory_equal(buffer, ((unsigned char[]){0xF9, 0x7E, 0x00}), 3);
+ assert_half_float_codec_identity();
+
+ // We discard all information bits in half-float NaNs. This is
+ // not required for the core CBOR protocol (it is only a suggestion in
+ // Section 3.9).
+ // See https://github.com/PJK/libcbor/issues/215
+ assert_size_equal(3, cbor_encode_half(nanf("2"), buffer, 512));
+ assert_memory_equal(buffer, ((unsigned char[]){0xF9, 0x7E, 0x00}), 3);
+ assert_half_float_codec_identity();
+}
+
+static void test_half_infinity(void **_CBOR_UNUSED(_state)) {
+ assert_size_equal(3, cbor_encode_half(INFINITY, buffer, 512));
+ assert_memory_equal(buffer, ((unsigned char[]){0xF9, 0x7C, 0x00}), 3);
+ assert_half_float_codec_identity();
+
+ assert_size_equal(3, cbor_encode_half(-INFINITY, buffer, 512));
+ assert_memory_equal(buffer, ((unsigned char[]){0xF9, 0xFC, 0x00}), 3);
+ assert_half_float_codec_identity();
+}
+
+static void test_float(void **_CBOR_UNUSED(_state)) {
+ assert_size_equal(5, cbor_encode_single(3.4028234663852886e+38, buffer, 512));
+ assert_memory_equal(buffer, ((unsigned char[]){0xFA, 0x7F, 0x7F, 0xFF, 0xFF}),
+ 5);
+
+ assert_size_equal(5, cbor_encode_single(NAN, buffer, 512));
+ assert_memory_equal(buffer, ((unsigned char[]){0xFA, 0x7F, 0xC0, 0x00, 0x00}),
+ 5);
+
+#ifndef _WIN32
+ // TODO: https://github.com/PJK/libcbor/issues/271
+ assert_size_equal(5, cbor_encode_single(nanf("3"), buffer, 512));
+ assert_memory_equal(buffer, ((unsigned char[]){0xFA, 0x7F, 0xC0, 0x00, 0x03}),
+ 5);
+#endif
+
+ assert_size_equal(5, cbor_encode_single(strtof("Inf", NULL), buffer, 512));
+ assert_memory_equal(buffer, ((unsigned char[]){0xFA, 0x7F, 0x80, 0x00, 0x00}),
+ 5);
+
+ assert_size_equal(5, cbor_encode_single(strtof("-Inf", NULL), buffer, 512));
+ assert_memory_equal(buffer, ((unsigned char[]){0xFA, 0xFF, 0x80, 0x00, 0x00}),
+ 5);
+}
+
+static void test_double(void **_CBOR_UNUSED(_state)) {
+ assert_size_equal(9, cbor_encode_double(1.0e+300, buffer, 512));
+ assert_memory_equal(
+ buffer,
+ ((unsigned char[]){0xFB, 0x7E, 0x37, 0xE4, 0x3C, 0x88, 0x00, 0x75, 0x9C}),
+ 9);
+
+ assert_size_equal(9, cbor_encode_double(nan(""), buffer, 512));
+ assert_memory_equal(
+ buffer,
+ ((unsigned char[]){0xFB, 0x7F, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}),
+ 9);
+
+#ifndef _WIN32
+ // TODO: https://github.com/PJK/libcbor/issues/271
+ assert_size_equal(9, cbor_encode_double(nan("3"), buffer, 512));
+ assert_memory_equal(
+ buffer,
+ ((unsigned char[]){0xFB, 0x7F, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03}),
+ 9);
+#endif
+
+ assert_size_equal(9, cbor_encode_double(strtod("Inf", NULL), buffer, 512));
+ assert_memory_equal(
+ buffer,
+ ((unsigned char[]){0xFB, 0x7F, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}),
+ 9);
+
+ assert_size_equal(9, cbor_encode_double(strtod("-Inf", NULL), buffer, 512));
+ assert_memory_equal(
+ buffer,
+ ((unsigned char[]){0xFB, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}),
+ 9);
+}
+
+int main(void) {
+ const struct CMUnitTest tests[] = {
+ cmocka_unit_test(test_bools), cmocka_unit_test(test_null),
+ cmocka_unit_test(test_undef), cmocka_unit_test(test_break),
+ cmocka_unit_test(test_half), cmocka_unit_test(test_float),
+ cmocka_unit_test(test_double), cmocka_unit_test(test_half_special),
+ cmocka_unit_test(test_half_infinity),
+ };
+ return cmocka_run_group_tests(tests, NULL, NULL);
+}
diff --git a/test/type_7_test.c b/test/float_ctrl_test.c
index 9d6e7c009a94..1bf8b7b7ba1d 100644
--- a/test/type_7_test.c
+++ b/test/float_ctrl_test.c
@@ -5,15 +5,17 @@
* it under the terms of the MIT license. See LICENSE for details.
*/
+#include <math.h>
#include <setjmp.h>
#include <stdarg.h>
#include <stddef.h>
+#include <stdint.h>
+#include <tgmath.h>
#include <cmocka.h>
-#include <tgmath.h>
-#include "assertions.h"
#include "cbor.h"
+#include "test_allocator.h"
cbor_item_t *float_ctrl;
struct cbor_load_result res;
@@ -22,7 +24,7 @@ static const float eps = 0.00001f;
unsigned char float2_data[] = {0xF9, 0x7B, 0xFF};
-static void test_float2(void **state) {
+static void test_float2(void **_CBOR_UNUSED(_state)) {
float_ctrl = cbor_load(float2_data, 3, &res);
assert_true(cbor_isa_float_ctrl(float_ctrl));
assert_true(cbor_is_float(float_ctrl));
@@ -35,7 +37,7 @@ static void test_float2(void **state) {
unsigned char float4_data[] = {0xFA, 0x47, 0xC3, 0x50, 0x00};
-static void test_float4(void **state) {
+static void test_float4(void **_CBOR_UNUSED(_state)) {
float_ctrl = cbor_load(float4_data, 5, &res);
assert_true(cbor_isa_float_ctrl(float_ctrl));
assert_true(cbor_is_float(float_ctrl));
@@ -49,7 +51,7 @@ static void test_float4(void **state) {
unsigned char float8_data[] = {0xFB, 0x7E, 0x37, 0xE4, 0x3C,
0x88, 0x00, 0x75, 0x9C};
-static void test_float8(void **state) {
+static void test_float8(void **_CBOR_UNUSED(_state)) {
float_ctrl = cbor_load(float8_data, 9, &res);
assert_true(cbor_isa_float_ctrl(float_ctrl));
assert_true(cbor_is_float(float_ctrl));
@@ -62,7 +64,7 @@ static void test_float8(void **state) {
unsigned char null_data[] = {0xF6};
-static void test_null(void **state) {
+static void test_null(void **_CBOR_UNUSED(_state)) {
float_ctrl = cbor_load(null_data, 1, &res);
assert_true(cbor_isa_float_ctrl(float_ctrl));
assert_true(cbor_is_null(float_ctrl));
@@ -72,7 +74,7 @@ static void test_null(void **state) {
unsigned char undef_data[] = {0xF7};
-static void test_undef(void **state) {
+static void test_undef(void **_CBOR_UNUSED(_state)) {
float_ctrl = cbor_load(undef_data, 1, &res);
assert_true(cbor_isa_float_ctrl(float_ctrl));
assert_true(cbor_is_undef(float_ctrl));
@@ -82,30 +84,54 @@ static void test_undef(void **state) {
unsigned char bool_data[] = {0xF4, 0xF5};
-static void test_bool(void **state) {
- float_ctrl = cbor_load(bool_data, 1, &res);
- assert_true(cbor_isa_float_ctrl(float_ctrl));
- assert_true(cbor_is_bool(float_ctrl));
- assert_false(cbor_get_bool(float_ctrl));
- cbor_set_bool(float_ctrl, true);
- assert_true(cbor_get_bool(float_ctrl));
- cbor_decref(&float_ctrl);
- assert_null(float_ctrl);
+static void test_bool(void **_CBOR_UNUSED(_state)) {
+ _CBOR_TEST_DISABLE_ASSERT({
+ float_ctrl = cbor_load(bool_data, 1, &res);
+ assert_true(cbor_isa_float_ctrl(float_ctrl));
+ assert_true(cbor_is_bool(float_ctrl));
+ assert_false(cbor_get_bool(float_ctrl));
+ cbor_set_bool(float_ctrl, true);
+ assert_true(cbor_get_bool(float_ctrl));
+ assert_true(isnan(cbor_float_get_float(float_ctrl)));
+ cbor_decref(&float_ctrl);
+ assert_null(float_ctrl);
+
+ float_ctrl = cbor_load(bool_data + 1, 1, &res);
+ assert_true(cbor_isa_float_ctrl(float_ctrl));
+ assert_true(cbor_is_bool(float_ctrl));
+ assert_true(cbor_get_bool(float_ctrl));
+ cbor_set_bool(float_ctrl, false);
+ assert_false(cbor_get_bool(float_ctrl));
+ assert_true(isnan(cbor_float_get_float(float_ctrl)));
+ cbor_decref(&float_ctrl);
+ assert_null(float_ctrl);
+ });
+}
- float_ctrl = cbor_load(bool_data + 1, 1, &res);
- assert_true(cbor_isa_float_ctrl(float_ctrl));
- assert_true(cbor_is_bool(float_ctrl));
- assert_true(cbor_get_bool(float_ctrl));
- cbor_set_bool(float_ctrl, false);
- assert_false(cbor_get_bool(float_ctrl));
- cbor_decref(&float_ctrl);
- assert_null(float_ctrl);
+static void test_float_ctrl_creation(void **_CBOR_UNUSED(_state)) {
+ WITH_FAILING_MALLOC({ assert_null(cbor_new_ctrl()); });
+ WITH_FAILING_MALLOC({ assert_null(cbor_new_float2()); });
+ WITH_FAILING_MALLOC({ assert_null(cbor_new_float4()); });
+ WITH_FAILING_MALLOC({ assert_null(cbor_new_float8()); });
+ WITH_FAILING_MALLOC({ assert_null(cbor_new_null()); });
+ WITH_FAILING_MALLOC({ assert_null(cbor_new_undef()); });
+
+ WITH_FAILING_MALLOC({ assert_null(cbor_build_bool(false)); });
+ WITH_FAILING_MALLOC({ assert_null(cbor_build_float2(3.14)); });
+ WITH_FAILING_MALLOC({ assert_null(cbor_build_float4(3.14)); });
+ WITH_FAILING_MALLOC({ assert_null(cbor_build_float8(3.14)); });
+ WITH_FAILING_MALLOC({ assert_null(cbor_build_ctrl(0xAF)); });
}
int main(void) {
const struct CMUnitTest tests[] = {
- cmocka_unit_test(test_float2), cmocka_unit_test(test_float4),
- cmocka_unit_test(test_float8), cmocka_unit_test(test_null),
- cmocka_unit_test(test_undef), cmocka_unit_test(test_bool)};
+ cmocka_unit_test(test_float2),
+ cmocka_unit_test(test_float4),
+ cmocka_unit_test(test_float8),
+ cmocka_unit_test(test_null),
+ cmocka_unit_test(test_undef),
+ cmocka_unit_test(test_bool),
+ cmocka_unit_test(test_float_ctrl_creation),
+ };
return cmocka_run_group_tests(tests, NULL, NULL);
}
diff --git a/test/fuzz_test.c b/test/fuzz_test.c
index 885424107bf1..a02ed7ea9287 100644
--- a/test/fuzz_test.c
+++ b/test/fuzz_test.c
@@ -5,13 +5,8 @@
* it under the terms of the MIT license. See LICENSE for details.
*/
-#include <setjmp.h>
-#include <stdarg.h>
-#include <stddef.h>
-
-#include <cmocka.h>
-
#include <time.h>
+#include "assertions.h"
#include "cbor.h"
#ifdef HUGE_FUZZ
@@ -31,16 +26,14 @@ static void printmem(const unsigned char *ptr, size_t length) {
unsigned seed;
-#if CBOR_CUSTOM_ALLOC
void *mock_malloc(size_t size) {
if (size > (1 << 19))
return NULL;
else
return malloc(size);
}
-#endif
-static void run_round() {
+static void run_round(void) {
cbor_item_t *item;
struct cbor_load_result res;
@@ -62,10 +55,8 @@ static void run_round() {
free(data);
}
-static void fuzz(void **state) {
-#if CBOR_CUSTOM_ALLOC
+static void fuzz(void **_CBOR_UNUSED(_state)) {
cbor_set_allocs(mock_malloc, realloc, free);
-#endif
printf("Fuzzing %llu rounds of up to %llu bytes with seed %u\n", ROUNDS,
MAXLEN, seed);
srand(seed);
diff --git a/test/type_5_encoders_test.c b/test/map_encoders_test.c
index dc6e430e74ed..bbb5fdc1ad91 100644
--- a/test/type_5_encoders_test.c
+++ b/test/map_encoders_test.c
@@ -5,30 +5,25 @@
* it under the terms of the MIT license. See LICENSE for details.
*/
-#include <setjmp.h>
-#include <stdarg.h>
-#include <stddef.h>
-
-#include <cmocka.h>
-
+#include "assertions.h"
#include "cbor.h"
unsigned char buffer[512];
-static void test_embedded_map_start(void **state) {
- assert_int_equal(1, cbor_encode_map_start(1, buffer, 512));
+static void test_embedded_map_start(void **_CBOR_UNUSED(_state)) {
+ assert_size_equal(1, cbor_encode_map_start(1, buffer, 512));
assert_memory_equal(buffer, ((unsigned char[]){0xA1}), 1);
}
-static void test_map_start(void **state) {
- assert_int_equal(5, cbor_encode_map_start(1000000, buffer, 512));
+static void test_map_start(void **_CBOR_UNUSED(_state)) {
+ assert_size_equal(5, cbor_encode_map_start(1000000, buffer, 512));
assert_memory_equal(buffer, ((unsigned char[]){0xBA, 0x00, 0x0F, 0x42, 0x40}),
5);
}
-static void test_indef_map_start(void **state) {
- assert_int_equal(1, cbor_encode_indef_map_start(buffer, 512));
- assert_int_equal(0, cbor_encode_indef_map_start(buffer, 0));
+static void test_indef_map_start(void **_CBOR_UNUSED(_state)) {
+ assert_size_equal(1, cbor_encode_indef_map_start(buffer, 512));
+ assert_size_equal(0, cbor_encode_indef_map_start(buffer, 0));
assert_memory_equal(buffer, ((unsigned char[]){0xBF}), 1);
}
diff --git a/test/type_5_test.c b/test/map_test.c
index dbad446d8ff7..11bd7a8d7242 100644
--- a/test/type_5_test.c
+++ b/test/map_test.c
@@ -8,26 +8,28 @@
#include <setjmp.h>
#include <stdarg.h>
#include <stddef.h>
+#include <stdint.h>
+#include <string.h>
#include <cmocka.h>
-#include <string.h>
#include "assertions.h"
#include "cbor.h"
+#include "test_allocator.h"
cbor_item_t *map;
struct cbor_load_result res;
unsigned char empty_map[] = {0xA0};
-static void test_empty_map(void **state) {
+static void test_empty_map(void **_CBOR_UNUSED(_state)) {
map = cbor_load(empty_map, 1, &res);
assert_non_null(map);
assert_true(cbor_typeof(map) == CBOR_TYPE_MAP);
assert_true(cbor_isa_map(map));
assert_true(cbor_map_size(map) == 0);
assert_true(res.read == 1);
- assert_int_equal(cbor_map_allocated(map), 0);
+ assert_size_equal(cbor_map_allocated(map), 0);
cbor_decref(&map);
assert_null(map);
}
@@ -35,7 +37,7 @@ static void test_empty_map(void **state) {
unsigned char simple_map[] = {0xA2, 0x01, 0x02, 0x03, 0x04};
/* {1: 2, 3: 4} */
-static void test_simple_map(void **state) {
+static void test_simple_map(void **_CBOR_UNUSED(_state)) {
map = cbor_load(simple_map, 5, &res);
assert_non_null(map);
assert_true(cbor_typeof(map) == CBOR_TYPE_MAP);
@@ -55,7 +57,7 @@ static void test_simple_map(void **state) {
unsigned char simple_indef_map[] = {0xBF, 0x01, 0x02, 0x03, 0x04, 0xFF};
/* {_ 1: 2, 3: 4} */
-static void test_indef_simple_map(void **state) {
+static void test_indef_simple_map(void **_CBOR_UNUSED(_state)) {
map = cbor_load(simple_indef_map, 6, &res);
assert_non_null(map);
assert_true(cbor_typeof(map) == CBOR_TYPE_MAP);
@@ -82,7 +84,7 @@ unsigned char def_nested_map[] = {
0x74, 0x69, 0x74, 0x6C, 0x65, 0x70, 0x65, 0x78, 0x61, 0x6D, 0x70, 0x6C,
0x65, 0x20, 0x67, 0x6C, 0x6F, 0x73, 0x73, 0x61, 0x72, 0x79};
-static void test_def_nested_map(void **state) {
+static void test_def_nested_map(void **_CBOR_UNUSED(_state)) {
map = cbor_load(def_nested_map, 34, &res);
assert_non_null(map);
assert_true(cbor_typeof(map) == CBOR_TYPE_MAP);
@@ -106,7 +108,7 @@ unsigned char streamed_key_map[] = {0xA1, 0x7F, 0x61, 0x61,
0x61, 0x62, 0xFF, 0xA0};
/* '{ (_"a" "b"): {}}' */
-static void test_streamed_key_map(void **state) {
+static void test_streamed_key_map(void **_CBOR_UNUSED(_state)) {
map = cbor_load(streamed_key_map, 8, &res);
assert_non_null(map);
assert_true(cbor_typeof(map) == CBOR_TYPE_MAP);
@@ -117,9 +119,9 @@ static void test_streamed_key_map(void **state) {
struct cbor_pair *handle = cbor_map_handle(map);
assert_true(cbor_typeof(handle[0].key) == CBOR_TYPE_STRING);
assert_true(cbor_string_is_indefinite(handle[0].key));
- assert_int_equal(cbor_string_chunk_count(handle[0].key), 2);
+ assert_size_equal(cbor_string_chunk_count(handle[0].key), 2);
assert_true(cbor_isa_map(handle[0].value));
- assert_int_equal(cbor_map_size(handle[0].value), 0);
+ assert_size_equal(cbor_map_size(handle[0].value), 0);
cbor_decref(&map);
assert_null(map);
}
@@ -128,21 +130,21 @@ unsigned char streamed_kv_map[] = {0xA1, 0x7F, 0x61, 0x61, 0x61, 0x62, 0xFF,
0x7F, 0x61, 0x63, 0x61, 0x64, 0xFF};
/* '{ (_"a" "b"): (_"c", "d")}' */
-static void test_streamed_kv_map(void **state) {
+static void test_streamed_kv_map(void **_CBOR_UNUSED(_state)) {
map = cbor_load(streamed_kv_map, 13, &res);
assert_non_null(map);
assert_true(cbor_typeof(map) == CBOR_TYPE_MAP);
assert_true(cbor_isa_map(map));
assert_true(cbor_map_is_definite(map));
- assert_int_equal(cbor_map_size(map), 1);
- assert_int_equal(res.read, 13);
+ assert_size_equal(cbor_map_size(map), 1);
+ assert_size_equal(res.read, 13);
struct cbor_pair *handle = cbor_map_handle(map);
assert_true(cbor_typeof(handle[0].key) == CBOR_TYPE_STRING);
assert_true(cbor_string_is_indefinite(handle[0].key));
- assert_int_equal(cbor_string_chunk_count(handle[0].key), 2);
+ assert_size_equal(cbor_string_chunk_count(handle[0].key), 2);
assert_true(cbor_typeof(handle[0].value) == CBOR_TYPE_STRING);
assert_true(cbor_string_is_indefinite(handle[0].value));
- assert_int_equal(cbor_string_chunk_count(handle[0].value), 2);
+ assert_size_equal(cbor_string_chunk_count(handle[0].value), 2);
assert_memory_equal(
cbor_string_handle(cbor_string_chunks_handle(handle[0].value)[1]), "d",
1);
@@ -155,21 +157,21 @@ unsigned char streamed_streamed_kv_map[] = {0xBF, 0x7F, 0x61, 0x61, 0x61,
0x61, 0x64, 0xFF, 0xFF};
/* '{_ (_"a" "b"): (_"c", "d")}' */
-static void test_streamed_streamed_kv_map(void **state) {
+static void test_streamed_streamed_kv_map(void **_CBOR_UNUSED(_state)) {
map = cbor_load(streamed_streamed_kv_map, 14, &res);
assert_non_null(map);
assert_true(cbor_typeof(map) == CBOR_TYPE_MAP);
assert_true(cbor_isa_map(map));
assert_true(cbor_map_is_indefinite(map));
- assert_int_equal(cbor_map_size(map), 1);
- assert_int_equal(res.read, 14);
+ assert_size_equal(cbor_map_size(map), 1);
+ assert_size_equal(res.read, 14);
struct cbor_pair *handle = cbor_map_handle(map);
assert_true(cbor_typeof(handle[0].key) == CBOR_TYPE_STRING);
assert_true(cbor_string_is_indefinite(handle[0].key));
- assert_int_equal(cbor_string_chunk_count(handle[0].key), 2);
+ assert_size_equal(cbor_string_chunk_count(handle[0].key), 2);
assert_true(cbor_typeof(handle[0].value) == CBOR_TYPE_STRING);
assert_true(cbor_string_is_indefinite(handle[0].value));
- assert_int_equal(cbor_string_chunk_count(handle[0].value), 2);
+ assert_size_equal(cbor_string_chunk_count(handle[0].value), 2);
assert_memory_equal(
cbor_string_handle(cbor_string_chunks_handle(handle[0].value)[1]), "d",
1);
@@ -177,6 +179,78 @@ static void test_streamed_streamed_kv_map(void **state) {
assert_null(map);
}
+static void test_map_add_full(void **_CBOR_UNUSED(_state)) {
+ map = cbor_new_definite_map(0);
+ cbor_item_t *one = cbor_build_uint8(1);
+ cbor_item_t *two = cbor_build_uint8(2);
+
+ assert_false(cbor_map_add(map, (struct cbor_pair){.key = one, .value = two}));
+
+ cbor_decref(&map);
+ cbor_decref(&one);
+ cbor_decref(&two);
+}
+
+static void test_map_add_too_big_to_realloc(void **_CBOR_UNUSED(_state)) {
+ map = cbor_new_indefinite_map();
+ struct _cbor_map_metadata *metadata =
+ (struct _cbor_map_metadata *)&map->metadata;
+ // Pretend we already have a huge memory block
+ metadata->allocated = SIZE_MAX;
+ metadata->end_ptr = SIZE_MAX;
+ cbor_item_t *one = cbor_build_uint8(1);
+ cbor_item_t *two = cbor_build_uint8(2);
+
+ assert_false(cbor_map_add(map, (struct cbor_pair){.key = one, .value = two}));
+
+ metadata->allocated = 0;
+ metadata->end_ptr = 0;
+ cbor_decref(&map);
+ cbor_decref(&one);
+ cbor_decref(&two);
+}
+
+static void test_map_creation(void **_CBOR_UNUSED(_state)) {
+ WITH_FAILING_MALLOC({ assert_null(cbor_new_definite_map(42)); });
+ WITH_MOCK_MALLOC({ assert_null(cbor_new_definite_map(42)); }, 2, MALLOC,
+ MALLOC_FAIL);
+
+ WITH_FAILING_MALLOC({ assert_null(cbor_new_indefinite_map()); });
+}
+
+static void test_map_add(void **_CBOR_UNUSED(_state)) {
+ WITH_MOCK_MALLOC(
+ {
+ cbor_item_t *map = cbor_new_indefinite_map();
+ cbor_item_t *key = cbor_build_uint8(0);
+ cbor_item_t *value = cbor_build_bool(true);
+
+ assert_false(
+ cbor_map_add(map, (struct cbor_pair){.key = key, .value = value}));
+ assert_size_equal(cbor_map_allocated(map), 0);
+ assert_null(map->data);
+
+ cbor_decref(&map);
+ cbor_decref(&key);
+ cbor_decref(&value);
+ },
+ 4, MALLOC, MALLOC, MALLOC, REALLOC_FAIL);
+}
+
+static unsigned char test_indef_map[] = {0xBF, 0x01, 0x02, 0x03, 0x04, 0xFF};
+static void test_indef_map_decode(void **_CBOR_UNUSED(_state)) {
+ WITH_MOCK_MALLOC(
+ {
+ cbor_item_t *map;
+ struct cbor_load_result res;
+ map = cbor_load(test_indef_map, 6, &res);
+
+ assert_null(map);
+ assert_size_equal(res.error.code, CBOR_ERR_MEMERROR);
+ },
+ 4, MALLOC, MALLOC, MALLOC, REALLOC_FAIL);
+}
+
int main(void) {
const struct CMUnitTest tests[] = {
cmocka_unit_test(test_empty_map),
@@ -185,6 +259,12 @@ int main(void) {
cmocka_unit_test(test_def_nested_map),
cmocka_unit_test(test_streamed_key_map),
cmocka_unit_test(test_streamed_kv_map),
- cmocka_unit_test(test_streamed_streamed_kv_map)};
+ cmocka_unit_test(test_streamed_streamed_kv_map),
+ cmocka_unit_test(test_map_add_full),
+ cmocka_unit_test(test_map_add_too_big_to_realloc),
+ cmocka_unit_test(test_map_creation),
+ cmocka_unit_test(test_map_add),
+ cmocka_unit_test(test_indef_map_decode),
+ };
return cmocka_run_group_tests(tests, NULL, NULL);
}
diff --git a/test/memory_allocation_test.c b/test/memory_allocation_test.c
deleted file mode 100644
index 991c16f87b33..000000000000
--- a/test/memory_allocation_test.c
+++ /dev/null
@@ -1,277 +0,0 @@
-/*
- * Copyright (c) 2014-2020 Pavel Kalvoda <me@pavelkalvoda.com>
- *
- * libcbor is free software; you can redistribute it and/or modify
- * it under the terms of the MIT license. See LICENSE for details.
- */
-
-#include <setjmp.h>
-#include <stdarg.h>
-#include <stddef.h>
-
-#include <cmocka.h>
-
-#include "cbor.h"
-
-// This test simulates cases when malloc unexpectedly fails and leaves a
-// possibly partially constructed object behind. It this is especially useful
-// in conjunction with the memory correctness check.
-//
-// WARNING: The test only works with CBOR_CUSTOM_ALLOC
-
-typedef enum call_expectation {
- MALLOC,
- MALLOC_FAIL,
- REALLOC,
- REALLOC_FAIL
-} call_expectation;
-
-// How many alloc calls we expect
-int alloc_calls_expected;
-// How many alloc calls we got
-int alloc_calls;
-// Array of booleans indicating whether to return a block or fail with NULL
-call_expectation *expectations;
-
-void set_mock_malloc(int calls, ...) {
- va_list args;
- va_start(args, calls);
- alloc_calls_expected = calls;
- alloc_calls = 0;
- expectations = calloc(calls, sizeof(expectations));
- for (int i = 0; i < calls; i++) {
- // Promotable types, baby
- expectations[i] = va_arg(args, call_expectation);
- }
- va_end(args);
-}
-
-void finalize_mock_malloc() {
- assert_int_equal(alloc_calls, alloc_calls_expected);
- free(expectations);
-}
-
-void *instrumented_malloc(size_t size) {
- if (alloc_calls >= alloc_calls_expected) {
- goto error;
- }
-
- if (expectations[alloc_calls] == MALLOC) {
- alloc_calls++;
- return malloc(size);
- } else if (expectations[alloc_calls] == MALLOC_FAIL) {
- alloc_calls++;
- return NULL;
- }
-
-error:
- print_error("Unexpected call to malloc");
- fail();
- return NULL;
-}
-
-void *instrumented_realloc(void *ptr, size_t size) {
- if (alloc_calls >= alloc_calls_expected) {
- goto error;
- }
-
- if (expectations[alloc_calls] == REALLOC) {
- alloc_calls++;
- return realloc(ptr, size);
- } else if (expectations[alloc_calls] == REALLOC_FAIL) {
- alloc_calls++;
- return NULL;
- }
-
-error:
- print_error("Unexpected call to realloc");
- fail();
- return NULL;
-}
-
-#define WITH_MOCK_MALLOC(block, malloc_calls, ...) \
- do { \
- set_mock_malloc(malloc_calls, __VA_ARGS__); \
- block; \
- finalize_mock_malloc(); \
- } while (0)
-
-#define WITH_FAILING_MALLOC(block) WITH_MOCK_MALLOC(block, 1, MALLOC_FAIL)
-
-static void test_int_creation(void **state) {
- WITH_FAILING_MALLOC({ assert_null(cbor_new_int8()); });
- WITH_FAILING_MALLOC({ assert_null(cbor_new_int16()); });
- WITH_FAILING_MALLOC({ assert_null(cbor_new_int32()); });
- WITH_FAILING_MALLOC({ assert_null(cbor_new_int64()); });
-
- WITH_FAILING_MALLOC({ assert_null(cbor_build_uint8(0xFF)); });
- WITH_FAILING_MALLOC({ assert_null(cbor_build_uint16(0xFF)); });
- WITH_FAILING_MALLOC({ assert_null(cbor_build_uint32(0xFF)); });
- WITH_FAILING_MALLOC({ assert_null(cbor_build_uint64(0xFF)); });
-
- WITH_FAILING_MALLOC({ assert_null(cbor_build_negint8(0xFF)); });
- WITH_FAILING_MALLOC({ assert_null(cbor_build_negint16(0xFF)); });
- WITH_FAILING_MALLOC({ assert_null(cbor_build_negint32(0xFF)); });
- WITH_FAILING_MALLOC({ assert_null(cbor_build_negint64(0xFF)); });
-}
-
-static void test_bytestring_creation(void **state) {
- WITH_FAILING_MALLOC({ assert_null(cbor_new_definite_bytestring()); });
-
- WITH_FAILING_MALLOC({ assert_null(cbor_new_indefinite_bytestring()); });
- WITH_MOCK_MALLOC({ assert_null(cbor_new_indefinite_bytestring()); }, 2,
- MALLOC, MALLOC_FAIL);
-
- unsigned char bytes[] = {0, 0, 0xFF, 0xAB};
-
- WITH_FAILING_MALLOC({ assert_null(cbor_build_bytestring(bytes, 4)); });
- WITH_MOCK_MALLOC({ assert_null(cbor_build_bytestring(bytes, 4)); }, 2, MALLOC,
- MALLOC_FAIL);
-}
-
-static void test_string_creation(void **state) {
- WITH_FAILING_MALLOC({ assert_null(cbor_new_definite_string()); });
-
- WITH_FAILING_MALLOC({ assert_null(cbor_new_indefinite_string()); });
- WITH_MOCK_MALLOC({ assert_null(cbor_new_indefinite_string()); }, 2, MALLOC,
- MALLOC_FAIL);
-
- WITH_FAILING_MALLOC({ assert_null(cbor_build_string("Test")); });
- WITH_MOCK_MALLOC({ assert_null(cbor_build_string("Test")); }, 2, MALLOC,
- MALLOC_FAIL);
-
- WITH_FAILING_MALLOC({ assert_null(cbor_build_stringn("Test", 4)); });
- WITH_MOCK_MALLOC({ assert_null(cbor_build_stringn("Test", 4)); }, 2, MALLOC,
- MALLOC_FAIL);
-}
-
-static void test_array_creation(void **state) {
- WITH_FAILING_MALLOC({ assert_null(cbor_new_definite_array(42)); });
- WITH_MOCK_MALLOC({ assert_null(cbor_new_definite_array(42)); }, 2, MALLOC,
- MALLOC_FAIL);
-
- WITH_FAILING_MALLOC({ assert_null(cbor_new_indefinite_array()); });
-}
-
-static void test_map_creation(void **state) {
- WITH_FAILING_MALLOC({ assert_null(cbor_new_definite_map(42)); });
- WITH_MOCK_MALLOC({ assert_null(cbor_new_definite_map(42)); }, 2, MALLOC,
- MALLOC_FAIL);
-
- WITH_FAILING_MALLOC({ assert_null(cbor_new_indefinite_map()); });
-}
-
-static void test_tag_creation(void **state) {
- WITH_FAILING_MALLOC({ assert_null(cbor_new_tag(42)); });
-}
-
-static void test_float_ctrl_creation(void **state) {
- WITH_FAILING_MALLOC({ assert_null(cbor_new_ctrl()); });
- WITH_FAILING_MALLOC({ assert_null(cbor_new_float2()); });
- WITH_FAILING_MALLOC({ assert_null(cbor_new_float4()); });
- WITH_FAILING_MALLOC({ assert_null(cbor_new_float8()); });
- WITH_FAILING_MALLOC({ assert_null(cbor_new_null()); });
- WITH_FAILING_MALLOC({ assert_null(cbor_new_undef()); });
-
- WITH_FAILING_MALLOC({ assert_null(cbor_build_bool(false)); });
- WITH_FAILING_MALLOC({ assert_null(cbor_build_float2(3.14)); });
- WITH_FAILING_MALLOC({ assert_null(cbor_build_float4(3.14)); });
- WITH_FAILING_MALLOC({ assert_null(cbor_build_float8(3.14)); });
- WITH_FAILING_MALLOC({ assert_null(cbor_build_ctrl(0xAF)); });
-}
-
-static void test_bytestring_add_chunk(void **state) {
- unsigned char bytes[] = {0, 0, 0xFF, 0xAB};
- WITH_MOCK_MALLOC(
- {
- cbor_item_t *bytestring = cbor_new_indefinite_bytestring();
- cbor_item_t *chunk = cbor_build_bytestring(bytes, 4);
-
- assert_false(cbor_bytestring_add_chunk(bytestring, chunk));
- assert_int_equal(cbor_bytestring_chunk_count(bytestring), 0);
- assert_int_equal(
- ((struct cbor_indefinite_string_data *)bytestring->data)
- ->chunk_capacity,
- 0);
-
- cbor_decref(&chunk);
- cbor_decref(&bytestring);
- },
- 5, MALLOC, MALLOC, MALLOC, MALLOC, REALLOC_FAIL);
-}
-
-static void test_string_add_chunk(void **state) {
- WITH_MOCK_MALLOC(
- {
- cbor_item_t *string = cbor_new_indefinite_string();
- cbor_item_t *chunk = cbor_build_string("Hello!");
-
- assert_false(cbor_string_add_chunk(string, chunk));
- assert_int_equal(cbor_string_chunk_count(string), 0);
- assert_int_equal(((struct cbor_indefinite_string_data *)string->data)
- ->chunk_capacity,
- 0);
-
- cbor_decref(&chunk);
- cbor_decref(&string);
- },
- 5, MALLOC, MALLOC, MALLOC, MALLOC, REALLOC_FAIL);
-}
-
-static void test_array_push(void **state) {
- WITH_MOCK_MALLOC(
- {
- cbor_item_t *array = cbor_new_indefinite_array();
- cbor_item_t *string = cbor_build_string("Hello!");
-
- assert_false(cbor_array_push(array, string));
- assert_int_equal(cbor_array_allocated(array), 0);
- assert_null(array->data);
- assert_int_equal(array->metadata.array_metadata.end_ptr, 0);
-
- cbor_decref(&string);
- cbor_decref(&array);
- },
- 4, MALLOC, MALLOC, MALLOC, REALLOC_FAIL);
-}
-
-static void test_map_add(void **state) {
- WITH_MOCK_MALLOC(
- {
- cbor_item_t *map = cbor_new_indefinite_map();
- cbor_item_t *key = cbor_build_uint8(0);
- cbor_item_t *value = cbor_build_bool(true);
-
- assert_false(
- cbor_map_add(map, (struct cbor_pair){.key = key, .value = value}));
- assert_int_equal(cbor_map_allocated(map), 0);
- assert_null(map->data);
-
- cbor_decref(&map);
- cbor_decref(&key);
- cbor_decref(&value);
- },
- 4, MALLOC, MALLOC, MALLOC, REALLOC_FAIL);
-}
-
-int main(void) {
- cbor_set_allocs(instrumented_malloc, instrumented_realloc, free);
-
- // TODO: string chunks realloc test
- const struct CMUnitTest tests[] = {
- cmocka_unit_test(test_int_creation),
- cmocka_unit_test(test_bytestring_creation),
- cmocka_unit_test(test_string_creation),
- cmocka_unit_test(test_array_creation),
- cmocka_unit_test(test_map_creation),
- cmocka_unit_test(test_tag_creation),
- cmocka_unit_test(test_float_ctrl_creation),
-
- cmocka_unit_test(test_bytestring_add_chunk),
- cmocka_unit_test(test_string_add_chunk),
- cmocka_unit_test(test_array_push),
- cmocka_unit_test(test_map_add),
- };
-
- return cmocka_run_group_tests(tests, NULL, NULL);
-}
diff --git a/test/memory_utils_test.c b/test/memory_utils_test.c
new file mode 100644
index 000000000000..6cf07c7da934
--- /dev/null
+++ b/test/memory_utils_test.c
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2014-2020 Pavel Kalvoda <me@pavelkalvoda.com>
+ *
+ * libcbor is free software; you can redistribute it and/or modify
+ * it under the terms of the MIT license. See LICENSE for details.
+ */
+
+#include "cbor/internal/memory_utils.h"
+#include <string.h>
+#include "assertions.h"
+
+static void test_safe_multiply(void **_CBOR_UNUSED(_state)) {
+ assert_true(_cbor_safe_to_multiply(1, 1));
+ assert_true(_cbor_safe_to_multiply(SIZE_MAX, 0));
+ assert_true(_cbor_safe_to_multiply(SIZE_MAX, 1));
+ assert_false(_cbor_safe_to_multiply(SIZE_MAX, 2));
+ assert_false(_cbor_safe_to_multiply(SIZE_MAX, SIZE_MAX));
+}
+
+static void test_safe_add(void **_CBOR_UNUSED(_state)) {
+ assert_true(_cbor_safe_to_add(1, 1));
+ assert_true(_cbor_safe_to_add(SIZE_MAX - 1, 1));
+ assert_true(_cbor_safe_to_add(SIZE_MAX, 0));
+ assert_false(_cbor_safe_to_add(SIZE_MAX, 1));
+ assert_false(_cbor_safe_to_add(SIZE_MAX, 2));
+ assert_false(_cbor_safe_to_add(SIZE_MAX, SIZE_MAX));
+ assert_false(_cbor_safe_to_add(SIZE_MAX - 1, SIZE_MAX));
+ assert_false(_cbor_safe_to_add(SIZE_MAX - 1, SIZE_MAX - 1));
+}
+
+static void test_safe_signalling_add(void **_CBOR_UNUSED(_state)) {
+ assert_size_equal(_cbor_safe_signaling_add(1, 2), 3);
+ assert_size_equal(_cbor_safe_signaling_add(0, 1), 0);
+ assert_size_equal(_cbor_safe_signaling_add(0, SIZE_MAX), 0);
+ assert_size_equal(_cbor_safe_signaling_add(1, SIZE_MAX), 0);
+ assert_size_equal(_cbor_safe_signaling_add(1, SIZE_MAX - 1), SIZE_MAX);
+}
+
+static void test_realloc_multiple(void **_CBOR_UNUSED(_state)) {
+ unsigned char *data = malloc(1);
+ data[0] = 0x2a;
+
+ data = _cbor_realloc_multiple(data, /*item_size=*/1, /*item_count=*/10);
+ assert_size_equal(data[0], 0x2a);
+ data[9] = 0x2b; // Sanitizer will stop us if not ok
+ free(data);
+
+ assert_null(_cbor_realloc_multiple(NULL, SIZE_MAX, 2));
+}
+
+int main(void) {
+ const struct CMUnitTest tests[] = {
+ cmocka_unit_test(test_safe_multiply),
+ cmocka_unit_test(test_safe_add),
+ cmocka_unit_test(test_safe_signalling_add),
+ cmocka_unit_test(test_realloc_multiple),
+ };
+ return cmocka_run_group_tests(tests, NULL, NULL);
+}
diff --git a/test/type_1_encoders_test.c b/test/negint_encoders_test.c
index 50edaa08cd7d..e9230fbe42ae 100644
--- a/test/type_1_encoders_test.c
+++ b/test/negint_encoders_test.c
@@ -5,62 +5,59 @@
* it under the terms of the MIT license. See LICENSE for details.
*/
-#include <setjmp.h>
-#include <stdarg.h>
-#include <stddef.h>
-
-#include <cmocka.h>
-
+#include "assertions.h"
#include "cbor.h"
unsigned char buffer[512];
-static void test_embedded_negint8(void **state) {
- assert_int_equal(1, cbor_encode_negint8(14, buffer, 512));
+static void test_embedded_negint8(void **_CBOR_UNUSED(_state)) {
+ assert_size_equal(1, cbor_encode_negint8(14, buffer, 512));
assert_memory_equal(buffer, (unsigned char[]){0x2E}, 1);
}
-static void test_negint8(void **state) {
- assert_int_equal(0, cbor_encode_negint8(180, buffer, 1));
- assert_int_equal(2, cbor_encode_negint8(255, buffer, 512));
+static void test_negint8(void **_CBOR_UNUSED(_state)) {
+ assert_size_equal(0, cbor_encode_negint8(180, buffer, 1));
+ assert_size_equal(2, cbor_encode_negint8(255, buffer, 512));
assert_memory_equal(buffer, ((unsigned char[]){0x38, 0xFF}), 2);
}
-static void test_negint16(void **state) {
- assert_int_equal(0, cbor_encode_negint16(1000, buffer, 2));
- assert_int_equal(3, cbor_encode_negint16(1000, buffer, 512));
+static void test_negint16(void **_CBOR_UNUSED(_state)) {
+ assert_size_equal(0, cbor_encode_negint16(1000, buffer, 2));
+ assert_size_equal(3, cbor_encode_negint16(1000, buffer, 512));
assert_memory_equal(buffer, ((unsigned char[]){0x39, 0x03, 0xE8}), 3);
}
-static void test_negint32(void **state) {
- assert_int_equal(0, cbor_encode_negint32(1000000, buffer, 4));
- assert_int_equal(5, cbor_encode_negint32(1000000, buffer, 512));
+static void test_negint32(void **_CBOR_UNUSED(_state)) {
+ assert_size_equal(0, cbor_encode_negint32(1000000, buffer, 4));
+ assert_size_equal(5, cbor_encode_negint32(1000000, buffer, 512));
assert_memory_equal(buffer, ((unsigned char[]){0x3A, 0x00, 0x0F, 0x42, 0x40}),
5);
}
-static void test_negint64(void **state) {
- assert_int_equal(0, cbor_encode_negint64(18446744073709551615ULL, buffer, 8));
- assert_int_equal(9,
- cbor_encode_negint64(18446744073709551615ULL, buffer, 512));
+static void test_negint64(void **_CBOR_UNUSED(_state)) {
+ assert_size_equal(0,
+ cbor_encode_negint64(18446744073709551615ULL, buffer, 8));
+ assert_size_equal(9,
+ cbor_encode_negint64(18446744073709551615ULL, buffer, 512));
assert_memory_equal(
buffer,
((unsigned char[]){0x3B, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}),
9);
}
-static void test_unspecified(void **state) {
- assert_int_equal(9, cbor_encode_negint(18446744073709551615ULL, buffer, 512));
+static void test_unspecified(void **_CBOR_UNUSED(_state)) {
+ assert_size_equal(9,
+ cbor_encode_negint(18446744073709551615ULL, buffer, 512));
assert_memory_equal(
buffer,
((unsigned char[]){0x3B, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}),
9);
- assert_int_equal(5, cbor_encode_negint(1000000, buffer, 512));
+ assert_size_equal(5, cbor_encode_negint(1000000, buffer, 512));
assert_memory_equal(buffer, ((unsigned char[]){0x3A, 0x00, 0x0F, 0x42, 0x40}),
5);
- assert_int_equal(3, cbor_encode_negint(1000, buffer, 512));
+ assert_size_equal(3, cbor_encode_negint(1000, buffer, 512));
assert_memory_equal(buffer, ((unsigned char[]){0x39, 0x03, 0xE8}), 3);
- assert_int_equal(2, cbor_encode_negint(255, buffer, 512));
+ assert_size_equal(2, cbor_encode_negint(255, buffer, 512));
assert_memory_equal(buffer, ((unsigned char[]){0x38, 0xFF}), 2);
}
diff --git a/test/type_1_test.c b/test/negint_test.c
index 8a27d7e8b639..66e7445b7f23 100644
--- a/test/type_1_test.c
+++ b/test/negint_test.c
@@ -5,13 +5,9 @@
* it under the terms of the MIT license. See LICENSE for details.
*/
-#include <setjmp.h>
-#include <stdarg.h>
-#include <stddef.h>
-
-#include <cmocka.h>
-
+#include "assertions.h"
#include "cbor.h"
+#include "test_allocator.h"
cbor_item_t *number;
struct cbor_load_result res;
@@ -23,7 +19,7 @@ unsigned char data4[] = {0x3a, 0xa5, 0xf7, 0x02, 0xb3, 0xFF};
unsigned char data5[] = {0x3b, 0xa5, 0xf7, 0x02, 0xb3,
0xa5, 0xf7, 0x02, 0xb3, 0xFF};
-static void test_very_short_int(void **state) {
+static void test_very_short_int(void **_CBOR_UNUSED(_state)) {
number = cbor_load(data1, 2, &res);
assert_true(cbor_typeof(number) == CBOR_TYPE_NEGINT);
assert_true(cbor_int_get_width(number) == CBOR_INT_8);
@@ -37,7 +33,7 @@ static void test_very_short_int(void **state) {
assert_null(number);
}
-static void test_short_int(void **state) {
+static void test_short_int(void **_CBOR_UNUSED(_state)) {
number = cbor_load(data2, 3, &res);
assert_true(cbor_typeof(number) == CBOR_TYPE_NEGINT);
assert_true(cbor_int_get_width(number) == CBOR_INT_8);
@@ -51,7 +47,7 @@ static void test_short_int(void **state) {
assert_null(number);
}
-static void test_half_int(void **state) {
+static void test_half_int(void **_CBOR_UNUSED(_state)) {
number = cbor_load(data3, 5, &res);
assert_true(cbor_typeof(number) == CBOR_TYPE_NEGINT);
assert_true(cbor_int_get_width(number) == CBOR_INT_16);
@@ -65,7 +61,7 @@ static void test_half_int(void **state) {
assert_null(number);
}
-static void test_int(void **state) {
+static void test_int(void **_CBOR_UNUSED(_state)) {
number = cbor_load(data4, 6, &res);
assert_true(cbor_typeof(number) == CBOR_TYPE_NEGINT);
assert_true(cbor_int_get_width(number) == CBOR_INT_32);
@@ -79,7 +75,7 @@ static void test_int(void **state) {
assert_null(number);
}
-static void test_long_int(void **state) {
+static void test_long_int(void **_CBOR_UNUSED(_state)) {
number = cbor_load(data5, 10, &res);
assert_true(cbor_typeof(number) == CBOR_TYPE_NEGINT);
assert_true(cbor_int_get_width(number) == CBOR_INT_64);
@@ -93,10 +89,26 @@ static void test_long_int(void **state) {
assert_null(number);
}
+static void test_int_creation(void **_CBOR_UNUSED(_state)) {
+ WITH_FAILING_MALLOC({ assert_null(cbor_new_int8()); });
+ WITH_FAILING_MALLOC({ assert_null(cbor_new_int16()); });
+ WITH_FAILING_MALLOC({ assert_null(cbor_new_int32()); });
+ WITH_FAILING_MALLOC({ assert_null(cbor_new_int64()); });
+
+ WITH_FAILING_MALLOC({ assert_null(cbor_build_negint8(0xFF)); });
+ WITH_FAILING_MALLOC({ assert_null(cbor_build_negint16(0xFF)); });
+ WITH_FAILING_MALLOC({ assert_null(cbor_build_negint32(0xFF)); });
+ WITH_FAILING_MALLOC({ assert_null(cbor_build_negint64(0xFF)); });
+}
+
int main(void) {
const struct CMUnitTest tests[] = {
- cmocka_unit_test(test_very_short_int), cmocka_unit_test(test_short_int),
- cmocka_unit_test(test_half_int), cmocka_unit_test(test_int),
- cmocka_unit_test(test_long_int)};
+ cmocka_unit_test(test_very_short_int),
+ cmocka_unit_test(test_short_int),
+ cmocka_unit_test(test_half_int),
+ cmocka_unit_test(test_int),
+ cmocka_unit_test(test_long_int),
+ cmocka_unit_test(test_int_creation),
+ };
return cmocka_run_group_tests(tests, NULL, NULL);
}
diff --git a/test/pretty_printer_test.c b/test/pretty_printer_test.c
index 978c72688859..4a6249c412d8 100644
--- a/test/pretty_printer_test.c
+++ b/test/pretty_printer_test.c
@@ -5,13 +5,8 @@
* it under the terms of the MIT license. See LICENSE for details.
*/
-#include <setjmp.h>
-#include <stdarg.h>
-#include <stddef.h>
-
-#include <cmocka.h>
-
#include <stdio.h>
+#include "assertions.h"
#include "cbor.h"
unsigned char data[] = {0x8B, 0x01, 0x20, 0x5F, 0x41, 0x01, 0x41, 0x02,
@@ -20,7 +15,7 @@ unsigned char data[] = {0x8B, 0x01, 0x20, 0x5F, 0x41, 0x01, 0x41, 0x02,
0xFF, 0xFB, 0x40, 0x09, 0x1E, 0xB8, 0x51, 0xEB,
0x85, 0x1F, 0xF6, 0xF7, 0xF5};
-static void test_pretty_printer(void **state) {
+static void test_pretty_printer(void **_CBOR_UNUSED(_state)) {
#if CBOR_PRETTY_PRINTER
FILE *outfile = tmpfile();
struct cbor_load_result res;
diff --git a/test/stack_over_limit_test.c b/test/stack_over_limit_test.c
index 09ea0d6e1d51..73b6bdc2567b 100644
--- a/test/stack_over_limit_test.c
+++ b/test/stack_over_limit_test.c
@@ -1,12 +1,5 @@
-#include <setjmp.h>
-#include <stdarg.h>
-#include <stddef.h>
-
-#include <cmocka.h>
-
#include "assertions.h"
#include "cbor.h"
-#include "stream_expectations.h"
static size_t generate_overflow_data(unsigned char **overflow_data) {
int i;
@@ -19,17 +12,17 @@ static size_t generate_overflow_data(unsigned char **overflow_data) {
return CBOR_MAX_STACK_SIZE + 3;
}
-static void test_stack_over_limit(void **state) {
+static void test_stack_over_limit(void **_CBOR_UNUSED(_state)) {
unsigned char *overflow_data;
size_t overflow_data_len;
struct cbor_load_result res;
overflow_data_len = generate_overflow_data(&overflow_data);
- cbor_load(overflow_data, overflow_data_len, &res);
+ assert_null(cbor_load(overflow_data, overflow_data_len, &res));
free(overflow_data);
- assert_int_equal(res.error.code, CBOR_ERR_MEMERROR);
+ assert_size_equal(res.error.code, CBOR_ERR_MEMERROR);
}
-int main() {
+int main(void) {
const struct CMUnitTest tests[] = {cmocka_unit_test(test_stack_over_limit)};
return cmocka_run_group_tests(tests, NULL, NULL);
}
diff --git a/test/stream_expectations.c b/test/stream_expectations.c
index 890fafa763ea..3592c9625da5 100644
--- a/test/stream_expectations.c
+++ b/test/stream_expectations.c
@@ -1,18 +1,10 @@
#include "stream_expectations.h"
-// TODO: The saved keystrokes are not worth the complexity. Get rid of this
-// file to prevent confusion, the fundamental structure is unlikely to change
-// in the future.
-
-/* Ordered from 0 to queue_size - 1 */
struct test_assertion assertions_queue[MAX_QUEUE_ITEMS];
int queue_size = 0;
int current_expectation = 0;
-decoder_t *decoder;
-
-void set_decoder(decoder_t *dec) { decoder = dec; }
-int clear_stream_assertions(void **state) {
+int clean_up_stream_assertions(void **state) {
if (queue_size != current_expectation) {
return 1; // We have not matched all expectations correctly
}
@@ -22,7 +14,7 @@ int clear_stream_assertions(void **state) {
}
/* Callbacks */
-struct test_assertion current() {
+struct test_assertion current(void) {
return assertions_queue[current_expectation];
}
@@ -33,7 +25,7 @@ void assert_uint8_eq(uint8_t actual) {
UINT8_EQ, (union test_expectation_data){.int8 = actual}};
}
-void uint8_callback(void *context, uint8_t actual) {
+void uint8_callback(void *_CBOR_UNUSED(_context), uint8_t actual) {
assert_true(current().expectation == UINT8_EQ);
assert_true(current().data.int8 == actual);
current_expectation++;
@@ -44,7 +36,7 @@ void assert_uint16_eq(uint16_t actual) {
UINT16_EQ, (union test_expectation_data){.int16 = actual}};
}
-void uint16_callback(void *context, uint16_t actual) {
+void uint16_callback(void *_CBOR_UNUSED(_context), uint16_t actual) {
assert_true(current().expectation == UINT16_EQ);
assert_true(current().data.int16 == actual);
current_expectation++;
@@ -55,7 +47,7 @@ void assert_uint32_eq(uint32_t actual) {
UINT32_EQ, (union test_expectation_data){.int32 = actual}};
}
-void uint32_callback(void *context, uint32_t actual) {
+void uint32_callback(void *_CBOR_UNUSED(_context), uint32_t actual) {
assert_true(current().expectation == UINT32_EQ);
assert_true(current().data.int32 == actual);
current_expectation++;
@@ -66,7 +58,7 @@ void assert_uint64_eq(uint64_t actual) {
UINT64_EQ, (union test_expectation_data){.int64 = actual}};
}
-void uint64_callback(void *context, uint64_t actual) {
+void uint64_callback(void *_CBOR_UNUSED(_context), uint64_t actual) {
assert_true(current().expectation == UINT64_EQ);
assert_true(current().data.int64 == actual);
current_expectation++;
@@ -77,7 +69,7 @@ void assert_negint8_eq(uint8_t actual) {
NEGINT8_EQ, (union test_expectation_data){.int8 = actual}};
}
-void negint8_callback(void *context, uint8_t actual) {
+void negint8_callback(void *_CBOR_UNUSED(_context), uint8_t actual) {
assert_true(current().expectation == NEGINT8_EQ);
assert_true(current().data.int8 == actual);
current_expectation++;
@@ -88,7 +80,7 @@ void assert_negint16_eq(uint16_t actual) {
NEGINT16_EQ, (union test_expectation_data){.int16 = actual}};
}
-void negint16_callback(void *context, uint16_t actual) {
+void negint16_callback(void *_CBOR_UNUSED(_context), uint16_t actual) {
assert_true(current().expectation == NEGINT16_EQ);
assert_true(current().data.int16 == actual);
current_expectation++;
@@ -99,7 +91,7 @@ void assert_negint32_eq(uint32_t actual) {
NEGINT32_EQ, (union test_expectation_data){.int32 = actual}};
}
-void negint32_callback(void *context, uint32_t actual) {
+void negint32_callback(void *_CBOR_UNUSED(_context), uint32_t actual) {
assert_true(current().expectation == NEGINT32_EQ);
assert_true(current().data.int32 == actual);
current_expectation++;
@@ -110,7 +102,7 @@ void assert_negint64_eq(uint64_t actual) {
NEGINT64_EQ, (union test_expectation_data){.int64 = actual}};
}
-void negint64_callback(void *context, uint64_t actual) {
+void negint64_callback(void *_CBOR_UNUSED(_context), uint64_t actual) {
assert_true(current().expectation == NEGINT64_EQ);
assert_true(current().data.int64 == actual);
current_expectation++;
@@ -122,29 +114,54 @@ void assert_bstring_mem_eq(cbor_data address, size_t length) {
(union test_expectation_data){.string = {address, length}}};
}
-void byte_string_callback(void *context, cbor_data address, size_t length) {
+void byte_string_callback(void *_CBOR_UNUSED(_context), cbor_data address,
+ uint64_t length) {
assert_true(current().expectation == BSTRING_MEM_EQ);
assert_true(current().data.string.address == address);
assert_true(current().data.string.length == length);
current_expectation++;
}
-void assert_bstring_indef_start() {
+void assert_bstring_indef_start(void) {
assertions_queue[queue_size++] =
(struct test_assertion){.expectation = BSTRING_INDEF_START};
}
-void byte_string_start_callback(void *context) {
+void byte_string_start_callback(void *_CBOR_UNUSED(_context)) {
assert_true(current().expectation == BSTRING_INDEF_START);
current_expectation++;
}
-void assert_indef_break() {
+void assert_string_mem_eq(cbor_data address, size_t length) {
+ assertions_queue[queue_size++] = (struct test_assertion){
+ STRING_MEM_EQ,
+ (union test_expectation_data){.string = {address, length}}};
+}
+
+void string_callback(void *_CBOR_UNUSED(_context), cbor_data address,
+ uint64_t length) {
+ assert_true(current().expectation == STRING_MEM_EQ);
+ assert_true(current().data.string.address == address);
+ assert_true(current().data.string.length == length);
+ current_expectation++;
+}
+
+void assert_string_indef_start(void) {
+ assertions_queue[queue_size++] =
+ (struct test_assertion){.expectation = STRING_INDEF_START};
+}
+
+void string_start_callback(void *_CBOR_UNUSED(_context)) {
+ assert_true(current().expectation == STRING_INDEF_START);
+ current_expectation++;
+}
+
+void assert_indef_break(void) {
assertions_queue[queue_size++] =
(struct test_assertion){.expectation = INDEF_BREAK};
}
-void indef_break_callback(void *context) {
+void indef_break_callback(void *_CBOR_UNUSED(_context)) {
assert_true(current().expectation == INDEF_BREAK);
current_expectation++;
}
@@ -154,18 +171,18 @@ void assert_array_start(size_t length) {
(struct test_assertion){ARRAY_START, {.length = length}};
}
-void array_start_callback(void *context, size_t length) {
+void array_start_callback(void *_CBOR_UNUSED(_context), uint64_t length) {
assert_true(current().expectation == ARRAY_START);
assert_true(current().data.length == length);
current_expectation++;
}
-void assert_indef_array_start() {
+void assert_indef_array_start(void) {
assertions_queue[queue_size++] =
(struct test_assertion){.expectation = ARRAY_INDEF_START};
}
-void indef_array_start_callback(void *context) {
+void indef_array_start_callback(void *_CBOR_UNUSED(_context)) {
assert_true(current().expectation == ARRAY_INDEF_START);
current_expectation++;
}
@@ -175,18 +192,18 @@ void assert_map_start(size_t length) {
(struct test_assertion){MAP_START, {.length = length}};
}
-void map_start_callback(void *context, size_t length) {
+void map_start_callback(void *_CBOR_UNUSED(_context), uint64_t length) {
assert_true(current().expectation == MAP_START);
assert_true(current().data.length == length);
current_expectation++;
}
-void assert_indef_map_start() {
+void assert_indef_map_start(void) {
assertions_queue[queue_size++] =
(struct test_assertion){.expectation = MAP_INDEF_START};
}
-void indef_map_start_callback(void *context) {
+void indef_map_start_callback(void *_CBOR_UNUSED(_context)) {
assert_true(current().expectation == MAP_INDEF_START);
current_expectation++;
}
@@ -196,7 +213,7 @@ void assert_tag_eq(uint64_t value) {
(struct test_assertion){TAG_EQ, {.int64 = value}};
}
-void tag_callback(void *context, uint64_t value) {
+void tag_callback(void *_CBOR_UNUSED(_context), uint64_t value) {
assert_true(current().expectation == TAG_EQ);
assert_true(current().data.int64 == value);
current_expectation++;
@@ -207,7 +224,7 @@ void assert_half(float value) {
(struct test_assertion){HALF_EQ, {.float2 = value}};
}
-void half_callback(void *context, float actual) {
+void half_callback(void *_CBOR_UNUSED(_context), float actual) {
assert_true(current().expectation == HALF_EQ);
assert_true(current().data.float2 == actual);
current_expectation++;
@@ -218,7 +235,7 @@ void assert_float(float value) {
(struct test_assertion){FLOAT_EQ, {.float4 = value}};
}
-void float_callback(void *context, float actual) {
+void float_callback(void *_CBOR_UNUSED(_context), float actual) {
assert_true(current().expectation == FLOAT_EQ);
assert_true(current().data.float4 == actual);
current_expectation++;
@@ -229,7 +246,7 @@ void assert_double(double value) {
(struct test_assertion){DOUBLE_EQ, {.float8 = value}};
}
-void double_callback(void *context, double actual) {
+void double_callback(void *_CBOR_UNUSED(_context), double actual) {
assert_true(current().expectation == DOUBLE_EQ);
assert_true(current().data.float8 == actual);
current_expectation++;
@@ -240,52 +257,48 @@ void assert_bool(bool value) {
(struct test_assertion){BOOL_EQ, {.boolean = value}};
}
-void assert_nil() {
+void assert_nil(void) {
assertions_queue[queue_size++] = (struct test_assertion){.expectation = NIL};
}
-void assert_undef() {
+void assert_undef(void) {
assertions_queue[queue_size++] =
(struct test_assertion){.expectation = UNDEF};
}
-void bool_callback(void *context, bool actual) {
+void bool_callback(void *_CBOR_UNUSED(_context), bool actual) {
assert_true(current().expectation == BOOL_EQ);
assert_true(current().data.boolean == actual);
current_expectation++;
}
-void null_callback(void *context) {
+void null_callback(void *_CBOR_UNUSED(_context)) {
assert_true(current().expectation == NIL);
current_expectation++;
}
-void undef_callback(void *context) {
+void undef_callback(void *_CBOR_UNUSED(_context)) {
assert_true(current().expectation == UNDEF);
current_expectation++;
}
const struct cbor_callbacks asserting_callbacks = {
-
.uint8 = &uint8_callback,
-
.uint16 = &uint16_callback,
-
.uint32 = &uint32_callback,
-
.uint64 = &uint64_callback,
.negint8 = &negint8_callback,
-
.negint16 = &negint16_callback,
-
.negint32 = &negint32_callback,
-
.negint64 = &negint64_callback,
.byte_string = &byte_string_callback,
.byte_string_start = &byte_string_start_callback,
+ .string = &string_callback,
+ .string_start = &string_start_callback,
+
.array_start = &array_start_callback,
.indef_array_start = &indef_array_start_callback,
@@ -295,9 +308,7 @@ const struct cbor_callbacks asserting_callbacks = {
.tag = &tag_callback,
.float2 = &half_callback,
-
.float4 = &float_callback,
-
.float8 = &double_callback,
.undefined = &undef_callback,
@@ -308,7 +319,7 @@ const struct cbor_callbacks asserting_callbacks = {
struct cbor_decoder_result decode(cbor_data source, size_t source_size) {
int last_expectation = current_expectation;
struct cbor_decoder_result result =
- decoder(source, source_size, &asserting_callbacks, NULL);
+ cbor_stream_decode(source, source_size, &asserting_callbacks, NULL);
if (result.status == CBOR_DECODER_FINISHED) {
// Check that we have matched an expectation from the queue
assert_true(last_expectation + 1 == current_expectation);
diff --git a/test/stream_expectations.h b/test/stream_expectations.h
index 84970ae943bc..bfc58e97cd9f 100644
--- a/test/stream_expectations.h
+++ b/test/stream_expectations.h
@@ -1,26 +1,23 @@
-/*
- * This file provides testing tools for the streaming decoder. The intended
- * usage is as follows: 1) SE API wrapper is initialized 2) Client builds
- * (ordered) series of expectations 3) The decoder is executed 4) SE checks all
- * assertions 5) Go to 2) if desired
- */
-
#ifndef STREAM_EXPECTATIONS_H_
#define STREAM_EXPECTATIONS_H_
-#include <setjmp.h>
-#include <stdarg.h>
-#include <stddef.h>
-
-#include <cmocka.h>
-
-#include <stdint.h>
+#include "assertions.h"
#include "cbor.h"
-// TODO: This setup is overengineered, we currently use one assertion at a time
-// TOOD: We never ensure that the queue is empty
#define MAX_QUEUE_ITEMS 30
+// Utilities to test `cbor_stream_decode`. See `cbor_stream_decode_test.cc`.
+//
+// Usage:
+// - The `assert_` helpers build a queue of `test_assertion`s
+// (`assertions_queue` in the implementation file), specifying
+// - Which callback is expected (`test_expectation`)
+// - And what is the expected argument value (if applicable,
+// `test_expectation_data`)
+// - `decode` will invoke `cbor_stream_decode` (test subject)
+// - `cbor_stream_decode` will invoke one of the `_callback` functions, which
+// will check the passed data against the `assertions_queue`
+
enum test_expectation {
UINT8_EQ,
UINT16_EQ,
@@ -32,10 +29,13 @@ enum test_expectation {
NEGINT32_EQ,
NEGINT64_EQ,
- BSTRING_MEM_EQ, /* Matches length and memory address for definite byte strings
- */
+ // Matches length and memory address for definite strings
+ BSTRING_MEM_EQ,
BSTRING_INDEF_START,
+ STRING_MEM_EQ,
+ STRING_INDEF_START,
+
ARRAY_START, /* Definite arrays only */
ARRAY_INDEF_START,
@@ -74,16 +74,11 @@ struct test_assertion {
union test_expectation_data data;
};
-/* Tested function */
-// TODO: This looks overengineered, we only ever use one (?) in the testsuite
-typedef struct cbor_decoder_result decoder_t(cbor_data, size_t,
- const struct cbor_callbacks *,
- void *);
-void set_decoder(decoder_t *);
+/* Test harness -- calls `cbor_stream_decode` and checks assertions */
struct cbor_decoder_result decode(cbor_data, size_t);
-/* Test setup */
-int clear_stream_assertions(void **);
+/* Verify all assertions were applied and clean up */
+int clean_up_stream_assertions(void **);
/* Assertions builders */
void assert_uint8_eq(uint8_t);
@@ -97,13 +92,16 @@ void assert_negint32_eq(uint32_t);
void assert_negint64_eq(uint64_t);
void assert_bstring_mem_eq(cbor_data, size_t);
-void assert_bstring_indef_start();
+void assert_bstring_indef_start(void);
+
+void assert_string_mem_eq(cbor_data, size_t);
+void assert_string_indef_start(void);
void assert_array_start(size_t);
-void assert_indef_array_start();
+void assert_indef_array_start(void);
void assert_map_start(size_t);
-void assert_indef_map_start();
+void assert_indef_map_start(void);
void assert_tag_eq(uint64_t);
@@ -112,10 +110,10 @@ void assert_float(float);
void assert_double(double);
void assert_bool(bool);
-void assert_nil(); /* assert_null already exists */
-void assert_undef();
+void assert_nil(void); /* assert_null already exists */
+void assert_undef(void);
-void assert_indef_break();
+void assert_indef_break(void);
/* Assertions verifying callbacks */
void uint8_callback(void *, uint8_t);
@@ -128,13 +126,16 @@ void negint16_callback(void *, uint16_t);
void negint32_callback(void *, uint32_t);
void negint64_callback(void *, uint64_t);
-void byte_string_callback(void *, cbor_data, size_t);
+void byte_string_callback(void *, cbor_data, uint64_t);
void byte_string_start_callback(void *);
-void array_start_callback(void *, size_t);
+void string_callback(void *, cbor_data, uint64_t);
+void string_start_callback(void *);
+
+void array_start_callback(void *, uint64_t);
void indef_array_start_callback(void *);
-void map_start_callback(void *, size_t);
+void map_start_callback(void *, uint64_t);
void indef_map_start_callback(void *);
void tag_callback(void *, uint64_t);
diff --git a/test/type_3_encoders_test.c b/test/string_encoders_test.c
index 823e90355087..6de1cfb27eb3 100644
--- a/test/type_3_encoders_test.c
+++ b/test/string_encoders_test.c
@@ -5,30 +5,25 @@
* it under the terms of the MIT license. See LICENSE for details.
*/
-#include <setjmp.h>
-#include <stdarg.h>
-#include <stddef.h>
-
-#include <cmocka.h>
-
+#include "assertions.h"
#include "cbor.h"
unsigned char buffer[512];
-static void test_embedded_string_start(void **state) {
- assert_int_equal(1, cbor_encode_string_start(1, buffer, 512));
+static void test_embedded_string_start(void **_CBOR_UNUSED(_state)) {
+ assert_size_equal(1, cbor_encode_string_start(1, buffer, 512));
assert_memory_equal(buffer, ((unsigned char[]){0x61}), 1);
}
-static void test_string_start(void **state) {
- assert_int_equal(5, cbor_encode_string_start(1000000, buffer, 512));
+static void test_string_start(void **_CBOR_UNUSED(_state)) {
+ assert_size_equal(5, cbor_encode_string_start(1000000, buffer, 512));
assert_memory_equal(buffer, ((unsigned char[]){0x7A, 0x00, 0x0F, 0x42, 0x40}),
5);
}
-static void test_indef_string_start(void **state) {
- assert_int_equal(1, cbor_encode_indef_string_start(buffer, 512));
- assert_int_equal(0, cbor_encode_indef_string_start(buffer, 0));
+static void test_indef_string_start(void **_CBOR_UNUSED(_state)) {
+ assert_size_equal(1, cbor_encode_indef_string_start(buffer, 512));
+ assert_size_equal(0, cbor_encode_indef_string_start(buffer, 0));
assert_memory_equal(buffer, ((unsigned char[]){0x7F}), 1);
}
diff --git a/test/type_3_test.c b/test/string_test.c
index fd882e3befa1..991aa578a26e 100644
--- a/test/type_3_test.c
+++ b/test/string_test.c
@@ -5,27 +5,23 @@
* it under the terms of the MIT license. See LICENSE for details.
*/
-#include <setjmp.h>
-#include <stdarg.h>
-#include <stddef.h>
-
-#include <cmocka.h>
-
#include <string.h>
+#include "assertions.h"
#include "cbor.h"
+#include "test_allocator.h"
cbor_item_t *string;
struct cbor_load_result res;
unsigned char empty_string_data[] = {0x60};
-static void test_empty_string(void **state) {
+static void test_empty_string(void **_CBOR_UNUSED(_state)) {
string = cbor_load(empty_string_data, 1, &res);
assert_non_null(string);
assert_true(cbor_typeof(string) == CBOR_TYPE_STRING);
assert_true(cbor_isa_string(string));
- assert_int_equal(cbor_string_length(string), 0);
- assert_int_equal(cbor_string_codepoint_count(string), 0);
+ assert_size_equal(cbor_string_length(string), 0);
+ assert_size_equal(cbor_string_codepoint_count(string), 0);
assert_true(res.read == 1);
cbor_decref(&string);
assert_null(string);
@@ -35,13 +31,13 @@ unsigned char short_string_data[] = {0x6C, 0x48, 0x65, 0x6C, 0x6C, 0x6F, 0x20,
0x77, 0x6F, 0x72, 0x6C, 0x64, 0x21};
/* 0x60 + 12 | Hello world! */
-static void test_short_string(void **state) {
+static void test_short_string(void **_CBOR_UNUSED(_state)) {
string = cbor_load(short_string_data, 13, &res);
assert_non_null(string);
assert_true(cbor_typeof(string) == CBOR_TYPE_STRING);
assert_true(cbor_isa_string(string));
- assert_int_equal(cbor_string_length(string), 12);
- assert_int_equal(cbor_string_codepoint_count(string), 12);
+ assert_size_equal(cbor_string_length(string), 12);
+ assert_size_equal(cbor_string_codepoint_count(string), 12);
assert_memory_equal(&"Hello world!", cbor_string_handle(string), 12);
assert_true(res.read == 13);
cbor_decref(&string);
@@ -53,13 +49,13 @@ unsigned char short_multibyte_string_data[] = {
0xC3, 0x9F, 0x76, 0xC4, 0x9B, 0x74, 0x65, 0x21};
/* 0x60 + 15 | Čaues ßvěte! */
-static void test_short_multibyte_string(void **state) {
+static void test_short_multibyte_string(void **_CBOR_UNUSED(_state)) {
string = cbor_load(short_multibyte_string_data, 16, &res);
assert_non_null(string);
assert_true(cbor_typeof(string) == CBOR_TYPE_STRING);
assert_true(cbor_isa_string(string));
- assert_int_equal(cbor_string_length(string), 15);
- assert_int_equal(cbor_string_codepoint_count(string), 12);
+ assert_size_equal(cbor_string_length(string), 15);
+ assert_size_equal(cbor_string_codepoint_count(string), 12);
assert_memory_equal(&"Čaues ßvěte!", cbor_string_handle(string), 15);
assert_true(res.read == 16);
cbor_decref(&string);
@@ -82,13 +78,13 @@ unsigned char int8_string_data[] = {
0x70, 0x6F, 0x73, 0x75, 0x65, 0x72, 0x65, 0x2E};
/* 150 | Lorem ....*/
-static void test_int8_string(void **state) {
+static void test_int8_string(void **_CBOR_UNUSED(_state)) {
string = cbor_load(int8_string_data, 152, &res);
assert_non_null(string);
assert_true(cbor_typeof(string) == CBOR_TYPE_STRING);
assert_true(cbor_isa_string(string));
- assert_int_equal(cbor_string_length(string), 150);
- assert_int_equal(cbor_string_codepoint_count(string), 150);
+ assert_size_equal(cbor_string_length(string), 150);
+ assert_size_equal(cbor_string_codepoint_count(string), 150);
assert_memory_equal(
&"Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec mi tellus, iaculis nec vestibulum quis, fermentum non felis. Maecenas ut justo posuere.",
cbor_string_handle(string),
@@ -116,13 +112,13 @@ unsigned char int16_string_data[] = {
/* 150 | Lorem ....*/
/* This valid but not realistic - length 150 could be encoded in a single
* uint8_t (but we need to keep the test files reasonably compact) */
-static void test_int16_string(void **state) {
+static void test_int16_string(void **_CBOR_UNUSED(_state)) {
string = cbor_load(int16_string_data, 153, &res);
assert_non_null(string);
assert_true(cbor_typeof(string) == CBOR_TYPE_STRING);
assert_true(cbor_isa_string(string));
- assert_int_equal(cbor_string_length(string), 150);
- assert_int_equal(cbor_string_codepoint_count(string), 150);
+ assert_size_equal(cbor_string_length(string), 150);
+ assert_size_equal(cbor_string_codepoint_count(string), 150);
assert_memory_equal(
&"Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec mi tellus, iaculis nec vestibulum quis, fermentum non felis. Maecenas ut justo posuere.",
cbor_string_handle(string),
@@ -149,13 +145,13 @@ unsigned char int32_string_data[] = {
0x74, 0x6F, 0x20, 0x70, 0x6F, 0x73, 0x75, 0x65, 0x72, 0x65, 0x2E};
/* 150 | Lorem ....*/
-static void test_int32_string(void **state) {
+static void test_int32_string(void **_CBOR_UNUSED(_state)) {
string = cbor_load(int32_string_data, 155, &res);
assert_non_null(string);
assert_true(cbor_typeof(string) == CBOR_TYPE_STRING);
assert_true(cbor_isa_string(string));
- assert_int_equal(cbor_string_length(string), 150);
- assert_int_equal(cbor_string_codepoint_count(string), 150);
+ assert_size_equal(cbor_string_length(string), 150);
+ assert_size_equal(cbor_string_codepoint_count(string), 150);
assert_memory_equal(
&"Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec mi tellus, iaculis nec vestibulum quis, fermentum non felis. Maecenas ut justo posuere.",
cbor_string_handle(string),
@@ -183,13 +179,13 @@ unsigned char int64_string_data[] = {
0x72, 0x65, 0x2E};
/* 150 | Lorem ....*/
-static void test_int64_string(void **state) {
+static void test_int64_string(void **_CBOR_UNUSED(_state)) {
string = cbor_load(int64_string_data, 159, &res);
assert_non_null(string);
assert_true(cbor_typeof(string) == CBOR_TYPE_STRING);
assert_true(cbor_isa_string(string));
- assert_int_equal(cbor_string_length(string), 150);
- assert_int_equal(cbor_string_codepoint_count(string), 150);
+ assert_size_equal(cbor_string_length(string), 150);
+ assert_size_equal(cbor_string_codepoint_count(string), 150);
assert_memory_equal(
&"Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec mi tellus, iaculis nec vestibulum quis, fermentum non felis. Maecenas ut justo posuere.",
cbor_string_handle(string),
@@ -205,7 +201,7 @@ unsigned char short_indef_string_data[] = {0x7F, 0x78, 0x01, 0x65, 0xFF, 0xFF};
/* start | string | break| extra
*/
-static void test_short_indef_string(void **state) {
+static void test_short_indef_string(void **_CBOR_UNUSED(_state)) {
string = cbor_load(short_indef_string_data, 6, &res);
assert_non_null(string);
assert_true(cbor_typeof(string) == CBOR_TYPE_STRING);
@@ -221,12 +217,64 @@ static void test_short_indef_string(void **state) {
assert_null(string);
}
-static void test_inline_creation(void **state) {
+static void test_inline_creation(void **_CBOR_UNUSED(_state)) {
string = cbor_build_string("Hello!");
assert_memory_equal(cbor_string_handle(string), "Hello!", strlen("Hello!"));
cbor_decref(&string);
}
+static void test_string_creation(void **_CBOR_UNUSED(_state)) {
+ WITH_FAILING_MALLOC({ assert_null(cbor_new_definite_string()); });
+
+ WITH_FAILING_MALLOC({ assert_null(cbor_new_indefinite_string()); });
+ WITH_MOCK_MALLOC({ assert_null(cbor_new_indefinite_string()); }, 2, MALLOC,
+ MALLOC_FAIL);
+
+ WITH_FAILING_MALLOC({ assert_null(cbor_build_string("Test")); });
+ WITH_MOCK_MALLOC({ assert_null(cbor_build_string("Test")); }, 2, MALLOC,
+ MALLOC_FAIL);
+
+ WITH_FAILING_MALLOC({ assert_null(cbor_build_stringn("Test", 4)); });
+ WITH_MOCK_MALLOC({ assert_null(cbor_build_stringn("Test", 4)); }, 2, MALLOC,
+ MALLOC_FAIL);
+}
+
+static void test_string_add_chunk(void **_CBOR_UNUSED(_state)) {
+ WITH_MOCK_MALLOC(
+ {
+ cbor_item_t *string = cbor_new_indefinite_string();
+ cbor_item_t *chunk = cbor_build_string("Hello!");
+
+ assert_false(cbor_string_add_chunk(string, chunk));
+ assert_size_equal(cbor_string_chunk_count(string), 0);
+ assert_size_equal(((struct cbor_indefinite_string_data *)string->data)
+ ->chunk_capacity,
+ 0);
+
+ cbor_decref(&chunk);
+ cbor_decref(&string);
+ },
+ 5, MALLOC, MALLOC, MALLOC, MALLOC, REALLOC_FAIL);
+}
+
+static void test_add_chunk_reallocation_overflow(void **_CBOR_UNUSED(_state)) {
+ string = cbor_new_indefinite_string();
+ cbor_item_t *chunk = cbor_build_string("Hello!");
+ struct cbor_indefinite_string_data *metadata =
+ (struct cbor_indefinite_string_data *)string->data;
+ // Pretend we already have many chunks allocated
+ metadata->chunk_count = SIZE_MAX;
+ metadata->chunk_capacity = SIZE_MAX;
+
+ assert_false(cbor_string_add_chunk(string, chunk));
+ assert_size_equal(cbor_refcount(chunk), 1);
+
+ metadata->chunk_count = 0;
+ metadata->chunk_capacity = 0;
+ cbor_decref(&chunk);
+ cbor_decref(&string);
+}
+
int main(void) {
const struct CMUnitTest tests[] = {
cmocka_unit_test(test_empty_string),
@@ -237,6 +285,10 @@ int main(void) {
cmocka_unit_test(test_int32_string),
cmocka_unit_test(test_int64_string),
cmocka_unit_test(test_short_indef_string),
- cmocka_unit_test(test_inline_creation)};
+ cmocka_unit_test(test_inline_creation),
+ cmocka_unit_test(test_string_creation),
+ cmocka_unit_test(test_string_add_chunk),
+ cmocka_unit_test(test_add_chunk_reallocation_overflow),
+ };
return cmocka_run_group_tests(tests, NULL, NULL);
}
diff --git a/test/type_6_encoders_test.c b/test/tag_encoders_test.c
index 84b66da00e33..5962dd9d8938 100644
--- a/test/type_6_encoders_test.c
+++ b/test/tag_encoders_test.c
@@ -5,23 +5,18 @@
* it under the terms of the MIT license. See LICENSE for details.
*/
-#include <setjmp.h>
-#include <stdarg.h>
-#include <stddef.h>
-
-#include <cmocka.h>
-
+#include "assertions.h"
#include "cbor.h"
unsigned char buffer[512];
-static void test_embedded_tag(void **state) {
- assert_int_equal(1, cbor_encode_tag(1, buffer, 512));
+static void test_embedded_tag(void **_CBOR_UNUSED(_state)) {
+ assert_size_equal(1, cbor_encode_tag(1, buffer, 512));
assert_memory_equal(buffer, ((unsigned char[]){0xC1}), 1);
}
-static void test_tag(void **state) {
- assert_int_equal(5, cbor_encode_tag(1000000, buffer, 512));
+static void test_tag(void **_CBOR_UNUSED(_state)) {
+ assert_size_equal(5, cbor_encode_tag(1000000, buffer, 512));
assert_memory_equal(buffer, ((unsigned char[]){0xDA, 0x00, 0x0F, 0x42, 0x40}),
5);
}
diff --git a/test/type_6_test.c b/test/tag_test.c
index 1d54afcdaaf5..4bf6c718f0b9 100644
--- a/test/type_6_test.c
+++ b/test/tag_test.c
@@ -5,21 +5,16 @@
* it under the terms of the MIT license. See LICENSE for details.
*/
-#include <setjmp.h>
-#include <stdarg.h>
-#include <stddef.h>
-
-#include <cmocka.h>
-
#include "assertions.h"
#include "cbor.h"
+#include "test_allocator.h"
cbor_item_t *tag;
struct cbor_load_result res;
unsigned char embedded_tag_data[] = {0xC0, 0x00};
-static void test_refcounting(void **state) {
+static void test_refcounting(void **_CBOR_UNUSED(_state)) {
tag = cbor_load(embedded_tag_data, 2, &res);
assert_true(cbor_refcount(tag) == 1);
cbor_item_t *item = cbor_tag_item(tag);
@@ -32,7 +27,7 @@ static void test_refcounting(void **state) {
}
/* Tag 0 + uint 0 */
-static void test_embedded_tag(void **state) {
+static void test_embedded_tag(void **_CBOR_UNUSED(_state)) {
tag = cbor_load(embedded_tag_data, 2, &res);
assert_true(cbor_typeof(tag) == CBOR_TYPE_TAG);
assert_true(cbor_tag_value(tag) == 0);
@@ -44,7 +39,7 @@ static void test_embedded_tag(void **state) {
unsigned char int8_tag_data[] = {0xD8, 0xFF, 0x01};
/* Tag 255 + uint 1 */
-static void test_int8_tag(void **state) {
+static void test_int8_tag(void **_CBOR_UNUSED(_state)) {
tag = cbor_load(int8_tag_data, 3, &res);
assert_true(cbor_typeof(tag) == CBOR_TYPE_TAG);
assert_true(cbor_tag_value(tag) == 255);
@@ -56,7 +51,7 @@ static void test_int8_tag(void **state) {
unsigned char int16_tag_data[] = {0xD9, 0xFF, 0x00, 0x02};
/* Tag 255 << 8 + uint 2 */
-static void test_int16_tag(void **state) {
+static void test_int16_tag(void **_CBOR_UNUSED(_state)) {
tag = cbor_load(int16_tag_data, 4, &res);
assert_true(cbor_typeof(tag) == CBOR_TYPE_TAG);
assert_true(cbor_tag_value(tag) == 255 << 8);
@@ -68,7 +63,7 @@ static void test_int16_tag(void **state) {
unsigned char int32_tag_data[] = {0xDA, 0xFF, 0x00, 0x00, 0x00, 0x03};
/* uint 3 */
-static void test_int32_tag(void **state) {
+static void test_int32_tag(void **_CBOR_UNUSED(_state)) {
tag = cbor_load(int32_tag_data, 6, &res);
assert_true(cbor_typeof(tag) == CBOR_TYPE_TAG);
assert_true(cbor_tag_value(tag) == 4278190080ULL);
@@ -81,7 +76,7 @@ unsigned char int64_tag_data[] = {0xDB, 0xFF, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x04};
/* uint 4 */
-static void test_int64_tag(void **state) {
+static void test_int64_tag(void **_CBOR_UNUSED(_state)) {
tag = cbor_load(int64_tag_data, 10, &res);
assert_true(cbor_typeof(tag) == CBOR_TYPE_TAG);
assert_true(cbor_tag_value(tag) == 18374686479671623680ULL);
@@ -93,7 +88,7 @@ static void test_int64_tag(void **state) {
unsigned char nested_tag_data[] = {0xC0, 0xC1, 0x18, 0x2A};
/* Tag 0, tag 1 + uint 0 */
-static void test_nested_tag(void **state) {
+static void test_nested_tag(void **_CBOR_UNUSED(_state)) {
tag = cbor_load(nested_tag_data, 4, &res);
assert_true(cbor_typeof(tag) == CBOR_TYPE_TAG);
assert_true(cbor_tag_value(tag) == 0);
@@ -107,11 +102,41 @@ static void test_nested_tag(void **state) {
assert_null(nested_tag);
}
+static void test_build_tag(void **_CBOR_UNUSED(_state)) {
+ tag = cbor_build_tag(1, cbor_move(cbor_build_uint8(42)));
+
+ assert_true(cbor_typeof(tag) == CBOR_TYPE_TAG);
+ assert_size_equal(cbor_tag_value(tag), 1);
+ assert_uint8(cbor_move(cbor_tag_item(tag)), 42);
+
+ cbor_decref(&tag);
+}
+
+static void test_build_tag_failure(void **_CBOR_UNUSED(_state)) {
+ cbor_item_t *tagged_item = cbor_build_uint8(42);
+
+ WITH_FAILING_MALLOC({ assert_null(cbor_build_tag(1, tagged_item)); });
+ assert_size_equal(cbor_refcount(tagged_item), 1);
+
+ cbor_decref(&tagged_item);
+}
+
+static void test_tag_creation(void **_CBOR_UNUSED(_state)) {
+ WITH_FAILING_MALLOC({ assert_null(cbor_new_tag(42)); });
+}
+
int main(void) {
const struct CMUnitTest tests[] = {
- cmocka_unit_test(test_refcounting), cmocka_unit_test(test_embedded_tag),
- cmocka_unit_test(test_int8_tag), cmocka_unit_test(test_int16_tag),
- cmocka_unit_test(test_int32_tag), cmocka_unit_test(test_int64_tag),
- cmocka_unit_test(test_nested_tag)};
+ cmocka_unit_test(test_refcounting),
+ cmocka_unit_test(test_embedded_tag),
+ cmocka_unit_test(test_int8_tag),
+ cmocka_unit_test(test_int16_tag),
+ cmocka_unit_test(test_int32_tag),
+ cmocka_unit_test(test_int64_tag),
+ cmocka_unit_test(test_nested_tag),
+ cmocka_unit_test(test_build_tag),
+ cmocka_unit_test(test_build_tag_failure),
+ cmocka_unit_test(test_tag_creation),
+ };
return cmocka_run_group_tests(tests, NULL, NULL);
}
diff --git a/test/test_allocator.c b/test/test_allocator.c
new file mode 100644
index 000000000000..72ccf6591d25
--- /dev/null
+++ b/test/test_allocator.c
@@ -0,0 +1,89 @@
+#include "test_allocator.h"
+
+#ifdef HAS_EXECINFO
+#include <execinfo.h>
+#endif
+
+// How many alloc calls we expect
+int alloc_calls_expected;
+// How many alloc calls we got
+int alloc_calls;
+// Array of booleans indicating whether to return a block or fail with NULL
+call_expectation *expectations;
+
+void set_mock_malloc(int calls, ...) {
+ va_list args;
+ va_start(args, calls);
+ alloc_calls_expected = calls;
+ alloc_calls = 0;
+ expectations = calloc(calls, sizeof(expectations));
+ for (int i = 0; i < calls; i++) {
+ // Promotable types, baby
+ expectations[i] = va_arg(args, call_expectation);
+ }
+ va_end(args);
+}
+
+void finalize_mock_malloc(void) {
+ assert_int_equal(alloc_calls, alloc_calls_expected);
+ free(expectations);
+}
+
+void print_backtrace() {
+#if HAS_EXECINFO
+ void *buffer[128];
+ int frames = backtrace(buffer, 128);
+ char **symbols = backtrace_symbols(buffer, frames);
+ // Skip this function and the caller
+ for (int i = 2; i < frames; ++i) {
+ printf("%s\n", symbols[i]);
+ }
+ free(symbols);
+#endif
+}
+
+void *instrumented_malloc(size_t size) {
+ if (alloc_calls >= alloc_calls_expected) {
+ goto error;
+ }
+
+ if (expectations[alloc_calls] == MALLOC) {
+ alloc_calls++;
+ return malloc(size);
+ } else if (expectations[alloc_calls] == MALLOC_FAIL) {
+ alloc_calls++;
+ return NULL;
+ }
+
+error:
+ print_error(
+ "Unexpected call to malloc(%zu) at position %d of %d; expected %d\n",
+ size, alloc_calls, alloc_calls_expected,
+ alloc_calls < alloc_calls_expected ? expectations[alloc_calls] : -1);
+ print_backtrace();
+ fail();
+ return NULL;
+}
+
+void *instrumented_realloc(void *ptr, size_t size) {
+ if (alloc_calls >= alloc_calls_expected) {
+ goto error;
+ }
+
+ if (expectations[alloc_calls] == REALLOC) {
+ alloc_calls++;
+ return realloc(ptr, size);
+ } else if (expectations[alloc_calls] == REALLOC_FAIL) {
+ alloc_calls++;
+ return NULL;
+ }
+
+error:
+ print_error(
+ "Unexpected call to realloc(%zu) at position %d of %d; expected %d\n",
+ size, alloc_calls, alloc_calls_expected,
+ alloc_calls < alloc_calls_expected ? expectations[alloc_calls] : -1);
+ print_backtrace();
+ fail();
+ return NULL;
+}
diff --git a/test/test_allocator.h b/test/test_allocator.h
new file mode 100644
index 000000000000..0e58454edbd6
--- /dev/null
+++ b/test/test_allocator.h
@@ -0,0 +1,35 @@
+#ifndef TEST_ALLOCATOR_H_
+#define TEST_ALLOCATOR_H_
+
+#include "assertions.h"
+#include "cbor.h"
+
+// Harness for mocking `malloc` and `realloc`
+
+typedef enum call_expectation {
+ MALLOC,
+ MALLOC_FAIL,
+ REALLOC,
+ REALLOC_FAIL
+} call_expectation;
+
+void set_mock_malloc(int calls, ...);
+
+void finalize_mock_malloc(void);
+
+void *instrumented_malloc(size_t size);
+
+void *instrumented_realloc(void *ptr, size_t size);
+
+#define WITH_MOCK_MALLOC(block, malloc_calls, ...) \
+ do { \
+ cbor_set_allocs(instrumented_malloc, instrumented_realloc, free); \
+ set_mock_malloc(malloc_calls, __VA_ARGS__); \
+ block; \
+ finalize_mock_malloc(); \
+ cbor_set_allocs(malloc, realloc, free); \
+ } while (0)
+
+#define WITH_FAILING_MALLOC(block) WITH_MOCK_MALLOC(block, 1, MALLOC_FAIL)
+
+#endif // TEST_ALLOCATOR_H_
diff --git a/test/type_4_test.c b/test/type_4_test.c
deleted file mode 100644
index b208c4e8f466..000000000000
--- a/test/type_4_test.c
+++ /dev/null
@@ -1,127 +0,0 @@
-/*
- * Copyright (c) 2014-2020 Pavel Kalvoda <me@pavelkalvoda.com>
- *
- * libcbor is free software; you can redistribute it and/or modify
- * it under the terms of the MIT license. See LICENSE for details.
- */
-
-#include <setjmp.h>
-#include <stdarg.h>
-#include <stddef.h>
-
-#include <cmocka.h>
-
-#include "assertions.h"
-#include "cbor.h"
-
-cbor_item_t *arr;
-struct cbor_load_result res;
-
-unsigned char data1[] = {0x80, 0xFF};
-
-static void test_empty_array(void **state) {
- arr = cbor_load(data1, 2, &res);
- assert_non_null(arr);
- assert_true(cbor_typeof(arr) == CBOR_TYPE_ARRAY);
- assert_true(cbor_isa_array(arr));
- assert_true(cbor_array_size(arr) == 0);
- assert_true(res.read == 1);
- cbor_decref(&arr);
- assert_null(arr);
-}
-
-unsigned char data2[] = {0x81, 0x01, 0xFF};
-
-static void test_simple_array(void **state) {
- arr = cbor_load(data2, 3, &res);
- assert_non_null(arr);
- assert_true(cbor_typeof(arr) == CBOR_TYPE_ARRAY);
- assert_true(cbor_isa_array(arr));
- assert_int_equal(cbor_array_size(arr), 1);
- assert_true(res.read == 2);
- assert_int_equal(cbor_array_allocated(arr), 1);
- /* Check the values */
- assert_uint8(cbor_array_handle(arr)[0], 1);
- cbor_item_t *intermediate = cbor_array_get(arr, 0);
- assert_uint8(intermediate, 1);
-
- cbor_item_t *new_val = cbor_build_uint8(10);
- assert_false(cbor_array_set(arr, 1, new_val));
- assert_false(cbor_array_set(arr, 3, new_val));
- cbor_decref(&new_val);
-
- cbor_decref(&arr);
- cbor_decref(&intermediate);
- assert_null(arr);
- assert_null(intermediate);
-}
-
-unsigned char data3[] = {0x82, 0x01, 0x81, 0x01, 0xFF};
-
-static void test_nested_arrays(void **state) {
- arr = cbor_load(data3, 5, &res);
- assert_non_null(arr);
- assert_true(cbor_typeof(arr) == CBOR_TYPE_ARRAY);
- assert_true(cbor_isa_array(arr));
- assert_true(cbor_array_size(arr) == 2);
- assert_true(res.read == 4);
- /* Check the values */
- assert_uint8(cbor_array_handle(arr)[0], 1);
-
- cbor_item_t *nested = cbor_array_handle(arr)[1];
- assert_true(cbor_isa_array(nested));
- assert_true(cbor_array_size(nested) == 1);
- assert_uint8(cbor_array_handle(nested)[0], 1);
-
- cbor_decref(&arr);
- assert_null(arr);
-}
-
-unsigned char test_indef_arrays_data[] = {0x9f, 0x01, 0x02, 0xFF};
-
-static void test_indef_arrays(void **state) {
- arr = cbor_load(test_indef_arrays_data, 4, &res);
- assert_non_null(arr);
- assert_true(cbor_typeof(arr) == CBOR_TYPE_ARRAY);
- assert_true(cbor_isa_array(arr));
- assert_true(cbor_array_size(arr) == 2);
- assert_true(res.read == 4);
- /* Check the values */
- assert_uint8(cbor_array_handle(arr)[0], 1);
- assert_uint8(cbor_array_handle(arr)[1], 2);
-
- assert_true(cbor_array_set(arr, 1, cbor_move(cbor_build_uint8(10))));
-
- cbor_decref(&arr);
- assert_null(arr);
-}
-
-unsigned char test_nested_indef_arrays_data[] = {0x9f, 0x01, 0x9f, 0x02,
- 0xFF, 0x03, 0xFF};
-
-static void test_nested_indef_arrays(void **state) {
- arr = cbor_load(test_nested_indef_arrays_data, 7, &res);
- assert_non_null(arr);
- assert_true(cbor_typeof(arr) == CBOR_TYPE_ARRAY);
- assert_true(cbor_isa_array(arr));
- assert_int_equal(cbor_array_size(arr), 3);
- assert_true(res.read == 7);
- /* Check the values */
- assert_uint8(cbor_array_handle(arr)[0], 1);
-
- cbor_item_t *nested = cbor_array_handle(arr)[1];
- assert_true(cbor_isa_array(nested));
- assert_true(cbor_array_size(nested) == 1);
- assert_uint8(cbor_array_handle(nested)[0], 2);
-
- cbor_decref(&arr);
- assert_null(arr);
-}
-
-int main(void) {
- const struct CMUnitTest tests[] = {
- cmocka_unit_test(test_empty_array), cmocka_unit_test(test_simple_array),
- cmocka_unit_test(test_nested_arrays), cmocka_unit_test(test_indef_arrays),
- cmocka_unit_test(test_nested_indef_arrays)};
- return cmocka_run_group_tests(tests, NULL, NULL);
-}
diff --git a/test/type_7_encoders_test.c b/test/type_7_encoders_test.c
deleted file mode 100644
index e06ea50a4d79..000000000000
--- a/test/type_7_encoders_test.c
+++ /dev/null
@@ -1,109 +0,0 @@
-/*
- * Copyright (c) 2014-2020 Pavel Kalvoda <me@pavelkalvoda.com>
- *
- * libcbor is free software; you can redistribute it and/or modify
- * it under the terms of the MIT license. See LICENSE for details.
- */
-
-#include <setjmp.h>
-#include <stdarg.h>
-#include <stddef.h>
-
-#include <cmocka.h>
-
-#include <math.h>
-#include "cbor.h"
-
-unsigned char buffer[512];
-
-static void test_bools(void **state) {
- assert_int_equal(1, cbor_encode_bool(false, buffer, 512));
- assert_memory_equal(buffer, ((unsigned char[]){0xF4}), 1);
- assert_int_equal(1, cbor_encode_bool(true, buffer, 512));
- assert_memory_equal(buffer, ((unsigned char[]){0xF5}), 1);
-}
-
-static void test_null(void **state) {
- assert_int_equal(1, cbor_encode_null(buffer, 512));
- assert_memory_equal(buffer, ((unsigned char[]){0xF6}), 1);
-}
-
-static void test_undef(void **state) {
- assert_int_equal(1, cbor_encode_undef(buffer, 512));
- assert_memory_equal(buffer, ((unsigned char[]){0xF7}), 1);
-}
-
-static void test_break(void **state) {
- assert_int_equal(1, cbor_encode_break(buffer, 512));
- assert_memory_equal(buffer, ((unsigned char[]){0xFF}), 1);
-}
-
-static void test_half(void **state) {
- assert_int_equal(3, cbor_encode_half(1.5f, buffer, 512));
- assert_memory_equal(buffer, ((unsigned char[]){0xF9, 0x3E, 0x00}), 3);
-
- assert_int_equal(3, cbor_encode_half(-0.0f, buffer, 512));
- assert_memory_equal(buffer, ((unsigned char[]){0xF9, 0x80, 0x00}), 3);
-
- assert_int_equal(3, cbor_encode_half(0.0f, buffer, 512));
- assert_memory_equal(buffer, ((unsigned char[]){0xF9, 0x00, 0x00}), 3);
-
- assert_int_equal(3, cbor_encode_half(65504.0f, buffer, 512));
- assert_memory_equal(buffer, ((unsigned char[]){0xF9, 0x7B, 0xFF}), 3);
-
- assert_int_equal(3, cbor_encode_half(0.00006103515625f, buffer, 512));
- assert_memory_equal(buffer, ((unsigned char[]){0xF9, 0x04, 0x00}), 3);
-
- assert_int_equal(3, cbor_encode_half(-4.0f, buffer, 512));
- assert_memory_equal(buffer, ((unsigned char[]){0xF9, 0xC4, 0x00}), 3);
-
- /* Smallest representable value */
- assert_int_equal(3, cbor_encode_half(5.960464477539063e-8f, buffer, 512));
- assert_memory_equal(buffer, ((unsigned char[]){0xF9, 0x00, 0x01}), 3);
-
- /* Smaller than the smallest, approximate magnitude representation */
- assert_int_equal(3, cbor_encode_half(5.960464477539062e-8f, buffer, 512));
- assert_memory_equal(buffer, ((unsigned char[]){0xF9, 0x00, 0x01}), 3);
-
- /* Smaller than the smallest and even the magnitude cannot be represented,
- round off to zero */
- assert_int_equal(3, cbor_encode_half(1e-25f, buffer, 512));
- assert_memory_equal(buffer, ((unsigned char[]){0xF9, 0x00, 0x00}), 3);
-
- assert_int_equal(3, cbor_encode_half(1.1920928955078125e-7, buffer, 512));
- assert_memory_equal(buffer, ((unsigned char[]){0xF9, 0x00, 0x02}), 3);
-
- assert_int_equal(3, cbor_encode_half(-1.1920928955078124e-7, buffer, 512));
- assert_memory_equal(buffer, ((unsigned char[]){0xF9, 0x80, 0x02}), 3);
-
- assert_int_equal(3, cbor_encode_half(INFINITY, buffer, 512));
- assert_memory_equal(buffer, ((unsigned char[]){0xF9, 0x7C, 0x00}), 3);
-}
-
-static void test_half_special(void **state) {
- assert_int_equal(3, cbor_encode_half(NAN, buffer, 512));
- assert_memory_equal(buffer, ((unsigned char[]){0xF9, 0x7E, 0x00}), 3);
-}
-
-static void test_float(void **state) {
- assert_int_equal(5, cbor_encode_single(3.4028234663852886e+38, buffer, 512));
- assert_memory_equal(buffer, ((unsigned char[]){0xFA, 0x7F, 0x7F, 0xFF, 0xFF}),
- 5);
-}
-
-static void test_double(void **state) {
- assert_int_equal(9, cbor_encode_double(1.0e+300, buffer, 512));
- assert_memory_equal(
- buffer,
- ((unsigned char[]){0xFB, 0x7E, 0x37, 0xE4, 0x3C, 0x88, 0x00, 0x75, 0x9C}),
- 9);
-}
-
-int main(void) {
- const struct CMUnitTest tests[] = {
- cmocka_unit_test(test_bools), cmocka_unit_test(test_null),
- cmocka_unit_test(test_undef), cmocka_unit_test(test_break),
- cmocka_unit_test(test_half), cmocka_unit_test(test_float),
- cmocka_unit_test(test_double), cmocka_unit_test(test_half_special)};
- return cmocka_run_group_tests(tests, NULL, NULL);
-}
diff --git a/test/type_0_encoders_test.c b/test/uint_encoders_test.c
index d6f2c15ef8b5..59b95a33026e 100644
--- a/test/type_0_encoders_test.c
+++ b/test/uint_encoders_test.c
@@ -5,61 +5,57 @@
* it under the terms of the MIT license. See LICENSE for details.
*/
-#include <setjmp.h>
-#include <stdarg.h>
-#include <stddef.h>
-
-#include <cmocka.h>
-
+#include "assertions.h"
#include "cbor.h"
unsigned char buffer[512];
-static void test_embedded_uint8(void **state) {
- assert_int_equal(1, cbor_encode_uint8(14, buffer, 512));
+static void test_embedded_uint8(void **_CBOR_UNUSED(_state)) {
+ assert_size_equal(1, cbor_encode_uint8(14, buffer, 512));
assert_memory_equal(buffer, (unsigned char[]){0x0E}, 1);
}
-static void test_uint8(void **state) {
- assert_int_equal(0, cbor_encode_uint8(180, buffer, 1));
- assert_int_equal(2, cbor_encode_uint8(255, buffer, 512));
+static void test_uint8(void **_CBOR_UNUSED(_state)) {
+ assert_size_equal(0, cbor_encode_uint8(180, buffer, 1));
+ assert_size_equal(2, cbor_encode_uint8(255, buffer, 512));
assert_memory_equal(buffer, ((unsigned char[]){0x18, 0xFF}), 2);
}
-static void test_uint16(void **state) {
- assert_int_equal(0, cbor_encode_uint16(1000, buffer, 2));
- assert_int_equal(3, cbor_encode_uint16(1000, buffer, 512));
+static void test_uint16(void **_CBOR_UNUSED(_state)) {
+ assert_size_equal(0, cbor_encode_uint16(1000, buffer, 2));
+ assert_size_equal(3, cbor_encode_uint16(1000, buffer, 512));
assert_memory_equal(buffer, ((unsigned char[]){0x19, 0x03, 0xE8}), 3);
}
-static void test_uint32(void **state) {
- assert_int_equal(0, cbor_encode_uint32(1000000, buffer, 4));
- assert_int_equal(5, cbor_encode_uint32(1000000, buffer, 512));
+static void test_uint32(void **_CBOR_UNUSED(_state)) {
+ assert_size_equal(0, cbor_encode_uint32(1000000, buffer, 4));
+ assert_size_equal(5, cbor_encode_uint32(1000000, buffer, 512));
assert_memory_equal(buffer, ((unsigned char[]){0x1A, 0x00, 0x0F, 0x42, 0x40}),
5);
}
-static void test_uint64(void **state) {
- assert_int_equal(0, cbor_encode_uint64(18446744073709551615ULL, buffer, 8));
- assert_int_equal(9, cbor_encode_uint64(18446744073709551615ULL, buffer, 512));
+static void test_uint64(void **_CBOR_UNUSED(_state)) {
+ assert_size_equal(0, cbor_encode_uint64(18446744073709551615ULL, buffer, 8));
+ assert_size_equal(9,
+ cbor_encode_uint64(18446744073709551615ULL, buffer, 512));
assert_memory_equal(
buffer,
((unsigned char[]){0x1B, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}),
9);
}
-static void test_unspecified(void **state) {
- assert_int_equal(9, cbor_encode_uint(18446744073709551615ULL, buffer, 512));
+static void test_unspecified(void **_CBOR_UNUSED(_state)) {
+ assert_size_equal(9, cbor_encode_uint(18446744073709551615ULL, buffer, 512));
assert_memory_equal(
buffer,
((unsigned char[]){0x1B, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}),
9);
- assert_int_equal(5, cbor_encode_uint(1000000, buffer, 512));
+ assert_size_equal(5, cbor_encode_uint(1000000, buffer, 512));
assert_memory_equal(buffer, ((unsigned char[]){0x1A, 0x00, 0x0F, 0x42, 0x40}),
5);
- assert_int_equal(3, cbor_encode_uint(1000, buffer, 512));
+ assert_size_equal(3, cbor_encode_uint(1000, buffer, 512));
assert_memory_equal(buffer, ((unsigned char[]){0x19, 0x03, 0xE8}), 3);
- assert_int_equal(2, cbor_encode_uint(255, buffer, 512));
+ assert_size_equal(2, cbor_encode_uint(255, buffer, 512));
assert_memory_equal(buffer, ((unsigned char[]){0x18, 0xFF}), 2);
}
diff --git a/test/type_0_test.c b/test/uint_test.c
index 8f7e480b7a62..89eb2b91833e 100644
--- a/test/type_0_test.c
+++ b/test/uint_test.c
@@ -5,11 +5,8 @@
* it under the terms of the MIT license. See LICENSE for details.
*/
-#include <setjmp.h>
-#include <stdarg.h>
-#include <stddef.h>
-
-#include <cmocka.h>
+#include "assertions.h"
+#include "test_allocator.h"
#include "cbor.h"
@@ -23,7 +20,7 @@ unsigned char data4[] = {0x1a, 0xa5, 0xf7, 0x02, 0xb3, 0xFF};
unsigned char data5[] = {0x1b, 0xa5, 0xf7, 0x02, 0xb3,
0xa5, 0xf7, 0x02, 0xb3, 0xFF};
-static void test_very_short_int(void **state) {
+static void test_very_short_int(void **_CBOR_UNUSED(_state)) {
number = cbor_load(data1, 2, &res);
assert_true(cbor_typeof(number) == CBOR_TYPE_UINT);
assert_true(cbor_int_get_width(number) == CBOR_INT_8);
@@ -37,13 +34,13 @@ static void test_very_short_int(void **state) {
assert_null(number);
}
-static void test_incomplete_data(void **state) {
+static void test_incomplete_data(void **_CBOR_UNUSED(_state)) {
number = cbor_load(data2, 1, &res);
assert_null(number);
assert_true(res.error.code == CBOR_ERR_NOTENOUGHDATA);
}
-static void test_short_int(void **state) {
+static void test_short_int(void **_CBOR_UNUSED(_state)) {
number = cbor_load(data2, 3, &res);
assert_true(cbor_typeof(number) == CBOR_TYPE_UINT);
assert_true(cbor_int_get_width(number) == CBOR_INT_8);
@@ -57,7 +54,7 @@ static void test_short_int(void **state) {
assert_null(number);
}
-static void test_half_int(void **state) {
+static void test_half_int(void **_CBOR_UNUSED(_state)) {
number = cbor_load(data3, 5, &res);
assert_true(cbor_typeof(number) == CBOR_TYPE_UINT);
assert_true(cbor_int_get_width(number) == CBOR_INT_16);
@@ -71,7 +68,7 @@ static void test_half_int(void **state) {
assert_null(number);
}
-static void test_int(void **state) {
+static void test_int(void **_CBOR_UNUSED(_state)) {
number = cbor_load(data4, 6, &res);
assert_true(cbor_typeof(number) == CBOR_TYPE_UINT);
assert_true(cbor_int_get_width(number) == CBOR_INT_32);
@@ -85,7 +82,7 @@ static void test_int(void **state) {
assert_null(number);
}
-static void test_long_int(void **state) {
+static void test_long_int(void **_CBOR_UNUSED(_state)) {
number = cbor_load(data5, 10, &res);
assert_true(cbor_typeof(number) == CBOR_TYPE_UINT);
assert_true(cbor_int_get_width(number) == CBOR_INT_64);
@@ -99,7 +96,7 @@ static void test_long_int(void **state) {
assert_null(number);
}
-static void test_refcounting(void **state) {
+static void test_refcounting(void **_CBOR_UNUSED(_state)) {
number = cbor_load(data5, 10, &res);
cbor_incref(number);
assert_true(number->refcount == 2);
@@ -109,13 +106,13 @@ static void test_refcounting(void **state) {
assert_null(number);
}
-static void test_empty_input(void **state) {
+static void test_empty_input(void **_CBOR_UNUSED(_state)) {
number = cbor_load(data5, 0, &res);
assert_null(number);
assert_true(res.error.code == CBOR_ERR_NODATA);
}
-static void test_inline_creation(void **state) {
+static void test_inline_creation(void **_CBOR_UNUSED(_state)) {
number = cbor_build_uint8(10);
assert_true(cbor_get_int(number) == 10);
cbor_decref(&number);
@@ -133,15 +130,30 @@ static void test_inline_creation(void **state) {
cbor_decref(&number);
}
+static void test_int_creation(void **_CBOR_UNUSED(_state)) {
+ WITH_FAILING_MALLOC({ assert_null(cbor_new_int8()); });
+ WITH_FAILING_MALLOC({ assert_null(cbor_new_int16()); });
+ WITH_FAILING_MALLOC({ assert_null(cbor_new_int32()); });
+ WITH_FAILING_MALLOC({ assert_null(cbor_new_int64()); });
+
+ WITH_FAILING_MALLOC({ assert_null(cbor_build_uint8(0xFF)); });
+ WITH_FAILING_MALLOC({ assert_null(cbor_build_uint16(0xFF)); });
+ WITH_FAILING_MALLOC({ assert_null(cbor_build_uint32(0xFF)); });
+ WITH_FAILING_MALLOC({ assert_null(cbor_build_uint64(0xFF)); });
+}
+
int main(void) {
- const struct CMUnitTest tests[] = {cmocka_unit_test(test_very_short_int),
- cmocka_unit_test(test_short_int),
- cmocka_unit_test(test_half_int),
- cmocka_unit_test(test_int),
- cmocka_unit_test(test_long_int),
- cmocka_unit_test(test_incomplete_data),
- cmocka_unit_test(test_refcounting),
- cmocka_unit_test(test_empty_input),
- cmocka_unit_test(test_inline_creation)};
+ const struct CMUnitTest tests[] = {
+ cmocka_unit_test(test_very_short_int),
+ cmocka_unit_test(test_short_int),
+ cmocka_unit_test(test_half_int),
+ cmocka_unit_test(test_int),
+ cmocka_unit_test(test_long_int),
+ cmocka_unit_test(test_incomplete_data),
+ cmocka_unit_test(test_refcounting),
+ cmocka_unit_test(test_empty_input),
+ cmocka_unit_test(test_inline_creation),
+ cmocka_unit_test(test_int_creation),
+ };
return cmocka_run_group_tests(tests, NULL, NULL);
}
diff --git a/test/unicode_test.c b/test/unicode_test.c
index 84afe45fbcfe..4b3613e77f78 100644
--- a/test/unicode_test.c
+++ b/test/unicode_test.c
@@ -5,31 +5,32 @@
* it under the terms of the MIT license. See LICENSE for details.
*/
-#include <setjmp.h>
-#include <stdarg.h>
-#include <stddef.h>
-
-#include <cmocka.h>
+#include "assertions.h"
#include "../src/cbor/internal/unicode.h"
-
struct _cbor_unicode_status status;
unsigned char missing_bytes_data[] = {0xC4, 0x8C};
/* Capital accented C */
-static void test_missing_bytes(void **state) {
- _cbor_unicode_codepoint_count(missing_bytes_data, 1, &status);
+static void test_missing_bytes(void **_CBOR_UNUSED(_state)) {
+ assert_true(_cbor_unicode_codepoint_count(missing_bytes_data, 1, &status) ==
+ 0);
assert_true(status.status == _CBOR_UNICODE_BADCP);
- _cbor_unicode_codepoint_count(missing_bytes_data, 2, &status);
+ assert_true(status.location == 1);
+
+ assert_true(_cbor_unicode_codepoint_count(missing_bytes_data, 2, &status) ==
+ 1);
assert_true(status.status == _CBOR_UNICODE_OK);
+ assert_true(status.location == 0);
}
unsigned char invalid_sequence_data[] = {0x65, 0xC4, 0x00};
/* e, invalid seq */
-static void test_invalid_sequence(void **state) {
- _cbor_unicode_codepoint_count(invalid_sequence_data, 3, &status);
+static void test_invalid_sequence(void **_CBOR_UNUSED(_state)) {
+ assert_true(
+ _cbor_unicode_codepoint_count(invalid_sequence_data, 3, &status) == 0);
assert_true(status.status == _CBOR_UNICODE_BADCP);
assert_true(status.location == 2);
}