libcbor: vendor update to 0.11.0

Sponsored by:	The FreeBSD Foundation
This commit is contained in:
Ed Maste 2024-05-03 19:33:50 -04:00
commit abd872540f
44 changed files with 748 additions and 215 deletions

View file

@ -4,12 +4,14 @@ commands:
linux-setup: linux-setup:
steps: steps:
- run: sudo apt-get update - run: sudo apt-get update
- run: sudo apt-get install -y cmake ${TOOLCHAIN_PACKAGES} # NEEDRESTART_MODE prevents automatic restarts which seem to hang.
- run: sudo apt install libcmocka-dev - run: sudo NEEDRESTART_MODE=l apt-get install -y cmake ${TOOLCHAIN_PACKAGES}
- run: sudo NEEDRESTART_MODE=l apt-get install -y libcmocka-dev libcjson-dev
build: build:
steps: steps:
- run: > - run: >
cmake -DWITH_TESTS=ON \ cmake -DWITH_TESTS=ON \
-DWITH_EXAMPLES=ON \
-DCMAKE_BUILD_TYPE=Debug \ -DCMAKE_BUILD_TYPE=Debug \
-DSANITIZE=OFF \ -DSANITIZE=OFF \
-DCOVERAGE="${CMAKE_COVERAGE:='OFF'}" \ -DCOVERAGE="${CMAKE_COVERAGE:='OFF'}" \
@ -31,14 +33,14 @@ orbs:
jobs: jobs:
static-test: static-test:
machine: machine: &default-machine
image: ubuntu-2204:2022.10.2 image: ubuntu-2204:2023.07.2
environment: environment:
TOOLCHAIN_PACKAGES: g++ TOOLCHAIN_PACKAGES: g++
steps: steps:
- checkout - checkout
- linux-setup - linux-setup
- run: sudo apt-get install -y clang-format doxygen cppcheck - run: sudo NEEDRESTART_MODE=l apt-get install -y clang-format doxygen cppcheck
- run: cppcheck --inline-suppr --error-exitcode=1 . - run: cppcheck --inline-suppr --error-exitcode=1 .
- run: bash clang-format.sh --verbose - run: bash clang-format.sh --verbose
- run: > - run: >
@ -60,14 +62,14 @@ jobs:
build-and-test: build-and-test:
machine: machine:
image: ubuntu-2204:2022.10.2 <<: *default-machine
environment: environment:
TOOLCHAIN_PACKAGES: g++ TOOLCHAIN_PACKAGES: g++
CMAKE_COVERAGE: ON CMAKE_COVERAGE: ON
steps: steps:
- checkout - checkout
- linux-setup - linux-setup
- run: sudo apt-get install -y valgrind - run: sudo NEEDRESTART_MODE=l apt-get install -y valgrind
- build - build
- test - test
- run: ctest -T Coverage - run: ctest -T Coverage
@ -81,7 +83,7 @@ jobs:
build-and-test-clang: build-and-test-clang:
machine: machine:
image: ubuntu-2204:2022.10.2 <<: *default-machine
environment: environment:
TOOLCHAIN_PACKAGES: clang TOOLCHAIN_PACKAGES: clang
CC: clang CC: clang
@ -94,11 +96,11 @@ jobs:
build-and-test-32b: build-and-test-32b:
machine: machine:
image: ubuntu-2204:2022.10.2 <<: *default-machine
steps: steps:
- checkout - checkout
- run: sudo apt-get update - run: sudo apt-get update
- run: sudo apt-get install -y cmake gcc-multilib g++-multilib libc6-dev-i386 - run: sudo NEEDRESTART_MODE=l apt-get install -y cmake gcc-multilib g++-multilib libc6-dev-i386
# Make cmocka from source w/ 32b setup # Make cmocka from source w/ 32b setup
- run: git clone https://git.cryptomilk.org/projects/cmocka.git ~/cmocka - run: git clone https://git.cryptomilk.org/projects/cmocka.git ~/cmocka
- run: > - run: >
@ -117,7 +119,7 @@ jobs:
build-and-test-release-clang: build-and-test-release-clang:
machine: machine:
image: ubuntu-2204:2022.10.2 <<: *default-machine
environment: environment:
TOOLCHAIN_PACKAGES: clang TOOLCHAIN_PACKAGES: clang
CC: clang CC: clang
@ -130,7 +132,7 @@ jobs:
llvm-coverage: llvm-coverage:
machine: machine:
image: ubuntu-2204:2022.10.2 <<: *default-machine
environment: environment:
TOOLCHAIN_PACKAGES: clang TOOLCHAIN_PACKAGES: clang
CC: clang CC: clang
@ -145,7 +147,7 @@ jobs:
build-and-test-arm: build-and-test-arm:
machine: machine:
image: ubuntu-2204:2022.10.2 <<: *default-machine
environment: environment:
TOOLCHAIN_PACKAGES: g++ TOOLCHAIN_PACKAGES: g++
resource_class: arm.medium resource_class: arm.medium
@ -157,7 +159,7 @@ jobs:
build-bazel: build-bazel:
machine: machine:
image: ubuntu-2204:2022.10.2 image: ubuntu-2204:2023.07.2
environment: environment:
TOOLCHAIN_PACKAGES: g++ TOOLCHAIN_PACKAGES: g++
steps: steps:

View file

@ -0,0 +1,26 @@
freebsd_task:
install_script:
- ASSUME_ALWAYS_YES=yes pkg bootstrap -f && pkg install -y cmocka cmake ninja
build_script:
- mkdir build
- cd build
- cmake -GNinja -DWITH_TESTS=ON
-DCBOR_CUSTOM_ALLOC=ON
-DCMAKE_BUILD_TYPE=Debug
-DSANITIZE=OFF
..
- ninja -j $(sysctl -n hw.ncpu)
test_script:
- cd build
- ctest -VV
matrix:
# From gcloud compute images list --project freebsd-org-cloud-dev --no-standard-images
- name: freebsd-13-2
freebsd_instance:
image_family: freebsd-13-2
- name: freebsd-14-0
freebsd_instance:
image_family: freebsd-14-0
- name: freebsd-15-0-snap
freebsd_instance:
image_family: freebsd-15-0-snap

View file

@ -0,0 +1,21 @@
# .readthedocs.yaml
# Read the Docs configuration file
# See https://docs.readthedocs.io/en/stable/config-file/v2.html for details
# Required
version: 2
# Set the version of Python and other tools you might need
build:
os: ubuntu-22.04
tools:
python: "3.11"
sphinx:
configuration: doc/source/conf.py
# We recommend specifying your dependencies to enable reproducible builds:
# https://docs.readthedocs.io/en/stable/guides/reproducible-builds.html
python:
install:
- requirements: doc/source/requirements.txt

View file

@ -4,6 +4,19 @@ Template:
Next Next
--------------------- ---------------------
0.11.0 (2024-02-04)
---------------------
- [Updated documentation to refer to RFC 8949](https://github.com/PJK/libcbor/issues/269)
- Improvements to `cbor_describe`
- [Bytestring data will now be printed as well](https://github.com/PJK/libcbor/pull/281) by [akallabeth](https://github.com/akallabeth)
- [Formatting consistency and clarity improvements](https://github.com/PJK/libcbor/pull/285)
- [Fix `cbor_string_set_handle` not setting the codepoint count](https://github.com/PJK/libcbor/pull/286)
- BREAKING: [`cbor_load` will no longer fail on input strings that are well-formed but not valid UTF-8](https://github.com/PJK/libcbor/pull/286)
- If you were relying on the validation, please check the result using `cbor_string_codepoint_count` instead
- BREAKING: [All decoders like `cbor_load` and `cbor_stream_decode` will accept all well-formed tag values](https://github.com/PJK/libcbor/pull/308) (bug discovered by [dskern-github](https://github.com/dskern-github))
- Previously, decoding of certain values would fail with `CBOR_ERR_MALFORMATED` or `CBOR_DECODER_ERROR`
- This also makes decoding symmetrical with serialization, which already accepts all values
0.10.2 (2023-01-31) 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)) - [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))
@ -117,7 +130,7 @@ Next
Breaks build & header compatibility due to: Breaks build & header compatibility due to:
- Improved build configuration and feature check macros - Improved build configuration and feature check macros
- Endianess configuration fixes (by Erwin Kroon and David Grigsby) - Endianness configuration fixes (by Erwin Kroon and David Grigsby)
- pkg-config compatibility (by Vincent Bernat) - pkg-config compatibility (by Vincent Bernat)
- enable use of versioned SONAME (by Vincent Bernat) - enable use of versioned SONAME (by Vincent Bernat)
- better fuzzer (wasn't random until now, ooops) - better fuzzer (wasn't random until now, ooops)

View file

@ -1,14 +1,18 @@
cmake_minimum_required(VERSION 3.0) cmake_minimum_required(VERSION 3.0)
project(libcbor) project(libcbor)
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/CMakeModules/") set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/CMakeModules/")
include(CTest) include(CTest)
include(GNUInstallDirs) # Provides CMAKE_INSTALL_ variables
SET(CBOR_VERSION_MAJOR "0") SET(CBOR_VERSION_MAJOR "0")
SET(CBOR_VERSION_MINOR "10") SET(CBOR_VERSION_MINOR "11")
SET(CBOR_VERSION_PATCH "2") SET(CBOR_VERSION_PATCH "0")
SET(CBOR_VERSION ${CBOR_VERSION_MAJOR}.${CBOR_VERSION_MINOR}.${CBOR_VERSION_PATCH}) SET(CBOR_VERSION ${CBOR_VERSION_MAJOR}.${CBOR_VERSION_MINOR}.${CBOR_VERSION_PATCH})
set(CMAKE_SKIP_INSTALL_ALL_DEPENDENCY true) option(CMAKE_SKIP_INSTALL_ALL_DEPENDENCY "cmake --build --target install does not depend on cmake --build" true)
option(BUILD_SHARED_LIBS "Build as a shared library" false)
include(CheckIncludeFiles) include(CheckIncludeFiles)
include(TestBigEndian) include(TestBigEndian)
@ -22,7 +26,7 @@ if(CBOR_CUSTOM_ALLOC)
message(WARNING message(WARNING
"CBOR_CUSTOM_ALLOC has been deprecated. Custom allocators are now enabled by default." "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. " "The flag is a no-op and will be removed in the next version. "
"Please remove CBOR_CUSTOM_ALLOC from your build configuation.") "Please remove CBOR_CUSTOM_ALLOC from your build configuration.")
endif(CBOR_CUSTOM_ALLOC) endif(CBOR_CUSTOM_ALLOC)
option(CBOR_PRETTY_PRINTER "Include a pretty-printing routine" ON) option(CBOR_PRETTY_PRINTER "Include a pretty-printing routine" ON)
@ -138,12 +142,10 @@ if (COVERAGE)
endif() endif()
endif (COVERAGE) endif (COVERAGE)
# We want to generate configuration.h from the template and make it so that it is accessible using the same # We want to generate configuration.h from the template and make it so that it is accessible using the same
# path during both library build and installed header use, without littering the source dir. # path during both library build and installed header use, without littering the source dir.
# Using cbor/configuration.h in the build dir works b/c headers will be installed to <prefix>/cbor
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/src/cbor/configuration.h.in ${PROJECT_BINARY_DIR}/cbor/configuration.h) configure_file(${CMAKE_CURRENT_SOURCE_DIR}/src/cbor/configuration.h.in ${PROJECT_BINARY_DIR}/cbor/configuration.h)
install(FILES ${PROJECT_BINARY_DIR}/cbor/configuration.h DESTINATION include/cbor) install(FILES ${PROJECT_BINARY_DIR}/cbor/configuration.h DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/cbor)
# Make the header visible at compile time # Make the header visible at compile time
include_directories(${PROJECT_BINARY_DIR}) include_directories(${PROJECT_BINARY_DIR})

View file

@ -2,7 +2,7 @@
libcbor is maintained by [@PJK](https://github.com/PJK) in his spare time on a best-effort basis. 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. 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 below.
## Principles ## Principles

View file

@ -48,7 +48,7 @@ PROJECT_NAME = libcbor
# could be handy for archiving the generated documentation or if some version # could be handy for archiving the generated documentation or if some version
# control system is used. # control system is used.
PROJECT_NUMBER = 0.10.2 PROJECT_NUMBER = 0.11.0
# Using the PROJECT_BRIEF tag one can provide an optional one line description # Using the PROJECT_BRIEF tag one can provide an optional one line description
# for a project that appears at the top of each page and should give viewer a # for a project that appears at the top of each page and should give viewer a

View file

@ -1,16 +1,15 @@
# [libcbor](https://github.com/PJK/libcbor) # [libcbor](https://github.com/PJK/libcbor)
[![CircleCI](https://circleci.com/gh/PJK/libcbor/tree/master.svg?style=svg)](https://circleci.com/gh/PJK/libcbor/tree/master) [![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) [![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) [![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) [![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](https://tools.ietf.org/html/rfc7049), the general-purpose schema-less binary data format. **libcbor** is a C library for parsing and generating [CBOR](https://cbor.io/), the general-purpose schema-less binary data format.
## Main features ## Main features
- Complete RFC conformance - Complete [IETF RFC 8949 (STD 94)](https://www.rfc-editor.org/info/std94) conformance
- Robust C99 implementation - Robust platform-independent C99 implementation
- Layered architecture offers both control and convenience - Layered architecture offers both control and convenience
- Flexible memory management - Flexible memory management
- No shared global state - threading friendly - No shared global state - threading friendly

View file

@ -1,14 +0,0 @@
image: Visual Studio 2022
version: '{build}'
platform: x64
skip_branch_with_pr: true
before_build:
- 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

View file

@ -1,7 +1,7 @@
Types of items Types of items
=============================================== ===============================================
Every :type:`cbor_item_t` has a :type:`cbor_type` associated with it - these constants correspond to the types specified by the `CBOR standard <http://tools.ietf.org/html/rfc7049>`_: Every :type:`cbor_item_t` has a :type:`cbor_type` associated with it - these constants correspond to the types specified by the `CBOR standard <https://www.rfc-editor.org/info/std94>`_:
.. doxygenenum:: cbor_type .. doxygenenum:: cbor_type

View file

@ -33,7 +33,8 @@
'breathe', 'breathe',
'sphinx.ext.mathjax', 'sphinx.ext.mathjax',
'sphinx.ext.autodoc', 'sphinx.ext.autodoc',
'sphinx.ext.ifconfig' 'sphinx.ext.ifconfig',
'sphinx_rtd_theme'
] ]
import subprocess, os import subprocess, os
@ -76,8 +77,8 @@
# built documents. # built documents.
# #
# The short X.Y version. # The short X.Y version.
version = '0.10' version = '0.11'
release = '0.10.2' release = '0.11.0'
# The language for content autogenerated by Sphinx. Refer to documentation # The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages. # for a list of supported languages.
@ -127,7 +128,7 @@
# The theme to use for HTML and HTML Help pages. See the documentation for # The theme to use for HTML and HTML Help pages. See the documentation for
# a list of builtin themes. # a list of builtin themes.
html_theme = 'default' html_theme = 'sphinx_rtd_theme'
# Theme options are theme-specific and customize the look and feel of a theme # Theme options are theme-specific and customize the look and feel of a theme
# further. For a list of options available for each theme, see the # further. For a list of options available for each theme, see the
@ -285,12 +286,3 @@
# If true, do not generate a @detailmenu in the "Top" node's menu. # If true, do not generate a @detailmenu in the "Top" node's menu.
#texinfo_no_detailmenu = False #texinfo_no_detailmenu = False
if not on_rtd: # only import and set the theme if we're building docs locally
import sphinx_rtd_theme
html_theme = 'sphinx_rtd_theme'
html_theme_path = [sphinx_rtd_theme.get_html_theme_path()]
# otherwise, readthedocs.org uses their theme by default, so no need to specify it

View file

@ -22,15 +22,15 @@ everywhere.
Goals Goals
~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~
RFC-conformance and full feature support Standard conformance and full feature support
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Anything the standard allows, libcbor can do. Anything the standard allows, libcbor can do.
**Why?** Because conformance and interoperability is the point of defining **Why?** Because conformance and interoperability is the point of defining
standards. Clients expect the support to be feature-complete and standards. Clients expect the support to be feature-complete and
there is no significant complexity reduction that can be achieved by slightly there is no significant complexity reduction that can be achieved by slightly
cutting corners, which means that the incremental cost of full RFC support is cutting corners, which means that the incremental cost of full [CBOR standard](https://www.rfc-editor.org/info/std94) support is
comparatively small over "almost-conformance" seen in many alternatives. comparatively small over "almost-conformance" seen in many alternatives.

View file

@ -9,7 +9,7 @@ Overview
Main features Main features
- Complete RFC conformance [#]_ - Complete `IETF RFC 8949 (STD 94) <https://www.rfc-editor.org/info/std94>`_ conformance [#]_
- Robust C99 implementation - Robust C99 implementation
- Layered architecture offers both control and convenience - Layered architecture offers both control and convenience
- Flexible memory management - Flexible memory management
@ -19,7 +19,7 @@ Main features
- Extensive documentation and test suite - Extensive documentation and test suite
- No runtime dependencies, small footprint - No runtime dependencies, small footprint
.. [#] See :doc:`rfc_conformance` .. [#] See :doc:`standard_conformance`
.. [#] With the exception of custom memory allocators (see :doc:`api/item_reference_counting`) .. [#] With the exception of custom memory allocators (see :doc:`api/item_reference_counting`)
@ -31,9 +31,9 @@ Contents
using using
api api
tests tests
rfc_conformance standard_conformance
internal internal
changelog changelog
development development
.. _CBOR: http://tools.ietf.org/html/rfc7049 .. _CBOR: https://www.rfc-editor.org/info/std94

View file

@ -6,7 +6,7 @@ Internal workings of *libcbor* are mostly derived from the specification. The pu
Terminology Terminology
--------------- ---------------
=== ====================== ======================================================================================================================================== === ====================== ========================================================================================================================================
MTB Major Type Byte http://tools.ietf.org/html/rfc7049#section-2.1 MTB Major Type Byte https://www.rfc-editor.org/rfc/rfc8949.html#section-3.1
--- ---------------------- ---------------------------------------------------------------------------------------------------------------------------------------- --- ---------------------- ----------------------------------------------------------------------------------------------------------------------------------------
DST Dynamically Sized Type Type whose storage requirements cannot be determined DST Dynamically Sized Type Type whose storage requirements cannot be determined
@ -32,7 +32,7 @@ and also borrowing from
General notes on the API design General notes on the API design
-------------------------------- --------------------------------
The API design has two main driving priciples: The API design has two main driving principles:
1. Let the client manage the memory as much as possible 1. Let the client manage the memory as much as possible
2. Behave exactly as specified by the standard 2. Behave exactly as specified by the standard

View file

@ -1,31 +1,31 @@
alabaster==0.7.12 alabaster==0.7.13
Babel==2.9.1 Babel==2.13.1
breathe==4.33.1 breathe==4.35.0
certifi==2022.12.7 certifi==2023.11.17
charset-normalizer==2.0.12 charset-normalizer==3.3.2
colorama==0.4.4 colorama==0.4.6
docutils==0.17.1 docutils==0.18.1
idna==3.3 idna==3.4
imagesize==1.3.0 imagesize==1.4.1
importlib-metadata==4.11.3 importlib-metadata==6.8.0
Jinja2==3.0.3 Jinja2==3.1.2
livereload==2.6.3 livereload==2.6.3
MarkupSafe==2.1.1 MarkupSafe==2.1.3
packaging==21.3 packaging==23.2
Pygments==2.11.2 Pygments==2.16.1
pyparsing==3.0.7 pyparsing==3.1.1
pytz==2021.3 pytz==2021.3
requests==2.27.1 requests==2.31.0
snowballstemmer==2.2.0 snowballstemmer==2.2.0
Sphinx==4.4.0 Sphinx==7.2.6
sphinx-autobuild==2021.3.14 sphinx-autobuild==2021.3.14
sphinx-rtd-theme==1.0.0 sphinx-rtd-theme==1.3.0
sphinxcontrib-applehelp==1.0.2 sphinxcontrib-applehelp==1.0.7
sphinxcontrib-devhelp==1.0.2 sphinxcontrib-devhelp==1.0.5
sphinxcontrib-htmlhelp==2.0.0 sphinxcontrib-htmlhelp==2.0.4
sphinxcontrib-jsmath==1.0.1 sphinxcontrib-jsmath==1.0.1
sphinxcontrib-qthelp==1.0.3 sphinxcontrib-qthelp==1.0.6
sphinxcontrib-serializinghtml==1.1.5 sphinxcontrib-serializinghtml==1.1.9
tornado==6.1 tornado==6.3.3
urllib3==1.26.9 urllib3==2.1.0
zipp==3.7.0 zipp==3.17.0

View file

@ -1,13 +1,13 @@
RFC conformance IETF standard conformance
========================= =========================
*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. *libcbor* is, generally speaking, a very faithful implementation of `IETF RFC 8949 (STD 94) <https://www.rfc-editor.org/info/std94>`_. There are, however, some limitations related to the numerical range and precision available in portable C99.
Bytestring length 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. 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.
.. [#] https://tools.ietf.org/html/rfc7049#section-2.2.2 .. [#] https://www.rfc-editor.org/rfc/rfc8949.html#section-3.2.3
"Half-precision" IEEE 754 floats "Half-precision" IEEE 754 floats
--------------------------------- ---------------------------------

View file

@ -22,6 +22,10 @@ if(CJSON_FOUND)
add_executable(cjson2cbor cjson2cbor.c) add_executable(cjson2cbor cjson2cbor.c)
target_include_directories(cjson2cbor PUBLIC ${CJSON_INCLUDE_DIRS}) target_include_directories(cjson2cbor PUBLIC ${CJSON_INCLUDE_DIRS})
target_link_libraries(cjson2cbor cbor ${CJSON_LIBRARY}) target_link_libraries(cjson2cbor cbor ${CJSON_LIBRARY})
add_executable(cbor2cjson cbor2cjson.c)
target_include_directories(cbor2cjson PUBLIC ${CJSON_INCLUDE_DIRS})
target_link_libraries(cbor2cjson cbor ${CJSON_LIBRARY})
endif() endif()
file(COPY data DESTINATION .) file(COPY data DESTINATION .)

View file

@ -2,8 +2,8 @@
#define LIBCBOR_CONFIGURATION_H #define LIBCBOR_CONFIGURATION_H
#define CBOR_MAJOR_VERSION 0 #define CBOR_MAJOR_VERSION 0
#define CBOR_MINOR_VERSION 10 #define CBOR_MINOR_VERSION 11
#define CBOR_PATCH_VERSION 2 #define CBOR_PATCH_VERSION 0
#define CBOR_BUFFER_GROWTH 2 #define CBOR_BUFFER_GROWTH 2
#define CBOR_MAX_STACK_SIZE 2048 #define CBOR_MAX_STACK_SIZE 2048

View file

@ -0,0 +1,123 @@
/*
* 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 <cjson/cJSON.h>
#include <stdio.h>
#include <string.h>
#include "cbor.h"
void usage(void) {
printf("Usage: cbor2cjson [input file]\n");
exit(1);
}
cJSON* cbor_to_cjson(cbor_item_t* item) {
switch (cbor_typeof(item)) {
case CBOR_TYPE_UINT:
return cJSON_CreateNumber(cbor_get_int(item));
case CBOR_TYPE_NEGINT:
return cJSON_CreateNumber(-1 - cbor_get_int(item));
case CBOR_TYPE_BYTESTRING:
// cJSON only handles null-terminated string -- binary data would have to
// be escaped
return cJSON_CreateString("Unsupported CBOR item: Bytestring");
case CBOR_TYPE_STRING:
if (cbor_string_is_definite(item)) {
// cJSON only handles null-terminated string
char* null_terminated_string = malloc(cbor_string_length(item) + 1);
memcpy(null_terminated_string, cbor_string_handle(item),
cbor_string_length(item));
null_terminated_string[cbor_string_length(item)] = 0;
cJSON* result = cJSON_CreateString(null_terminated_string);
free(null_terminated_string);
return result;
}
return cJSON_CreateString("Unsupported CBOR item: Chunked string");
case CBOR_TYPE_ARRAY: {
cJSON* result = cJSON_CreateArray();
for (size_t i = 0; i < cbor_array_size(item); i++) {
cJSON_AddItemToArray(result, cbor_to_cjson(cbor_array_get(item, i)));
}
return result;
}
case CBOR_TYPE_MAP: {
cJSON* result = cJSON_CreateObject();
for (size_t i = 0; i < cbor_map_size(item); i++) {
char* key = malloc(128);
snprintf(key, 128, "Surrogate key %zu", i);
// JSON only support string keys
if (cbor_isa_string(cbor_map_handle(item)[i].key) &&
cbor_string_is_definite(cbor_map_handle(item)[i].key)) {
size_t key_length = cbor_string_length(cbor_map_handle(item)[i].key);
if (key_length > 127) key_length = 127;
// Null-terminated madness
memcpy(key, cbor_string_handle(cbor_map_handle(item)[i].key),
key_length);
key[key_length] = 0;
}
cJSON_AddItemToObject(result, key,
cbor_to_cjson(cbor_map_handle(item)[i].value));
free(key);
}
return result;
}
case CBOR_TYPE_TAG:
return cJSON_CreateString("Unsupported CBOR item: Tag");
case CBOR_TYPE_FLOAT_CTRL:
if (cbor_float_ctrl_is_ctrl(item)) {
if (cbor_is_bool(item)) return cJSON_CreateBool(cbor_get_bool(item));
if (cbor_is_null(item)) return cJSON_CreateNull();
return cJSON_CreateString("Unsupported CBOR item: Control value");
}
return cJSON_CreateNumber(cbor_float_get_float(item));
}
return cJSON_CreateNull();
}
/*
* Reads CBOR data from a file and outputs JSON using cJSON
* $ ./examples/cbor2cjson examples/data/nested_array.cbor
*/
int main(int argc, char* argv[]) {
if (argc != 2) usage();
FILE* f = fopen(argv[1], "rb");
if (f == NULL) usage();
fseek(f, 0, SEEK_END);
size_t length = (size_t)ftell(f);
fseek(f, 0, SEEK_SET);
unsigned char* buffer = malloc(length);
fread(buffer, length, 1, f);
/* 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(
"There was an error while reading the input near byte %zu (read %zu "
"bytes in total): ",
result.error.position, result.read);
exit(1);
}
cJSON* cjson_item = cbor_to_cjson(item);
char* json_string = cJSON_Print(cjson_item);
printf("%s\n", json_string);
free(json_string);
fflush(stdout);
/* Deallocate the result */
cbor_decref(&item);
cJSON_Delete(cjson_item);
fclose(f);
}

View file

@ -7,7 +7,7 @@
/** /**
* This code demonstrates how cJSON (https://github.com/DaveGamble/cJSON) * This code demonstrates how cJSON (https://github.com/DaveGamble/cJSON)
* callbacks can be used in conjuction with the streaming parser to translate * callbacks can be used in conjunction with the streaming parser to translate
* JSON to CBOR. Please note that cbor_builder_* APIs are internal and thus * JSON to CBOR. Please note that cbor_builder_* APIs are internal and thus
* subject to change. * subject to change.
* *
@ -111,7 +111,7 @@ void cjson_cbor_stream_decode(cJSON *source,
} }
void usage(void) { void usage(void) {
printf("Usage: cjson [input JSON file]\n"); printf("Usage: cjson2cbor [input JSON file]\n");
exit(1); exit(1);
} }

Binary file not shown.

View file

@ -58,7 +58,7 @@ int main(int argc, char* argv[]) {
case CBOR_ERR_SYNTAXERROR: { case CBOR_ERR_SYNTAXERROR: {
printf( printf(
"Syntactically malformed data -- see " "Syntactically malformed data -- see "
"http://tools.ietf.org/html/rfc7049\n"); "https://www.rfc-editor.org/info/std94\n");
break; break;
} }
case CBOR_ERR_NONE: { case CBOR_ERR_NONE: {

View file

@ -1,4 +1,4 @@
#!/bin/bash -eu #!/bin/bash -eux
# Copyright 2019 Google Inc. # Copyright 2019 Google Inc.
# #
# Licensed under the Apache License, Version 2.0 (the "License"); # Licensed under the Apache License, Version 2.0 (the "License");

View file

@ -1,6 +1,5 @@
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) 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(JoinPaths)
include(CheckFunctionExists) include(CheckFunctionExists)
set(CMAKE_SKIP_BUILD_RPATH FALSE) set(CMAKE_SKIP_BUILD_RPATH FALSE)
@ -49,3 +48,23 @@ install(FILES cbor.h DESTINATION ${CMAKE_INSTALL_INCLUDEDIR})
install(FILES "${CMAKE_CURRENT_BINARY_DIR}/libcbor.pc" install(FILES "${CMAKE_CURRENT_BINARY_DIR}/libcbor.pc"
DESTINATION "${CMAKE_INSTALL_LIBDIR}/pkgconfig") DESTINATION "${CMAKE_INSTALL_LIBDIR}/pkgconfig")
include(CMakePackageConfigHelpers)
configure_package_config_file(
libcborConfig.cmake.in
${CMAKE_CURRENT_BINARY_DIR}/libcborConfig.cmake
INSTALL_DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/libcbor
PATH_VARS CMAKE_INSTALL_INCLUDEDIR
)
write_basic_package_version_file(
${CMAKE_CURRENT_BINARY_DIR}/libcborConfigVersion.cmake
VERSION ${CBOR_VERSION}
COMPATIBILITY SameMajorVersion
)
install(
FILES
${CMAKE_CURRENT_BINARY_DIR}/libcborConfig.cmake
${CMAKE_CURRENT_BINARY_DIR}/libcborConfigVersion.cmake
DESTINATION
${CMAKE_INSTALL_LIBDIR}/cmake/libcbor
)

View file

@ -9,6 +9,7 @@
#include "cbor/internal/builder_callbacks.h" #include "cbor/internal/builder_callbacks.h"
#include "cbor/internal/loaders.h" #include "cbor/internal/loaders.h"
#pragma clang diagnostic push
cbor_item_t *cbor_load(cbor_data source, size_t source_size, cbor_item_t *cbor_load(cbor_data source, size_t source_size,
struct cbor_load_result *result) { struct cbor_load_result *result) {
/* Context stack */ /* Context stack */
@ -289,7 +290,6 @@ cbor_item_t *cbor_copy(cbor_item_t *item) {
#include <inttypes.h> #include <inttypes.h>
#include <locale.h> #include <locale.h>
#include <stdlib.h>
#include <wchar.h> #include <wchar.h>
#define __STDC_FORMAT_MACROS #define __STDC_FORMAT_MACROS
@ -301,89 +301,105 @@ static int _pow(int b, int ex) {
return res; return res;
} }
static void _cbor_type_marquee(FILE *out, char *label, int indent) {
fprintf(out, "%*.*s[%s] ", indent, indent, " ", label);
}
static void _cbor_nested_describe(cbor_item_t *item, FILE *out, int indent) { static void _cbor_nested_describe(cbor_item_t *item, FILE *out, int indent) {
setlocale(LC_ALL, ""); const int indent_offset = 4;
switch (cbor_typeof(item)) { switch (cbor_typeof(item)) {
case CBOR_TYPE_UINT: { case CBOR_TYPE_UINT: {
fprintf(out, "%*s[CBOR_TYPE_UINT] ", indent, " "); _cbor_type_marquee(out, "CBOR_TYPE_UINT", indent);
fprintf(out, "Width: %dB, ", _pow(2, cbor_int_get_width(item))); fprintf(out, "Width: %dB, ", _pow(2, cbor_int_get_width(item)));
fprintf(out, "Value: %" PRIu64 "\n", cbor_get_int(item)); fprintf(out, "Value: %" PRIu64 "\n", cbor_get_int(item));
break; break;
} }
case CBOR_TYPE_NEGINT: { case CBOR_TYPE_NEGINT: {
fprintf(out, "%*s[CBOR_TYPE_NEGINT] ", indent, " "); _cbor_type_marquee(out, "CBOR_TYPE_NEGINT", indent);
fprintf(out, "Width: %dB, ", _pow(2, cbor_int_get_width(item))); fprintf(out, "Width: %dB, ", _pow(2, cbor_int_get_width(item)));
fprintf(out, "Value: -%" PRIu64 " -1\n", cbor_get_int(item)); fprintf(out, "Value: -%" PRIu64 " - 1\n", cbor_get_int(item));
break; break;
} }
case CBOR_TYPE_BYTESTRING: { case CBOR_TYPE_BYTESTRING: {
fprintf(out, "%*s[CBOR_TYPE_BYTESTRING] ", indent, " "); _cbor_type_marquee(out, "CBOR_TYPE_BYTESTRING", indent);
if (cbor_bytestring_is_indefinite(item)) { if (cbor_bytestring_is_indefinite(item)) {
fprintf(out, "Indefinite, with %zu chunks:\n", fprintf(out, "Indefinite, Chunks: %zu, Chunk data:\n",
cbor_bytestring_chunk_count(item)); cbor_bytestring_chunk_count(item));
for (size_t i = 0; i < cbor_bytestring_chunk_count(item); i++) for (size_t i = 0; i < cbor_bytestring_chunk_count(item); i++)
_cbor_nested_describe(cbor_bytestring_chunks_handle(item)[i], out, _cbor_nested_describe(cbor_bytestring_chunks_handle(item)[i], out,
indent + 4); indent + indent_offset);
} else { } else {
fprintf(out, "Definite, length %zuB\n", cbor_bytestring_length(item)); const unsigned char *data = cbor_bytestring_handle(item);
fprintf(out, "Definite, Length: %zuB, Data:\n",
cbor_bytestring_length(item));
fprintf(out, "%*s", indent + indent_offset, " ");
for (size_t i = 0; i < cbor_bytestring_length(item); i++)
fprintf(out, "%02x", (int)(data[i] & 0xff));
fprintf(out, "\n");
} }
break; break;
} }
case CBOR_TYPE_STRING: { case CBOR_TYPE_STRING: {
fprintf(out, "%*s[CBOR_TYPE_STRING] ", indent, " "); _cbor_type_marquee(out, "CBOR_TYPE_STRING", indent);
if (cbor_string_is_indefinite(item)) { if (cbor_string_is_indefinite(item)) {
fprintf(out, "Indefinite, with %zu chunks:\n", fprintf(out, "Indefinite, Chunks: %zu, Chunk data:\n",
cbor_string_chunk_count(item)); cbor_string_chunk_count(item));
for (size_t i = 0; i < cbor_string_chunk_count(item); i++) for (size_t i = 0; i < cbor_string_chunk_count(item); i++)
_cbor_nested_describe(cbor_string_chunks_handle(item)[i], out, _cbor_nested_describe(cbor_string_chunks_handle(item)[i], out,
indent + 4); indent + indent_offset);
} else { } else {
fprintf(out, "Definite, length %zuB, %zu codepoints\n", fprintf(out, "Definite, Length: %zuB, Codepoints: %zu, Data:\n",
cbor_string_length(item), cbor_string_codepoint_count(item)); cbor_string_length(item), cbor_string_codepoint_count(item));
/* Careful - this doesn't support multibyte characters! */ fprintf(out, "%*s", indent + indent_offset, " ");
/* Printing those is out of the scope of this demo :) */ // Note: The string is not escaped, whitespace and control character
/* libICU is your friend */ // will be printed in verbatim and take effect.
fprintf(out, "%*s", indent + 4, " "); fwrite(cbor_string_handle(item), sizeof(unsigned char),
/* XXX: no null at the end -> confused vprintf */ cbor_string_length(item), out);
fwrite(cbor_string_handle(item), (int)cbor_string_length(item), 1, out);
fprintf(out, "\n"); fprintf(out, "\n");
} }
break; break;
} }
case CBOR_TYPE_ARRAY: { case CBOR_TYPE_ARRAY: {
fprintf(out, "%*s[CBOR_TYPE_ARRAY] ", indent, " "); _cbor_type_marquee(out, "CBOR_TYPE_ARRAY", indent);
if (cbor_array_is_definite(item)) { if (cbor_array_is_definite(item)) {
fprintf(out, "Definite, size: %zu\n", cbor_array_size(item)); fprintf(out, "Definite, Size: %zu, Contents:\n", cbor_array_size(item));
} else { } else {
fprintf(out, "Indefinite, size: %zu\n", cbor_array_size(item)); fprintf(out, "Indefinite, Size: %zu, Contents:\n",
cbor_array_size(item));
} }
for (size_t i = 0; i < cbor_array_size(item); i++) for (size_t i = 0; i < cbor_array_size(item); i++)
_cbor_nested_describe(cbor_array_handle(item)[i], out, indent + 4); _cbor_nested_describe(cbor_array_handle(item)[i], out,
indent + indent_offset);
break; break;
} }
case CBOR_TYPE_MAP: { case CBOR_TYPE_MAP: {
fprintf(out, "%*s[CBOR_TYPE_MAP] ", indent, " "); _cbor_type_marquee(out, "CBOR_TYPE_MAP", indent);
if (cbor_map_is_definite(item)) { if (cbor_map_is_definite(item)) {
fprintf(out, "Definite, size: %zu\n", cbor_map_size(item)); fprintf(out, "Definite, Size: %zu, Contents:\n", cbor_map_size(item));
} else { } else {
fprintf(out, "Indefinite, size: %zu\n", cbor_map_size(item)); fprintf(out, "Indefinite, Size: %zu, Contents:\n", cbor_map_size(item));
} }
// TODO: Label and group keys and values
for (size_t i = 0; i < cbor_map_size(item); i++) { for (size_t i = 0; i < cbor_map_size(item); i++) {
_cbor_nested_describe(cbor_map_handle(item)[i].key, out, indent + 4); fprintf(out, "%*sMap entry %zu\n", indent + indent_offset, " ", i);
_cbor_nested_describe(cbor_map_handle(item)[i].value, out, indent + 4); _cbor_nested_describe(cbor_map_handle(item)[i].key, out,
indent + 2 * indent_offset);
_cbor_nested_describe(cbor_map_handle(item)[i].value, out,
indent + 2 * indent_offset);
} }
break; break;
} }
case CBOR_TYPE_TAG: { case CBOR_TYPE_TAG: {
fprintf(out, "%*s[CBOR_TYPE_TAG] ", indent, " "); _cbor_type_marquee(out, "CBOR_TYPE_TAG", indent);
fprintf(out, "Value: %" PRIu64 "\n", cbor_tag_value(item)); fprintf(out, "Value: %" PRIu64 "\n", cbor_tag_value(item));
_cbor_nested_describe(cbor_move(cbor_tag_item(item)), out, indent + 4); _cbor_nested_describe(cbor_move(cbor_tag_item(item)), out,
indent + indent_offset);
break; break;
} }
case CBOR_TYPE_FLOAT_CTRL: { case CBOR_TYPE_FLOAT_CTRL: {
fprintf(out, "%*s[CBOR_TYPE_FLOAT_CTRL] ", indent, " "); _cbor_type_marquee(out, "CBOR_TYPE_FLOAT_CTRL", indent);
if (cbor_float_ctrl_is_ctrl(item)) { if (cbor_float_ctrl_is_ctrl(item)) {
if (cbor_is_bool(item)) if (cbor_is_bool(item))
fprintf(out, "Bool: %s\n", cbor_get_bool(item) ? "true" : "false"); fprintf(out, "Bool: %s\n", cbor_get_bool(item) ? "true" : "false");
@ -392,10 +408,10 @@ static void _cbor_nested_describe(cbor_item_t *item, FILE *out, int indent) {
else if (cbor_is_null(item)) else if (cbor_is_null(item))
fprintf(out, "Null\n"); fprintf(out, "Null\n");
else else
fprintf(out, "Simple value %d\n", cbor_ctrl_value(item)); fprintf(out, "Simple value: %d\n", cbor_ctrl_value(item));
} else { } else {
fprintf(out, "Width: %dB, ", _pow(2, cbor_float_get_width(item))); fprintf(out, "Width: %dB, ", _pow(2, cbor_float_get_width(item)));
fprintf(out, "value: %lf\n", cbor_float_get_float(item)); fprintf(out, "Value: %lf\n", cbor_float_get_float(item));
} }
break; break;
} }

View file

@ -157,7 +157,7 @@ _CBOR_NODISCARD
CBOR_EXPORT cbor_type cbor_typeof( CBOR_EXPORT cbor_type cbor_typeof(
const cbor_item_t *item); /* Will be inlined iff link-time opt is enabled */ const cbor_item_t *item); /* Will be inlined iff link-time opt is enabled */
/* Standard item types as described by the RFC */ /* Standard CBOR Major item types */
/** Does the item have the appropriate major type? /** Does the item have the appropriate major type?
* @param item the item * @param item the item

View file

@ -67,14 +67,14 @@ void _cbor_builder_append(cbor_item_t *item,
// Note: We use 0 and 1 subitems to distinguish between keys and values in // Note: We use 0 and 1 subitems to distinguish between keys and values in
// indefinite items // indefinite items
if (ctx->stack->top->subitems % 2) { if (ctx->stack->top->subitems % 2) {
/* Odd record, this is a value */ // Odd record, this is a value.
if (!_cbor_map_add_value(ctx->stack->top->item, item)) { ctx->creation_failed =
ctx->creation_failed = true; !_cbor_map_add_value(ctx->stack->top->item, item);
cbor_decref(&item); // Adding a value never fails since the memory is allocated when the
break; // key is added
} CBOR_ASSERT(!ctx->creation_failed);
} else { } else {
/* Even record, this is a key */ // Even record, this is a key.
if (!_cbor_map_add_key(ctx->stack->top->item, item)) { if (!_cbor_map_add_key(ctx->stack->top->item, item)) {
ctx->creation_failed = true; ctx->creation_failed = true;
cbor_decref(&item); cbor_decref(&item);
@ -256,18 +256,8 @@ void cbor_builder_string_callback(void *context, cbor_data data,
uint64_t length) { uint64_t length) {
struct _cbor_decoder_context *ctx = context; struct _cbor_decoder_context *ctx = context;
CHECK_LENGTH(ctx, length); CHECK_LENGTH(ctx, length);
struct _cbor_unicode_status unicode_status;
uint64_t codepoint_count =
_cbor_unicode_codepoint_count(data, length, &unicode_status);
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) { if (new_handle == NULL) {
ctx->creation_failed = true; ctx->creation_failed = true;
return; return;
@ -281,7 +271,6 @@ void cbor_builder_string_callback(void *context, cbor_data data,
return; return;
} }
cbor_string_set_handle(new_chunk, new_handle, length); cbor_string_set_handle(new_chunk, new_handle, length);
new_chunk->metadata.string_metadata.codepoint_count = codepoint_count;
// If an indef string is on the stack, extend it (if it were closed, it would // If an indef string is on the stack, extend it (if it were closed, it would
// have been popped). Handle any syntax errors upstream. // have been popped). Handle any syntax errors upstream.
@ -355,6 +344,8 @@ bool _cbor_is_indefinite(cbor_item_t *item) {
case CBOR_TYPE_MAP: case CBOR_TYPE_MAP:
return cbor_map_is_indefinite(item); return cbor_map_is_indefinite(item);
default: default:
// Should never happen since a non-nested item cannot be on top of the
// stack.
return false; return false;
} }
} }

View file

@ -49,7 +49,7 @@ uint64_t _cbor_load_uint64(const unsigned char *source) {
#endif #endif
} }
/* As per http://tools.ietf.org/html/rfc7049#appendix-D */ /* As per https://www.rfc-editor.org/rfc/rfc8949.html#name-half-precision */
float _cbor_decode_half(unsigned char *halfp) { float _cbor_decode_half(unsigned char *halfp) {
int half = (halfp[0] << 8) + halfp[1]; int half = (halfp[0] << 8) + halfp[1];
int exp = (half >> 10) & 0x1f; int exp = (half >> 10) & 0x1f;

View file

@ -21,7 +21,7 @@ bool _cbor_safe_to_multiply(size_t a, size_t b);
_CBOR_NODISCARD _CBOR_NODISCARD
bool _cbor_safe_to_add(size_t a, size_t b); bool _cbor_safe_to_add(size_t a, size_t b);
/** Adds `a` and `b`, propagating zeros and returing 0 on overflow. */ /** Adds `a` and `b`, propagating zeros and returning 0 on overflow. */
_CBOR_NODISCARD _CBOR_NODISCARD
size_t _cbor_safe_signaling_add(size_t a, size_t b); size_t _cbor_safe_signaling_add(size_t a, size_t b);

View file

@ -66,12 +66,12 @@ uint32_t _cbor_unicode_decode(uint32_t* state, uint32_t* codep, uint32_t byte) {
return *state; return *state;
} }
uint64_t _cbor_unicode_codepoint_count(cbor_data source, uint64_t source_length, size_t _cbor_unicode_codepoint_count(cbor_data source, size_t source_length,
struct _cbor_unicode_status* status) { struct _cbor_unicode_status* status) {
*status = *status =
(struct _cbor_unicode_status){.location = 0, .status = _CBOR_UNICODE_OK}; (struct _cbor_unicode_status){.location = 0, .status = _CBOR_UNICODE_OK};
uint32_t codepoint, state = UTF8_ACCEPT, res; uint32_t codepoint, state = UTF8_ACCEPT, res;
uint64_t pos = 0, count = 0; size_t pos = 0, count = 0;
for (; pos < source_length; pos++) { for (; pos < source_length; pos++) {
res = _cbor_unicode_decode(&state, &codepoint, source[pos]); res = _cbor_unicode_decode(&state, &codepoint, source[pos]);

View file

@ -19,11 +19,11 @@ enum _cbor_unicode_status_error { _CBOR_UNICODE_OK, _CBOR_UNICODE_BADCP };
/** Signals unicode validation error and possibly its location */ /** Signals unicode validation error and possibly its location */
struct _cbor_unicode_status { struct _cbor_unicode_status {
enum _cbor_unicode_status_error status; enum _cbor_unicode_status_error status;
uint64_t location; size_t location;
}; };
_CBOR_NODISCARD _CBOR_NODISCARD
uint64_t _cbor_unicode_codepoint_count(cbor_data source, uint64_t source_length, size_t _cbor_unicode_codepoint_count(cbor_data source, size_t source_length,
struct _cbor_unicode_status* status); struct _cbor_unicode_status* status);
#ifdef __cplusplus #ifdef __cplusplus

View file

@ -103,6 +103,7 @@ bool _cbor_map_add_value(cbor_item_t *item, cbor_item_t *value) {
return true; return true;
} }
// TODO: Add a more convenient API like add(item, key, val)
bool cbor_map_add(cbor_item_t *item, struct cbor_pair pair) { bool cbor_map_add(cbor_item_t *item, struct cbor_pair pair) {
CBOR_ASSERT(cbor_isa_map(item)); CBOR_ASSERT(cbor_isa_map(item));
if (!_cbor_map_add_key(item, pair.key)) return false; if (!_cbor_map_add_key(item, pair.key)) return false;

View file

@ -437,23 +437,21 @@ struct cbor_decoder_result cbor_stream_decode(
callbacks->indef_map_start(context); callbacks->indef_map_start(context);
return result; return result;
} }
case 0xC0: /* See https://www.iana.org/assignments/cbor-tags/cbor-tags.xhtml for tag
/* Text date/time - RFC 3339 tag, fallthrough */ * assignment. All well-formed tags are processed regardless of validity
case 0xC1: * since maintaining the known mapping would be impractical.
/* Epoch date tag, fallthrough */ *
case 0xC2: * Moreover, even tags in the reserved "standard" range are not assigned
/* Positive bignum tag, fallthrough */ * but may get assigned in the future (see e.g.
case 0xC3: * https://github.com/PJK/libcbor/issues/307), so processing all tags
/* Negative bignum tag, fallthrough */ * improves forward compatibility.
case 0xC4: */
/* Fraction, fallthrough */ case 0xC0: /* Fallthrough */
case 0xC5: case 0xC1: /* Fallthrough */
/* Big float */ case 0xC2: /* Fallthrough */
{ case 0xC3: /* Fallthrough */
callbacks->tag(context, (uint64_t)(_cbor_load_uint8(source) - case 0xC4: /* Fallthrough */
0xC0)); /* 0xC0 offset */ case 0xC5: /* Fallthrough */
return result;
}
case 0xC6: /* Fallthrough */ case 0xC6: /* Fallthrough */
case 0xC7: /* Fallthrough */ case 0xC7: /* Fallthrough */
case 0xC8: /* Fallthrough */ case 0xC8: /* Fallthrough */
@ -468,13 +466,10 @@ struct cbor_decoder_result cbor_stream_decode(
case 0xD1: /* Fallthrough */ case 0xD1: /* Fallthrough */
case 0xD2: /* Fallthrough */ case 0xD2: /* Fallthrough */
case 0xD3: /* Fallthrough */ case 0xD3: /* Fallthrough */
case 0xD4: /* Unassigned tag value */ case 0xD4: /* Fallthrough */
{ case 0xD5: /* Fallthrough */
return (struct cbor_decoder_result){.status = CBOR_DECODER_ERROR}; case 0xD6: /* Fallthrough */
} case 0xD7: /* Fallthrough */
case 0xD5: /* Expected b64url conversion tag - fallthrough */
case 0xD6: /* Expected b64 conversion tag - fallthrough */
case 0xD7: /* Expected b16 conversion tag */
{ {
callbacks->tag(context, (uint64_t)(_cbor_load_uint8(source) - callbacks->tag(context, (uint64_t)(_cbor_load_uint8(source) -
0xC0)); /* 0xC0 offset */ 0xC0)); /* 0xC0 offset */

View file

@ -8,6 +8,7 @@
#include "strings.h" #include "strings.h"
#include <string.h> #include <string.h>
#include "internal/memory_utils.h" #include "internal/memory_utils.h"
#include "internal/unicode.h"
cbor_item_t *cbor_new_definite_string(void) { cbor_item_t *cbor_new_definite_string(void) {
cbor_item_t *item = _cbor_malloc(sizeof(cbor_item_t)); cbor_item_t *item = _cbor_malloc(sizeof(cbor_item_t));
@ -66,6 +67,15 @@ void cbor_string_set_handle(cbor_item_t *item,
CBOR_ASSERT(cbor_string_is_definite(item)); CBOR_ASSERT(cbor_string_is_definite(item));
item->data = data; item->data = data;
item->metadata.string_metadata.length = length; item->metadata.string_metadata.length = length;
struct _cbor_unicode_status unicode_status;
size_t codepoint_count =
_cbor_unicode_codepoint_count(data, length, &unicode_status);
CBOR_ASSERT(codepoint_count <= length);
if (unicode_status.status == _CBOR_UNICODE_OK) {
item->metadata.string_metadata.codepoint_count = codepoint_count;
} else {
item->metadata.string_metadata.codepoint_count = 0;
}
} }
cbor_item_t **cbor_string_chunks_handle(const cbor_item_t *item) { cbor_item_t **cbor_string_chunks_handle(const cbor_item_t *item) {

View file

@ -33,7 +33,8 @@ _CBOR_NODISCARD CBOR_EXPORT size_t cbor_string_length(const cbor_item_t *item);
/** The number of codepoints in this string /** The number of codepoints in this string
* *
* Might differ from length if there are multibyte ones * Might differ from `cbor_string_length` if there are multibyte codepoints.
* If the string data is not valid UTF-8, returns 0.
* *
* @param item A string * @param item A string
* @return The number of codepoints in this string * @return The number of codepoints in this string
@ -71,6 +72,8 @@ cbor_string_handle(const cbor_item_t *item);
/** Set the handle to the underlying string /** Set the handle to the underlying string
* *
* The data is assumed to be a valid UTF-8 string. If the string is non-empty
* and invalid, `cbor_string_codepoint_count` will return 0.
* *
* \rst * \rst
* .. warning:: Using a pointer to a stack allocated constant is a common * .. warning:: Using a pointer to a stack allocated constant is a common
@ -144,7 +147,11 @@ _CBOR_NODISCARD CBOR_EXPORT cbor_item_t *cbor_new_indefinite_string(void);
/** Creates a new string and initializes it /** Creates a new string and initializes it
* *
* The `val` will be copied to a newly allocated block * The data from `val` will be copied to a newly allocated memory block.
*
* Note that valid UTF-8 strings do not contain null bytes, so this routine is
* correct for all valid inputs. If the input is not guaranteed to be valid,
* use `cbor_build_stringn` instead.
* *
* @param val A null-terminated UTF-8 string * @param val A null-terminated UTF-8 string
* @return Reference to the new string item. The item's reference count is * @return Reference to the new string item. The item's reference count is
@ -155,10 +162,12 @@ _CBOR_NODISCARD CBOR_EXPORT cbor_item_t *cbor_build_string(const char *val);
/** Creates a new string and initializes it /** Creates a new string and initializes it
* *
* The `handle` will be copied to a newly allocated block * The data from `handle` will be copied to a newly allocated memory block.
* *
* @param val A UTF-8 string, at least @p `length` long (excluding the null * All @p `length` bytes will be stored in the string, even if there are null
* byte) * bytes or invalid UTF-8 sequences.
*
* @param val A UTF-8 string, at least @p `length` bytes long
* @param length Length (in bytes) of the string passed in @p `val`. * @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 * @return Reference to the new string item. The item's reference count is
* initialized to one. * initialized to one.

View file

@ -0,0 +1,8 @@
set(CBOR_VERSION @CBOR_VERSION@)
@PACKAGE_INIT@
set_and_check(CBOR_INCLUDE_DIR "@PACKAGE_CMAKE_INSTALL_INCLUDEDIR@")
set_and_check(CBOR_INCLUDE_DIRS "@PACKAGE_CMAKE_INSTALL_INCLUDEDIR@")
check_required_components(libcbor)

View file

@ -371,6 +371,30 @@ static void test_invalid_indef_break(void** _CBOR_UNUSED(_state)) {
assert_true(res.error.code == CBOR_ERR_SYNTAXERROR); assert_true(res.error.code == CBOR_ERR_SYNTAXERROR);
} }
static void test_invalid_state_indef_break(void** _CBOR_UNUSED(_state)) {
struct _cbor_stack stack = _cbor_stack_init();
assert_non_null(_cbor_stack_push(&stack, cbor_new_int8(), /*subitems=*/0));
struct _cbor_decoder_context context = {
.creation_failed = false,
.syntax_error = false,
.root = NULL,
.stack = &stack,
};
cbor_builder_indef_break_callback(&context);
assert_false(context.creation_failed);
assert_true(context.syntax_error);
assert_size_equal(context.stack->size, 1);
// The stack remains unchanged
cbor_item_t* small_int = stack.top->item;
assert_size_equal(cbor_refcount(small_int), 1);
assert_true(cbor_isa_uint(small_int));
cbor_decref(&small_int);
_cbor_stack_pop(&stack);
}
int main(void) { int main(void) {
const struct CMUnitTest tests[] = { const struct CMUnitTest tests[] = {
cmocka_unit_test(test_default_callbacks), cmocka_unit_test(test_default_callbacks),
@ -388,6 +412,7 @@ int main(void) {
cmocka_unit_test(test_append_array_failure), cmocka_unit_test(test_append_array_failure),
cmocka_unit_test(test_append_map_failure), cmocka_unit_test(test_append_map_failure),
cmocka_unit_test(test_invalid_indef_break), cmocka_unit_test(test_invalid_indef_break),
cmocka_unit_test(test_invalid_state_indef_break),
}; };
cmocka_run_group_tests(tests, NULL, NULL); cmocka_run_group_tests(tests, NULL, NULL);

View file

@ -218,6 +218,34 @@ static void test_serialize_definite_string(void **_CBOR_UNUSED(_state)) {
cbor_decref(&item); cbor_decref(&item);
} }
static void test_serialize_definite_string_4b_header(
void **_CBOR_UNUSED(_state)) {
#if SIZE_MAX > UINT16_MAX
cbor_item_t *item = cbor_new_definite_string();
const size_t size = (size_t)UINT16_MAX + 1;
unsigned char *data = malloc(size);
memset(data, 0, size);
cbor_string_set_handle(item, data, size);
assert_size_equal(cbor_serialized_size(item), 1 + 4 + size);
cbor_decref(&item);
#endif
}
static void test_serialize_definite_string_8b_header(
void **_CBOR_UNUSED(_state)) {
#if SIZE_MAX > UINT32_MAX
cbor_item_t *item = cbor_new_definite_string();
const size_t size = (size_t)UINT32_MAX + 1;
unsigned char *data = malloc(1);
data[0] = '\0';
cbor_string_set_handle(item, data, 1);
// Pretend that we have a big item to avoid the huge malloc
item->metadata.string_metadata.length = size;
assert_size_equal(cbor_serialized_size(item), 1 + 8 + size);
cbor_decref(&item);
#endif
}
static void test_serialize_indefinite_string(void **_CBOR_UNUSED(_state)) { static void test_serialize_indefinite_string(void **_CBOR_UNUSED(_state)) {
cbor_item_t *item = cbor_new_indefinite_string(); cbor_item_t *item = cbor_new_indefinite_string();
cbor_item_t *chunk = cbor_new_definite_string(); cbor_item_t *chunk = cbor_new_definite_string();
@ -242,6 +270,7 @@ static void test_serialize_indefinite_string(void **_CBOR_UNUSED(_state)) {
static void test_serialize_string_no_space(void **_CBOR_UNUSED(_state)) { static void test_serialize_string_no_space(void **_CBOR_UNUSED(_state)) {
cbor_item_t *item = cbor_new_definite_string(); cbor_item_t *item = cbor_new_definite_string();
unsigned char *data = malloc(12); unsigned char *data = malloc(12);
memset(data, 0, 12);
cbor_string_set_handle(item, data, 12); cbor_string_set_handle(item, data, 12);
assert_size_equal(cbor_serialize(item, buffer, 1), 0); assert_size_equal(cbor_serialize(item, buffer, 1), 0);
@ -254,6 +283,7 @@ static void test_serialize_indefinite_string_no_space(
cbor_item_t *item = cbor_new_indefinite_string(); cbor_item_t *item = cbor_new_indefinite_string();
cbor_item_t *chunk = cbor_new_definite_string(); cbor_item_t *chunk = cbor_new_definite_string();
unsigned char *data = malloc(256); unsigned char *data = malloc(256);
memset(data, 0, 256);
cbor_string_set_handle(chunk, data, 256); cbor_string_set_handle(chunk, data, 256);
assert_true(cbor_string_add_chunk(item, cbor_move(chunk))); assert_true(cbor_string_add_chunk(item, cbor_move(chunk)));
@ -638,6 +668,8 @@ int main(void) {
cmocka_unit_test(test_serialize_bytestring_no_space), cmocka_unit_test(test_serialize_bytestring_no_space),
cmocka_unit_test(test_serialize_indefinite_bytestring_no_space), cmocka_unit_test(test_serialize_indefinite_bytestring_no_space),
cmocka_unit_test(test_serialize_definite_string), cmocka_unit_test(test_serialize_definite_string),
cmocka_unit_test(test_serialize_definite_string_4b_header),
cmocka_unit_test(test_serialize_definite_string_8b_header),
cmocka_unit_test(test_serialize_indefinite_string), cmocka_unit_test(test_serialize_indefinite_string),
cmocka_unit_test(test_serialize_string_no_space), cmocka_unit_test(test_serialize_string_no_space),
cmocka_unit_test(test_serialize_indefinite_string_no_space), cmocka_unit_test(test_serialize_indefinite_string_no_space),

View file

@ -613,9 +613,9 @@ static void test_int64_tag_decoding(void **_CBOR_UNUSED(_state)) {
assert_minimum_input_size(9, int64_tag_data); assert_minimum_input_size(9, int64_tag_data);
} }
unsigned char bad_tag_data[] = {0xC6}; unsigned char reserved_byte_data[] = {0xDC};
static void test_bad_tag_decoding(void **_CBOR_UNUSED(_state)) { static void test_reserved_byte_decoding(void **_CBOR_UNUSED(_state)) {
assert_decoder_result(0, CBOR_DECODER_ERROR, decode(bad_tag_data, 1)); assert_decoder_result(0, CBOR_DECODER_ERROR, decode(reserved_byte_data, 1));
} }
unsigned char float2_data[] = {0xF9, 0x7B, 0xFF}; unsigned char float2_data[] = {0xF9, 0x7B, 0xFF};
@ -729,7 +729,7 @@ int main(void) {
stream_test(test_int16_tag_decoding), stream_test(test_int16_tag_decoding),
stream_test(test_int32_tag_decoding), stream_test(test_int32_tag_decoding),
stream_test(test_int64_tag_decoding), stream_test(test_int64_tag_decoding),
stream_test(test_bad_tag_decoding), stream_test(test_reserved_byte_decoding),
stream_test(test_float2_decoding), stream_test(test_float2_decoding),
stream_test(test_float4_decoding), stream_test(test_float4_decoding),

View file

@ -30,7 +30,7 @@ static void test_float2(void **_CBOR_UNUSED(_state)) {
assert_true(cbor_is_float(float_ctrl)); assert_true(cbor_is_float(float_ctrl));
assert_true(cbor_float_get_width(float_ctrl) == CBOR_FLOAT_16); assert_true(cbor_float_get_width(float_ctrl) == CBOR_FLOAT_16);
assert_true(cbor_float_get_float2(float_ctrl) == 65504.0F); assert_true(cbor_float_get_float2(float_ctrl) == 65504.0F);
assert_true(fabs(cbor_float_get_float(float_ctrl) - 65504.0F) < eps); assert_float_equal(cbor_float_get_float(float_ctrl), 65504.0F, eps);
cbor_decref(&float_ctrl); cbor_decref(&float_ctrl);
assert_null(float_ctrl); assert_null(float_ctrl);
} }
@ -43,7 +43,7 @@ static void test_float4(void **_CBOR_UNUSED(_state)) {
assert_true(cbor_is_float(float_ctrl)); assert_true(cbor_is_float(float_ctrl));
assert_true(cbor_float_get_width(float_ctrl) == CBOR_FLOAT_32); assert_true(cbor_float_get_width(float_ctrl) == CBOR_FLOAT_32);
assert_true(cbor_float_get_float4(float_ctrl) == 100000.0F); assert_true(cbor_float_get_float4(float_ctrl) == 100000.0F);
assert_true(fabs(cbor_float_get_float(float_ctrl) - 100000.0F) < eps); assert_float_equal(cbor_float_get_float(float_ctrl), 100000.0F, eps);
cbor_decref(&float_ctrl); cbor_decref(&float_ctrl);
assert_null(float_ctrl); assert_null(float_ctrl);
} }
@ -58,6 +58,8 @@ static void test_float8(void **_CBOR_UNUSED(_state)) {
assert_true(cbor_float_get_width(float_ctrl) == CBOR_FLOAT_64); assert_true(cbor_float_get_width(float_ctrl) == CBOR_FLOAT_64);
// XXX: the cast prevents promotion to 80-bit floats on 32-bit x86 // XXX: the cast prevents promotion to 80-bit floats on 32-bit x86
assert_true(cbor_float_get_float8(float_ctrl) == (double)1.0e+300); assert_true(cbor_float_get_float8(float_ctrl) == (double)1.0e+300);
// Not using `assert_double_equal` since CI has an old version of cmocka
assert_true(fabs(cbor_float_get_float(float_ctrl) - (double)1.0e+300) < eps);
cbor_decref(&float_ctrl); cbor_decref(&float_ctrl);
assert_null(float_ctrl); assert_null(float_ctrl);
} }

View file

@ -6,33 +6,200 @@
*/ */
#include <stdio.h> #include <stdio.h>
#include <string.h>
#include "assertions.h" #include "assertions.h"
#include "cbor.h" #include "cbor.h"
unsigned char data[] = {0x8B, 0x01, 0x20, 0x5F, 0x41, 0x01, 0x41, 0x02, void assert_describe_result(cbor_item_t *item, char *expected_result) {
0xFF, 0x7F, 0x61, 0x61, 0x61, 0x62, 0xFF, 0x9F,
0xFF, 0xA1, 0x61, 0x61, 0x61, 0x62, 0xC0, 0xBF,
0xFF, 0xFB, 0x40, 0x09, 0x1E, 0xB8, 0x51, 0xEB,
0x85, 0x1F, 0xF6, 0xF7, 0xF5};
static void test_pretty_printer(void **_CBOR_UNUSED(_state)) {
#if CBOR_PRETTY_PRINTER #if CBOR_PRETTY_PRINTER
// We know the expected size based on `expected_result`, but read everything
// in order to get the full actual output in a useful error message.
const size_t buffer_size = 512;
FILE *outfile = tmpfile(); FILE *outfile = tmpfile();
struct cbor_load_result res;
cbor_item_t *item = cbor_load(data, 37, &res);
cbor_describe(item, outfile); cbor_describe(item, outfile);
cbor_decref(&item); rewind(outfile);
// Treat string as null-terminated since cmocka doesn't have asserts
item = cbor_new_ctrl(); // for explicit length strings.
cbor_set_ctrl(item, 1); char *output = malloc(buffer_size);
cbor_describe(item, outfile); assert_non_null(output);
cbor_decref(&item); size_t output_size = fread(output, sizeof(char), buffer_size, outfile);
output[output_size] = '\0';
assert_string_equal(output, expected_result);
assert_true(feof(outfile));
free(output);
fclose(outfile); fclose(outfile);
#endif #endif
} }
static void test_uint(void **_CBOR_UNUSED(_state)) {
cbor_item_t *item = cbor_build_uint8(42);
assert_describe_result(item, "[CBOR_TYPE_UINT] Width: 1B, Value: 42\n");
cbor_decref(&item);
}
static void test_negint(void **_CBOR_UNUSED(_state)) {
cbor_item_t *item = cbor_build_negint16(40);
assert_describe_result(item,
"[CBOR_TYPE_NEGINT] Width: 2B, Value: -40 - 1\n");
cbor_decref(&item);
}
static void test_definite_bytestring(void **_CBOR_UNUSED(_state)) {
unsigned char data[] = {0x01, 0x02, 0x03};
cbor_item_t *item = cbor_build_bytestring(data, 3);
assert_describe_result(item,
"[CBOR_TYPE_BYTESTRING] Definite, Length: 3B, Data:\n"
" 010203\n");
cbor_decref(&item);
}
static void test_indefinite_bytestring(void **_CBOR_UNUSED(_state)) {
unsigned char data[] = {0x01, 0x02, 0x03};
cbor_item_t *item = cbor_new_indefinite_bytestring();
assert_true(cbor_bytestring_add_chunk(
item, cbor_move(cbor_build_bytestring(data, 3))));
assert_true(cbor_bytestring_add_chunk(
item, cbor_move(cbor_build_bytestring(data, 2))));
assert_describe_result(
item,
"[CBOR_TYPE_BYTESTRING] Indefinite, Chunks: 2, Chunk data:\n"
" [CBOR_TYPE_BYTESTRING] Definite, Length: 3B, Data:\n"
" 010203\n"
" [CBOR_TYPE_BYTESTRING] Definite, Length: 2B, Data:\n"
" 0102\n");
cbor_decref(&item);
}
static void test_definite_string(void **_CBOR_UNUSED(_state)) {
char *string = "Hello!";
cbor_item_t *item = cbor_build_string(string);
assert_describe_result(
item,
"[CBOR_TYPE_STRING] Definite, Length: 6B, Codepoints: 6, Data:\n"
" Hello!\n");
cbor_decref(&item);
}
static void test_indefinite_string(void **_CBOR_UNUSED(_state)) {
char *string = "Hello!";
cbor_item_t *item = cbor_new_indefinite_string();
assert_true(
cbor_string_add_chunk(item, cbor_move(cbor_build_string(string))));
assert_true(
cbor_string_add_chunk(item, cbor_move(cbor_build_string(string))));
assert_describe_result(
item,
"[CBOR_TYPE_STRING] Indefinite, Chunks: 2, Chunk data:\n"
" [CBOR_TYPE_STRING] Definite, Length: 6B, Codepoints: 6, Data:\n"
" Hello!\n"
" [CBOR_TYPE_STRING] Definite, Length: 6B, Codepoints: 6, Data:\n"
" Hello!\n");
cbor_decref(&item);
}
static void test_multibyte_string(void **_CBOR_UNUSED(_state)) {
// "Štěstíčko" in UTF-8
char *string = "\xc5\xa0t\xc4\x9bst\xc3\xad\xc4\x8dko";
cbor_item_t *item = cbor_build_string(string);
assert_describe_result(
item,
"[CBOR_TYPE_STRING] Definite, Length: 13B, Codepoints: 9, Data:\n"
" \xc5\xa0t\xc4\x9bst\xc3\xad\xc4\x8dko\n");
cbor_decref(&item);
}
static void test_definite_array(void **_CBOR_UNUSED(_state)) {
cbor_item_t *item = cbor_new_definite_array(2);
assert_true(cbor_array_push(item, cbor_move(cbor_build_uint8(1))));
assert_true(cbor_array_push(item, cbor_move(cbor_build_uint8(2))));
assert_describe_result(item,
"[CBOR_TYPE_ARRAY] Definite, Size: 2, Contents:\n"
" [CBOR_TYPE_UINT] Width: 1B, Value: 1\n"
" [CBOR_TYPE_UINT] Width: 1B, Value: 2\n");
cbor_decref(&item);
}
static void test_indefinite_array(void **_CBOR_UNUSED(_state)) {
cbor_item_t *item = cbor_new_indefinite_array();
assert_true(cbor_array_push(item, cbor_move(cbor_build_uint8(1))));
assert_true(cbor_array_push(item, cbor_move(cbor_build_uint8(2))));
assert_describe_result(item,
"[CBOR_TYPE_ARRAY] Indefinite, Size: 2, Contents:\n"
" [CBOR_TYPE_UINT] Width: 1B, Value: 1\n"
" [CBOR_TYPE_UINT] Width: 1B, Value: 2\n");
cbor_decref(&item);
}
static void test_definite_map(void **_CBOR_UNUSED(_state)) {
cbor_item_t *item = cbor_new_definite_map(1);
assert_true(cbor_map_add(
item, (struct cbor_pair){.key = cbor_move(cbor_build_uint8(1)),
.value = cbor_move(cbor_build_uint8(2))}));
assert_describe_result(item,
"[CBOR_TYPE_MAP] Definite, Size: 1, Contents:\n"
" Map entry 0\n"
" [CBOR_TYPE_UINT] Width: 1B, Value: 1\n"
" [CBOR_TYPE_UINT] Width: 1B, Value: 2\n");
cbor_decref(&item);
}
static void test_indefinite_map(void **_CBOR_UNUSED(_state)) {
cbor_item_t *item = cbor_new_indefinite_map();
assert_true(cbor_map_add(
item, (struct cbor_pair){.key = cbor_move(cbor_build_uint8(1)),
.value = cbor_move(cbor_build_uint8(2))}));
assert_describe_result(item,
"[CBOR_TYPE_MAP] Indefinite, Size: 1, Contents:\n"
" Map entry 0\n"
" [CBOR_TYPE_UINT] Width: 1B, Value: 1\n"
" [CBOR_TYPE_UINT] Width: 1B, Value: 2\n");
cbor_decref(&item);
}
static void test_tag(void **_CBOR_UNUSED(_state)) {
cbor_item_t *item = cbor_build_tag(42, cbor_move(cbor_build_uint8(1)));
assert_describe_result(item,
"[CBOR_TYPE_TAG] Value: 42\n"
" [CBOR_TYPE_UINT] Width: 1B, Value: 1\n");
cbor_decref(&item);
}
static void test_floats(void **_CBOR_UNUSED(_state)) {
cbor_item_t *item = cbor_new_indefinite_array();
assert_true(cbor_array_push(item, cbor_move(cbor_build_bool(true))));
assert_true(
cbor_array_push(item, cbor_move(cbor_build_ctrl(CBOR_CTRL_UNDEF))));
assert_true(
cbor_array_push(item, cbor_move(cbor_build_ctrl(CBOR_CTRL_NULL))));
assert_true(cbor_array_push(item, cbor_move(cbor_build_ctrl(24))));
assert_true(cbor_array_push(item, cbor_move(cbor_build_float4(3.14f))));
assert_describe_result(
item,
"[CBOR_TYPE_ARRAY] Indefinite, Size: 5, Contents:\n"
" [CBOR_TYPE_FLOAT_CTRL] Bool: true\n"
" [CBOR_TYPE_FLOAT_CTRL] Undefined\n"
" [CBOR_TYPE_FLOAT_CTRL] Null\n"
" [CBOR_TYPE_FLOAT_CTRL] Simple value: 24\n"
" [CBOR_TYPE_FLOAT_CTRL] Width: 4B, Value: 3.140000\n");
cbor_decref(&item);
}
int main(void) { int main(void) {
const struct CMUnitTest tests[] = {cmocka_unit_test(test_pretty_printer)}; const struct CMUnitTest tests[] = {
cmocka_unit_test(test_uint),
cmocka_unit_test(test_negint),
cmocka_unit_test(test_definite_bytestring),
cmocka_unit_test(test_indefinite_bytestring),
cmocka_unit_test(test_definite_string),
cmocka_unit_test(test_indefinite_string),
cmocka_unit_test(test_multibyte_string),
cmocka_unit_test(test_definite_array),
cmocka_unit_test(test_indefinite_array),
cmocka_unit_test(test_definite_map),
cmocka_unit_test(test_indefinite_map),
cmocka_unit_test(test_tag),
cmocka_unit_test(test_floats),
};
return cmocka_run_group_tests(tests, NULL, NULL); return cmocka_run_group_tests(tests, NULL, NULL);
} }

View file

@ -217,6 +217,22 @@ static void test_short_indef_string(void **_CBOR_UNUSED(_state)) {
assert_null(string); assert_null(string);
} }
static void test_invalid_utf(void **_CBOR_UNUSED(_state)) {
/* 0x60 + 1 | 0xC5 (invalid unfinished 2B codepoint) */
unsigned char string_data[] = {0x61, 0xC5};
string = cbor_load(string_data, 2, &res);
assert_non_null(string);
assert_true(cbor_typeof(string) == CBOR_TYPE_STRING);
assert_true(cbor_isa_string(string));
assert_size_equal(cbor_string_length(string), 1);
assert_size_equal(cbor_string_codepoint_count(string), 0);
assert_true(cbor_string_is_definite(string));
assert_true(res.read == 2);
cbor_decref(&string);
}
static void test_inline_creation(void **_CBOR_UNUSED(_state)) { static void test_inline_creation(void **_CBOR_UNUSED(_state)) {
string = cbor_build_string("Hello!"); string = cbor_build_string("Hello!");
assert_memory_equal(cbor_string_handle(string), "Hello!", strlen("Hello!")); assert_memory_equal(cbor_string_handle(string), "Hello!", strlen("Hello!"));
@ -275,6 +291,53 @@ static void test_add_chunk_reallocation_overflow(void **_CBOR_UNUSED(_state)) {
cbor_decref(&string); cbor_decref(&string);
} }
static void test_set_handle(void **_CBOR_UNUSED(_state)) {
string = cbor_new_definite_string();
char *test_string = "Hello";
unsigned char *string_data = malloc(strlen(test_string));
memcpy(string_data, test_string, strlen(test_string));
assert_ptr_not_equal(string_data, NULL);
cbor_string_set_handle(string, string_data, strlen(test_string));
assert_ptr_equal(cbor_string_handle(string), string_data);
assert_size_equal(cbor_string_length(string), 5);
assert_size_equal(cbor_string_codepoint_count(string), 5);
cbor_decref(&string);
}
static void test_set_handle_multibyte_codepoint(void **_CBOR_UNUSED(_state)) {
string = cbor_new_definite_string();
// "Štěstíčko" in UTF-8
char *test_string = "\xc5\xa0t\xc4\x9bst\xc3\xad\xc4\x8dko";
unsigned char *string_data = malloc(strlen(test_string));
memcpy(string_data, test_string, strlen(test_string));
assert_ptr_not_equal(string_data, NULL);
cbor_string_set_handle(string, string_data, strlen(test_string));
assert_ptr_equal(cbor_string_handle(string), string_data);
assert_size_equal(cbor_string_length(string), 13);
assert_size_equal(cbor_string_codepoint_count(string), 9);
cbor_decref(&string);
}
static void test_set_handle_invalid_utf(void **_CBOR_UNUSED(_state)) {
string = cbor_new_definite_string();
// Invalid multi-byte character (missing the second byte).
char *test_string = "Test: \xc5";
unsigned char *string_data = malloc(strlen(test_string));
memcpy(string_data, test_string, strlen(test_string));
assert_ptr_not_equal(string_data, NULL);
cbor_string_set_handle(string, string_data, strlen(test_string));
assert_ptr_equal(cbor_string_handle(string), string_data);
assert_size_equal(cbor_string_length(string), 7);
assert_size_equal(cbor_string_codepoint_count(string), 0);
cbor_decref(&string);
}
int main(void) { int main(void) {
const struct CMUnitTest tests[] = { const struct CMUnitTest tests[] = {
cmocka_unit_test(test_empty_string), cmocka_unit_test(test_empty_string),
@ -285,10 +348,14 @@ int main(void) {
cmocka_unit_test(test_int32_string), cmocka_unit_test(test_int32_string),
cmocka_unit_test(test_int64_string), cmocka_unit_test(test_int64_string),
cmocka_unit_test(test_short_indef_string), cmocka_unit_test(test_short_indef_string),
cmocka_unit_test(test_invalid_utf),
cmocka_unit_test(test_inline_creation), cmocka_unit_test(test_inline_creation),
cmocka_unit_test(test_string_creation), cmocka_unit_test(test_string_creation),
cmocka_unit_test(test_string_add_chunk), cmocka_unit_test(test_string_add_chunk),
cmocka_unit_test(test_add_chunk_reallocation_overflow), cmocka_unit_test(test_add_chunk_reallocation_overflow),
cmocka_unit_test(test_set_handle),
cmocka_unit_test(test_set_handle_multibyte_codepoint),
cmocka_unit_test(test_set_handle_invalid_utf),
}; };
return cmocka_run_group_tests(tests, NULL, NULL); return cmocka_run_group_tests(tests, NULL, NULL);
} }

View file

@ -102,6 +102,28 @@ static void test_nested_tag(void **_CBOR_UNUSED(_state)) {
assert_null(nested_tag); assert_null(nested_tag);
} }
static void test_all_tag_values_supported(void **_CBOR_UNUSED(_state)) {
/* Test all items in the protected range of
* https://www.iana.org/assignments/cbor-tags/cbor-tags.xhtml */
for (int64_t tag_value = 0; tag_value <= 32767; tag_value++) {
cbor_item_t *tag_item =
cbor_build_tag(tag_value, cbor_move(cbor_build_uint8(42)));
unsigned char *serialized_tag;
size_t serialized_tag_size =
cbor_serialize_alloc(tag_item, &serialized_tag, NULL);
assert_true(serialized_tag_size > 0);
tag = cbor_load(serialized_tag, serialized_tag_size, &res);
assert_true(res.read == serialized_tag_size);
assert_true(cbor_typeof(tag) == CBOR_TYPE_TAG);
assert_true(cbor_tag_value(tag) == tag_value);
cbor_decref(&tag);
assert_null(tag);
cbor_decref(&tag_item);
assert_null(tag_item);
free(serialized_tag);
}
}
static void test_build_tag(void **_CBOR_UNUSED(_state)) { static void test_build_tag(void **_CBOR_UNUSED(_state)) {
tag = cbor_build_tag(1, cbor_move(cbor_build_uint8(42))); tag = cbor_build_tag(1, cbor_move(cbor_build_uint8(42)));
@ -134,6 +156,7 @@ int main(void) {
cmocka_unit_test(test_int32_tag), cmocka_unit_test(test_int32_tag),
cmocka_unit_test(test_int64_tag), cmocka_unit_test(test_int64_tag),
cmocka_unit_test(test_nested_tag), cmocka_unit_test(test_nested_tag),
cmocka_unit_test(test_all_tag_values_supported),
cmocka_unit_test(test_build_tag), cmocka_unit_test(test_build_tag),
cmocka_unit_test(test_build_tag_failure), cmocka_unit_test(test_build_tag_failure),
cmocka_unit_test(test_tag_creation), cmocka_unit_test(test_tag_creation),

View file

@ -29,7 +29,7 @@ void finalize_mock_malloc(void) {
free(expectations); free(expectations);
} }
void print_backtrace() { void print_backtrace(void) {
#if HAS_EXECINFO #if HAS_EXECINFO
void *buffer[128]; void *buffer[128];
int frames = backtrace(buffer, 128); int frames = backtrace(buffer, 128);