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