Scroll to navigation

LIBCBOR(3) libcbor LIBCBOR(3)

NAME

libcbor - libcbor Documentation

Documentation for version 0.11.0, updated on Sep 16, 2024.

OVERVIEW

libcbor is a C library for parsing and generating CBOR, the general-purpose schema-less binary data format.

  • Complete IETF RFC 8949 (STD 94) conformance [1]
  • Robust C99 implementation
  • Layered architecture offers both control and convenience
  • Flexible memory management
  • No shared global state - threading friendly [2]
  • Proper handling of UTF-8
  • Full support for streams & incremental processing
  • Extensive documentation and test suite
  • No runtime dependencies, small footprint


[1]
See IETF standard conformance
[2]
With the exception of custom memory allocators (see Memory management and reference counting)

CONTENTS

Getting started

Pre-built Linux packages are available in most mainstream distributions

Ubuntu, Debian, etc.:

apt-get install libcbor-dev


Fedora, openSUSE, etc.:

yum install libcbor-devel


OS X users can use Homebrew:

brew install libcbor


For other platforms, you will need to compile it from source.

Building & installing libcbor

  • C99 compiler
  • CMake 2.8 or newer (might also be called cmakesetup, cmake-gui or ccmake depending on the installed version and system)
  • C build system CMake can target (make, Apple Xcode, MinGW, ...)


Configuration options

A handful of configuration flags can be passed to cmake. The following table lists libcbor compile-time directives and several important generic flags.

Option Meaning Default Possible values
CMAKE_C_COMPILER C compiler to use cc gcc, clang, clang-3.5, ...
CMAKE_INSTALL_PREFIX Installation prefix System-dependent /usr/local/lib, ...
BUILD_SHARED_LIBS Build as a shared library OFF ON, OFF
HUGE_FUZZ Fuzz test with 8GB of data OFF ON, OFF
SANE_MALLOC Assume malloc will refuse unreasonable allocations OFF ON, OFF
COVERAGE Generate test coverage instrumentation OFF ON, OFF
WITH_TESTS Build unit tests (see Development) OFF ON, OFF

The following configuration options will also be defined as macros [1] in <cbor/common.h> and can therefore be used in client code:

Option Meaning Default Possible values
CBOR_PRETTY_PRINTER Include a pretty-printing routine ON ON, OFF
CBOR_BUFFER_GROWTH Factor for buffer growth & shrinking 2 Decimals > 1
[1]
ON & OFF will be translated to 1 and 0 using cmakedefine.

If you want to pass other custom configuration options, please refer to http://www.cmake.org/Wiki/CMake_Useful_Variables.

WARNING:

CBOR_CUSTOM_ALLOC has been removed. Custom allocators (historically a controlled by a build flag) are always enabled.


Building using make

CMake will generate a Makefile and other configuration files for the build. As a rule of thumb, you should configure the build outside of the source tree in order to keep different configurations isolated. If you are unsure where to execute the build, just use a temporary directory:

cd $(mktemp -d /tmp/cbor_build.XXXX)


Now, assuming you are in the directory where you want to build, build libcbor as a static library:

cmake -DCMAKE_BUILD_TYPE=Release path_to_libcbor_dir
make cbor


... or as a dynamic library:

cmake -DCMAKE_BUILD_TYPE=Release  -DBUILD_SHARED_LIBS=ON path_to_libcbor_dir
make cbor


To install locally:

make install


Root permissions are required on most systems when using the default installation prefix.

Portability

libcbor is highly portable and works on both little- and big-endian systems regardless of the operating system. After building on an exotic platform, you might wish to verify the result by running the test suite. If you encounter any problems, please report them to the issue tracker.

libcbor is known to successfully work on ARM Android devices. Cross-compilation is possible with arm-linux-gnueabi-gcc.

Linking with libcbor

If you include and linker paths include the directories to which libcbor has been installed, compiling programs that uses libcbor requires no extra considerations.

You can verify that everything has been set up properly by creating a file with the following contents

#include <cbor.h>
#include <stdio.h>
int main(int argc, char * argv[])
{

printf("Hello from libcbor %s\n", CBOR_VERSION); }


and compiling it

cc hello_cbor.c -lcbor -o hello_cbor


libcbor also comes with pkg-config support. If you install libcbor with a custom prefix, you can use pkg-config to resolve the headers and objects:

cc $(pkg-config --cflags libcbor) hello_cbor.c $(pkg-config --libs libcbor) -o hello_cbor


A note on linkage

libcbor is primarily intended to be linked statically. The shared library versioning scheme generally follows SemVer, but is irregular for the 0.X.Y development branch for historical reasons. The following version identifiers are used as a part of the SONAME (Linux) or the dylib "Compatibility version" (OS X):

  • 0.Y for the 0.Y.Z branch. Patches are backwards compatible, minor releases are generally not and require re-compilation of any dependent code.
  • X for the X.Y.Z stable versions starting 1.X.Y. All minor release of the major version are backwards compatible.



WARNING:

Please note that releases up to and including v0.6.0 may export misleading .so/.dylib version number.


Troubleshooting

cbor.h not found: The headers directory is probably not in your include path. First, verify the installation location by checking the installation log. If you used make, it will look something like

...
-- Installing: /usr/local/include/cbor
-- Installing: /usr/local/include/cbor/callbacks.h
-- Installing: /usr/local/include/cbor/encoding.h
...


Make sure that CMAKE_INSTALL_PREFIX (if you provided it) was correct. Including the path path during compilation should suffice, e.g.:

cc -I/usr/local/include hello_cbor.c -lcbor -o hello_cbor


cannot find -lcbor during linking: Most likely the same problem as before. Include the installation directory in the linker shared path using -R, e.g.:

cc -Wl,-rpath,/usr/local/lib -lcbor -o hello_cbor


shared library missing during execution: Verify the linkage using ldd, otool, or similar and adjust the compilation directives accordingly:

⇒  ldd hello_cbor

linux-vdso.so.1 => (0x00007ffe85585000)
libcbor.so => /usr/local/lib/libcbor.so (0x00007f9af69da000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f9af65eb000)
/lib64/ld-linux-x86-64.so.2 (0x00007f9af6be9000)


compilation failed: If your compiler supports C99 yet the compilation has failed, please report the issue to the issue tracker.

Usage & preliminaries

Version information

libcbor exports its version using three self-explanatory macros:

  • CBOR_MAJOR_VERSION
  • CBOR_MINOR_VERSION
  • CBOR_PATCH_VERSION



The CBOR_VERSION is a string concatenating these three identifiers into one (e.g. 0.2.0).

In order to simplify version comparisons, the version is also exported as

#define CBOR_HEX_VERSION ((CBOR_MAJOR_VERSION << 16) | (CBOR_MINOR_VERSION << 8) | CBOR_PATCH_VERSION)


Since macros are difficult to work with through FFIs, the same information is also available through three uint8_t constants, namely

  • cbor_major_version
  • cbor_minor_version
  • cbor_patch_version



Headers to include

The cbor.h header includes all the symbols. If, for any reason, you don't want to include all the exported symbols, feel free to use just some of the cbor/*.h headers:

  • cbor/arrays.h - Type 4 – Arrays
  • cbor/bytestrings.h - Type 2 – Byte strings
  • cbor/callbacks.h - Callbacks used for Streaming Decoding
  • cbor/common.h - Common utilities - always transitively included
  • cbor/data.h - Data types definitions - always transitively included
  • cbor/encoding.h - Streaming encoders for Streaming Encoding
  • cbor/floats_ctrls.h - Type 7 – Floats & control tokens
  • cbor/ints.h - Types 0 & 1 – Positive and negative integers
  • cbor/maps.h - Type 5 – Maps
  • cbor/serialization.h - High level serialization such as cbor_serialize()
  • cbor/streaming.h - Home of cbor_stream_decode()
  • cbor/strings.h - Type 3 – UTF-8 strings
  • cbor/tags.h - Type 6 – Semantic tags



Using libcbor

If you want to get more familiar with CBOR, we recommend the cbor.io website. Once you get the grasp of what is it CBOR does, the examples (located in the examples directory) should give you a good feel of the API. The API documentation should then provide with all the information you may need.

Creating and serializing items

#include "cbor.h"
#include <stdio.h>
int main(int argc, char * argv[])
{

/* Preallocate the map structure */
cbor_item_t * root = cbor_new_definite_map(2);
/* Add the content */
cbor_map_add(root, (struct cbor_pair) {
.key = cbor_move(cbor_build_string("Is CBOR awesome?")),
.value = cbor_move(cbor_build_bool(true))
});
cbor_map_add(root, (struct cbor_pair) {
.key = cbor_move(cbor_build_uint8(42)),
.value = cbor_move(cbor_build_string("Is the answer"))
});
/* Output: `buffer_size` bytes of data in the `buffer` */
unsigned char * buffer;
size_t buffer_size;
cbor_serialize_alloc(root, &buffer, &buffer_size);
fwrite(buffer, 1, buffer_size, stdout);
free(buffer);
fflush(stdout);
cbor_decref(&root); }


Reading serialized data

#include "cbor.h"
#include <stdio.h>
/*

* Reads data from a file. Example usage:
* $ ./examples/readfile examples/data/nested_array.cbor
*/ int main(int argc, char * argv[]) {
FILE * f = fopen(argv[1], "rb");
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 `info.st_size` bytes of input data */
struct cbor_load_result result;
cbor_item_t * item = cbor_load(buffer, length, &result);
/* Pretty-print the result */
cbor_describe(item, stdout);
fflush(stdout);
/* Deallocate the result */
cbor_decref(&item);
fclose(f); }


Using the streaming parser

#include "cbor.h"
#include <stdio.h>
#include <string.h>
/*

* Illustrates how one might skim through a map (which is assumed to have
* string keys and values only), looking for the value of a specific key
*
* Use the examples/data/map.cbor input to test this.
*/ const char * key = "a secret key"; bool key_found = false; void find_string(void * _ctx, cbor_data buffer, size_t len) {
if (key_found) {
printf("Found the value: %*s\n", (int) len, buffer);
key_found = false;
} else if (len == strlen(key)) {
key_found = (memcmp(key, buffer, len) == 0);
} } int main(int argc, char * argv[]) {
FILE * f = fopen(argv[1], "rb");
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);
struct cbor_callbacks callbacks = cbor_empty_callbacks;
struct cbor_decoder_result decode_result;
size_t bytes_read = 0;
callbacks.string = find_string;
while (bytes_read < length) {
decode_result = cbor_stream_decode(buffer + bytes_read,
length - bytes_read,
&callbacks, NULL);
bytes_read += decode_result.read;
}
fclose(f); }


API

The data API is centered around cbor_item_t, a generic handle for any CBOR item. There are functions to

  • create items,
  • set items' data,
  • parse serialized data into items,
  • manage, move, and links item together.



The single most important thing to keep in mind is: cbor_item_t is an opaque type and should only be manipulated using the appropriate functions! Think of it as an object.

The libcbor API closely follows the semantics outlined by CBOR standard. This part of the documentation provides a short overview of the CBOR constructs, as well as a general introduction to the libcbor API. Remaining reference can be found in the following files structured by data types.

The API is designed to allow both very tight control & flexibility and general convenience with sane defaults. [1] For example, client with very specific requirements (constrained environment, custom application protocol built on top of CBOR, etc.) may choose to take full control (and responsibility) of memory and data structures management by interacting directly with the decoder. Other clients might want to take control of specific aspects (streamed collections, hash maps storage), but leave other responsibilities to libcbor. More general clients might prefer to be abstracted away from all aforementioned details and only be presented complete data structures.

  • stateless encoders and decoders
  • encoding and decoding drivers, routines that coordinate encoding and decoding of complex structures
  • data structures to represent and transform CBOR structures
  • routines for building and manipulating these structures
  • utilities for inspection and debugging


Types of items

Every cbor_item_t has a cbor_type associated with it - these constants correspond to the types specified by the CBOR standard:

Specifies the Major type of cbor_item_t.

Values:

0 - positive integers

1 - negative integers






7 - decimals and special values (true, false, nil, ...)


To find out the type of an item, one can use


Please note the distinction between functions like cbor_isa_uint() and cbor_is_int(). The following functions work solely with the major type value.

Binary queries

Alternatively, there are functions to query each particular type.

WARNING:

Passing an invalid cbor_item_t reference to any of these functions results in undefined behavior.


Does the item have the appropriate major type?
the item
Is the item an CBOR_TYPE_UINT?


Does the item have the appropriate major type?
the item
Is the item a CBOR_TYPE_NEGINT?


Does the item have the appropriate major type?
the item
Is the item a CBOR_TYPE_BYTESTRING?


Does the item have the appropriate major type?
the item
Is the item a CBOR_TYPE_STRING?


Does the item have the appropriate major type?
the item
Is the item an CBOR_TYPE_ARRAY?


Does the item have the appropriate major type?
the item
Is the item a CBOR_TYPE_MAP?


Does the item have the appropriate major type?
the item
Is the item a CBOR_TYPE_TAG?


Does the item have the appropriate major type?
the item
Is the item a CBOR_TYPE_FLOAT_CTRL?


Logical queries

These functions provide information about the item type from a more high-level perspective

Is the item an integer, either positive or negative?
the item
Is the item an integer, either positive or negative?


Is the item an a floating point number?
the item
Is the item a floating point number?


Is the item an a boolean?
the item
Is the item a boolean?


Does this item represent null

WARNING:

This is in no way related to the value of the pointer. Passing a null pointer will most likely result in a crash.


the item
Is the item (CBOR logical) null?


Does this item represent undefined

WARNING:

Care must be taken to distinguish nulls and undefined values in C.


the item
Is the item (CBOR logical) undefined?


Memory management and reference counting

Due to the nature of its domain, libcbor will need to work with heap memory. The stateless decoder and encoder doesn't allocate any memory.

If you have specific requirements, you should consider rolling your own driver for the stateless API.

Using custom allocator

libcbor gives you with the ability to provide your own implementations of malloc, realloc, and free. This can be useful if you are using a custom allocator throughout your application, or if you want to implement custom policies (e.g. tighter restrictions on the amount of allocated memory).

cbor_set_allocs(malloc, realloc, free);


Sets the memory management routines to use.

By default, libcbor will use the standard library malloc, realloc, and free.

NOTE:

realloc implementation must correctly support NULL reallocation (see e.g. http://en.cppreference.com/w/c/memory/realloc)


WARNING:

This function modifies the global state and should therefore be used accordingly. Changing the memory handlers while allocated items exist will result in a free/malloc mismatch. This function is not thread safe with respect to both itself and all the other libcbor functions that work with the heap.


malloc implementation
realloc implementation
free implementation


Reference counting

As CBOR items may require complex cleanups at the end of their lifetime, there is a reference counting mechanism in place. This also enables a very simple GC when integrating libcbor into a managed environment. Every item starts its life (by either explicit creation, or as a result of parsing) with reference count set to 1. When the refcount reaches zero, it will be destroyed.

Items containing nested items will be destroyed recursively - the refcount of every nested item will be decreased by one.

The destruction is synchronous and renders any pointers to items with refcount zero invalid immediately after calling cbor_decref().

Increases the item's reference count by one.

Constant complexity; items referring to this one or items being referred to are not updated.

This function can be used to extend reference counting to client code.

Reference to an item
The input item


Decreases the item's reference count by one, deallocating the item if needed.

In case the item is deallocated, the reference count of all items this item references will also be cbor_decref 'ed recursively.

Reference to an item. Will be set to NULL if deallocated


Decreases the item's reference count by one, deallocating the item if needed.

Convenience wrapper for cbor_decref when its set-to-null behavior is not needed

Reference to an item


Get the item's reference count.

Add some inline examples for reference counting

WARNING:

This does not account for transitive references.


the item
the reference count


Provides CPP-like move construct.

Decreases the reference count by one, but does not deallocate the item even if its refcount reaches zero. This is useful for passing intermediate values to functions that increase reference count. Should only be used with functions that incref their arguments.

WARNING:

If the item is moved without correctly increasing the reference count afterwards, the memory will be leaked.


Reference to an item
the item with reference count decreased by one


Take a deep copy of an item.

All items this item points to (array and map members, string chunks, tagged items) will be copied recursively using cbor_copy. The new item doesn't alias or point to any items from the original item. All the reference counts in the new structure are set to one.

item to copy
Reference to the new item. The item's reference count is initialized to one.
NULL if memory allocation fails


Decoding

The following diagram illustrates the relationship among different parts of libcbor from the decoding standpoint.

┌──────────────────────────────────────────────────────────────────────────────────────────────┐
│                                                                                              │
│                                      Client application                                      │
│                                                                                              │
│                                                 ┌────────────────────────────────────────────┘
│                                                 │                     ↕
│                                                 │ ┌──────────────────────────────────────────┐
│                                                 │ │                                          │
│                                                 │ │          Manipulation routines           │
│                                                 │ │                                          │
│           ┌─────────────────────────────────────┘ └──────────────────────────────────────────┘
│           │     ↑    ↑                  ↑                              ↑
│           │     │    │    ┌─────────────╫──────────┬───────────────────┴─┐
│           │     │   CDS   │             ║          │                     │
│           │     │    │   PDS            ║         PDS                   PDS
│           │     ↓    ↓    ↓             ↓          ↓                     ↓
│           │ ┌─────────────────┐   ┌────────────────────┐   ┌────────────────────────────┐
│           │ │                 │   │                    │   │                            │
│           │ │  Custom driver  │ ↔ │  Streaming driver  │ ↔ │       Default driver       │ ↔ CD
│           │ │                 │   │                    │   │                            │
└───────────┘ └─────────────────┘   └────────────────────┘   └────────────────────────────┘

↕ ↕ ↕ ↕ ┌──────────────────────────────────────────────────────────────────────────────────────────────┐ │ │ │ Stateless event─driven decoder │ │ │ └──────────────────────────────────────────────────────────────────────────────────────────────┘
(PSD = Provided Data Structures, CDS = Custom Data Structures)


This section will deal with the API that is labeled as the "Default driver" in the diagram. That is, routines that decode complete libcbor data items

Loads data item from a buffer.
The buffer

[out] Result indicator. CBOR_ERR_NONE on success
Decoded CBOR item. The item's reference count is initialized to one.
NULL on failure. In that case, result contains the location and description of the error.


Associated data structures

Possible decoding errors.

Values:





Memory error - item allocation failed.

Is it too big for your allocator?


Stack parsing algorithm failed.


High-level decoding result.

Public Members

Error indicator.

Number of bytes read.


High-level decoding error.

Public Members

Approximate position.

Description.


Encoding

The easiest way to encode data items is using the cbor_serialize() or cbor_serialize_alloc() functions:

Serialize the given item.
A data item
Buffer to serialize to
Size of the buffer
Length of the result. 0 on failure.


Serialize the given item, allocating buffers as needed.

Since libcbor v0.10, the return value is always the same as buffer_size (if provided, see https://github.com/PJK/libcbor/pull/251/). New clients should ignore the return value.

WARNING:

It is the caller's responsibility to free the buffer using an appropriate free implementation.


A data item
[out] Buffer containing the result
[out] Size of the buffer, or 0 on memory allocation failure.
Length of the result in bytes
0 on memory allocation failure, in which case buffer is NULL.


To determine the number of bytes needed to serialize an item, use cbor_serialized_size():

Compute the length (in bytes) of the item when serialized using cbor_serialize.

Time complexity is proportional to the number of nested items.

A data item
Length (>= 1) of the item when serialized. 0 if the length overflows size_t.


Type-specific serializers

In case you know the type of the item you want to serialize beforehand, you can use one of the type-specific serializers.

NOTE:

Unless compiled in debug mode, these do not verify the type. Passing an incorrect item will result in an undefined behavior.


Serialize an uint.
A uint
[out] Buffer to serialize to
Size of the buffer
Length of the result
0 if the buffer_size doesn't fit the result


Serialize a negint.
A negint
[out] Buffer to serialize to
Size of the buffer
Length of the result
0 if the buffer_size doesn't fit the result


Serialize a bytestring.
A bytestring
[out] Buffer to serialize to
Size of the buffer
Length of the result
0 if the buffer_size doesn't fit the result. The buffer may still be modified


Serialize a string.
A string
[out] Buffer to serialize to
Size of the buffer
Length of the result
0 if the buffer_size doesn't fit the result. The buffer may still be modified


Serialize an array.
An array
[out] Buffer to serialize to
Size of the buffer
Length of the result
0 if the buffer_size doesn't fit the result. The buffer may still be modified


Serialize a map.
A map
[out] Buffer to serialize to
Size of the buffer
Length of the result
0 if the buffer_size doesn't fit the result. The buffer may still be modified


Serialize a tag.
A tag
[out] Buffer to serialize to
Size of the buffer
Length of the result
0 if the buffer_size doesn't fit the result. The buffer may still be modified


Serialize a.
A float or ctrl
[out] Buffer to serialize to
Size of the buffer
Length of the result
0 if the buffer_size doesn't fit the result


Streaming Decoding

libcbor exposes a stateless decoder that reads a stream of input bytes from a buffer and invokes user-provided callbacks as it decodes the input:

Stateless decoder.

Will try parsing the source and will invoke the appropriate callback on success. Decodes one item at a time. No memory allocations occur.

Input buffer
Length of the buffer
The callback bundle
An arbitrary pointer to allow for maintaining context.


For example, when cbor_stream_decode() encounters a 1B unsigned integer, it will invoke the function pointer stored in cbor_callbacks.uint8. Complete usage example: examples/streaming_parser.c

The callbacks are defined by


When building custom sets of callbacks, feel free to start from

Dummy callback bundle - does nothing.

Callback types definition











Streaming Encoding

cbor/encoding.h exposes a low-level encoding API to encode CBOR objects on the fly. Unlike cbor_serialize(), these functions take logical values (integers, floats, strings, etc.) instead of cbor_item_t. The client is responsible for constructing the compound types correctly (e.g. terminating arrays).

Streaming encoding is typically used to create an streaming (indefinite length) CBOR strings, byte strings, arrays, and maps. Complete example: examples/streaming_array.c























Encodes a half-precision float.

Since there is no native representation or semantics for half floats in the language, we use single-precision floats, as every value that can be expressed as a half-float can also be expressed as a float.

This however means that not all floats passed to this function can be unambiguously encoded. The behavior is as follows:.INDENT 7.0

  • Infinity, NaN are preserved
  • Zero is preserved
  • Denormalized numbers keep their sign bit and 10 most significant bit of the significand
  • All other numbers.INDENT 2.0
  • If the logical value of the exponent is < -24, the output is zero
  • If the logical value of the exponent is between -23 and -14, the output is cut off to represent the 'magnitude' of the input, by which we mean (-1)^{signbit} x 1.0e{exponent}. The value in the significand is lost.
  • In all other cases, the sign bit, the exponent, and 10 most significant bits of the significand are kept







Types 0 & 1 – Positive and negative integers

CBOR has two types of integers – positive (which may be effectively regarded as unsigned), and negative. There are four possible widths for an integer – 1, 2, 4, or 8 bytes. These are represented by


Type 0 - positive integers

Corresponding cbor_type CBOR_TYPE_UINT
Number of allocations One per lifetime
Storage requirements sizeof(cbor_item_t) + sizeof(uint*_t)

Note: once a positive integer has been created, its width cannot be changed.

Type 1 - negative integers

Corresponding cbor_type CBOR_TYPE_NEGINT
Number of allocations One per lifetime
Storage requirements sizeof(cbor_item_t) + sizeof(uint*_t)

Note: once a positive integer has been created, its width cannot be changed.

Type 0 & 1

Due to their largely similar semantics, the following functions can be used for both Type 0 and Type 1 items. One can convert between them freely using the conversion functions.

Actual Type of the integer can be checked using item types API.

An integer item is created with one of the four widths. Because integers' storage is bundled together with the handle, the width cannot be changed over its lifetime.

WARNING:

Due to the fact that CBOR negative integers represent integers in the range [-1, -2^N], cbor_set_uint API is somewhat counter-intuitive as the resulting logical value is 1 less. This behavior is necessary in order to permit uniform manipulation with the full range of permitted values. For example, the following snippet

cbor_item_t * item = cbor_new_int8();
cbor_mark_negint(item);
cbor_set_uint8(0);


will produce an item with the logical value of -1. There is, however, an upside to this as well: There is only one representation of zero.



Building new items

Constructs a new positive integer.
the value to use
new positive integer or NULL on memory allocation failure


Constructs a new positive integer.
the value to use
new positive integer or NULL on memory allocation failure


Constructs a new positive integer.
the value to use
new positive integer or NULL on memory allocation failure


Constructs a new positive integer.
the value to use
new positive integer or NULL on memory allocation failure


Retrieving values

Extracts the integer value.
positive or negative integer
the value


Extracts the integer value.
positive or negative integer
the value


Extracts the integer value.
positive or negative integer
the value


Extracts the integer value.
positive or negative integer
the value


Setting values

Assigns the integer value.
positive or negative integer item
the value to assign. For negative integer, the logical value is -value - 1


Assigns the integer value.
positive or negative integer item
the value to assign. For negative integer, the logical value is -value - 1


Assigns the integer value.
positive or negative integer item
the value to assign. For negative integer, the logical value is -value - 1


Assigns the integer value.
positive or negative integer item
the value to assign. For negative integer, the logical value is -value - 1


Dealing with width

Queries the integer width.
positive or negative integer item
the width


Dealing with signedness

Marks the integer item as a positive integer.

The data value is not changed

positive or negative integer item


Marks the integer item as a negative integer.

The data value is not changed

positive or negative integer item


Creating new items

Allocates new integer with 1B width.

The width cannot be changed once allocated

new positive integer or NULL on memory allocation failure. The value is not initialized


Allocates new integer with 2B width.

The width cannot be changed once allocated

new positive integer or NULL on memory allocation failure. The value is not initialized


Allocates new integer with 4B width.

The width cannot be changed once allocated

new positive integer or NULL on memory allocation failure. The value is not initialized


Allocates new integer with 8B width.

The width cannot be changed once allocated

new positive integer or NULL on memory allocation failure. The value is not initialized


Type 2 – Byte strings

CBOR byte strings are just (ordered) series of bytes without further interpretation (unless there is a tag). Byte string's length may or may not be known during encoding. These two kinds of byte strings can be distinguished using cbor_bytestring_is_definite() and cbor_bytestring_is_indefinite() respectively.

In case a byte string is indefinite, it is encoded as a series of definite byte strings. These are called "chunks". For example, the encoded item

0xf5            Start indefinite byte string

0x41 Byte string (1B long)
0x00
0x41 Byte string (1B long)
0xff
0xff "Break" control token


represents two bytes, 0x00 and 0xff. This on one hand enables streaming messages even before they are fully generated, but on the other hand it adds more complexity to the client code.

Corresponding cbor_type CBOR_TYPE_BYTESTRING
Number of allocations (definite) One plus any manipulations with the data
Number of allocations (indefinite) One plus logarithmically many reallocations relative to chunk count
Storage requirements (definite) sizeof(cbor_item_t) + length(handle)
Storage requirements (indefinite) sizeof(cbor_item_t) * (1 + chunk_count) + chunks

Getting metadata

Returns the length of the binary data.

For definite byte strings only

a definite bytestring
length of the binary data. Zero if no chunk has been attached yet


Is the byte string definite?
a byte string
Is the byte string definite?


Is the byte string indefinite?
a byte string
Is the byte string indefinite?


Get the number of chunks this string consist of.
A indefinite bytestring
The chunk count. 0 for freshly created items.


Reading data

Get the handle to the binary data.

Definite items only. Modifying the data is allowed. In that case, the caller takes responsibility for the effect on items this item might be a part of

A definite byte string
The address of the underlying binary data
NULL if no data have been assigned yet.


Get the handle to the array of chunks.

Manipulations with the memory block (e.g. sorting it) are allowed, but the validity and the number of chunks must be retained.

A indefinite byte string
array of cbor_bytestring_chunk_count definite bytestrings


Creating new items

Creates a new definite byte string.

The handle is initialized to NULL and length to 0

Reference to the new bytestring item. The item's reference count is initialized to one.
NULL if memory allocation fails


Creates a new indefinite byte string.

The chunks array is initialized to NULL and chunk count to 0

Reference to the new bytestring item. The item's reference count is initialized to one.
NULL if memory allocation fails


Building items

Creates a new byte string and initializes it.

The handle will be copied to a newly allocated block

Block of binary data
Length of data
Reference to the new bytestring item. The item's reference count is initialized to one.
NULL if memory allocation fails


Manipulating existing items

Set the handle to the binary data.
A definite byte string
The memory block. The caller gives up the ownership of the block. libcbor will deallocate it when appropriate using the free implementation configured using cbor_set_allocs
Length of the data block


Appends a chunk to the bytestring.

Indefinite byte strings only.

May realloc the chunk storage.

An indefinite byte string
A definite byte string. Its reference count will be be increased by one.
true on success, false on realloc failure. In that case, the refcount of chunk is not increased and the item is left intact.


Type 3 – UTF-8 strings

CBOR strings have the same structure as Type 2 – Byte strings.

Corresponding cbor_type CBOR_TYPE_STRING
Number of allocations (definite) One plus any manipulations with the data
Number of allocations (indefinite) One plus logarithmically many reallocations relative to chunk count
Storage requirements (definite) sizeof(cbor_item_t) + length(handle)
Storage requirements (indefinite) sizeof(cbor_item_t) * (1 + chunk_count) + chunks

UTF-8 encoding validation

libcbor considers UTF-8 encoding validity to be a part of the well-formedness notion of CBOR and therefore invalid UTF-8 strings will be rejected by the parser. Strings created by the user are not checked.

Getting metadata

Returns the length of the underlying string in bytes.

There can be fewer unicode character than bytes (see cbor_string_codepoint_count). For definite strings only.

a definite string
length of the string. Zero if no chunk has been attached yet


Is the string definite?
a string
Is the string definite?


Is the string indefinite?
a string
Is the string indefinite?


Get the number of chunks this string consist of.
A indefinite string
The chunk count. 0 for freshly created items.


Reading data

Get the handle to the underlying string.

Definite items only. Modifying the data is allowed. In that case, the caller takes responsibility for the effect on items this item might be a part of

A definite string
The address of the underlying string.
NULL if no data have been assigned yet.


Get the handle to the array of chunks.

Manipulations with the memory block (e.g. sorting it) are allowed, but the validity and the number of chunks must be retained.

A indefinite string
array of cbor_string_chunk_count definite strings


Creating new items

Creates a new definite string.

The handle is initialized to NULL and length to 0

Reference to the new string item. The item's reference count is initialized to one.
NULL if memory allocation fails


Creates a new indefinite string.

The chunks array is initialized to NULL and chunkcount to 0

Reference to the new string item. The item's reference count is initialized to one.
NULL if memory allocation fails


Building items

Creates a new string and initializes it.

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.

A null-terminated UTF-8 string
Reference to the new string item. The item's reference count is initialized to one.
NULL if memory allocation fails


Manipulating existing items

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.

WARNING:

Using a pointer to a stack allocated constant is a common mistake. Lifetime of the string will expire when it goes out of scope and the CBOR item will be left inconsistent.


A definite string
The memory block. The caller gives up the ownership of the block. libcbor will deallocate it when appropriate using its free function
Length of the data block


Appends a chunk to the string.

Indefinite strings only.

May realloc the chunk storage.

An indefinite string
A definite string item. Its reference count will be increased by one.
true on success. false on memory allocation failure. In that case, the refcount of `chunk` is not increased and the `item` is left intact.


Type 4 – Arrays

CBOR arrays, just like byte strings and strings, can be encoded either as definite, or as indefinite. Definite arrays have a fixed size which is stored in the header, whereas indefinite arrays do not and are terminated by a special "break" byte instead.

Arrays are explicitly created or decoded as definite or indefinite and will be encoded using the corresponding wire representation, regardless of whether the actual size is known at the time of encoding.

NOTE:

Indefinite arrays can be conveniently used with streaming decoding and encoding.


Corresponding cbor_type CBOR_TYPE_ARRAY
Number of allocations (definite) Two plus any manipulations with the data
Number of allocations (indefinite) Two plus logarithmically many reallocations relative to additions
Storage requirements (definite) (sizeof(cbor_item_t) + 1) * size
Storage requirements (indefinite) <= sizeof(cbor_item_t) + sizeof(cbor_item_t) * size * BUFFER_GROWTH

Examples

0x9f        Start indefinite array

0x01 Unsigned integer 1
0xff "Break" control token


0x9f        Start array, 1B length follows
0x20        Unsigned integer 32

... 32 items follow


Getting metadata

Get the number of members.
An array
The number of members


Get the size of the allocated storage.
An array
The size of the allocated storage (number of items)


Is the array definite?
An array
Is the array definite?


Is the array indefinite?
An array
Is the array indefinite?


Reading data

Get the array contents.

The items may be reordered and modified as long as references remain consistent.

An array item
An array of cbor_item_t pointers of size cbor_array_size.


Get item by index.

Increases the reference count of the underlying item. The returned reference must be released using cbor_decref.

An array
The index (zero-based)
Reference to the item, or NULL in case of boundary violation.


Creating new items

Create new definite array.
Number of slots to preallocate
Reference to the new array item. The item's reference count is initialized to one.
NULL if memory allocation fails


Create new indefinite array.
Reference to the new array item. The item's reference count is initialized to one.
NULL if memory allocation fails


Modifying items

Append to the end.

For indefinite items, storage may be reallocated. For definite items, only the preallocated capacity is available.

An array
The item to push. Its reference count will be increased by one.
true on success, false on failure


Replace item at an index.

The reference to the item being replaced will be released using cbor_decref.

An array
The item to assign. Its reference count will be increased by one.
The index (zero-based)
true on success, false on allocation failure.


Set item by index.

If the index is out of bounds, the array is not modified and false is returned. Creating arrays with holes is not possible.

An array
The item to assign
The index (zero-based)
true on success, false on allocation failure.


Type 5 – Maps

CBOR maps are the plain old associative maps similar JSON objects or Python dictionaries.

Definite maps have a fixed size which is stored in the header, whereas indefinite maps do not and are terminated by a special "break" byte instead.

Map are explicitly created or decoded as definite or indefinite and will be encoded using the corresponding wire representation, regardless of whether the actual size is known at the time of encoding.

NOTE:

Indefinite maps can be conveniently used with streaming decoding and encoding. Keys and values can simply be output one by one, alternating keys and values.


WARNING:

Any CBOR data item is a legal map key (not just strings).


Corresponding cbor_type CBOR_TYPE_MAP
Number of allocations (definite) Two plus any manipulations with the data
Number of allocations (indefinite) Two plus logarithmically many reallocations relative to additions
Storage requirements (definite) sizeof(cbor_pair) * size + sizeof(cbor_item_t)
Storage requirements (indefinite) <= sizeof(cbor_item_t) + sizeof(cbor_pair) * size * BUFFER_GROWTH

Examples

0xbf        Start indefinite map (represents {1: 2})

0x01 Unsigned integer 1 (key)
0x02 Unsigned integer 2 (value)
0xff "Break" control token


0xa0        Map of size 0


Getting metadata

Get the number of pairs.
A map
The number of pairs


Get the size of the allocated storage.
A map
Allocated storage size (as the number of cbor_pair items)


Is this map definite?
A map
Is this map definite?


Is this map indefinite?
A map
Is this map indefinite?


Reading data

Get the pairs storage.
A map
Array of cbor_map_size pairs. Manipulation is possible as long as references remain valid.


Creating new items

Create a new definite map.
The number of slots to preallocate
Reference to the new map item. The item's reference count is initialized to one.
NULL if memory allocation fails


Create a new indefinite map.
Reference to the new map item. The item's reference count is initialized to one.
NULL if memory allocation fails


Modifying items

Add a pair to the map.

For definite maps, items can only be added to the preallocated space. For indefinite maps, the storage will be expanded as needed

A map
The key-value pair to add. Reference count of the cbor_pair.key and cbor_pair.value will be increased by one.
true on success, false if memory allocation failed (indefinite maps) or the preallocated storage is full (definite maps)


Type 6 – Semantic tags

Tag are additional metadata that can be used to extend or specialize the meaning or interpretation of the other data items.

For example, one might tag an array of numbers to communicate that it should be interpreted as a vector.

Please consult the official IANA repository of CBOR tags before inventing new ones.

Corresponding cbor_type CBOR_TYPE_TAG
Number of allocations One plus any manipulations with the data reallocations relative to chunk count
Storage requirements sizeof(cbor_item_t) + the tagged item
Create a new tag.
The tag value. Please consult the tag repository
Reference to the new tag item. The item's reference count is initialized to one.
NULL if memory allocation fails


Get the tagged item.

Increases the reference count of the underlying item. The returned reference must be released using cbor_decref.

A tag
Reference to the tagged item


Get tag value.
A tag
The tag value. Please consult the tag repository


Set the tagged item.
A tag
The item to tag. Its reference count will be increased by one.


Type 7 – Floats & control tokens

This type combines two completely unrelated types of items -- floating point numbers and special values such as true, false, null, etc. We refer to these special values as 'control values' or 'ctrls' for short throughout the code.

Just like integers, they have different possible width (resulting in different value ranges and precisions).

Possible widths of CBOR_TYPE_FLOAT_CTRL items.

Values:

Internal use - ctrl and special values.


Single float.



Corresponding cbor_type CBOR_TYPE_FLOAT_CTRL
Number of allocations One per lifetime
Storage requirements sizeof(cbor_item_t) + 1/4/8

Getting metadata

Is this a ctrl value?
A float or ctrl item
Is this a ctrl value?


Get the float width.
A float or ctrl item
The width.


Reading data

Get a half precision float.

The item must have the corresponding width

A half precision float
half precision value


Get a single precision float.

The item must have the corresponding width

A single precision float
single precision value


Get a double precision float.

The item must have the corresponding width

A double precision float
double precision value


Get the float value represented as double.

Can be used regardless of the width.

Any float
double precision value


Reads the control value.
A ctrl item
the simple value


Get value from a boolean ctrl item.
A ctrl item
boolean value


Creating new items

Constructs a new ctrl item.

The width cannot be changed once the item is created

Reference to the new ctrl item. The item's reference count is initialized to one.
NULL if memory allocation fails


Constructs a new float item.

The width cannot be changed once the item is created

Reference to the new float item. The item's reference count is initialized to one.
NULL if memory allocation fails


Constructs a new float item.

The width cannot be changed once the item is created

Reference to the new float item. The item's reference count is initialized to one.
NULL if memory allocation fails


Constructs a new float item.

The width cannot be changed once the item is created

Reference to the new float item. The item's reference count is initialized to one.
NULL if memory allocation fails


Constructs new null ctrl item.
Reference to the new null item. The item's reference count is initialized to one.
NULL if memory allocation fails


Constructs new undef ctrl item.
Reference to the new undef item. The item's reference count is initialized to one.
NULL if memory allocation fails


Building items

Constructs new boolean ctrl item.
The value to use
Reference to the new boolean item. The item's reference count is initialized to one.
NULL if memory allocation fails


Constructs a ctrl item.
the value to use
Reference to the new ctrl item. The item's reference count is initialized to one.
NULL if memory allocation fails


Constructs a new float.
the value to use
Reference to the new float item. The item's reference count is initialized to one.
NULL if memory allocation fails


Constructs a new float.
the value to use
Reference to the new float item. The item's reference count is initialized to one.
NULL if memory allocation fails


Constructs a new float.
the value to use
Reference to the new float item. The item's reference count is initialized to one.
NULL if memory allocation fails


Manipulating existing items

Assign a control value.

WARNING:

It is possible to produce an invalid CBOR value by assigning a invalid value using this mechanism. Please consult the standard before use.


A ctrl item
The simple value to assign. Please consult the standard for allowed values


Assign a boolean value to a boolean ctrl item.
A ctrl item
The simple value to assign.


Assigns a float value.
A half precision float
The value to assign


Assigns a float value.
A single precision float
The value to assign


Assigns a float value.
A double precision float
The value to assign


Half floats

CBOR supports two bytes wide ("half-precision") floats which are not supported by the C language. libcbor represents them using float <https://en.cppreference.com/w/c/language/type> values throughout the API. Encoding will be performed by cbor_encode_half(), which will handle any values that cannot be represented as a half-float.

[1]
http://softwareengineering.vazexqi.com/files/pattern.html

Tests

Unit tests

There is a comprehensive test suite employing CMocka. You can run all of them using ctest in the build directory. Individual tests are themselves runnable. Please refer to CTest documentation for detailed information on how to specify particular subset of tests.

Testing for memory leaks

Every release is tested for memory correctness. You can run these tests by passing the -T memcheck flag to ctest. [1]

[1]
Project should be configured with -DCMAKE_BUILD_TYPE=Debug to obtain meaningful description of location of the leak. You might also need --dsymutil=yes on OS X.

Code coverage

Every release is inspected using GCOV/LCOV. Platform-independent code should be fully covered by the test suite. Simply run

make coverage


or alternatively run lcov by hand using

lcov --capture --directory . --output-file coverage.info
genhtml coverage.info --output-directory out


Fuzz testing

Every release is tested using a fuzz test. In this test, a huge buffer filled with random data is passed to the decoder. We require that it either succeeds or fail with a sensible error, without leaking any memory. This is intended to simulate real-world situations where data received from the network are CBOR-decoded before any further processing.

IETF standard conformance

libcbor is, generally speaking, a very faithful implementation of IETF RFC 8949 (STD 94). 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. [1] libcbor will not handle byte strings with more chunks than the maximum value of 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.

[1]
https://www.rfc-editor.org/rfc/rfc8949.html#section-3.2.3

"Half-precision" IEEE 754 floats

As of C99 and even C11, there is no standard implementation for 2 bytes floats. libcbor packs them as a float <https://en.cppreference.com/w/c/language/type>. When encoding, libcbor selects the appropriate wire representation based on metadata and the actual value. This applies both to canonical and normal mode.

For more information on half-float serialization, please refer to the section on Half floats.

Internal mechanics

Internal workings of libcbor are mostly derived from the specification. The purpose of this document is to describe technical choices made during design & implementation and to explicate the reasoning behind those choices.

Terminology

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 during compilation (originated in the Rust community)

Conventions

API symbols start with cbor_ or CBOR_ prefix, internal symbols have _cbor_ or _CBOR_ prefix.

Most of the API is largely modelled after existing JSON libraries, including

  • Jansson
  • json-c
  • Gnome's JsonGlib



and also borrowing from

  • msgpack-c
  • Google Protocol Buffers.



General notes on the API design

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



Combining these two principles in practice turns out to be quite difficult. Indefinite-length strings, arrays, and maps require client to handle every fixed-size chunk explicitly in order to

  • ensure the client never runs out of memory due to libcbor
  • use realloc() sparsely and predictably [1]
  • provide strong guarantees about its usage (to prevent latency spikes)
  • provide APIs to avoid realloc() altogether



allow proper handling of (streamed) data bigger than available memory

[1]
Reasonable handling of DSTs requires reallocation if the API is to remain sane.


Coding style

This code loosely follows the Linux kernel coding style. Tabs are tabs, and they are 4 characters wide.

Memory layout

CBOR is very dynamic in the sense that it contains many data elements of variable length, sometimes even indefinite length. This section describes internal representation of all CBOR data types.

Generally speaking, data items consist of three parts:

  • a generic handle,
  • the associated metadata,
  • and the actual data



Represents the item. Used as an opaque type
Type discriminator

Reference counter. Used by cbor_decref(), cbor_incref()

Union discriminated by type. Contains type-specific metadata

Contains pointer to the actual data. Small, fixed size items (Types 0 & 1 – Positive and negative integers, Type 6 – Semantic tags, Type 7 – Floats & control tokens) are allocated as a single memory block.

Consider the following snippet

cbor_item_t * item = cbor_new_int8();


then the memory is laid out as follows

+-----------+---------------+---------------+-----------------------------------++-----------+
|           |               |               |                                   ||           |
|   type    |   refcount    |   metadata    |              data                 ||  uint8_t  |
|           |               |               |   (= item + sizeof(cbor_item_t))  ||           |
+-----------+---------------+---------------+-----------------------------------++-----------+
^                                                                                ^
|                                                                                |
+--- item                                                                        +--- item->data


Dynamically sized types (Type 2 – Byte strings, Type 3 – UTF-8 strings, Type 4 – Arrays, Type 5 – Maps) may store handle and data in separate locations. This enables creating large items (e.g byte strings) without realloc() or copying large blocks of memory. One simply attaches the correct pointer to the handle.




Decoding

As outlined in API, there decoding is based on the streaming decoder Essentially, the decoder is a custom set of callbacks for the streaming decoder.

Changelog

Template: - [Fix issue X in feature Y](https://github.com/PJK/libcbor/pull/XXX) (by [YYY](https://github.com/YYY))

Next

0.11.0 (2024-02-04)


0.10.2 (2023-01-31)


0.10.1 (2022-12-30)

[Fix a regression in cbor_serialize_alloc that caused serialization of zero-length strings and bytestrings or byte/strings with zero-length chunks to fail](https://github.com/PJK/libcbor/pull/260) (discovered by [martelletto](https://github.com/martelletto))

0.10.0 (2022-12-29)


0.9.0 (2021-11-14)

https://github.com/PJK/libcbor/pull/186hg)
  • Callbacks for bytestrings, strings, arrays, and maps use uint64_t instead of size_t to allow handling of large items that exceed size_t even if size_t < uint64_t
  • cbor_decode explicitly checks size to avoid overflows (previously broken, potentially resulting in erroneous decoding on affected systems)
  • The change should be a noop for 64b systems


Added a [Bazel](https://bazel.build/) build example [[#196]](https://github.com/PJK/libcbor/pull/196) (by [andyjgf@](https://github.com/andyjgf))

0.8.0 (2020-09-20)

https://github.com/PJK/libcbor/pull/156)
cbor_stream_decode will set CBOR_DECODER_NEDATA instead if the input buffer is empty



0.7.0 (2020-04-25)

https://github.com/PJK/libcbor/issues/53) (discovered by [BSipos-RKF](https://github.com/BSipos-RKF))
Warning: Previous versions encoded NaNs as 0xf9e700 instead of 0xf97e00; if you rely on the broken behavior, this will be a breaking change


https://github.com/PJK/libcbor/issues/63)
  • Rename cbor_ctrl_is_bool to cbor_get_bool and fix the behavior
  • Add cbor_set_bool


https://github.com/PJK/libcbor/pull/138) (by [James-ZHANG](https://github.com/James-ZHANG))
If your usecase requires parsing very deeply nested structures, you might need to increase the default 2k limit via CBOR_MAX_STACK_SIZE


https://cmake.org/cmake/help/latest/module/CheckIPOSupported.html#module:CheckIPOSupported) [[#143]](https://github.com/PJK/libcbor/pull/143) (by [xanderlent](https://github.com/xanderlent))
If you rely on LTO being enabled and use CMake version older than 3.9, you will need to re-enable it manually or upgrade your CMake



0.6.1 (2020-03-26)

[Fix bad shared library version number](https://github.com/PJK/libcbor/pull/131)
Warning: Shared library built from the 0.6.0 release is erroneously marked as version "0.6.0", which makes it incompatible with future releases including the v0.6.X line even though they may be compatible API/ABI-wise. Refer to the documentation for the new SO versioning scheme.



0.6.0 (2020-03-15)

https://github.com/PJK/libcbor/issues/52).
Warning: All previous releases will be identified as 0.0 by the linker.



0.5.0 (2017-02-06)


0.4.0 (2015-12-25)

Breaks build & header compatibility due to:

  • Improved build configuration and feature check macros
  • 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)

0.3.1 (2015-05-21)

documentation and comments improvements, mostly for the API reference

0.3.0 (2015-05-21)

  • Fixes, polishing, niceties across the code base
  • Updated examples
  • cbor_copy
  • cbor_build_negint8, 16, 32, 64, matching asserts
  • cbor_build_stringn
  • cbor_build_tag
  • cbor_build_float2, ...

0.2.1 (2015-05-17)

C99 support

0.2.0 (2015-05-17)

  • cbor_ctrl_bool -> cbor_ctrl_is_bool
  • Added cbor_array_allocated & map equivalent
  • Overhauled endianess conversion - ARM now works as expected
  • 'sort.c' example added
  • Significantly improved and doxyfied documentation

0.1.0 (2015-05-06)

The initial release, yay!

Development

Vision and principles

Consistency and coherence are one of the key characteristics of good software. While the reality is never black and white, it is important libcbor contributors are working towards the same high-level goal. This document attempts to set out the basic principles of libcbor and the rationale behind them. If you are contributing to libcbor or looking to evaluate whether libcbor is the right choice for your project, it might be worthwhile to skim through the section below.

Mission statement

libcbor is the compact, full-featured, and safe CBOR library that works everywhere.

Goals

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 [CBOR standard](https://www.rfc-editor.org/info/std94) support is comparatively small over "almost-conformance" seen in many alternatives.

Safety

Untrusted bytes from the network are the typical input.

Why? Because it is the client expectation. Vast majority of security vulnerabilities are violations of contracts -- in other words, bugs -- anyway.

Self-containment

libcbor has no runtime dependencies.

Why? Because any constraint imposed on libcbor has to be enforced transitively, which is difficult and leads to incompatibilities and distribution issues, especially in IoT applications.

Portability

If you can compile C for it, libcbor will work there.

Why? Lowest-common-denominator solution for system-level and IoT software was the original niche of libcbor. Users who rely on libcbor expect future updates to work on their target platform.

Stable and predictable API

libcbor will not break without a warning.

Why? Industry-standard versioning is a basic requirement for production-quality software. This is especially relevant in IoT environments where updates may be costly.

Performance

libcbor is fast and resource-efficient by design

Why? Because the main maintainer is an avid hater of slow bloated software. Who wouldn't want more bang per their electricity buck?

Non-goals

  • Convenience -- libcbor only provides the minimum surface to make it usable
  • FFI/SWIG/interop support -- libcbor is primarily a C library for C clients
  • One-off usecases support -- although there are primitives to reuse, the basic assumption is that most clients want most of CBOR features



Development dependencies

  • CMocka (testing)
  • Python and pip (Sphinx platform)
  • Doxygen
  • Sphinx (documentation)
  • There are some Ruby scripts in misc
  • Valgrind (memory correctness & profiling)
  • GCOV/LCOV (test coverage)
  • clang-format

Installing sphinx

pip install sphinx
pip install sphinx_rtd_theme
pip install breathe
pip install https://github.com/lepture/python-livereload/archive/master.zip
pip install sphinx-autobuild


Further instructions on configuring advanced features can be found at http://read-the-docs.readthedocs.org/en/latest/install.html.

Live preview of docs

cd doc
make livehtml


Set up git hooks

A catch-all git hook that runs clang-format and automatically refreshes the GH pages contents located in docs can be symlinked:

ln -sf $(pwd)/misc/hooks/pre-commit .git/hooks


Testing and code coverage

Please refer to Tests

AUTHOR

Pavel Kalvoda

COPYRIGHT

2024 - 2020, Pavel Kalvoda

September 16, 2024 0.11