mirror of
https://git.FreeBSD.org/src.git
synced 2024-10-18 02:19:39 +00:00
libcbor: update to 0.10.2
Sponsored by: The FreeBSD Foundation
(cherry picked from commit 5d3e7166f6
)
This commit is contained in:
parent
d578a19e2c
commit
5300b20934
224
contrib/libcbor/.circleci/config.yml
Normal file
224
contrib/libcbor/.circleci/config.yml
Normal file
@ -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]
|
20
contrib/libcbor/.github/ISSUE_TEMPLATE/bug_report.md
vendored
Normal file
20
contrib/libcbor/.github/ISSUE_TEMPLATE/bug_report.md
vendored
Normal file
@ -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).
|
15
contrib/libcbor/.github/PULL_REQUEST_TEMPLATE
vendored
Normal file
15
contrib/libcbor/.github/PULL_REQUEST_TEMPLATE
vendored
Normal file
@ -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?
|
25
contrib/libcbor/.github/workflows/fuzz-pr.yml
vendored
Normal file
25
contrib/libcbor/.github/workflows/fuzz-pr.yml
vendored
Normal file
@ -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
|
6
contrib/libcbor/.github/workflows/fuzz.yml
vendored
6
contrib/libcbor/.github/workflows/fuzz.yml
vendored
@ -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
|
||||
|
8
contrib/libcbor/.gitignore
vendored
8
contrib/libcbor/.gitignore
vendored
@ -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
|
||||
|
@ -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
|
100
contrib/libcbor/Bazel.md
Normal file
100
contrib/libcbor/Bazel.md
Normal file
@ -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;
|
||||
```
|
@ -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))
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
23
contrib/libcbor/CMakeModules/JoinPaths.cmake
Normal file
23
contrib/libcbor/CMakeModules/JoinPaths.cmake
Normal file
@ -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()
|
35
contrib/libcbor/CONTRIBUTING.md
Normal file
35
contrib/libcbor/CONTRIBUTING.md
Normal file
@ -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)
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -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);
|
||||
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, length, stdout);
|
||||
free(buffer);
|
||||
fwrite(buffer, 1, buffer_size, stdout);
|
||||
free(buffer);
|
||||
|
||||
fflush(stdout);
|
||||
cbor_decref(&root);
|
||||
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)!
|
||||
|
||||
|
@ -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
|
@ -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}
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
65
contrib/libcbor/doc/source/api/streaming_encoding.rst
Normal file
65
contrib/libcbor/doc/source/api/streaming_encoding.rst
Normal file
@ -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
|
||||
|
@ -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
|
||||
~~~~~~~~~~~~~~~~~
|
||||
|
||||
|
@ -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
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
@ -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
|
||||
~~~~~~~~~~~~~~~~~
|
||||
|
@ -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
|
||||
~~~~~~~~~~~~~~~~~
|
||||
|
@ -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.
|
||||
|
@ -76,8 +76,8 @@
|
||||
# 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.
|
||||
|
@ -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
|
||||
|
@ -30,7 +30,6 @@ Contents
|
||||
getting_started
|
||||
using
|
||||
api
|
||||
streaming
|
||||
tests
|
||||
rfc_conformance
|
||||
internal
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
---------------------------------
|
||||
|
@ -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
|
@ -1,4 +0,0 @@
|
||||
Encoding
|
||||
=============================
|
||||
|
||||
TODO
|
@ -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);
|
||||
|
@ -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)
|
||||
|
||||
|
33
contrib/libcbor/examples/bazel/README.md
Normal file
33
contrib/libcbor/examples/bazel/README.md
Normal file
@ -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
|
||||
```
|
19
contrib/libcbor/examples/bazel/WORKSPACE
Normal file
19
contrib/libcbor/examples/bazel/WORKSPACE
Normal file
@ -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",
|
||||
)
|
||||
|
46
contrib/libcbor/examples/bazel/src/BUILD
Normal file
46
contrib/libcbor/examples/bazel/src/BUILD
Normal file
@ -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",
|
||||
],
|
||||
)
|
||||
|
7
contrib/libcbor/examples/bazel/src/hello.cc
Normal file
7
contrib/libcbor/examples/bazel/src/hello.cc
Normal file
@ -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);
|
||||
}
|
8
contrib/libcbor/examples/bazel/src/hello.h
Normal file
8
contrib/libcbor/examples/bazel/src/hello.h
Normal file
@ -0,0 +1,8 @@
|
||||
#ifndef HELLO_H_
|
||||
#define HELLO_H_
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
void print_cbor_version(void);
|
||||
|
||||
#endif // HELLO_H_
|
10
contrib/libcbor/examples/bazel/src/hello_test.cc
Normal file
10
contrib/libcbor/examples/bazel/src/hello_test.cc
Normal file
@ -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);
|
||||
}
|
||||
|
10
contrib/libcbor/examples/bazel/src/main.cc
Normal file
10
contrib/libcbor/examples/bazel/src/main.cc
Normal file
@ -0,0 +1,10 @@
|
||||
#include "src/hello.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
int main() {
|
||||
print_cbor_version();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
1
contrib/libcbor/examples/bazel/third_party/BUILD
vendored
Normal file
1
contrib/libcbor/examples/bazel/third_party/BUILD
vendored
Normal file
@ -0,0 +1 @@
|
||||
exports_files(["libcbor.BUILD"])
|
21
contrib/libcbor/examples/bazel/third_party/libcbor.BUILD
vendored
Normal file
21
contrib/libcbor/examples/bazel/third_party/libcbor.BUILD
vendored
Normal file
@ -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",
|
||||
],
|
||||
)
|
11
contrib/libcbor/examples/bazel/third_party/libcbor/BUILD
vendored
Normal file
11
contrib/libcbor/examples/bazel/third_party/libcbor/BUILD
vendored
Normal file
@ -0,0 +1,11 @@
|
||||
cc_library(
|
||||
name = "config",
|
||||
hdrs = [
|
||||
"cbor/cbor_export.h",
|
||||
"cbor/configuration.h",
|
||||
],
|
||||
includes = [
|
||||
"./",
|
||||
],
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
42
contrib/libcbor/examples/bazel/third_party/libcbor/cbor/cbor_export.h
vendored
Normal file
42
contrib/libcbor/examples/bazel/third_party/libcbor/cbor/cbor_export.h
vendored
Normal file
@ -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 */
|
15
contrib/libcbor/examples/bazel/third_party/libcbor/cbor/configuration.h
vendored
Normal file
15
contrib/libcbor/examples/bazel/third_party/libcbor/cbor/configuration.h
vendored
Normal file
@ -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
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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(
|
||||
|
@ -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);
|
||||
|
47
contrib/libcbor/examples/streaming_array.c
Normal file
47
contrib/libcbor/examples/streaming_array.c
Normal file
@ -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);
|
||||
}
|
@ -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;
|
||||
|
@ -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 @@
|
||||
|
||||
|
||||
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 @@ def replace(file_path, pattern, replacement):
|
||||
|
||||
# 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 = '.*'
|
||||
|
@ -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
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
return malloc(size);
|
||||
if (size == 0) {
|
||||
return nullptr;
|
||||
}
|
||||
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);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -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
|
||||
|
@ -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")
|
||||
|
@ -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;
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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>
|
||||
|
@ -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){
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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,
|
||||
};
|
||||
|
@ -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 *);
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
*
|
||||
* No dependent items are affected.
|
||||
* Constant complexity; items referring to this one or items being referred to
|
||||
* are not updated.
|
||||
*
|
||||
* @param item[incref] item the item
|
||||
* @return the input reference
|
||||
* This function can be used to extend reference counting to client code.
|
||||
*
|
||||
* @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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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) |
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
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);
|
||||
}
|
||||
} else {
|
||||
/* Indefinite array, don't bother with subitems */
|
||||
if (!cbor_array_push(ctx->stack->top->item, item)) {
|
||||
ctx->creation_failed = true;
|
||||
}
|
||||
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));
|
||||
}
|
||||
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 */
|
||||
}
|
||||
break;
|
||||
}
|
||||
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;
|
||||
}
|
||||
default: {
|
||||
cbor_decref(&item);
|
||||
ctx->syntax_error = true;
|
||||
}
|
||||
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;
|
||||
}
|
||||
}
|
||||
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;
|
||||
cbor_string_set_handle(new_chunk, new_handle, length);
|
||||
new_chunk->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;
|
||||
// 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);
|
||||
}
|
||||
|
@ -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 *);
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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};
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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,
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
/** Largest integer that can be encoded as embedded in the item leading byte. */
|
||||
const uint64_t kMaxEmbeddedInt = 23;
|
||||
|
||||
/** 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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
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;
|
||||
}
|
||||
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) {
|
||||
size_t bfr_size = 32;
|
||||
unsigned char *bfr = _CBOR_MALLOC(bfr_size), *tmp_bfr;
|
||||
if (bfr == NULL) {
|
||||
*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;
|
||||
}
|
||||
|
||||
size_t written;
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
tmp_bfr = _CBOR_REALLOC(bfr, bfr_size *= 2);
|
||||
|
||||
if (tmp_bfr == NULL) {
|
||||
_CBOR_FREE(bfr);
|
||||
return 0;
|
||||
}
|
||||
bfr = tmp_bfr;
|
||||
}
|
||||
*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;
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user