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:
steps:
- run: sudo apt-get update
- run: sudo apt-get install -y cmake ${TOOLCHAIN_PACKAGES}
- run: sudo apt install libcmocka-dev
# NEEDRESTART_MODE prevents automatic restarts which seem to hang.
- 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:
steps:
- run: >
cmake -DWITH_TESTS=ON \
-DWITH_EXAMPLES=ON \
-DCMAKE_BUILD_TYPE=Debug \
-DSANITIZE=OFF \
-DCOVERAGE="${CMAKE_COVERAGE:='OFF'}" \
@ -31,14 +33,14 @@ orbs:
jobs:
static-test:
machine:
image: ubuntu-2204:2022.10.2
machine: &default-machine
image: ubuntu-2204:2023.07.2
environment:
TOOLCHAIN_PACKAGES: g++
steps:
- checkout
- 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: bash clang-format.sh --verbose
- run: >
@ -60,14 +62,14 @@ jobs:
build-and-test:
machine:
image: ubuntu-2204:2022.10.2
<<: *default-machine
environment:
TOOLCHAIN_PACKAGES: g++
CMAKE_COVERAGE: ON
steps:
- checkout
- linux-setup
- run: sudo apt-get install -y valgrind
- run: sudo NEEDRESTART_MODE=l apt-get install -y valgrind
- build
- test
- run: ctest -T Coverage
@ -81,7 +83,7 @@ jobs:
build-and-test-clang:
machine:
image: ubuntu-2204:2022.10.2
<<: *default-machine
environment:
TOOLCHAIN_PACKAGES: clang
CC: clang
@ -94,11 +96,11 @@ jobs:
build-and-test-32b:
machine:
image: ubuntu-2204:2022.10.2
<<: *default-machine
steps:
- checkout
- 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
- run: git clone https://git.cryptomilk.org/projects/cmocka.git ~/cmocka
- run: >
@ -117,7 +119,7 @@ jobs:
build-and-test-release-clang:
machine:
image: ubuntu-2204:2022.10.2
<<: *default-machine
environment:
TOOLCHAIN_PACKAGES: clang
CC: clang
@ -130,7 +132,7 @@ jobs:
llvm-coverage:
machine:
image: ubuntu-2204:2022.10.2
<<: *default-machine
environment:
TOOLCHAIN_PACKAGES: clang
CC: clang
@ -145,7 +147,7 @@ jobs:
build-and-test-arm:
machine:
image: ubuntu-2204:2022.10.2
<<: *default-machine
environment:
TOOLCHAIN_PACKAGES: g++
resource_class: arm.medium
@ -157,7 +159,7 @@ jobs:
build-bazel:
machine:
image: ubuntu-2204:2022.10.2
image: ubuntu-2204:2023.07.2
environment:
TOOLCHAIN_PACKAGES: g++
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
---------------------
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)
---------------------
- [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:
- 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)
- enable use of versioned SONAME (by Vincent Bernat)
- better fuzzer (wasn't random until now, ooops)

View File

@ -1,14 +1,18 @@
cmake_minimum_required(VERSION 3.0)
project(libcbor)
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/CMakeModules/")
include(CTest)
include(GNUInstallDirs) # Provides CMAKE_INSTALL_ variables
SET(CBOR_VERSION_MAJOR "0")
SET(CBOR_VERSION_MINOR "10")
SET(CBOR_VERSION_PATCH "2")
SET(CBOR_VERSION_MINOR "11")
SET(CBOR_VERSION_PATCH "0")
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(TestBigEndian)
@ -19,10 +23,10 @@ endif()
option(CBOR_CUSTOM_ALLOC "Custom, dynamically defined allocator support" OFF)
if(CBOR_CUSTOM_ALLOC)
message(WARNING
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.")
"Please remove CBOR_CUSTOM_ALLOC from your build configuration.")
endif(CBOR_CUSTOM_ALLOC)
option(CBOR_PRETTY_PRINTER "Include a pretty-printing routine" ON)
@ -138,12 +142,10 @@ if (COVERAGE)
endif()
endif (COVERAGE)
# 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.
# 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)
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
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.
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

View File

@ -48,7 +48,7 @@ PROJECT_NAME = libcbor
# could be handy for archiving the generated documentation or if some version
# 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
# 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)
[![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](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
- Complete RFC conformance
- Robust C99 implementation
- Complete [IETF RFC 8949 (STD 94)](https://www.rfc-editor.org/info/std94) conformance
- Robust platform-independent C99 implementation
- Layered architecture offers both control and convenience
- Flexible memory management
- 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
===============================================
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

View File

@ -33,7 +33,8 @@ extensions = [
'breathe',
'sphinx.ext.mathjax',
'sphinx.ext.autodoc',
'sphinx.ext.ifconfig'
'sphinx.ext.ifconfig',
'sphinx_rtd_theme'
]
import subprocess, os
@ -76,8 +77,8 @@ copyright = '2014 - 2020, Pavel Kalvoda'
# built documents.
#
# The short X.Y version.
version = '0.10'
release = '0.10.2'
version = '0.11'
release = '0.11.0'
# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
@ -127,7 +128,7 @@ pygments_style = 'sphinx'
# The theme to use for HTML and HTML Help pages. See the documentation for
# 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
# further. For a list of options available for each theme, see the
@ -285,12 +286,3 @@ texinfo_documents = [
# If true, do not generate a @detailmenu in the "Top" node's menu.
#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
~~~~~~~~~~~~~~~~~~~~~~
RFC-conformance and full feature support
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Standard conformance and full feature support
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Anything the standard allows, libcbor can do.
**Why?** Because conformance and interoperability is the point of defining
standards. Clients expect the support to be feature-complete and
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.

View File

@ -9,7 +9,7 @@ Overview
Main features
- Complete RFC conformance [#]_
- Complete `IETF RFC 8949 (STD 94) <https://www.rfc-editor.org/info/std94>`_ conformance [#]_
- Robust C99 implementation
- Layered architecture offers both control and convenience
- Flexible memory management
@ -19,7 +19,7 @@ Main features
- Extensive documentation and test suite
- 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`)
@ -31,9 +31,9 @@ Contents
using
api
tests
rfc_conformance
standard_conformance
internal
changelog
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
---------------
=== ====================== ========================================================================================================================================
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
@ -32,7 +32,7 @@ and also borrowing from
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
2. Behave exactly as specified by the standard

View File

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

View File

@ -22,6 +22,10 @@ if(CJSON_FOUND)
add_executable(cjson2cbor cjson2cbor.c)
target_include_directories(cjson2cbor PUBLIC ${CJSON_INCLUDE_DIRS})
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()
file(COPY data DESTINATION .)

View File

@ -2,8 +2,8 @@
#define LIBCBOR_CONFIGURATION_H
#define CBOR_MAJOR_VERSION 0
#define CBOR_MINOR_VERSION 10
#define CBOR_PATCH_VERSION 2
#define CBOR_MINOR_VERSION 11
#define CBOR_PATCH_VERSION 0
#define CBOR_BUFFER_GROWTH 2
#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)
* 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
* subject to change.
*
@ -111,7 +111,7 @@ void cjson_cbor_stream_decode(cJSON *source,
}
void usage(void) {
printf("Usage: cjson [input JSON file]\n");
printf("Usage: cjson2cbor [input JSON file]\n");
exit(1);
}

Binary file not shown.

View File

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

View File

@ -1,4 +1,4 @@
#!/bin/bash -eu
#!/bin/bash -eux
# Copyright 2019 Google Inc.
#
# 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)
include(GNUInstallDirs)
include(JoinPaths)
include(CheckFunctionExists)
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"
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/loaders.h"
#pragma clang diagnostic push
cbor_item_t *cbor_load(cbor_data source, size_t source_size,
struct cbor_load_result *result) {
/* Context stack */
@ -289,7 +290,6 @@ cbor_item_t *cbor_copy(cbor_item_t *item) {
#include <inttypes.h>
#include <locale.h>
#include <stdlib.h>
#include <wchar.h>
#define __STDC_FORMAT_MACROS
@ -301,89 +301,105 @@ static int _pow(int b, int ex) {
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) {
setlocale(LC_ALL, "");
const int indent_offset = 4;
switch (cbor_typeof(item)) {
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, "Value: %" PRIu64 "\n", cbor_get_int(item));
break;
}
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, "Value: -%" PRIu64 " -1\n", cbor_get_int(item));
fprintf(out, "Value: -%" PRIu64 " - 1\n", cbor_get_int(item));
break;
}
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)) {
fprintf(out, "Indefinite, with %zu chunks:\n",
fprintf(out, "Indefinite, Chunks: %zu, Chunk data:\n",
cbor_bytestring_chunk_count(item));
for (size_t i = 0; i < cbor_bytestring_chunk_count(item); i++)
_cbor_nested_describe(cbor_bytestring_chunks_handle(item)[i], out,
indent + 4);
indent + indent_offset);
} 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;
}
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)) {
fprintf(out, "Indefinite, with %zu chunks:\n",
fprintf(out, "Indefinite, Chunks: %zu, Chunk data:\n",
cbor_string_chunk_count(item));
for (size_t i = 0; i < cbor_string_chunk_count(item); i++)
_cbor_nested_describe(cbor_string_chunks_handle(item)[i], out,
indent + 4);
indent + indent_offset);
} 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));
/* Careful - this doesn't support multibyte characters! */
/* Printing those is out of the scope of this demo :) */
/* libICU is your friend */
fprintf(out, "%*s", indent + 4, " ");
/* XXX: no null at the end -> confused vprintf */
fwrite(cbor_string_handle(item), (int)cbor_string_length(item), 1, out);
fprintf(out, "%*s", indent + indent_offset, " ");
// Note: The string is not escaped, whitespace and control character
// will be printed in verbatim and take effect.
fwrite(cbor_string_handle(item), sizeof(unsigned char),
cbor_string_length(item), out);
fprintf(out, "\n");
}
break;
}
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)) {
fprintf(out, "Definite, size: %zu\n", cbor_array_size(item));
fprintf(out, "Definite, Size: %zu, Contents:\n", cbor_array_size(item));
} 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++)
_cbor_nested_describe(cbor_array_handle(item)[i], out, indent + 4);
_cbor_nested_describe(cbor_array_handle(item)[i], out,
indent + indent_offset);
break;
}
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)) {
fprintf(out, "Definite, size: %zu\n", cbor_map_size(item));
fprintf(out, "Definite, Size: %zu, Contents:\n", cbor_map_size(item));
} 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++) {
_cbor_nested_describe(cbor_map_handle(item)[i].key, out, indent + 4);
_cbor_nested_describe(cbor_map_handle(item)[i].value, out, indent + 4);
fprintf(out, "%*sMap entry %zu\n", indent + indent_offset, " ", i);
_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;
}
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));
_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;
}
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_is_bool(item))
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))
fprintf(out, "Null\n");
else
fprintf(out, "Simple value %d\n", cbor_ctrl_value(item));
fprintf(out, "Simple value: %d\n", cbor_ctrl_value(item));
} else {
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;
}

View File

@ -157,7 +157,7 @@ _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 */
/* Standard CBOR Major item types */
/** Does the item have the appropriate major type?
* @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
// 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;
}
// Odd record, this is a value.
ctx->creation_failed =
!_cbor_map_add_value(ctx->stack->top->item, item);
// Adding a value never fails since the memory is allocated when the
// key is added
CBOR_ASSERT(!ctx->creation_failed);
} else {
/* Even record, this is a key */
// Even record, this is a key.
if (!_cbor_map_add_key(ctx->stack->top->item, item)) {
ctx->creation_failed = true;
cbor_decref(&item);
@ -256,18 +256,8 @@ void cbor_builder_string_callback(void *context, cbor_data data,
uint64_t length) {
struct _cbor_decoder_context *ctx = context;
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);
if (new_handle == NULL) {
ctx->creation_failed = true;
return;
@ -281,7 +271,6 @@ void cbor_builder_string_callback(void *context, cbor_data data,
return;
}
cbor_string_set_handle(new_chunk, new_handle, length);
new_chunk->metadata.string_metadata.codepoint_count = codepoint_count;
// If an indef string is on the stack, extend it (if it were closed, it would
// have been popped). Handle any syntax errors upstream.
@ -355,6 +344,8 @@ bool _cbor_is_indefinite(cbor_item_t *item) {
case CBOR_TYPE_MAP:
return cbor_map_is_indefinite(item);
default:
// Should never happen since a non-nested item cannot be on top of the
// stack.
return false;
}
}

View File

@ -49,7 +49,7 @@ uint64_t _cbor_load_uint64(const unsigned char *source) {
#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) {
int half = (halfp[0] << 8) + halfp[1];
int exp = (half >> 10) & 0x1f;

View File

@ -21,7 +21,7 @@ bool _cbor_safe_to_multiply(size_t a, size_t b);
_CBOR_NODISCARD
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
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;
}
uint64_t _cbor_unicode_codepoint_count(cbor_data source, uint64_t source_length,
struct _cbor_unicode_status* status) {
size_t _cbor_unicode_codepoint_count(cbor_data source, size_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;
uint64_t pos = 0, count = 0;
size_t pos = 0, count = 0;
for (; pos < source_length; pos++) {
res = _cbor_unicode_decode(&state, &codepoint, source[pos]);

View File

@ -19,12 +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;
uint64_t location;
size_t location;
};
_CBOR_NODISCARD
uint64_t _cbor_unicode_codepoint_count(cbor_data source, uint64_t source_length,
struct _cbor_unicode_status* status);
size_t _cbor_unicode_codepoint_count(cbor_data source, size_t source_length,
struct _cbor_unicode_status* status);
#ifdef __cplusplus
}

View File

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

View File

@ -8,6 +8,7 @@
#include "strings.h"
#include <string.h>
#include "internal/memory_utils.h"
#include "internal/unicode.h"
cbor_item_t *cbor_new_definite_string(void) {
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));
item->data = data;
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) {

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
*
* 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
* @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
*
* 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
* .. 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
*
* 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
* @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
*
* 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
* byte)
* All @p `length` bytes will be stored in the string, even if there are null
* 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`.
* @return Reference to the new string item. The item's reference count is
* 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);
}
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) {
const struct CMUnitTest tests[] = {
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_map_failure),
cmocka_unit_test(test_invalid_indef_break),
cmocka_unit_test(test_invalid_state_indef_break),
};
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);
}
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)) {
cbor_item_t *item = cbor_new_indefinite_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)) {
cbor_item_t *item = cbor_new_definite_string();
unsigned char *data = malloc(12);
memset(data, 0, 12);
cbor_string_set_handle(item, data, 12);
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 *chunk = cbor_new_definite_string();
unsigned char *data = malloc(256);
memset(data, 0, 256);
cbor_string_set_handle(chunk, data, 256);
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_indefinite_bytestring_no_space),
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_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);
}
unsigned char bad_tag_data[] = {0xC6};
static void test_bad_tag_decoding(void **_CBOR_UNUSED(_state)) {
assert_decoder_result(0, CBOR_DECODER_ERROR, decode(bad_tag_data, 1));
unsigned char reserved_byte_data[] = {0xDC};
static void test_reserved_byte_decoding(void **_CBOR_UNUSED(_state)) {
assert_decoder_result(0, CBOR_DECODER_ERROR, decode(reserved_byte_data, 1));
}
unsigned char float2_data[] = {0xF9, 0x7B, 0xFF};
@ -729,7 +729,7 @@ int main(void) {
stream_test(test_int16_tag_decoding),
stream_test(test_int32_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_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_float_get_width(float_ctrl) == CBOR_FLOAT_16);
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);
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_float_get_width(float_ctrl) == CBOR_FLOAT_32);
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);
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);
// 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);
// 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);
assert_null(float_ctrl);
}

View File

@ -6,33 +6,200 @@
*/
#include <stdio.h>
#include <string.h>
#include "assertions.h"
#include "cbor.h"
unsigned char data[] = {0x8B, 0x01, 0x20, 0x5F, 0x41, 0x01, 0x41, 0x02,
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)) {
void assert_describe_result(cbor_item_t *item, char *expected_result) {
#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();
struct cbor_load_result res;
cbor_item_t *item = cbor_load(data, 37, &res);
cbor_describe(item, outfile);
cbor_decref(&item);
item = cbor_new_ctrl();
cbor_set_ctrl(item, 1);
cbor_describe(item, outfile);
cbor_decref(&item);
rewind(outfile);
// Treat string as null-terminated since cmocka doesn't have asserts
// for explicit length strings.
char *output = malloc(buffer_size);
assert_non_null(output);
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);
#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) {
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);
}

View File

@ -217,6 +217,22 @@ static void test_short_indef_string(void **_CBOR_UNUSED(_state)) {
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)) {
string = cbor_build_string("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);
}
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) {
const struct CMUnitTest tests[] = {
cmocka_unit_test(test_empty_string),
@ -285,10 +348,14 @@ int main(void) {
cmocka_unit_test(test_int32_string),
cmocka_unit_test(test_int64_string),
cmocka_unit_test(test_short_indef_string),
cmocka_unit_test(test_invalid_utf),
cmocka_unit_test(test_inline_creation),
cmocka_unit_test(test_string_creation),
cmocka_unit_test(test_string_add_chunk),
cmocka_unit_test(test_add_chunk_reallocation_overflow),
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);
}

View File

@ -102,6 +102,28 @@ static void test_nested_tag(void **_CBOR_UNUSED(_state)) {
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)) {
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_int64_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_failure),
cmocka_unit_test(test_tag_creation),

View File

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