LIBCBOR(1)
๐ NAME ๐
okay so bestie, welcome to LIBCBOR(1) โ the libcbor manual page, no cap. This is the documentation for version 0.7.0, updated on Aug 09, 2021. Consider this your group chat briefing. ๐ซถ
โจ OVERVIEW โจ
libcbor is a C library for parsing and generating CBOR โ that's the general-purpose schema-less binary data format, iykyk. Iconic behavior, honestly.
๐ Main features ๐
- Complete RFC conformance [1] ๐ฅ
- Robust C99 implementation
- Layered architecture offers both control and convenience (the way that it gives you both?? obsessed)
- 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 (she's low-maintenance, we love her)
[1] Seerfc_conformance. [2] With the exception of custom memory allocators (seeapi/item_reference_counting).
๐ CONTENTS ๐
๐ Getting started ๐
Pre-built Linux packages are distributed from the libcbor website. slay.
OS X users can use Homebrew, literally just:
brew tap pjk/libcbor
brew install libcbor
For other platforms, you will need to compile it from source. That's the vibe, ngl.
๐ฆ Building & installing libcbor ๐ฆ
Prerequisites, bestie โ get these sorted first:
- C99 compiler
- CMake 2.8 or newer (might also be called
cmakesetup,cmake-guiorccmakedepending on the installed version and system โ she goes by many names ๐ ) - C build system CMake can target (
make,Apple Xcode,MinGW, ...)
NOTE: As of May 2015, not even the 2015 release candidate of Visual Studio supports C99. While CMake will be happy to generate a VS solution that you can play with, libcbor currently cannot be compiled using the MSVC toolchain. ICC, GCC under Cygwin, and MinGW's GCC will all work. The MinGW build process is described below. ๐
๐ง 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. (Original was a table, we're doing list energy โ same facts, cuter packaging.)
CMAKE_C_COMPILERโ C compiler to use. Default:cc. Possible values:gcc,clang,clang-3.5, ...CMAKE_INSTALL_PREFIXโ Installation prefix. Default: System-dependent. Possible values:/usr/local/lib, ...HUGE_FUZZโ Fuzz test with 8GB of data. Default:OFF. Possible values:ON,OFFSANE_MALLOCโ Assumemallocwill refuse unreasonable allocations. Default:OFF. Possible values:ON,OFFCOVERAGEโ Generate test coverage instrumentation. Default:OFF. Possible values:ON,OFFWITH_TESTSโ Build unit tests (seedevelopment). Default:OFF. Possible values:ON,OFF
The following configuration options will also be defined as macros[#]_ in <cbor/common.h> and can therefore be used in client code โ so they're your macros too, bestie:
CBOR_CUSTOM_ALLOCโ Enable custom allocator support. Default:OFF. Possible values:ON,OFFCBOR_PRETTY_PRINTERโ Include a pretty-printing routine. Default:ON. Possible values:ON,OFFCBOR_BUFFER_GROWTHโ Factor for buffer growth & shrinking. Default:2. Possible values: Decimals > 1
[1]ON&OFFwill be translated to1and0usingcmakedefine. If you want to pass other custom configuration options, please refer tohttp://www.cmake.org/Wiki/CMake_Useful_Variables.
๐ธ 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, execute the following to configure the build and run make:
cmake -DCMAKE_BUILD_TYPE=Release path_to_libcbor_dir
make cbor cbor_shared
Both the shared (libcbor.so) and the static (libcbor.a) libraries should now be in the src subdirectory. periodt. ๐
In order to install the libcbor headers and libraries, the usual
make install
is what your're looking for. Root permissions are required on most systems when using the default installation prefix. (yes, that apostrophe situation is straight from the original โ we leave it, it's part of the lore ๐)
โญ 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. easy.
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.Yfor the0.Y.Zbranch. Patches are backwards compatible, minor releases are generally not and require re-compilation of any dependent code.Xfor theX.Y.Zstable versions starting1.X.Y. All minor release of the major version are backwards compatible.
WARNING: Please note that releases up to and includingv0.6.0may export misleading.so/.dylibversion number. ๐ญ watch out for that one.
๐ MinGW build instructions ๐
Prerequisites:
MinGWCMake GUI
First of all, create a folder that will be used for the output. For this demonstration, we will use cbor_out. Start CMake and select the source path and the destination folder. [image]
Then hit the 'Configure' button. You will be prompted to select the build system: [image]
Choose MinGW and confirm.
NOTE: If you select Visual Studio at this point, a MSVC project will be generated for you. This is useful if you just want to browse through the source code. main character energy for browsing, honestly. โจ
...okay so this is where you fiddle with your build options ๐๏ธ โ and bestie, the defaults will work just fine. Hit Generate when you're done. [image]
Then you adjust the build options (yep, same deal). The defaults will work just fine. Hit Generate when you're done.
Pop open the shell ๐, navigate to the output directory, and run mingw32-make cbor cbor_shared. [image]
libcbor gets built and your .dll should be sitting there ready at this point โจ [image]
Absolutely feel free to also build and run a few of the examples too, like mingw32-make sort [image]
๐ฉน Troubleshooting
cbor.hnot found โ the headers directory is probably not in your include path. First step: verify where the install actually landed by checking the installation log. If you usedmake, it'll look something like
...
-- Installing: /usr/local/include/cbor
-- Installing: /usr/local/include/cbor/callbacks.h
-- Installing: /usr/local/include/cbor/encoding.h
...
Double-check that CMAKE_INSTALL_PREFIX (if you gave it one) was actually correct. Including the path during compilation should be enough, like:
cc -I/usr/local/include hello_cbor.c -lcbor -o hello_cbor
cannot find -lcborduring linking โ most likely the exact same problem as above ๐. Stick the installation directory into the linker shared path with-R, like:
cc -Wl,-rpath,/usr/local/lib -lcbor -o hello_cbor
- shared library missing during execution โ verify the linkage using
ldd,otool, or similar, then adjust your 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 but the compilation still failed, please report the issue to the issue tracker ๐.
๐ Usage & preliminaries ๐
๐ Version information
libcbor exports its version using three self-explanatory macros:
CBOR_MAJOR_VERSIONCBOR_MINOR_VERSIONCBOR_PATCH_VERSION
CBOR_VERSION is a string that concatenates those three identifiers into one (e.g. 0.2.0).
And to make version comparisons less of a whole thing, the version is also exported as
#define CBOR_HEX_VERSION ((CBOR_MAJOR_VERSION << 16) | (CBOR_MINOR_VERSION << 8) | CBOR_PATCH_VERSION)
Since macros are, like, genuinely painful to work with through FFIs, the same info is also available through three uint8_t constants, namely:
cbor_major_versioncbor_minor_versioncbor_patch_version
๐ Headers to include
The cbor.h header includes all the symbols. If for any reason you don't want all the exported symbols, feel free to use just some of the cbor/*.h headers:
cbor/arrays.h-api/type_4cbor/bytestrings.h-api/type_2cbor/callbacks.h- Callbacks used for streaming/decodingcbor/common.h- Common utilities - always transitively includedcbor/data.h- Data types definitions - always transitively includedcbor/encoding.h- Streaming encoders for streaming/encodingcbor/floats_ctrls.h-api/type_7cbor/ints.h-api/type_0_1cbor/maps.h-api/type_5cbor/serialization.h- High level serialization such ascbor_serialize()cbor/streaming.h- Home ofcbor_stream_decode()cbor/strings.h-api/type_3cbor/tags.h-api/type_6
๐ฆ Using libcbor
If you wanna get more familiar with CBOR, we recommend the cbor.io website ๐. Once you've got the grasp of what it is CBOR does, the examples (located in the examples directory) should give you a good feel of the API. The API documentation should then provide you with all the info 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: `length` bytes of data in the `buffer` */
unsigned char * buffer;
size_t buffer_size, length = cbor_serialize_alloc(root, &buffer, &buffer_size);
fwrite(buffer, 1, length, stdout);
free(buffer);
fflush(stdout);
cbor_decref(&root);
}
๐ธ 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, fr fr ๐ซถ.
The libcbor API follows the semantics outlined by the CBOR standard super closely. This part of the docs gives you a short overview of the CBOR constructs, plus a general intro to the libcbor API. The rest of the reference lives 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, a 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 structure 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 the aforementioned details and only be presented complete data structures.
libcbor provides
- 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:
enum cbor_typeโ Specifies the Major type ofcbor_item_t.- Values:
CBOR_TYPE_UINTโ0- positive integersCBOR_TYPE_NEGINTโ1- negative integersCBOR_TYPE_BYTESTRINGโ2- byte stringsCBOR_TYPE_STRINGโ3- stringsCBOR_TYPE_ARRAYโ4- arraysCBOR_TYPE_MAPโ5- mapsCBOR_TYPE_TAGโ6- tagsCBOR_TYPE_FLOAT_CTRLโ7- decimals and special values (true,false,nil, ...)
- Values:
To find out the type of an item, one can use
cbor_type cbor_typeof(const cbor_item_t *item)
Get the type of the item.
- Return โ The type
- Parameters
item[borrow]:
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. No cap, do not do it.
bool cbor_isa_uint(const cbor_item_t *item)
Does the item have the appropriate major type?
- Return โ Is the item an
CBOR_TYPE_UINT? - Parameters
item[borrow]: the item
bool cbor_isa_negint(const cbor_item_t *item)
Does the item have the appropriate major type?
- Return โ Is the item a
CBOR_TYPE_NEGINT? - Parameters
item[borrow]: the item
bool cbor_isa_bytestring(const cbor_item_t *item)โ does the item have the right major type? ๐
Returns: is it a CBOR_TYPE_BYTESTRING?
Parameters:
item[borrow]: the item
bool cbor_isa_string(const cbor_item_t *item)โ major type check, bestie โจ
Returns: is it a CBOR_TYPE_STRING?
Parameters:
item[borrow]: the item
bool cbor_isa_array(const cbor_item_t *item)โ is the major type giving what it's supposed to give? ๐
Returns: is it a CBOR_TYPE_ARRAY?
Parameters:
item[borrow]: the item
bool cbor_isa_map(const cbor_item_t *item)โ major type check, no cap ๐ง
Returns: is it a CBOR_TYPE_MAP?
Parameters:
item[borrow]: the item
bool cbor_isa_tag(const cbor_item_t *item)โ yup, another major type check ๐ฅ
Returns: is it a CBOR_TYPE_TAG?
Parameters:
item[borrow]: the item
bool cbor_isa_float_ctrl(const cbor_item_t *item)โ the last of the major type checkers, iconic ๐
Returns: is it a CBOR_TYPE_FLOAT_CTRL?
Parameters:
item[borrow]: the item
๐ธ Logical queries ๐ธ
These ones are the vibe check functions โ they tell you about the item's type from a way more high-level, human perspective instead of just "which major type byte is this." ๐ฆ
bool cbor_is_int(const cbor_item_t *item)โ is the item an integer, either positive or negative? โญ
Returns: is the item an integer, either positive or negative?
Parameters:
item[borrow]: the item
bool cbor_is_float(const cbor_item_t *item)โ is the item a floating point number? ๐
Returns: is the item a floating point number?
Parameters:
item[borrow]: the item
bool cbor_is_bool(const cbor_item_t *item)โ is the item a boolean? (yes, "an a boolean", the original said it, we're keeping the energy) ๐
Returns: is the item a boolean?
Parameters:
item[borrow]: the item
bool cbor_is_null(const cbor_item_t *item)โ 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. ๐ญ Like, do NOT do that.
Returns: is the item (CBOR logical) null?
Parameters:
item[borrow]: the item
bool cbor_is_undef(const cbor_item_t *item)โ does this item represent undefined? ๐ซ๏ธ
WARNING: care must be taken to distinguish nulls and undefined values in C. They are not the same thing, bestie, do not conflate them ๐
Returns: is the item (CBOR logical) undefined?
Parameters:
item[borrow]: the item
๐ Memory management and reference counting ๐
Okay so here's the tea: because of the nature of its domain, libcbor will need to work with heap memory ๐ซถ. The stateless decoder and encoder don't allocate any memory โ slay, zero allocation, main character behavior โจ.
If you have specific requirements, you should consider rolling your own driver for the stateless API ๐.
๐ Using custom allocator ๐
libcbor gives you the ability to provide your own implementations of malloc, realloc, and free ๐ ๏ธ. This is useful if you are using a custom allocator throughout your application, or if you want to implement custom policies (e.g. tighter restrictions on the amount of allocated memory) ๐.
In order to use this feature, libcbor has to be compiled with the appropriate flags. You can verify the configuration using the CBOR_CUSTOM_ALLOC macro ๐. A simple usage might be as follows:
#if CBOR_CUSTOM_ALLOC
cbor_set_allocs(malloc, realloc, free);
#else
#error "libcbor built with support for custom allocation is required"
#endif
void cbor_set_allocs(_cbor_malloc_t custom_malloc, _cbor_realloc_t custom_realloc, _cbor_free_t custom_free) โ sets the memory management routines to use ๐
Only available when CBOR_CUSTOM_ALLOC is truthy โ ๏ธ
WARNING: this function modifies the global state and should therefore be used accordingly ๐ฌ. Changing the memory handlers while allocated items exist will result in afree/mallocmismatch ๐. This function is not thread safe with respect to both itself and all the otherlibcborfunctions that work with the heap ๐ญ.
note: thereallocimplementation must correctly supportNULLreallocation (see e.g. http://en.cppreference.com/w/c/memory/realloc) ๐
Parameters:
custom_malloc:mallocimplementationcustom_realloc:reallocimplementationcustom_free:freeimplementation
๐ฆ Reference counting ๐ฆ
As CBOR items may require complex cleanups at the end of their lifetime, there is a reference counting mechanism in place ๐. This also enables very simple GC when integrating libcbor into managed environment ๐ฟ. Every item starts its life (by either explicit creation, or as a result of parsing) with reference count set to 1. When the refcount reaches zero, it will be destroyed ๐ฅ.
Items containing nested items will be destroyed recursively โ the refcount of every nested item will be decreased by one ๐ช.
The destruction is synchronous and renders any pointers to items with refcount zero invalid immediately after calling the cbor_decref() โณ. Like, gone. Poof. Don't touch that pointer after, fr fr ๐
cbor_item_t *cbor_incref(cbor_item_t *item)โ increases the reference count by one โฌ๏ธ. No dependent items are affected.
Returns: the input reference
Parameters:
item[incref]: item the item
void cbor_decref(cbor_item_t **item)โ decreases the reference count by one, deallocating the item if needed โฌ๏ธ. In case the item is deallocated, the reference count of any dependent items is adjusted accordingly in a recursive manner ๐.
Parameters:
item[take]: the item. Set toNULLif deallocated
void cbor_intermediate_decref(cbor_item_t *item)โ decreases the reference count by one, deallocating the item if needed. It's basically a convenience wrapper forcbor_decrefwhen its set-to-null behavior is not needed ๐.
Parameters:
item[take]: the item
size_t cbor_refcount(const cbor_item_t *item)โ get the reference count ๐ข
WARNING: this does not account for transitive references ๐
Returns: the reference count
Parameters:
item[borrow]: the item
cbor_item_t *cbor_move(cbor_item_t *item)โ provides a 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 ๐ง๐ญ
Returns: the item with reference count decreased by one
Parameters:
item[take]: the item
cbor_item_t *cbor_copy(cbor_item_t *item)โ deep copy of an item ๐. All the reference counts in the new structure are set to one ๐ฏ.
Returns: new CBOR deep copy
Parameters:
item[borrow]: item to copy
๐ Decoding ๐
The following diagram illustrates the relationship among different parts of libcbor from the decoding standpoint ๐บ๏ธโจ
okay so picture this โ the whole libcbor architecture, one diagram, and it's giving chef's kiss ๐
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ โ
โ 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 ๐
cbor_load
cbor_item_t *cbor_load(cbor_data source, size_t source_size, struct cbor_load_result *result)
Loads a data item from a buffer. yes bestie, one whole item, straight out of the bytes โจ
Return new CBOR item or NULL on failure. In that case, result contains location and description of the error.
Parameters
- source: the buffer
- source_size: (that's the size, you got this ๐ซถ)
- result [out]: result indicator.
CBOR_ERR_NONEon success
๐ Associated data structures
enum cbor_error_code
Possible decoding errors.
Values:
- enumerator
CBOR_ERR_NONE - enumerator
CBOR_ERR_NOTENOUGHDATA - enumerator
CBOR_ERR_NODATA - enumerator
CBOR_ERR_MALFORMATED - enumerator
CBOR_ERR_MEMERRORโ memory error, the item allocation failed. is it too big for your allocator? ๐ญ - enumerator
CBOR_ERR_SYNTAXERRORโ the stack parsing algorithm failed.
struct cbor_load_result
High-level decoding result.
Public Members
struct cbor_error errorโ error indicatorsize_t readโ number of bytes read
struct cbor_error
High-level decoding error.
Public Members
size_t positionโ aproximate position (their spelling, not mine ๐)cbor_error_code codeโ description
๐ฅ Encoding
The easiest way to encode data items is using the cbor_serialize() or cbor_serialize_alloc() functions:
cbor_serialize
size_t cbor_serialize(const cbor_item_t *item, cbor_mutable_data buffer, size_t buffer_size)
Serialize the given item. slay โจ
Return length of the result. 0 on failure.
Parameters
- item [borrow]: a data item
- buffer: buffer to serialize to
- buffer_size: size of the buffer
cbor_serialize_alloc
size_t cbor_serialize_alloc(const cbor_item_t *item, cbor_mutable_data *buffer, size_t *buffer_size)
Serialize the given item, allocating buffers as needed.
WARNING: it is your responsibility to free the buffer using an appropriate free implementation. no cap, that's on you ๐ซต
Return length of the result. 0 on failure, in which case buffer is NULL.
Parameters
- item [borrow]: a data item
- buffer [out]: buffer containing the result
- buffer_size [out]: size of the buffer
๐ธ 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. that's the scary kind, bestie โ like, "we don't talk about what happens next" kind of undefined ๐
cbor_serialize_uint
size_t cbor_serialize_uint(const cbor_item_t *item, cbor_mutable_data buffer, size_t buffer_size)
Serialize an uint.
Return length of the result. 0 on failure.
Parameters
- item [borrow]: a uint
- buffer: buffer to serialize to
- buffer_size: size of the buffer
cbor_serialize_negint
size_t cbor_serialize_negint(const cbor_item_t *item, cbor_mutable_data buffer, size_t buffer_size)
Serialize a negint.
Return length of the result. 0 on failure.
Parameters
- item [borrow]: a neging (and yes, the source spells it "A neging" โ we stan a typo ๐)
- buffer: buffer to serialize to
- buffer_size: size of the buffer
cbor_serialize_bytestring
size_t cbor_serialize_bytestring(const cbor_item_t *item, cbor_mutable_data buffer, size_t buffer_size)
Serialize a bytestring.
Return length of the result. 0 on failure.
Parameters
- item [borrow]: a bytestring
- buffer: buffer to serialize to
- buffer_size: size of the buffer
cbor_serialize_string
size_t cbor_serialize_string(const cbor_item_t *item, cbor_mutable_data buffer, size_t buffer_size)
Serialize a string.
Return length of the result. 0 on failure.
Parameters
- item [borrow]: a string
- buffer: buffer to serialize to
- buffer_size: size of the buffer
cbor_serialize_array
size_t cbor_serialize_array(const cbor_item_t *item, cbor_mutable_data buffer, size_t buffer_size)
Serialize an array.
Return length of the result. 0 on failure.
Parameters
- item [borrow]: an array
- buffer: buffer to serialize to
- buffer_size: size of the buffer
cbor_serialize_map
size_t cbor_serialize_map(const cbor_item_t *item, cbor_mutable_data buffer, size_t buffer_size)
Serialize a map.
Return length of the result. 0 on failure.
Parameters
- item [borrow]: a map
- buffer: buffer to serialize to
- buffer_size: size of the buffer
cbor_serialize_tag
size_t cbor_serialize_tag(const cbor_item_t *item, cbor_mutable_data buffer, size_t buffer_size)
Serialize a tag.
Return length of the result. 0 on failure.
Parameters
- item [borrow]: a tag
- buffer: buffer to serialize to
- buffer_size: size of the buffer
cbor_serialize_float_ctrl
size_t cbor_serialize_float_ctrl(const cbor_item_t *item, cbor_mutable_data buffer, size_t buffer_size)
Serialize a. (that's the whole sentence. "Serialize a." iconic, no notes ๐ )
Return length of the result. 0 on failure.
Parameters
- item [borrow]: a float or ctrl
- buffer: buffer to serialize to
- buffer_size: size of the buffer
๐ฆ 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
enum cbor_int_width
Possible widths of CBOR_TYPE_UINT items.
Values:
- enumerator
CBOR_INT_8 - enumerator
CBOR_INT_16 - enumerator
CBOR_INT_32 - enumerator
CBOR_INT_64
โจ 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 (yes, the page says this here too): once a positive integer has been created, its width cannot be changed.
๐งฎ Type 0 & 1 ๐งฎ
okay so bestie, because Type 0 and Type 1 are largely similar in semantics, the functions below work for both of them. You can convert between them freely using the conversion functions. ๐ซ
You can check the actual type of the integer using the 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_uintAPI is somewhat counter-intuitive as the resulting logical value is1less. This behavior is necessary in order to permit uniform manipulation with the full range of permitted values. For example, the following snippetc 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 ๐ ๏ธ
cbor_item_t *cbor_build_uint8(uint8_t value)โ Constructs a new positive integer.- Returns: new positive integer or
NULLon memory allocation failure - Parameters:
value: the value to use
- Returns: new positive integer or
cbor_item_t *cbor_build_uint16(uint16_t value)โ Constructs a new positive integer.- Returns: new positive integer or
NULLon memory allocation failure - Parameters:
value: the value to use
- Returns: new positive integer or
cbor_item_t *cbor_build_uint32(uint32_t value)โ Constructs a new positive integer.- Returns: new positive integer or
NULLon memory allocation failure - Parameters:
value: the value to use
- Returns: new positive integer or
cbor_item_t *cbor_build_uint64(uint64_t value)โ Constructs a new positive integer.- Returns: new positive integer or
NULLon memory allocation failure - Parameters:
value: the value to use
- Returns: new positive integer or
๐ Retrieving values ๐
uint8_t cbor_get_uint8(const cbor_item_t *item)โ Extracts the integer value.- Returns: the value
- Parameters:
item[borrow]: positive or negative integer
uint16_t cbor_get_uint16(const cbor_item_t *item)โ Extracts the integer value.- Returns: the value
- Parameters:
item[borrow]: positive or negative integer
uint32_t cbor_get_uint32(const cbor_item_t *item)โ Extracts the integer value.- Returns: the value
- Parameters:
item[borrow]: positive or negative integer
uint64_t cbor_get_uint64(const cbor_item_t *item)โ Extracts the integer value.- Returns: the value
- Parameters:
item[borrow]: positive or negative integer
โ๏ธ Setting values โ๏ธ
void cbor_set_uint8(cbor_item_t *item, uint8_t value)โ Assigns the integer value.- Parameters:
item[borrow]: positive or negative integer itemvalue: the value to assign. For negative integer, the logical value is-value - 1
- Parameters:
void cbor_set_uint16(cbor_item_t *item, uint16_t value)โ Assigns the integer value.- Parameters:
item[borrow]: positive or negative integer itemvalue: the value to assign. For negative integer, the logical value is-value - 1
- Parameters:
void cbor_set_uint32(cbor_item_t *item, uint32_t value)โ Assigns the integer value.- Parameters:
item[borrow]: positive or negative integer itemvalue: the value to assign. For negative integer, the logical value is-value - 1
- Parameters:
void cbor_set_uint64(cbor_item_t *item, uint64_t value)โ Assigns the integer value.- Parameters:
item[borrow]: positive or negative integer itemvalue: the value to assign. For negative integer, the logical value is-value - 1
- Parameters:
๐ Dealing with width ๐
cbor_int_width cbor_int_get_width(const cbor_item_t *item)โ Queries the integer width.- Returns: the width
- Parameters:
item[borrow]: positive or negative integer item
๐ญ Dealing with signedness ๐ญ
void cbor_mark_uint(cbor_item_t *item)โ Marks the integer item as a positive integer.- The data value is not changed
- Parameters:
item[borrow]: positive or negative integer item
void cbor_mark_negint(cbor_item_t *item)โ Marks the integer item as a negative integer.- The data value is not changed
- Parameters:
item[borrow]: positive or negative integer item
๐ Creating new items ๐
cbor_item_t *cbor_new_int8()โ Allocates new integer with1Bwidth.- The width cannot be changed once allocated
- Returns: new positive integer or
NULLon memory allocation failure. The value is not initialized
cbor_item_t *cbor_new_int16()โ Allocates new integer with2Bwidth.- The width cannot be changed once allocated
- Returns: new positive integer or
NULLon memory allocation failure. The value is not initialized
cbor_item_t *cbor_new_int32()โ Allocates new integer with4Bwidth.- The width cannot be changed once allocated
- Returns: new positive integer or
NULLon memory allocation failure. The value is not initialized
cbor_item_t *cbor_new_int64()โ Allocates new integer with8Bwidth.- The width cannot be changed once allocated
- Returns: new positive integer or
NULLon 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
So indefinite byte strings are literally represented by two bytes, 0x00 and 0xff โ that's the whole vibe check. And like, lowkey this is a double-edged sword ๐ก๏ธ: on one hand it enables streaming messages even before they're fully generated (iconic, slay), but on the other hand it adds more complexity to the client code (๐ญ the tradeoff is real).
Here's the receipt for what it costs you, bestie ๐ธ:
- 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
๐ Streaming indefinite byte strings
Please refer to /streaming โ that's where the tea is โ (no cap, go read it).
๐ Getting metadata
size_t cbor_bytestring_length(const cbor_item_t *item)โ returns the length of the binary data. For definite byte strings only, okay? Don't come for me. It returns the length of the binary data, and zero if no chunk has been attached yet. Parameters:item[borrow]: a definite bytestring
bool cbor_bytestring_is_definite(const cbor_item_t *item)โ is the byte string definite? Returns whether the byte string is definite. Parameters:item[borrow]: a byte string
bool cbor_bytestring_is_indefinite(const cbor_item_t *item)โ is the byte string indefinite? Returns whether the byte string is indefinite. Parameters:item[borrow]: a byte string
size_t cbor_bytestring_chunk_count(const cbor_item_t *item)โ get the number of chunks this string consists of. Returns the chunk count, and0for freshly created items. Parameters:item[borrow]: an indefinite bytestring
๐ Reading data
cbor_mutable_data cbor_bytestring_handle(const cbor_item_t *item)โ get the handle to the binary data. Definite items only. Modifying the data is allowed โ but in that case, the caller takes responsibility for the effect on items this item might be a part of ๐ซฃ (yes, you own that chaos). Returns the address of the binary data, orNULLif no data have been assigned yet. Parameters:item[borrow]: a definite byte string
cbor_item_t **cbor_bytestring_chunks_handle(const cbor_item_t *item)โ 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. Returns an array ofcbor_bytestring_chunk_countdefinite bytestrings. Parameters:item[borrow]: an indefinite byte string
โจ Creating new items
cbor_item_t *cbor_new_definite_bytestring()โ creates a new definite byte string. The handle is initialized toNULLand length to0. Returns a new definite bytestring, orNULLonmallocfailure ๐.cbor_item_t *cbor_new_indefinite_bytestring()โ creates a new indefinite byte string. The chunks array is initialized toNULLand chunkcount to0. Returns a new indefinite bytestring, orNULLonmallocfailure ๐.
๐ ๏ธ Building items
cbor_item_t *cbor_build_bytestring(cbor_data handle, size_t length)โ creates a new byte string and initializes it. The handle will be copied to a newly allocated block (so it's a whole new copy, not a borrow, iykyk). Returns a new byte string with contenthandle, orNULLonmallocfailure. Parameters:handle: block of binary datalength: length of data
๐ Manipulating existing items
void cbor_bytestring_set_handle(cbor_item_t *item, cbor_mutable_data data, size_t length)โ set the handle to the binary data. Parameters:item[borrow]: a definite byte stringdata: the memory block. The caller gives up the ownership of the block โ libcbor will deallocate it when appropriate using its free function. So like, hands off after this, bestie ๐ซถlength: length of the data block
bool cbor_bytestring_add_chunk(cbor_item_t *item, cbor_item_t *chunk)โ appends a chunk to the bytestring. Indefinite byte strings only. May realloc the chunk storage. Returnstrueon success,falseon realloc failure โ and in that case, the refcount ofchunkis not increased and the item is left intact (no half-broken vibes, we love to see it). Parameters:item[borrow]: an indefinite byte stringitem[incref]: a definite byte string
๐ Type 3 โ UTF-8 strings ๐
okay so CBOR strings work in much the same ways as type_2 โ here's the whole vibe check, bestie:
- 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
๐ฆ Streaming indefinite strings ๐ฆ
Please refer to /streaming.
๐ 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 ๐
size_t cbor_string_length(const cbor_item_t *item)โ returns the length of the underlying string.- For definite strings only
- Return: length of the string. Zero if no chunk has been attached yet.
- Parameters:
item[borrow]: a definite string
bool cbor_string_is_definite(const cbor_item_t *item)โ is the string definite?- Return: Is the string definite?
- Parameters:
item[borrow]: a string
bool cbor_string_is_indefinite(const cbor_item_t *item)โ is the string indefinite?- Return: Is the string indefinite?
- Parameters:
item[borrow]: a string
size_t cbor_string_chunk_count(const cbor_item_t *item)โ get the number of chunks this string consist of.- Return: the chunk count.
0for freshly created items. - Parameters:
item[borrow]: A indefinite string
- Return: the chunk count.
๐ธ Reading data ๐ธ
cbor_mutable_data cbor_string_handle(const cbor_item_t *item)โ get the handle to the underlying string.- Definite items only. Modifying the data is allowed. In that case, the caller takes responsibility for the effect on items this item might be a part of.
- Return: The address of the underlying string.
NULLif no data have been assigned yet. - Parameters:
item[borrow]: A definite string
cbor_item_t **cbor_string_chunks_handle(const cbor_item_t *item)โ 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.
- Return: array of
cbor_string_chunk_countdefinite strings - Parameters:
item[borrow]: A indefinite string
โจ Creating new items โจ
cbor_item_t *cbor_new_definite_string()โ creates a new definite string.- The handle is initialized to
NULLand length to0 - Return: new definite string.
NULLonmallocfailure.
- The handle is initialized to
cbor_item_t *cbor_new_indefinite_string()โ creates a new indefinite string.- The chunks array is initialized to
NULLand chunkcount to0 - Return: new indefinite string.
NULLonmallocfailure.
- The chunks array is initialized to
๐ Building items ๐
cbor_item_t *cbor_build_string(const char *val)โ creates a new string and initializes it.- The
valwill be copied to a newly allocated block - Return: A new string with content handle.
NULLonmallocfailure. - Parameters:
val: A null-terminated UTF-8 string
- The
๐ Manipulating existing items ๐
void cbor_string_set_handle(cbor_item_t *item, cbor_mutable_data data, size_t length)โ set the handle to the underlying string.- > 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.
- Parameters:
item[borrow]: A definite stringdata: The memory block. The caller gives up the ownership of the block.libcborwill deallocate it when appropriate using its free functionlength: Length of the data block
bool cbor_string_add_chunk(cbor_item_t *item, cbor_item_t *chunk)โ appends a chunk to the string.- Indefinite strings only.
- May realloc the chunk storage.
- Return:
trueon success.falseon realloc failure. In that case, the refcount ofchunkis not increased and the item is left intact. - Parameters:
item[borrow]: An indefinite stringchunk[incref]: A definite string
๐ Type 4 โ Arrays
Bestie, CBOR arrays are just like byte strings and strings: they can be encoded either definite or indefinite. No cap. ๐
Hereโs the spec vibe:
- 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
๐ Streaming indefinite arrays
Please refer to /streaming.
๐ Getting metadata
size_t cbor_array_size(const cbor_item_t *item)โ get the number of members.- Return: The number of members
- Parameters:
item[borrow]: An array
size_t cbor_array_allocated(const cbor_item_t *item)โ get the size of the allocated storage.- Return: The size of the allocated storage (number of items)
- Parameters:
item[borrow]: An array
bool cbor_array_is_definite(const cbor_item_t *item)โ is the array definite?- Return: Is the array definite?
- Parameters:
item[borrow]: An array
bool cbor_array_is_indefinite(const cbor_item_t *item)โ is the array indefinite?- Return: Is the array indefinite?
- Parameters:
item[borrow]: An array
๐ Reading data
cbor_item_t **cbor_array_handle(const cbor_item_t *item)โ get the array contents.- The items may be reordered and modified as long as references remain consistent.
- Return:
cbor_array_sizeitems - Parameters:
item[borrow]: An array
cbor_item_t *cbor_array_get(const cbor_item_t *item, size_t index)โ get item by index.- Return:
increfThe item, orNULLin case of boundary violation - Parameters:
item[borrow]: An arrayindex: The index
- Return:
๐ฃ Creating new items
cbor_item_t *cbor_new_definite_array(size_t size)โ create new definite array.- Return: new array or
NULLuponmallocfailure - Parameters:
size: Number of slots to preallocate
- Return: new array or
cbor_item_t *cbor_new_indefinite_array()โ create new indefinite array.- Return: new array or
NULLuponmallocfailure
- Return: new array or
๐ ๏ธ Modifying items
bool cbor_array_push(cbor_item_t *array, cbor_item_t *pushee)โ append to the end.- For indefinite items, storage may be realloacted. For definite items, only the preallocated capacity is available.
- Return:
trueon success,falseon failure - Parameters:
array[borrow]: An arraypushee[incref]: The item to push
bool cbor_array_replace(cbor_item_t *item, size_t index, cbor_item_t *value)โ replace item at an index.- The item being replaced will be
cbor_decref'ed. - Return:
trueon success,falseon allocation failure. - Parameters:
item[borrow]: An arrayvalue[incref]: The item to assignindex: The index, first item is0.
- The item being replaced will be
bool cbor_array_set(cbor_item_t *item, size_t index, cbor_item_t *value)โ set item by index.- Creating arrays with holes is not possible ๐ธ
- Return:
trueon success,falseon allocation failure. - Parameters:
item[borrow]: An arrayvalue[incref]: The item to assignindex: The index, first item is0.
๐บ๏ธ Type 5 โ Maps
CBOR maps are the plain old associate hash maps known from JSON and many other formats and languages, with one exception: any CBOR data item can be a key, not just strings. This is somewhat unusual and you, as an application developer, should keep that in mind. ๐
Maps can be either definite or indefinite, in much the same way as type_4.
Hereโs the map spec tea:
- 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
๐ Streaming maps
Please refer to /streaming.
๐ Getting metadata
size_t cbor_map_size(const cbor_item_t *item)โ get the number of pairs.- Return: The number of pairs
- Parameters:
item[borrow]: A map
size_t cbor_map_allocated(const cbor_item_t *item)โ get the size of the allocated storage.- Return: Allocated storage size (as the number of
cbor_pairitems) - Parameters:
item[borrow]: A map
- Return: Allocated storage size (as the number of
bool cbor_map_is_definite(const cbor_item_t *item)โ is this map definite?- Return: Is this map definite?
- Parameters:
item[borrow]: A map
bool cbor_map_is_indefinite(const cbor_item_t *item)โ is this map indefinite?- Return: Is this map indefinite?
- Parameters:
item[borrow]: A map
๐ Reading data
struct cbor_pair *cbor_map_handle(const cbor_item_t *item)โ get the pairs storage.- Return: Array of
cbor_map_sizepairs. Manipulation is possible as long as references remain valid. - Parameters:
item[borrow]: A map
- Return: Array of
๐ฃ Creating new items
cbor_item_t *cbor_new_definite_map(size_t size)โ create a new definite map.- Return: new definite map.
NULLonmallocfailure. - Parameters:
size: The number of slots to preallocate
- Return: new definite map.
cbor_item_t *cbor_new_indefinite_map()โ create a new indefinite map.- Return: new definite map.
NULLonmallocfailure. - Parameters:
size: The number of slots to preallocate
- Return: new definite map.
Yes bestie, that size parameter is listed right there even though the signature takes no arguments โ Iโm keeping it exactly as the page says ๐ซถ
๐ ๏ธ Modifying items
bool cbor_map_add(cbor_item_t *item, struct cbor_pair pair)โ 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.
- Return:
trueon success,falseif either reallocation failed or the preallocated storage is full - Parameters:
item[borrow]: A mappair[incref]: The key-value pair to add (increfis member-wise)
๐ท๏ธ Type 6 โ Semantic tags
Tags 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. Like, for real bestie โ the registry is right there, don't just make up numbers, that's not the vibe ๐
Tag vibe check:
- 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
cbor_item_t *cbor_new_tag(uint64_t value)โ creates a new tag, iconic behavior honestly โจ
Returns: the new tag. The item reference is NULL. Returns NULL upon memory allocation failure ๐ญ
Parameters:
valueโ the tag value. Please consult the tag repository (yes, again, we're serious)
cbor_item_t *cbor_tag_item(const cbor_item_t *item)โ gets the tagged item ๐
Returns: incref'd tagged item (it ups the ref count, that's the whole point)
Parameters:
item[borrow]โ a tag
uint64_t cbor_tag_value(const cbor_item_t *item)โ gets the tag value ๐
Returns: the tag value. Please consult the tag repository (we keep saying it because it matters)
Parameters:
item[borrow]โ a tag
void cbor_tag_set_item(cbor_item_t *item, cbor_item_t *tagged_item)โ sets the tagged item, slay ๐ซถ
Parameters:
item[borrow]โ a tagtagged_item[incref]โ the item to tag
๐ธ Type 7 โ Floats & control tokens ๐ธ
Okay so this type is a total chaotic duo โ it smashes together two completely unrelated kinds of items: floating point numbers, and special values like true, false, null, etc. We call those special values 'control values' or 'ctrls' for short all throughout the code, iykyk ๐
And just like integers, they come in different possible widths (which means different value ranges and precisions โ the width is literally the whole personality).
enum cbor_float_width
These are the possible widths of CBOR_TYPE_FLOAT_CTRL items โจ
Values:
CBOR_FLOAT_0โ internal use: ctrl and special values ๐๏ธCBOR_FLOAT_16โ half float ๐CBOR_FLOAT_32โ single floatCBOR_FLOAT_64โ double
Float/ctrl vibe check:
- Corresponding cbor_type:
CBOR_TYPE_FLOAT_CTRL - Number of allocations: one per lifetime ๐ฑ
- Storage requirements:
sizeof(cbor_item_t)+1/4/8
๐ Getting metadata
bool cbor_float_ctrl_is_ctrl(const cbor_item_t *item)โ is this a ctrl value? ๐
Returns: is this a ctrl value?
Parameters:
item[borrow]โ a float or ctrl item
cbor_float_width cbor_float_get_width(const cbor_item_t *item)โ gets the float width ๐
Returns: the width.
Parameters:
item[borrow]โ a float or ctrl item
๐ Reading data
float cbor_float_get_float2(const cbor_item_t *item)โ gets a half precision float ๐ง
The item must have the corresponding width, no cap.
Returns: half precision value
Parameters:
[borrow]โ a half precision float
float cbor_float_get_float4(const cbor_item_t *item)โ gets a single precision float
The item must have the corresponding width.
Returns: single precision value
Parameters:
[borrow]โ a single precision float
double cbor_float_get_float8(const cbor_item_t *item)โ gets a double precision float ๐ฅ
The item must have the corresponding width.
Returns: double precision value
Parameters:
[borrow]โ a double precision float
double cbor_float_get_float(const cbor_item_t *item)โ gets the float value represented as a double, the flexible icon ๐
Can be used regardless of the width โ she doesn't care about your width drama.
Returns: double precision value
Parameters:
[borrow]โ any float
uint8_t cbor_ctrl_value(const cbor_item_t *item)โ reads the control value ๐๏ธ
Returns: the simple value
Parameters:
item[borrow]โ a ctrl item
bool cbor_get_bool(const cbor_item_t *item)โ gets the value from a boolean ctrl item โ
Returns: boolean value
Parameters:
item[borrow]โ a ctrl item
๐ ๏ธ Creating new items
cbor_item_t *cbor_new_ctrl()โ constructs a new ctrl item
The width cannot be changed once the item is created (choose wisely bestie).
Returns: new 1B ctrl, or NULL upon memory allocation failure ๐ญ
cbor_item_t *cbor_new_float2()โ constructs a new float item
The width cannot be changed once the item is created.
Returns: new 2B float, or NULL upon memory allocation failure
cbor_item_t *cbor_new_float4()โ constructs a new float item
The width cannot be changed once the item is created.
Returns: new 4B float, or NULL upon memory allocation failure
cbor_item_t *cbor_new_float8()โ constructs a new float item
The width cannot be changed once the item is created.
Returns: new 8B float, or NULL upon memory allocation failure
cbor_item_t *cbor_new_null()โ constructs a newnullctrl item ๐ซฅ
Returns: new null ctrl item, or NULL upon memory allocation failure
cbor_item_t *cbor_new_undef()โ constructs a newundefctrl item ๐ซ๏ธ
Returns: new undef ctrl item, or NULL upon memory allocation failure
๐๏ธ Building items
cbor_item_t *cbor_build_bool(bool value)โ constructs a new boolean ctrl item ๐
Returns: new boolean ctrl item, or NULL upon memory allocation failure
Parameters:
valueโ the value to use
cbor_item_t *cbor_build_ctrl(uint8_t value)โ constructs a ctrl item
Returns: new ctrl item, or NULL upon memory allocation failure
Parameters:
valueโ the value to use
cbor_item_t *cbor_build_float2(float value)โ constructs a new float โจ
Returns: new float
Parameters:
valueโ the value to use
cbor_item_t *cbor_build_float4(float value)โ constructs a new float
Returns: new float, or NULL upon memory allocation failure
Parameters:
valueโ the value to use
cbor_item_t *cbor_build_float8(double value)โ constructs a new float
Returns: new float, or NULL upon memory allocation failure
Parameters:
valueโ the value to use
๐จ Manipulating existing items
void cbor_set_ctrl(cbor_item_t *item, uint8_t value)โ assigns a control value
โ ๏ธ WARNING: it is possible to produce an invalid CBOR value by assigning an invalid value using this mechanism. Please consult the standard before use. Like, genuinely, don't just yolo it ๐ญ
Parameters:
item[borrow]โ a ctrl itemvalueโ the simple value to assign. Please consult the standard for allowed values
void cbor_set_bool(cbor_item_t *item, bool value)โ assigns a boolean value to a boolean ctrl item โ
Parameters:
item[borrow]โ a ctrl itemvalueโ the simple value to assign.
void cbor_set_float2(cbor_item_t *item, float value)โ assigns a float value ๐
Parameters:
item[borrow]โ a half precision floatvalueโ the value to assign
void cbor_set_float4(cbor_item_t *item, float value)โ assigns a float value
Parameters:
item[borrow]โ a single precision floatvalueโ the value to assign
void cbor_set_float8(cbor_item_t *item, double value)โ assigns a float value ๐ฅ
Parameters:
item[borrow]โ a double precision floatvalueโ the value to assign
๐ง Half floats (the cursed ones, lowkey)
CBOR supports two-bytes-wide ("half-precision") floats, which the C language does not support natively ๐. libcbor represents them using float <https://en.cppreference.com/w/c/language/type> values throughout the API, and that has important implications when you're manipulating these values.
Specifically: if you use some of the manipulation APIs (e.g. cbor_set_float2(), cbor_new_float2()) to introduce a value that doesn't have an exact half-float representation, the encoding semantics are given by cbor_encode_half() as follows:
size_t cbor_encode_half(float value, unsigned char *buffer, size_t buffer_size)
Encodes a half-precision float โจ
Since there's no native representation or semantics for half floats in the language, we use single-precision floats โ because 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:
- Infinity,
NaNare preserved โพ๏ธ - Zero is preserved 0๏ธโฃ
- Denormalized numbers keep their sign bit and 10 most significant bits of the significand
- All other numbers:
- If the logical value of the exponent is
< -24, the output is zero - If the logical value of the exponent is between
-23and-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 ๐
- If the logical value of the exponent is
- In all other cases, the sign bit, the exponent, and the 10 most significant bits of the significand are kept ๐ซถ
Returns the number of bytes written.
Parameters
value:buffer: Target bufferbuffer_size: Available space in the buffer
[1] http://softwareengineering.vazexqi.com/files/pattern.html
๐ Streaming & indefinite items ๐
Okay so this is the good stuff bestie. CBOR strings, byte strings, arrays, and maps can be encoded as indefinite, meaning their length or size is justโฆ not specified. Instead, they get divided into chunks (that's for strings and byte strings), or they're explicitly terminated (that's for arrays and maps) โจ
This is genuinely one of the most important features of CBOR โ and, due to poor implementations, also one of the most underutilized. It enables low-overhead streaming just about anywhere without dealing with channels or pub/sub mechanisms. No cap. ๐ฅ
But bestie, real talk: it is important to recognize that CBOR streaming is not a substitute for Websockets [1] and similar technologies. Different vibe, different job ๐
[1] RFC 6455
๐ Decoding ๐
Another way to decode data using libcbor is to specify callbacks that will be invoked when certain items are found in the input. This service is provided by:
struct cbor_decoder_result cbor_stream_decode(cbor_data buffer, size_t buffer_size, const struct cbor_callbacks *callbacks, void *context)
Stateless decoder.
Will try parsing the buffer and will invoke the appropriate callback on success. Decodes one item at a time. No memory allocations occur. Obsessed with the zero-alloc life honestly ๐ง
Parameters
buffer: Input bufferbuffer_size: Length of the buffercallbacks: The callback bundlecontext: An arbitrary pointer to allow for maintaining context.
To get started, you might want to have a look at the simple streaming example:
#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;
}
free(buffer);
fclose(f);
}
The callbacks are defined by:
struct cbor_callbacks
Callback bundle passed to the decoder.
Public Members
cbor_int8_callback uint8โ Unsigned int.cbor_int16_callback uint16โ Unsigned int.cbor_int32_callback uint32โ Unsigned int.cbor_int64_callback uint64โ Unsigned int.cbor_int64_callback negint64โ Negative int.cbor_int32_callback negint32โ Negative int.cbor_int16_callback negint16โ Negative int.cbor_int8_callback negint8โ Negative int.cbor_simple_callback byte_string_startโ Definite byte string.cbor_string_callback byte_stringโ Indefinite byte string start.cbor_string_callback stringโ Definite string.cbor_simple_callback string_startโ Indefinite string start.cbor_simple_callback indef_array_startโ Definite array.cbor_collection_callback array_startโ Indefinite array.cbor_simple_callback indef_map_startโ Definite map.cbor_collection_callback map_startโ Indefinite map.cbor_int64_callback tagโ Tags.cbor_float_callback float2โ Half float.cbor_float_callback float4โ Single float.cbor_double_callback float8โ Double float.cbor_simple_callback undefinedโ Undef.cbor_simple_callback nullโ Null.cbor_bool_callback booleanโ Bool.cbor_simple_callback indef_breakโ Indefinite item break.
When building custom sets of callbacks, feel free to start from:
const struct cbor_callbacks cbor_empty_callbacks
Dummy callback bundle - does nothing. Literally the blank canvas of callbacks ๐จ
๐งฉ Related structures ๐งฉ
enum cbor_decoder_status
Streaming decoder result - status.
Values:
enumerator CBOR_DECODER_FINISHEDโ OK, finished. slay ๐enumerator CBOR_DECODER_NEDATAโ Not enough data - mismatch with MTB.enumerator CBOR_DECODER_EBUFFERโ Buffer manipulation problem.enumerator CBOR_DECODER_ERRORโ Malformed or reserved MTB/value.
struct cbor_decoder_result
Streaming decoder result.
Public Members
size_t readโ Bytes read.enum cbor_decoder_status statusโ The result.size_t requiredโ Whenstatus == CBOR_DECODER_NEDATA, the minimum number of bytes required to continue parsing.
๐ Callback types definition ๐
typedef void (*cbor_int8_callback)(void*, uint8_t)
Callback prototype.
typedef void (*cbor_int16_callback)(void*, uint16_t)
Callback prototype.
typedef void (*cbor_int32_callback)(void*, uint32_t)
Callback prototype.
typedef void (*cbor_int64_callback)(void*, uint64_t)
Callback prototype.
typedef void (*cbor_simple_callback)(void*)
Callback prototype.
typedef void (*cbor_string_callback)(void*, cbor_data, size_t)
Callback prototype.
typedef void (*cbor_collection_callback)(void*, size_t)
Callback prototype.
typedef void (*cbor_float_callback)(void*, float)
Callback prototype.
typedef void (*cbor_double_callback)(void*, double)
Callback prototype.
typedef void (*cbor_bool_callback)(void*, bool)
Callback prototype.
โ๏ธ Encoding โ๏ธ
TODO
Not me telling you the manpage literally just says TODO ๐ญ That's it. That's the whole section. We move ๐
๐งช 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 a 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 fails 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. Chaos-proofing, basically ๐
๐ RFC conformance ๐
libcbor is, generally speaking, a very faithful implementation of RFC 7049. There are, however, some limitations imposed by technical constraints.
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 a 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] http://tools.ietf.org/html/rfc7049#section-2.2.2
Half-precision IEEE 754 floats
As of C99 and even C11, there is no standard implementation for 2-byte 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 api_type_7_hard_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. Peak transparency, we love to see it ๐
โจ Terminology โจ
ok so two lil vocab words before we go any further, bestie, you're gonna see these everywhere:
- MTB โ Major Type Byte. iykyk, it's the thing at
http://tools.ietf.org/html/rfc7049#section-2.1 - DST โ Dynamically Sized Type. it's a type whose storage requirements cannot be determined during compilation (this term literally originated in the Rust community, periodt)
โจ Conventions โจ
so the naming sitch is: API symbols start with cbor_ or CBOR_ prefix, and the internal symbols are the shy ones โ they get _cbor_ or _CBOR_. easy.
โจ Inspiration & related projects โจ
ngl 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.
like. we studied the icons. ๐
โจ General notes on the API design โจ
the API design has two main driving priciples (yes, that's how it's spelled in the source, we stan):
- Let the client manage the memory as much as possible
- 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. no notes. ๐
โจ 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. slay.
generally speaking, data items consist of three parts:
- a generic handle,
- the associated metadata,
- and the actual data
type cbor_item_t
Represents the item. Used as an opaque type.
cbor_type typeโ Type discriminatorsize_t refcountโ Reference counter. Used bycbor_decref(),cbor_incref()union cbor_item_metadata metadataโ Union discriminated by type. Contains type-specific metadataunsigned char *dataโ Contains pointer to the actual data. Small, fixed size items (api/type_0_1,api/type_6,api/type_7) 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 (api/type_2, api/type_3, api/type_4, api/type_5) 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. iconic honestly.
type cbor_item_metadata
Union type of the following members, based on the item type:
struct _cbor_int_metadata int_metadataโ Used both by bothapi/type_0_1struct _cbor_bytestring_metadata bytestring_metadatastruct _cbor_string_metadata string_metadatastruct _cbor_array_metadata array_metadatastruct _cbor_map_metadata map_metadatastruct _cbor_tag_metadata tag_metadatastruct _cbor_float_ctrl_metadata float_ctrl_metadata
โจ Decoding โจ
as outlined in api, there decoding is based on the streaming decoder (that triple "there" is the original's, bestie, we don't touch it ๐). essentially, the decoder is a custom set of callbacks for the streaming decoder. cute, right?
๐ Changelog ๐
Next
0.7.0 (2020-04-25)
- Fix bad encoding of NaN half-floats [
Fixes #53](https://github.com/PJK/libcbor/issues/53) (discovered by [BSipos-RKF](https://github.com/BSipos-RKF))- Warning: Previous versions encoded NaNs as
0xf9e700instead of0xf97e00; if you rely on the broken behavior, this will be a breaking change
- Warning: Previous versions encoded NaNs as
- Fix potentially bad encoding of negative half-float with exponent < -14 [
Fixes #112](https://github.com/PJK/libcbor/issues/112) (discovered by [yami36](https://github.com/yami36)) - BREAKING: Improved bool support [
Fixes #63](https://github.com/PJK/libcbor/issues/63)- Rename
cbor_ctrl_is_booltocbor_get_booland fix the behavior - Add
cbor_set_bool
- Rename
- Fix
memory_allocation_testbreaking the build withoutCBOR_CUSTOM_ALLOC[Fixes #128](https://github.com/PJK/libcbor/issues/128) (by [panlinux](https://github.com/panlinux)) - [Fix a potential build issue where cJSON includes may be misconfigured](
https://github.com/PJK/libcbor/pull/132) - Breaking: [Add a limit on the size of the decoding context stack](
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
- If your usecase requires parsing very deeply nested structures, you might need to increase the default 2k limit via
- Enable LTO/IPO based on [CheckIPOSupported](
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)
- Correctly set
.soversion [Fixes #52](https://github.com/PJK/libcbor/issues/52).- Warning: All previous releases will be identified as 0.0 by the linker.
- Fix & prevent heap overflow error in example code [
#74](https://github.com/PJK/libcbor/pull/74) [#76](https://github.com/PJK/libcbor/pull/76) (by @nevun) - Correctly set OSX dynamic library version [
Fixes #75](https://github.com/PJK/libcbor/issues/75) - [Fix misplaced 0xFF bytes in maps possibly causing memory corruption](
https://github.com/PJK/libcbor/pull/82) - BREAKING: Fix handling & cleanup of failed memory allocation in constructor and builder helper functions [
Fixes #84](https://github.com/PJK/libcbor/issues/84) โ Allcbor_new_*andcbor_build_*functions will now explicitly returnNULLwhen memory allocation fails โ It is up to the client to handle such cases - Globally enforced code style [
Fixes #83](https://github.com/PJK/libcbor/issues/83) - Fix issue possible memory corruption bug on repeated
cbor_(byte)string_add_chunkcalls with intermittently failing realloc calls - Fix possibly misaligned reads and writes when
endian.his uses or when running on a big-endian machine [Fixes #99](https://github.com/PJK/libcbor/issues/99), [#100](https://github.com/PJK/libcbor/issues/100) - [Improved CI setup with Travis-native arm64 support](
https://github.com/PJK/libcbor/pull/116) - [Docs migrated to Sphinx 2.4 and Python3](
https://github.com/PJK/libcbor/pull/117)
0.5.0 (2017-02-06)
- Remove cmocka from the subtree (always rely on system or user-provided version)
- Windows CI
- Only build tests if explicitly enabled (
-DWITH_TESTS=ON) - Fixed static header declarations (by cedric-d)
- Improved documentation (by Michael Richardson)
- Improved
examples/readfile.c - Reworked (re)allocation to handle huge inputs and overflows in
size_t[Fixes #16](https://github.com/PJK/libcbor/issues/16) - Improvements to C++ linkage (corrected
cbor_empty_callbacks, fixed restrict pointers) (by Dennis Bijwaard) - Fixed Linux installation directory depending on architecture [
Fixes #34](https://github.com/PJK/libcbor/issues/34) (by jvymazal) - Improved 32-bit support [
Fixes #35](https://github.com/PJK/libcbor/issues/35) - Fixed MSVC compatibility [
Fixes #31](https://github.com/PJK/libcbor/issues/31) - Fixed and improved half-float encoding [
Fixes #5](https://github.com/PJK/libcbor/issues/5), [#11](https://github.com/PJK/libcbor/issues/11)
0.4.0 (2015-12-25)
Breaks build & header compatibility due to:
- Improved build configuration and feature check macros
- Endianess 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_copycbor_build_negint8,16,32,64, matching assertscbor_build_stringncbor_build_tagcbor_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
okay so, consistency and coherence are literally one of the key characteristics of good software. Reality is never black and white, but it is important that libcbor contributors are all working towards the same high-level goal. This document is doing its best to set out the basic principles of libcbor and the rationale behind them. If you're contributing to libcbor, or you're trying to figure out whether libcbor is the right choice for your project, it might genuinely be worth skimming through the section below. ๐
Mission statement
libcbor is the compact, full-featured, and safe CBOR library that works everywhere. periodt. ๐ฆ
Goals
RFC-conformance and full feature support
Anything the standard allows, libcbor can do. โจ
Why? Because conformance and interoperability is the point of defining standards, bestie. Clients expect the support to be feature-complete, and there's no significant complexity reduction you can achieve by slightly cutting corners โ which means the incremental cost of full RFC support is comparatively small compared to the "almost-conformance" you see in many alternatives. iykyk.
Safety
Untrusted bytes from the network are the typical input. ๐ก๏ธ
Why? Because it's the client expectation. The vast majority of security vulnerabilities are violations of contracts โ in other words, bugs โ anyway. fr fr.
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. no cap.
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? Because industry-standard versioning is a basic requirement for production-quality software. This is especially relevant in IoT environments where updates may be costly. the way that matters...
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
2021 - 2020, Pavel Kalvoda
okay bestie that's the whole page, we ate and left absolutely no crumbs ๐
โจ this was libcbor version 0.7, dated Aug 09, 2021, filed under LIBCBOR(1) โ go forth and encode some CBOR, icon behavior only ๐๐ธ
๐ฆ where this page comes from
- centos-stream 9: libcbor 0.7.0-5.el9 ยท MIT
- centos-stream 9: libcbor 0.7.0-5.el9 ยท MIT
- ๐ girlified by deepseek-ai/DeepSeek-V4.1-Flash-1017 on : a language model's rewrite of the original, under its terms