SkillAgentSearch skills...

QCBOR

Comprehensive, powerful, commercial-quality CBOR encoder/ decoder that is still suited for small devices.

Install / Use

/learn @laurencelundblade/QCBOR

README

QCBOR Logo

QCBOR is a powerful, commercial-quality CBOR encoder-decoder that implements these RFCs:

  • RFC8949 The CBOR Standard. (Nearly everything except sorting of encoded maps)
  • RFC7049 The previous CBOR standard. Replaced by RFC 8949.
  • RFC8742 CBOR Sequences
  • RFC8943 CBOR Dates

QCBOR v2 alpha release

Alpha releases of QCBOR 2.0 are available here. It includes:

  • Better tag handling
  • Map sorting
  • Modes for CDE and Preferred Serialization
  • dCBOR support
  • Better big number support

QCBOR Characteristics

Implemented in C with minimal dependency – Dependent only on C99, <stdint.h>, <stddef.h>, <stdbool.h> and <string.h> making it highly portable. <math.h> and <fenv.h> are used too, but their use can disabled. No #ifdefs or compiler options need to be set for QCBOR to run correctly.

Focused on C / native data representation – Careful conversion of CBOR data types in to C data types, handling over and underflow, strict typing and such so the caller doesn't have to worry so much about this and so code using QCBOR passes static analyzers easier. Simpler code because there is no support for encoding/decoding to/from JSON, pretty printing, diagnostic notation... Only encoding from native C representations and decoding to native C representations is supported.

Small simple memory model – Malloc is not needed. The encode context is 176 bytes, decode context is 312 bytes and the description of decoded data item is 56 bytes. Stack use is light and there is no recursion. The caller supplies the memory to hold the encoded CBOR and encode/decode contexts so caller has full control of memory usage making it good for embedded implementations that have to run in small fixed memory.

Easy decoding of maps – The "spiffy decode" functions allow fetching map items directly by label. Detection of duplicate map items is automatically performed. This makes decoding of complex protocols much simpler, say when compared to TinyCBOR.

Supports most of RFC 8949 – With some size limits, all data types and formats in the specification are supported. Map sorting is main CBOR feature that is not supported. The same decoding API supports both definite and indefinite-length map and array decoding. Decoding indefinite length strings is supported but requires a string allocator be set up. Encoding of indefinite length strings is planned, but not yet supported.

Extensible and general – Provides a way to handle data types that are not directly supported.

Secure coding style – Uses a construct called UsefulBuf as a discipline for very safe coding and handling of binary data.

Small code size – In the smallest configuration the object code is less than 4KB on 64-bit x86 CPUs. The design is such that object code for QCBOR APIs not used is not referenced.

Clear documented public interface – The public interface is separated from the implementation. It can be put to use without reading the source.

Comprehensive test suite – Easy to verify on a new platform or OS with the test suite. The test suite dependencies are minimal and the same as the library's.

Documentation

Full API documentation is at https://www.securitytheory.com/qcbor-docs/

Spiffy Decode

These are functions to decode particular data types. They are an alternative to and built on top of QCBORDecode_GetNext(). They do type checking and in some cases sophisticated type conversion.

Spiffy decode supports easier map and array decoding. A map can be descended into with QCBORDecode_EnterMap(). When a map has been entered, members can be retrieved by label. Detection of duplicate map labels, an error, is automatically performed.

An internal error state is maintained. This simplifies the decode implementation as an error check is only needed at the end of the decode, rather than on every function.

An outcome is that decoding implementations are simple and involve many fewer lines of code. They also tend to parallel the encoding implementations as seen in the following example.

 /* Encode */
 QCBOREncode_Init(&EncodeCtx, Buffer);
 QCBOREncode_OpenMap(&EncodeCtx);
 QCBOREncode_AddTextToMapSZ(&EncodeCtx, "Manufacturer", pE->Manufacturer);
 QCBOREncode_AddInt64ToMapSZ(&EncodeCtx, "Displacement", pE->uDisplacement);
 QCBOREncode_AddInt64ToMapSZ(&EncodeCtx, "Horsepower", pE->uHorsePower);
 QCBOREncode_CloseMap(&EncodeCtx);
 uErr = QCBOREncode_Finish(&EncodeCtx, &EncodedEngine);

 /* Decode */
 QCBORDecode_Init(&DecodeCtx, EncodedEngine, QCBOR_DECODE_MODE_NORMAL);
 QCBORDecode_EnterMap(&DecodeCtx);
 QCBORDecode_GetTextStringInMapSZ(&DecodeCtx, "Manufacturer", &(pE->Manufacturer));
 QCBORDecode_GetInt64InMapSZ(&DecodeCtx, "Displacement", &(pE->uDisplacement));
 QCBORDecode_GetInt64InMapSZ(&DecodeCtx, "Horsepower", &(pE->uHorsePower));
 QCBORDecode_ExitMap(&DecodeCtx);
 uErr = QCBORDecode_Finish(&DecodeCtx);

The spiffy decode functions will handle definite and indefinite length maps and arrays without the caller having to do anything. This includes mixed definite and indefinte maps and arrays. (Some work remains to support map searching with indefinite length strings.)

Comparison to TinyCBOR

TinyCBOR is a popular widely used implementation. Like QCBOR, it is a solid, well-maintained commercial quality implementation. This section is for folks trying to understand the difference in the approach between QCBOR and TinyCBOR.

TinyCBOR's API is more minimalist and closer to the CBOR encoding mechanics than QCBOR's. QCBOR's API is at a somewhat higher level of abstraction.

QCBOR really does implement just about everything described in RFC 8949. The main part missing is sorting of maps when encoding. TinyCBOR implements a smaller part of the standard.

No detailed code size comparison has been made, but in a spot check that encodes and decodes a single integer shows QCBOR about 25% larger. QCBOR encoding is actually smaller, but QCBOR decoding is larger. This includes the code to call the library, which is about the same for both libraries, and the code linked from the libraries. QCBOR is a bit more powerful, so you get value for the extra code brought in, especially when decoding more complex protocols.

QCBOR tracks encoding and decoding errors internally so the caller doesn't have to check the return code of every call to an encode or decode function. In many cases the error check is only needed as the last step or an encode or decode. TinyCBOR requires an error check on each call.

QCBOR provides a substantial feature that allows searching for data items in a map by label. It works for integer and text string labels (and at some point byte-string labels). This includes detection of items with duplicate labels. This makes the code for decoding CBOR simpler, similar to the encoding code and easier to read. TinyCBOR supports search by string, but no integer, nor duplicate detection.

QCBOR provides explicit support many of the registered CBOR tags. For example, QCBOR supports big numbers and decimal fractions including their conversion to floats, uint64_t and such.

Generally, QCBOR supports safe conversion of most CBOR number formats into number formats supported in C. For example, a data item can be fetched and converted to a C uint64_t whether the input CBOR is an unsigned 64-bit integer, signed 64-bit integer, floating-point number, big number, decimal fraction or a big float. The conversion is performed with full proper error detection of overflow and underflow.

QCBOR has a special feature for decoding byte-string wrapped CBOR. It treats this similar to entering an array with one item. This is particularly use for CBOR protocols like COSE that make use of byte-string wrapping. The implementation of these protocols is simpler and uses less memory.

QCBOR's test suite is written in the same portable C that QCBOR is where TinyCBOR requires Qt for its test. QCBOR's test suite is designed to be able to run on small embedded devices the same as QCBOR.

Code Status

The official current release is version 1.6.1. Changes over the last few years have been only minor bug fixes, minor feature additions and documentation improvements. QCBOR 1.x is highly stable.

Work on some larger feature additions is ongoing in "dev" branch. This includes more explicit support for preferred serialization and CDE (CBOR Deterministic Encoding). It will eventually be release as QCBOR 2.x.

QCBOR was originally developed by Qualcomm. It was open sourced through CAF with a permissive Linux license, September 2018 (thanks Qualcomm!).

Building

There is a simple makefile for the UNIX style command line binary that compiles everything to run the tests. CMake is also available, please read the "Building with CMake" section for more information.

These eleven files, the contents of the src and inc directories, make up the entire implementation.

  • inc
    • UsefulBuf.h
    • qcbor_private.h
    • qcbor_common.h
    • qcbor_encode.h
    • qcbor_decode.h
    • qcbor_spiffy_decode.h
  • src
    • UsefulBuf.c
    • qcbor_encode.c
    • qcbor_decode.c
    • ieee754.h
    • ieee754.c

For most use cases you should just be able to add them to your project. Hopefully the easy portability of this implementation makes this work straight away, whatever your development environment is.

The test directory includes the tests that are nearly as portable as the main implementation. If your development environment doesn't support UNIX style command line and make, you should be able to make a simple project an

View on GitHub
GitHub Stars226
CategoryDevelopment
Updated7d ago
Forks62

Languages

C

Security Score

85/100

Audited on Mar 20, 2026

No findings