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