Name Date Size #Lines LOC

..--

include/cppbor/H25-Apr-2025-1,482795

src/H25-Apr-2025-1,2631,033

tests/H25-Apr-2025-2,3171,880

.clang-formatH A D25-Apr-2025291 1413

Android.bpH A D25-Apr-20252.7 KiB133124

LICENSEH A D25-Apr-202511.1 KiB203169

METADATAH A D25-Apr-202539 43

README.mdH A D25-Apr-20259.1 KiB224182

rules.mkH A D25-Apr-20251.1 KiB3210

README.md

1LibCppBor: A Modern C++ CBOR Parser and Generator
2==============================================
3
4LibCppBor provides a natural and easy-to-use syntax for constructing and
5parsing CBOR messages.  It does not (yet) support all features of
6CBOR, nor (yet) support validation against CDDL schemata, though both
7are planned.  CBOR features that aren't supported include:
8
9* Parsing Indefinite length view-only values for major types 2 (byte string) and 3 (text string)
10* Writing Indefinite length values
11* Semantic tagging
12* Half floating point
13
14LibCppBor requires C++-17.
15
16## CBOR representation
17
18LibCppBor represents CBOR data items as instances of the `Item` class or,
19more precisely, as instances of subclasses of `Item`, since `Item` is a
20pure interface.  The subclasses of `Item` correspond almost one-to-one
21with CBOR major types, and are named to match the CDDL names to which
22they correspond.  They are:
23
24* `Uint` corresponds to major type 0, and can hold unsigned integers
25  up through (2^64 - 1).
26* `Nint` corresponds to major type 1.  It can only hold values from -1
27  to -(2^63 - 1), since it's internal representation is an int64_t.
28  This can be fixed, but it seems unlikely that applications will need
29  the omitted range from -(2^63) to (2^64 - 1), since it's
30  inconvenient to represent them in many programming languages.
31* `Int` is an abstract base of `Uint` and `Nint` that facilitates
32  working with all signed integers representable with int64_t.
33* `Bstr` corresponds to major type 2, a byte string.
34* `Tstr` corresponds to major type 3, a text string.
35* `Array` corresponds to major type 4, an Array.  It holds a
36  variable-length array of `Item`s.
37* `Map` corresponds to major type 5, a Map.  It holds a
38  variable-length array of pairs of `Item`s.
39* `Simple` corresponds to major type 7.  It's an abstract class since
40  items require more specific type.
41* `Bool` is implemented as a subclass of `Simple`.
42* `Null` is implemented as a subclass of `Simple`.
43* `Float` is implemented as a subclass of `Simple`.
44* `Double` is implemented as a subclass of `Simple`.
45
46Note that major type 6, semantic tag, is not yet implemented.
47
48In practice, users of LibCppBor will rarely use most of these classes
49when generating CBOR encodings.  This is because LibCppBor provides
50straightforward conversions from the obvious normal C++ types.
51Specifically, the following conversions are provided in appropriate
52contexts:
53
54* Signed and unsigned integers convert to `Uint` or `Nint`, as
55  appropriate.
56* `std::string`, `std::string_view`, `const char*` and
57  `std::pair<char iterator, char iterator>` convert to `Tstr`.
58* `std::vector<uint8_t>`, `std::pair<uint8_t iterator, uint8_t
59  iterator>` and `std::pair<uint8_t*, size_t>` convert to `Bstr`.
60* `bool` converts to `Bool`.
61
62## CBOR generation
63
64### Complete tree generation
65
66The set of `encode` methods in `Item` provide the interface for
67producing encoded CBOR.  The basic process for "complete tree"
68generation (as opposed to "incremental" generation, which is discussed
69below) is to construct an `Item` which models the data to be encoded,
70and then call one of the `encode` methods, whichever is convenient for
71the encoding destination.  A trivial example:
72
73```
74cppbor::Uint val(0);
75std::vector<uint8_t> encoding = val.encode();
76```
77
78    It's relatively rare that single values are encoded as above.  More often, the
79    "root" data item will be an `Array` or `Map` which contains a more complex structure.For example
80    :
81
82``` using cppbor::Map;
83using cppbor::Array;
84
85std::vector<uint8_t> vec =  // ...
86    Map val("key1", Array(Map("key_a", 99 "key_b", vec), "foo"), "key2", true);
87std::vector<uint8_t> encoding = val.encode();
88```
89
90This creates a map with two entries, with `Tstr` keys "Outer1" and
91"Outer2", respectively.  The "Outer1" entry has as its value an
92`Array` containing a `Map` and a `Tstr`.  The "Outer2" entry has a
93`Bool` value.
94
95This example demonstrates how automatic conversion of C++ types to
96LibCppBor `Item` subclass instances is done.  Where the caller provides a
97C++ or C string, a `Tstr` entry is added.  Where the caller provides
98an integer literal or variable, a `Uint` or `Nint` is added, depending
99on whether the value is positive or negative.
100
101As an alternative, a more fluent-style API is provided for building up
102structures.  For example:
103
104```
105using cppbor::Map;
106using cppbor::Array;
107
108std::vector<uint8_t> vec =  // ...
109    Map val();
110val.add("key1", Array().add(Map().add("key_a", 99).add("key_b", vec)).add("foo")).add("key2", true);
111std::vector<uint8_t> encoding = val.encode();
112```
113
114    An advantage of this interface over the constructor -
115    based creation approach above is that it need not be done all at once.
116    The `add` methods return a reference to the object added to to allow calls to be chained,
117    but chaining is not necessary; calls can be made
118    sequentially, as the data to add is available.
119
120#### `encode` methods
121
122There are several variations of `Item::encode`, all of which
123accomplish the same task but output the encoded data in different
124ways, and with somewhat different performance characteristics.  The
125provided options are:
126
127* `bool encode(uint8\_t** pos, const uint8\_t* end)` encodes into the
128  buffer referenced by the range [`*pos`, end).  `*pos` is moved.  If
129  the encoding runs out of buffer space before finishing, the method
130  returns false.  This is the most efficient way to encode, into an
131  already-allocated buffer.
132* `void encode(EncodeCallback encodeCallback)` calls `encodeCallback`
133  for each encoded byte.  It's the responsibility of the implementor
134  of the callback to behave safely in the event that the output buffer
135  (if applicable) is exhausted.  This is less efficient than the prior
136  method because it imposes an additional function call for each byte.
137* `template </*...*/> void encode(OutputIterator i)`
138  encodes into the provided iterator.  SFINAE ensures that the
139  template doesn't match for non-iterators.  The implementation
140  actually uses the callback-based method, plus has whatever overhead
141  the iterator adds.
142* `std::vector<uint8_t> encode()` creates a new std::vector, reserves
143  sufficient capacity to hold the encoding, and inserts the encoded
144  bytes with a std::pushback_iterator and the previous method.
145* `std::string toString()` does the same as the previous method, but
146  returns a string instead of a vector.
147
148### Incremental generation
149
150Incremental generation requires deeper understanding of CBOR, because
151the library can't do as much to ensure that the output is valid.  The
152basic tool for intcremental generation is the `encodeHeader`
153function.  There are two variations, one which writes into a buffer,
154and one which uses a callback.  Both simply write out the bytes of a
155header.  To construct the same map as in the above examples,
156incrementally, one might write:
157
158```
159using namespace cppbor;  // For example brevity
160
161std::vector encoding;
162auto iter = std::back_inserter(result);
163encodeHeader(MAP, 2 /* # of map entries */, iter);
164std::string s = "key1";
165encodeHeader(TSTR, s.size(), iter);
166std::copy(s.begin(), s.end(), iter);
167encodeHeader(ARRAY, 2 /* # of array entries */, iter);
168Map().add("key_a", 99).add("key_b", vec).encode(iter)
169s = "foo";
170encodeHeader(TSTR, foo.size(), iter);
171std::copy(s.begin(), s.end(), iter);
172s = "key2";
173encodeHeader(TSTR, foo.size(), iter);
174std::copy(s.begin(), s.end(), iter);
175encodeHeader(SIMPLE, TRUE, iter);
176```
177
178As the above example demonstrates, the styles can be mixed -- Note the
179creation and encoding of the inner Map using the fluent style.
180
181## Parsing
182
183LibCppBor also supports parsing of encoded CBOR data, with the same
184feature set as encoding.  There are two basic approaches to parsing,
185"full" and "stream"
186
187### Full parsing
188
189Full parsing means completely parsing a (possibly-compound) data
190item from a byte buffer.  The `parse` functions that do not take a
191`ParseClient` pointer do this.  They return a `ParseResult` which is a
192tuple of three values:
193
194* std::unique_ptr<Item> that points to the parsed item, or is nullptr
195  if there was a parse error.
196* const uint8_t* that points to the byte after the end of the decoded
197  item, or to the first unparseable byte in the event of an error.
198* std::string that is empty on success or contains an error message if
199  a parse error occurred.
200
201Assuming a successful parse, you can then use `Item::type()` to
202discover the type of the parsed item (e.g. MAP), and then use the
203appropriate `Item::as*()` method (e.g. `Item::asMap()`) to get a
204pointer to an interface which allows you to retrieve specific values.
205
206### Stream parsing
207
208Stream parsing is more complex, but more flexible.  To use
209StreamParsing, you must create your own subclass of `ParseClient` and
210call one of the `parse` functions that accepts it.  See the
211`ParseClient` methods docstrings for details.
212
213One unusual feature of stream parsing is that the `ParseClient`
214callback methods not only provide the parsed Item, but also pointers
215to the portion of the buffer that encode that Item.  This is useful
216if, for example, you want to find an element inside of a structure,
217and then copy the encoding of that sub-structure, without bothering to
218parse the rest.
219
220The full parser is implemented with the stream parser.
221
222### Disclaimer
223This is not an officially supported Google product
224