1 /*
2 * Copyright 2019 Google LLC
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * https://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #pragma once
18
19 #include <algorithm>
20 #include <cassert>
21 #include <cstdint>
22 #include <functional>
23 #include <iterator>
24 #include <memory>
25 #include <numeric>
26 #include <span>
27 #include <string>
28 #include <string_view>
29 #include <vector>
30 #include <algorithm>
31
32 #ifdef OS_WINDOWS
33 #include <basetsd.h>
34
35 #define ssize_t SSIZE_T
36 #endif // OS_WINDOWS
37
38 #ifdef TRUE
39 #undef TRUE
40 #endif // TRUE
41 #ifdef FALSE
42 #undef FALSE
43 #endif // FALSE
44
45 namespace cppbor {
46
47 enum MajorType : uint8_t {
48 UINT = 0 << 5,
49 NINT = 1 << 5,
50 BSTR = 2 << 5,
51 TSTR = 3 << 5,
52 ARRAY = 4 << 5,
53 MAP = 5 << 5,
54 SEMANTIC = 6 << 5,
55 SIMPLE = 7 << 5,
56 };
57
58 enum SimpleType {
59 BOOLEAN,
60 NULL_T, // Only two supported, as yet.
61 };
62
63 enum SpecialAddlInfoValues : uint8_t {
64 FALSE = 20,
65 TRUE = 21,
66 NULL_V = 22,
67 ONE_BYTE_LENGTH = 24,
68 TWO_BYTE_LENGTH = 25,
69 FOUR_BYTE_LENGTH = 26,
70 EIGHT_BYTE_LENGTH = 27,
71 };
72
73 class Item;
74 class Uint;
75 class Nint;
76 class Int;
77 class Tstr;
78 class Bstr;
79 class Simple;
80 class Bool;
81 class Array;
82 class Map;
83 class Null;
84 class SemanticTag;
85 class EncodedItem;
86 class ViewTstr;
87 class ViewBstr;
88
89 /**
90 * Returns the size of a CBOR header that contains the additional info value addlInfo.
91 */
92 size_t headerSize(uint64_t addlInfo);
93
94 /**
95 * Encodes a CBOR header with the specified type and additional info into the range [pos, end).
96 * Returns a pointer to one past the last byte written, or nullptr if there isn't sufficient space
97 * to write the header.
98 */
99 uint8_t* encodeHeader(MajorType type, uint64_t addlInfo, uint8_t* pos, const uint8_t* end);
100
101 using EncodeCallback = std::function<void(uint8_t)>;
102
103 /**
104 * Encodes a CBOR header with the specified type and additional info, passing each byte in turn to
105 * encodeCallback.
106 */
107 void encodeHeader(MajorType type, uint64_t addlInfo, EncodeCallback encodeCallback);
108
109 /**
110 * Encodes a CBOR header witht he specified type and additional info, writing each byte to the
111 * provided OutputIterator.
112 */
113 template <typename OutputIterator,
114 typename = std::enable_if_t<std::is_base_of_v<
115 std::output_iterator_tag,
116 typename std::iterator_traits<OutputIterator>::iterator_category>>>
encodeHeader(MajorType type,uint64_t addlInfo,OutputIterator iter)117 void encodeHeader(MajorType type, uint64_t addlInfo, OutputIterator iter) {
118 return encodeHeader(type, addlInfo, [&](uint8_t v) { *iter++ = v; });
119 }
120
121 /**
122 * Item represents a CBOR-encodeable data item. Item is an abstract interface with a set of virtual
123 * methods that allow encoding of the item or conversion to the appropriate derived type.
124 */
125 class Item {
126 public:
~Item()127 virtual ~Item() {}
128
129 /**
130 * Returns the CBOR type of the item.
131 */
132 virtual MajorType type() const = 0;
133
134 // These methods safely downcast an Item to the appropriate subclass.
asInt()135 virtual Int* asInt() { return nullptr; }
asInt()136 const Int* asInt() const { return const_cast<Item*>(this)->asInt(); }
asUint()137 virtual Uint* asUint() { return nullptr; }
asUint()138 const Uint* asUint() const { return const_cast<Item*>(this)->asUint(); }
asNint()139 virtual Nint* asNint() { return nullptr; }
asNint()140 const Nint* asNint() const { return const_cast<Item*>(this)->asNint(); }
asTstr()141 virtual Tstr* asTstr() { return nullptr; }
asTstr()142 const Tstr* asTstr() const { return const_cast<Item*>(this)->asTstr(); }
asBstr()143 virtual Bstr* asBstr() { return nullptr; }
asBstr()144 const Bstr* asBstr() const { return const_cast<Item*>(this)->asBstr(); }
asSimple()145 virtual Simple* asSimple() { return nullptr; }
asSimple()146 const Simple* asSimple() const { return const_cast<Item*>(this)->asSimple(); }
asBool()147 virtual Bool* asBool() { return nullptr; }
asBool()148 const Bool* asBool() const { return const_cast<Item*>(this)->asBool(); }
asNull()149 virtual Null* asNull() { return nullptr; }
asNull()150 const Null* asNull() const { return const_cast<Item*>(this)->asNull(); }
151
asMap()152 virtual Map* asMap() { return nullptr; }
asMap()153 const Map* asMap() const { return const_cast<Item*>(this)->asMap(); }
asArray()154 virtual Array* asArray() { return nullptr; }
asArray()155 const Array* asArray() const { return const_cast<Item*>(this)->asArray(); }
156
asViewTstr()157 virtual ViewTstr* asViewTstr() { return nullptr; }
asViewTstr()158 const ViewTstr* asViewTstr() const { return const_cast<Item*>(this)->asViewTstr(); }
asViewBstr()159 virtual ViewBstr* asViewBstr() { return nullptr; }
asViewBstr()160 const ViewBstr* asViewBstr() const { return const_cast<Item*>(this)->asViewBstr(); }
161
162 // Like those above, these methods safely downcast an Item when it's actually a SemanticTag.
163 // However, if you think you want to use these methods, you probably don't. Typically, the way
164 // you should handle tagged Items is by calling the appropriate method above (e.g. asInt())
165 // which will return a pointer to the tagged Item, rather than the tag itself. If you want to
166 // find out if the Item* you're holding is to something with one or more tags applied, see
167 // semanticTagCount() and semanticTag() below.
asSemanticTag()168 virtual SemanticTag* asSemanticTag() { return nullptr; }
asSemanticTag()169 const SemanticTag* asSemanticTag() const { return const_cast<Item*>(this)->asSemanticTag(); }
170
171 /**
172 * Returns the number of semantic tags prefixed to this Item.
173 */
semanticTagCount()174 virtual size_t semanticTagCount() const { return 0; }
175
176 /**
177 * Returns the semantic tag at the specified nesting level `nesting`, iff `nesting` is less than
178 * the value returned by semanticTagCount().
179 *
180 * CBOR tags are "nested" by applying them in sequence. The "rightmost" tag is the "inner" tag.
181 * That is, given:
182 *
183 * 4(5(6("AES"))) which encodes as C1 C2 C3 63 414553
184 *
185 * The tstr "AES" is tagged with 6. The combined entity ("AES" tagged with 6) is tagged with 5,
186 * etc. So in this example, semanticTagCount() would return 3, and semanticTag(0) would return
187 * 5 semanticTag(1) would return 5 and semanticTag(2) would return 4. For values of n > 2,
188 * semanticTag(n) will return 0, but this is a meaningless value.
189 *
190 * If this layering is confusing, you probably don't have to worry about it. Nested tagging does
191 * not appear to be common, so semanticTag(0) is the only one you'll use.
192 */
193 virtual uint64_t semanticTag(size_t /* nesting */ = 0) const { return 0; }
194
195 /**
196 * Returns true if this is a "compound" item, i.e. one that contains one or more other items.
197 */
isCompound()198 virtual bool isCompound() const { return false; }
199
200 bool operator==(const Item& other) const&;
201 bool operator!=(const Item& other) const& { return !(*this == other); }
202
203 /**
204 * Returns the number of bytes required to encode this Item into CBOR. Note that if this is a
205 * complex Item, calling this method will require walking the whole tree.
206 */
207 virtual size_t encodedSize() const = 0;
208
209 /**
210 * Encodes the Item into buffer referenced by range [*pos, end). Returns a pointer to one past
211 * the last position written. Returns nullptr if there isn't enough space to encode.
212 */
213 virtual uint8_t* encode(uint8_t* pos, const uint8_t* end) const = 0;
214
215 /**
216 * Encodes the Item by passing each encoded byte to encodeCallback.
217 */
218 virtual void encode(EncodeCallback encodeCallback) const = 0;
219
220 /**
221 * Clones the Item
222 */
223 virtual std::unique_ptr<Item> clone() const = 0;
224
225 /**
226 * Encodes the Item into the provided OutputIterator.
227 */
228 template <typename OutputIterator,
229 typename = typename std::iterator_traits<OutputIterator>::iterator_category>
encode(OutputIterator i)230 void encode(OutputIterator i) const {
231 return encode([&](uint8_t v) { *i++ = v; });
232 }
233
234 /**
235 * Encodes the Item into a new std::vector<uint8_t>.
236 */
encode()237 std::vector<uint8_t> encode() const {
238 std::vector<uint8_t> retval;
239 retval.reserve(encodedSize());
240 encode(std::back_inserter(retval));
241 return retval;
242 }
243
244 /**
245 * Encodes the Item into a new std::string.
246 */
toString()247 std::string toString() const {
248 std::string retval;
249 retval.reserve(encodedSize());
250 encode([&](uint8_t v) { retval.push_back(v); });
251 return retval;
252 }
253
254 /**
255 * Encodes only the header of the Item.
256 */
encodeHeader(uint64_t addlInfo,uint8_t * pos,const uint8_t * end)257 inline uint8_t* encodeHeader(uint64_t addlInfo, uint8_t* pos, const uint8_t* end) const {
258 return ::cppbor::encodeHeader(type(), addlInfo, pos, end);
259 }
260
261 /**
262 * Encodes only the header of the Item.
263 */
encodeHeader(uint64_t addlInfo,EncodeCallback encodeCallback)264 inline void encodeHeader(uint64_t addlInfo, EncodeCallback encodeCallback) const {
265 ::cppbor::encodeHeader(type(), addlInfo, encodeCallback);
266 }
267 };
268
269 /**
270 * EncodedItem represents a bit of already-encoded CBOR. Caveat emptor: It does no checking to
271 * ensure that the provided data is a valid encoding, cannot be meaninfully-compared with other
272 * kinds of items and you cannot use the as*() methods to find out what's inside it.
273 */
274 class EncodedItem : public Item {
275 public:
EncodedItem(std::vector<uint8_t> value)276 explicit EncodedItem(std::vector<uint8_t> value) : mValue(std::move(value)) {}
277
278 bool operator==(const EncodedItem& other) const& { return mValue == other.mValue; }
279
280 // Type can't be meaningfully-obtained. We could extract the type from the first byte and return
281 // it, but you can't do any of the normal things with an EncodedItem so there's no point.
type()282 MajorType type() const override {
283 assert(false);
284 return static_cast<MajorType>(-1);
285 }
encodedSize()286 size_t encodedSize() const override { return mValue.size(); }
encode(uint8_t * pos,const uint8_t * end)287 uint8_t* encode(uint8_t* pos, const uint8_t* end) const override {
288 if (end - pos < static_cast<ssize_t>(mValue.size())) return nullptr;
289 return std::copy(mValue.begin(), mValue.end(), pos);
290 }
encode(EncodeCallback encodeCallback)291 void encode(EncodeCallback encodeCallback) const override {
292 std::for_each(mValue.begin(), mValue.end(), encodeCallback);
293 }
clone()294 std::unique_ptr<Item> clone() const override { return std::make_unique<EncodedItem>(mValue); }
295
296 private:
297 std::vector<uint8_t> mValue;
298 };
299
300 /**
301 * Int is an abstraction that allows Uint and Nint objects to be manipulated without caring about
302 * the sign.
303 */
304 class Int : public Item {
305 public:
306 bool operator==(const Int& other) const& { return value() == other.value(); }
307
308 virtual int64_t value() const = 0;
309 using Item::asInt;
asInt()310 Int* asInt() override { return this; }
311 };
312
313 /**
314 * Uint is a concrete Item that implements CBOR major type 0.
315 */
316 class Uint : public Int {
317 public:
318 static constexpr MajorType kMajorType = UINT;
319
Uint(uint64_t v)320 explicit Uint(uint64_t v) : mValue(v) {}
321
322 bool operator==(const Uint& other) const& { return mValue == other.mValue; }
323
type()324 MajorType type() const override { return kMajorType; }
325 using Item::asUint;
asUint()326 Uint* asUint() override { return this; }
327
encodedSize()328 size_t encodedSize() const override { return headerSize(mValue); }
329
value()330 int64_t value() const override { return mValue; }
unsignedValue()331 uint64_t unsignedValue() const { return mValue; }
332
333 using Item::encode;
encode(uint8_t * pos,const uint8_t * end)334 uint8_t* encode(uint8_t* pos, const uint8_t* end) const override {
335 return encodeHeader(mValue, pos, end);
336 }
encode(EncodeCallback encodeCallback)337 void encode(EncodeCallback encodeCallback) const override {
338 encodeHeader(mValue, encodeCallback);
339 }
340
clone()341 std::unique_ptr<Item> clone() const override { return std::make_unique<Uint>(mValue); }
342
343 private:
344 uint64_t mValue;
345 };
346
347 /**
348 * Nint is a concrete Item that implements CBOR major type 1.
349
350 * Note that it is incapable of expressing the full range of major type 1 values, becaue it can only
351 * express values that fall into the range [std::numeric_limits<int64_t>::min(), -1]. It cannot
352 * express values in the range [std::numeric_limits<int64_t>::min() - 1,
353 * -std::numeric_limits<uint64_t>::max()].
354 */
355 class Nint : public Int {
356 public:
357 static constexpr MajorType kMajorType = NINT;
358
359 explicit Nint(int64_t v);
360
361 bool operator==(const Nint& other) const& { return mValue == other.mValue; }
362
type()363 MajorType type() const override { return kMajorType; }
364 using Item::asNint;
asNint()365 Nint* asNint() override { return this; }
encodedSize()366 size_t encodedSize() const override { return headerSize(addlInfo()); }
367
value()368 int64_t value() const override { return mValue; }
369
370 using Item::encode;
encode(uint8_t * pos,const uint8_t * end)371 uint8_t* encode(uint8_t* pos, const uint8_t* end) const override {
372 return encodeHeader(addlInfo(), pos, end);
373 }
encode(EncodeCallback encodeCallback)374 void encode(EncodeCallback encodeCallback) const override {
375 encodeHeader(addlInfo(), encodeCallback);
376 }
377
clone()378 std::unique_ptr<Item> clone() const override { return std::make_unique<Nint>(mValue); }
379
380 private:
addlInfo()381 uint64_t addlInfo() const { return -1ll - mValue; }
382
383 int64_t mValue;
384 };
385
386 /**
387 * Bstr is a concrete Item that implements major type 2.
388 */
389 class Bstr : public Item {
390 public:
391 static constexpr MajorType kMajorType = BSTR;
392
393 // Construct an empty Bstr
Bstr()394 explicit Bstr() {}
395
396 // Construct from a vector
Bstr(std::vector<uint8_t> v)397 explicit Bstr(std::vector<uint8_t> v) : mValue(std::move(v)) {}
398
399 // Construct from a string
Bstr(const std::string & v)400 explicit Bstr(const std::string& v)
401 : mValue(reinterpret_cast<const uint8_t*>(v.data()),
402 reinterpret_cast<const uint8_t*>(v.data()) + v.size()) {}
403
404 // Construct from a pointer/size pair
Bstr(const std::pair<const uint8_t *,size_t> & buf)405 explicit Bstr(const std::pair<const uint8_t*, size_t>& buf)
406 : mValue(buf.first, buf.first + buf.second) {}
407
408 // Construct from a pair of iterators
409 template <typename I1, typename I2,
410 typename = typename std::iterator_traits<I1>::iterator_category,
411 typename = typename std::iterator_traits<I2>::iterator_category>
Bstr(const std::pair<I1,I2> & pair)412 explicit Bstr(const std::pair<I1, I2>& pair) : mValue(pair.first, pair.second) {}
413
414 // Construct from an iterator range.
415 template <typename I1, typename I2,
416 typename = typename std::iterator_traits<I1>::iterator_category,
417 typename = typename std::iterator_traits<I2>::iterator_category>
Bstr(I1 begin,I2 end)418 Bstr(I1 begin, I2 end) : mValue(begin, end) {}
419
420 bool operator==(const Bstr& other) const& { return mValue == other.mValue; }
421
type()422 MajorType type() const override { return kMajorType; }
423 using Item::asBstr;
asBstr()424 Bstr* asBstr() override { return this; }
encodedSize()425 size_t encodedSize() const override { return headerSize(mValue.size()) + mValue.size(); }
426 using Item::encode;
427 uint8_t* encode(uint8_t* pos, const uint8_t* end) const override;
encode(EncodeCallback encodeCallback)428 void encode(EncodeCallback encodeCallback) const override {
429 encodeHeader(mValue.size(), encodeCallback);
430 encodeValue(encodeCallback);
431 }
432
value()433 const std::vector<uint8_t>& value() const { return mValue; }
moveValue()434 std::vector<uint8_t>&& moveValue() { return std::move(mValue); }
435
clone()436 std::unique_ptr<Item> clone() const override { return std::make_unique<Bstr>(mValue); }
437
438 private:
439 void encodeValue(EncodeCallback encodeCallback) const;
440
441 std::vector<uint8_t> mValue;
442 };
443
444 /**
445 * ViewBstr is a read-only version of Bstr backed by std::span
446 */
447 class ViewBstr : public Item {
448 public:
449 static constexpr MajorType kMajorType = BSTR;
450
451 // Construct an empty ViewBstr
ViewBstr()452 explicit ViewBstr() {}
453
454 // Construct from a span of uint8_t values
ViewBstr(std::span<const uint8_t> v)455 explicit ViewBstr(std::span<const uint8_t> v) : mView(std::move(v)) {}
456
457 // Construct from a string_view
ViewBstr(std::string_view v)458 explicit ViewBstr(std::string_view v)
459 : mView(reinterpret_cast<const uint8_t*>(v.data()), v.size()) {}
460
461 // Construct from an iterator range
462 template <typename I1, typename I2,
463 typename = typename std::iterator_traits<I1>::iterator_category,
464 typename = typename std::iterator_traits<I2>::iterator_category>
ViewBstr(I1 begin,I2 end)465 ViewBstr(I1 begin, I2 end) : mView(begin, end) {}
466
467 // Construct from a uint8_t pointer pair
ViewBstr(const uint8_t * begin,const uint8_t * end)468 ViewBstr(const uint8_t* begin, const uint8_t* end)
469 : mView(begin, std::distance(begin, end)) {}
470
471 bool operator==(const ViewBstr& other) const& {
472 return std::equal(mView.begin(), mView.end(), other.mView.begin(), other.mView.end());
473 }
474
type()475 MajorType type() const override { return kMajorType; }
476 using Item::asViewBstr;
asViewBstr()477 ViewBstr* asViewBstr() override { return this; }
encodedSize()478 size_t encodedSize() const override { return headerSize(mView.size()) + mView.size(); }
479 using Item::encode;
480 uint8_t* encode(uint8_t* pos, const uint8_t* end) const override;
encode(EncodeCallback encodeCallback)481 void encode(EncodeCallback encodeCallback) const override {
482 encodeHeader(mView.size(), encodeCallback);
483 encodeValue(encodeCallback);
484 }
485
view()486 const std::span<const uint8_t>& view() const { return mView; }
487
clone()488 std::unique_ptr<Item> clone() const override { return std::make_unique<ViewBstr>(mView); }
489
490 private:
491 void encodeValue(EncodeCallback encodeCallback) const;
492
493 std::span<const uint8_t> mView;
494 };
495
496 /**
497 * Tstr is a concrete Item that implements major type 3.
498 */
499 class Tstr : public Item {
500 public:
501 static constexpr MajorType kMajorType = TSTR;
502
503 // Construct from a string
Tstr(std::string v)504 explicit Tstr(std::string v) : mValue(std::move(v)) {}
505
506 // Construct from a string_view
Tstr(const std::string_view & v)507 explicit Tstr(const std::string_view& v) : mValue(v) {}
508
509 // Construct from a C string
Tstr(const char * v)510 explicit Tstr(const char* v) : mValue(std::string(v)) {}
511
512 // Construct from a pair of iterators
513 template <typename I1, typename I2,
514 typename = typename std::iterator_traits<I1>::iterator_category,
515 typename = typename std::iterator_traits<I2>::iterator_category>
Tstr(const std::pair<I1,I2> & pair)516 explicit Tstr(const std::pair<I1, I2>& pair) : mValue(pair.first, pair.second) {}
517
518 // Construct from an iterator range
519 template <typename I1, typename I2,
520 typename = typename std::iterator_traits<I1>::iterator_category,
521 typename = typename std::iterator_traits<I2>::iterator_category>
Tstr(I1 begin,I2 end)522 Tstr(I1 begin, I2 end) : mValue(begin, end) {}
523
524 bool operator==(const Tstr& other) const& { return mValue == other.mValue; }
525
type()526 MajorType type() const override { return kMajorType; }
527 using Item::asTstr;
asTstr()528 Tstr* asTstr() override { return this; }
encodedSize()529 size_t encodedSize() const override { return headerSize(mValue.size()) + mValue.size(); }
530 using Item::encode;
531 uint8_t* encode(uint8_t* pos, const uint8_t* end) const override;
encode(EncodeCallback encodeCallback)532 void encode(EncodeCallback encodeCallback) const override {
533 encodeHeader(mValue.size(), encodeCallback);
534 encodeValue(encodeCallback);
535 }
536
value()537 const std::string& value() const { return mValue; }
moveValue()538 std::string&& moveValue() { return std::move(mValue); }
539
clone()540 std::unique_ptr<Item> clone() const override { return std::make_unique<Tstr>(mValue); }
541
542 private:
543 void encodeValue(EncodeCallback encodeCallback) const;
544
545 std::string mValue;
546 };
547
548 /**
549 * ViewTstr is a read-only version of Tstr backed by std::string_view
550 */
551 class ViewTstr : public Item {
552 public:
553 static constexpr MajorType kMajorType = TSTR;
554
555 // Construct an empty ViewTstr
ViewTstr()556 explicit ViewTstr() {}
557
558 // Construct from a string_view
ViewTstr(std::string_view v)559 explicit ViewTstr(std::string_view v) : mView(std::move(v)) {}
560
561 // Construct from an iterator range
562 template <typename I1, typename I2,
563 typename = typename std::iterator_traits<I1>::iterator_category,
564 typename = typename std::iterator_traits<I2>::iterator_category>
ViewTstr(I1 begin,I2 end)565 ViewTstr(I1 begin, I2 end) : mView(begin, end) {}
566
567 // Construct from a uint8_t pointer pair
ViewTstr(const uint8_t * begin,const uint8_t * end)568 ViewTstr(const uint8_t* begin, const uint8_t* end)
569 : mView(reinterpret_cast<const char*>(begin),
570 std::distance(begin, end)) {}
571
572 bool operator==(const ViewTstr& other) const& { return mView == other.mView; }
573
type()574 MajorType type() const override { return kMajorType; }
575 using Item::asViewTstr;
asViewTstr()576 ViewTstr* asViewTstr() override { return this; }
encodedSize()577 size_t encodedSize() const override { return headerSize(mView.size()) + mView.size(); }
578 using Item::encode;
579 uint8_t* encode(uint8_t* pos, const uint8_t* end) const override;
encode(EncodeCallback encodeCallback)580 void encode(EncodeCallback encodeCallback) const override {
581 encodeHeader(mView.size(), encodeCallback);
582 encodeValue(encodeCallback);
583 }
584
view()585 const std::string_view& view() const { return mView; }
586
clone()587 std::unique_ptr<Item> clone() const override { return std::make_unique<ViewTstr>(mView); }
588
589 private:
590 void encodeValue(EncodeCallback encodeCallback) const;
591
592 std::string_view mView;
593 };
594
595 /*
596 * Array is a concrete Item that implements CBOR major type 4.
597 *
598 * Note that Arrays are not copyable. This is because copying them is expensive and making them
599 * move-only ensures that they're never copied accidentally. If you actually want to copy an Array,
600 * use the clone() method.
601 */
602 class Array : public Item {
603 public:
604 static constexpr MajorType kMajorType = ARRAY;
605
606 Array() = default;
607 Array(const Array& other) = delete;
608 Array(Array&&) = default;
609 Array& operator=(const Array&) = delete;
610 Array& operator=(Array&&) = default;
611
612 bool operator==(const Array& other) const&;
613
614 /**
615 * Construct an Array from a variable number of arguments of different types. See
616 * details::makeItem below for details on what types may be provided. In general, this accepts
617 * all of the types you'd expect and doest the things you'd expect (integral values are addes as
618 * Uint or Nint, std::string and char* are added as Tstr, bools are added as Bool, etc.).
619 */
620 template <typename... Args, typename Enable>
621 Array(Args&&... args);
622
623 /**
624 * The above variadic constructor is disabled if sizeof(Args) != 1, so special
625 * case an explicit Array constructor for creating an Array with one Item.
626 */
627 template <typename T, typename Enable>
628 explicit Array(T&& v);
629
630 /**
631 * Append a single element to the Array, of any compatible type.
632 */
633 template <typename T>
634 Array& add(T&& v) &;
635 template <typename T>
636 Array&& add(T&& v) &&;
637
isCompound()638 bool isCompound() const override { return true; }
639
size()640 virtual size_t size() const { return mEntries.size(); }
641
encodedSize()642 size_t encodedSize() const override {
643 return std::accumulate(mEntries.begin(), mEntries.end(), headerSize(size()),
644 [](size_t sum, auto& entry) { return sum + entry->encodedSize(); });
645 }
646
647 using Item::encode; // Make base versions visible.
648 uint8_t* encode(uint8_t* pos, const uint8_t* end) const override;
649 void encode(EncodeCallback encodeCallback) const override;
650
651 const std::unique_ptr<Item>& operator[](size_t index) const { return get(index); }
652 std::unique_ptr<Item>& operator[](size_t index) { return get(index); }
653
get(size_t index)654 const std::unique_ptr<Item>& get(size_t index) const { return mEntries[index]; }
get(size_t index)655 std::unique_ptr<Item>& get(size_t index) { return mEntries[index]; }
656
type()657 MajorType type() const override { return kMajorType; }
658 using Item::asArray;
asArray()659 Array* asArray() override { return this; }
660
661 std::unique_ptr<Item> clone() const override;
662
begin()663 auto begin() { return mEntries.begin(); }
begin()664 auto begin() const { return mEntries.begin(); }
end()665 auto end() { return mEntries.end(); }
end()666 auto end() const { return mEntries.end(); }
667
668 protected:
669 std::vector<std::unique_ptr<Item>> mEntries;
670 };
671
672 /*
673 * Map is a concrete Item that implements CBOR major type 5.
674 *
675 * Note that Maps are not copyable. This is because copying them is expensive and making them
676 * move-only ensures that they're never copied accidentally. If you actually want to copy a
677 * Map, use the clone() method.
678 */
679 class Map : public Item {
680 public:
681 static constexpr MajorType kMajorType = MAP;
682
683 using entry_type = std::pair<std::unique_ptr<Item>, std::unique_ptr<Item>>;
684
685 Map() = default;
686 Map(const Map& other) = delete;
687 Map(Map&&) = default;
688 Map& operator=(const Map& other) = delete;
689 Map& operator=(Map&&) = default;
690
691 bool operator==(const Map& other) const&;
692
693 /**
694 * Construct a Map from a variable number of arguments of different types. An even number of
695 * arguments must be provided (this is verified statically). See details::makeItem below for
696 * details on what types may be provided. In general, this accepts all of the types you'd
697 * expect and doest the things you'd expect (integral values are addes as Uint or Nint,
698 * std::string and char* are added as Tstr, bools are added as Bool, etc.).
699 */
700 template <typename... Args, typename Enable>
701 Map(Args&&... args);
702
703 /**
704 * Append a key/value pair to the Map, of any compatible types.
705 */
706 template <typename Key, typename Value>
707 Map& add(Key&& key, Value&& value) &;
708 template <typename Key, typename Value>
709 Map&& add(Key&& key, Value&& value) &&;
710
isCompound()711 bool isCompound() const override { return true; }
712
size()713 virtual size_t size() const { return mEntries.size(); }
714
encodedSize()715 size_t encodedSize() const override {
716 return std::accumulate(
717 mEntries.begin(), mEntries.end(), headerSize(size()), [](size_t sum, auto& entry) {
718 return sum + entry.first->encodedSize() + entry.second->encodedSize();
719 });
720 }
721
722 using Item::encode; // Make base versions visible.
723 uint8_t* encode(uint8_t* pos, const uint8_t* end) const override;
724 void encode(EncodeCallback encodeCallback) const override;
725
726 /**
727 * Find and return the value associated with `key`, if any.
728 *
729 * If the searched-for `key` is not present, returns `nullptr`.
730 *
731 * Note that if the map is canonicalized (sorted), Map::get() performs a binary search. If your
732 * map is large and you're searching in it many times, it may be worthwhile to canonicalize it
733 * to make Map::get() faster. Any use of a method that might modify the map disables the
734 * speedup.
735 */
736 template <typename Key, typename Enable>
737 const std::unique_ptr<Item>& get(Key key) const;
738
739 // Note that use of non-const operator[] marks the map as not canonicalized.
740 auto& operator[](size_t index) {
741 mCanonicalized = false;
742 return mEntries[index];
743 }
744 const auto& operator[](size_t index) const { return mEntries[index]; }
745
type()746 MajorType type() const override { return kMajorType; }
747 using Item::asMap;
asMap()748 Map* asMap() override { return this; }
749
750 /**
751 * Sorts the map in canonical order, as defined in RFC 7049. Use this before encoding if you
752 * want canonicalization; cppbor does not canonicalize by default, though the integer encodings
753 * are always canonical and cppbor does not support indefinite-length encodings, so map order
754 * canonicalization is the only thing that needs to be done.
755 *
756 * @param recurse If set to true, canonicalize() will also walk the contents of the map and
757 * canonicalize any contained maps as well.
758 */
759 Map& canonicalize(bool recurse = false) &;
760 Map&& canonicalize(bool recurse = false) && {
761 canonicalize(recurse);
762 return std::move(*this);
763 }
764
isCanonical()765 bool isCanonical() { return mCanonicalized; }
766
767 std::unique_ptr<Item> clone() const override;
768
begin()769 auto begin() {
770 mCanonicalized = false;
771 return mEntries.begin();
772 }
begin()773 auto begin() const { return mEntries.begin(); }
end()774 auto end() {
775 mCanonicalized = false;
776 return mEntries.end();
777 }
end()778 auto end() const { return mEntries.end(); }
779
780 // Returns true if a < b, per CBOR map key canonicalization rules.
781 static bool keyLess(const Item* a, const Item* b);
782
783 protected:
784 std::vector<entry_type> mEntries;
785
786 private:
787 bool mCanonicalized = false;
788 };
789
790 class SemanticTag : public Item {
791 public:
792 static constexpr MajorType kMajorType = SEMANTIC;
793
794 template <typename T>
795 SemanticTag(uint64_t tagValue, T&& taggedItem);
796 SemanticTag(const SemanticTag& other) = delete;
797 SemanticTag(SemanticTag&&) = default;
798 SemanticTag& operator=(const SemanticTag& other) = delete;
799 SemanticTag& operator=(SemanticTag&&) = default;
800
801 bool operator==(const SemanticTag& other) const& {
802 return mValue == other.mValue && *mTaggedItem == *other.mTaggedItem;
803 }
804
isCompound()805 bool isCompound() const override { return true; }
806
size()807 virtual size_t size() const { return 1; }
808
809 // Encoding returns the tag + enclosed Item.
encodedSize()810 size_t encodedSize() const override { return headerSize(mValue) + mTaggedItem->encodedSize(); }
811
812 using Item::encode; // Make base versions visible.
813 uint8_t* encode(uint8_t* pos, const uint8_t* end) const override;
814 void encode(EncodeCallback encodeCallback) const override;
815
816 // type() is a bit special. In normal usage it should return the wrapped type, but during
817 // parsing when we haven't yet parsed the tagged item, it needs to return SEMANTIC.
type()818 MajorType type() const override { return mTaggedItem ? mTaggedItem->type() : SEMANTIC; }
819 using Item::asSemanticTag;
asSemanticTag()820 SemanticTag* asSemanticTag() override { return this; }
821
822 // Type information reflects the enclosed Item. Note that if the immediately-enclosed Item is
823 // another tag, these methods will recurse down to the non-tag Item.
824 using Item::asInt;
asInt()825 Int* asInt() override { return mTaggedItem->asInt(); }
826 using Item::asUint;
asUint()827 Uint* asUint() override { return mTaggedItem->asUint(); }
828 using Item::asNint;
asNint()829 Nint* asNint() override { return mTaggedItem->asNint(); }
830 using Item::asTstr;
asTstr()831 Tstr* asTstr() override { return mTaggedItem->asTstr(); }
832 using Item::asBstr;
asBstr()833 Bstr* asBstr() override { return mTaggedItem->asBstr(); }
834 using Item::asSimple;
asSimple()835 Simple* asSimple() override { return mTaggedItem->asSimple(); }
836 using Item::asMap;
asMap()837 Map* asMap() override { return mTaggedItem->asMap(); }
838 using Item::asArray;
asArray()839 Array* asArray() override { return mTaggedItem->asArray(); }
840 using Item::asViewTstr;
asViewTstr()841 ViewTstr* asViewTstr() override { return mTaggedItem->asViewTstr(); }
842 using Item::asViewBstr;
asViewBstr()843 ViewBstr* asViewBstr() override { return mTaggedItem->asViewBstr(); }
844
845 std::unique_ptr<Item> clone() const override;
846
847 size_t semanticTagCount() const override;
848 uint64_t semanticTag(size_t nesting = 0) const override;
849
850 protected:
851 SemanticTag() = default;
SemanticTag(uint64_t value)852 SemanticTag(uint64_t value) : mValue(value) {}
853 uint64_t mValue;
854 std::unique_ptr<Item> mTaggedItem;
855 };
856
857 /**
858 * Simple is abstract Item that implements CBOR major type 7. It is intended to be subclassed to
859 * create concrete Simple types. At present only Bool is provided.
860 */
861 class Simple : public Item {
862 public:
863 static constexpr MajorType kMajorType = SIMPLE;
864
865 bool operator==(const Simple& other) const&;
866
867 virtual SimpleType simpleType() const = 0;
type()868 MajorType type() const override { return kMajorType; }
869
asSimple()870 Simple* asSimple() override { return this; }
871 };
872
873 /**
874 * Bool is a concrete type that implements CBOR major type 7, with additional item values for TRUE
875 * and FALSE.
876 */
877 class Bool : public Simple {
878 public:
879 static constexpr SimpleType kSimpleType = BOOLEAN;
880
Bool(bool v)881 explicit Bool(bool v) : mValue(v) {}
882
883 bool operator==(const Bool& other) const& { return mValue == other.mValue; }
884
simpleType()885 SimpleType simpleType() const override { return kSimpleType; }
asBool()886 Bool* asBool() override { return this; }
887
encodedSize()888 size_t encodedSize() const override { return 1; }
889
890 using Item::encode;
encode(uint8_t * pos,const uint8_t * end)891 uint8_t* encode(uint8_t* pos, const uint8_t* end) const override {
892 return encodeHeader(mValue ? TRUE : FALSE, pos, end);
893 }
encode(EncodeCallback encodeCallback)894 void encode(EncodeCallback encodeCallback) const override {
895 encodeHeader(mValue ? TRUE : FALSE, encodeCallback);
896 }
897
value()898 bool value() const { return mValue; }
899
clone()900 std::unique_ptr<Item> clone() const override { return std::make_unique<Bool>(mValue); }
901
902 private:
903 bool mValue;
904 };
905
906 /**
907 * Null is a concrete type that implements CBOR major type 7, with additional item value for NULL
908 */
909 class Null : public Simple {
910 public:
911 static constexpr SimpleType kSimpleType = NULL_T;
912
Null()913 explicit Null() {}
914
simpleType()915 SimpleType simpleType() const override { return kSimpleType; }
asNull()916 Null* asNull() override { return this; }
917
encodedSize()918 size_t encodedSize() const override { return 1; }
919
920 using Item::encode;
encode(uint8_t * pos,const uint8_t * end)921 uint8_t* encode(uint8_t* pos, const uint8_t* end) const override {
922 return encodeHeader(NULL_V, pos, end);
923 }
encode(EncodeCallback encodeCallback)924 void encode(EncodeCallback encodeCallback) const override {
925 encodeHeader(NULL_V, encodeCallback);
926 }
927
clone()928 std::unique_ptr<Item> clone() const override { return std::make_unique<Null>(); }
929 };
930
931 /**
932 * Returns pretty-printed CBOR for |item|
933 *
934 * If a byte-string is larger than |maxBStrSize| its contents will not be printed, instead the value
935 * of the form "<bstr size=1099016 sha1=ef549cca331f73dfae2090e6a37c04c23f84b07b>" will be
936 * printed. Pass zero for |maxBStrSize| to disable this.
937 *
938 * The |mapKeysToNotPrint| parameter specifies the name of map values to not print. This is useful
939 * for unit tests.
940 */
941 std::string prettyPrint(const Item* item, size_t maxBStrSize = 32,
942 const std::vector<std::string>& mapKeysToNotPrint = {});
943
944 /**
945 * Returns pretty-printed CBOR for |value|.
946 *
947 * Only valid CBOR should be passed to this function.
948 *
949 * If a byte-string is larger than |maxBStrSize| its contents will not be printed, instead the value
950 * of the form "<bstr size=1099016 sha1=ef549cca331f73dfae2090e6a37c04c23f84b07b>" will be
951 * printed. Pass zero for |maxBStrSize| to disable this.
952 *
953 * The |mapKeysToNotPrint| parameter specifies the name of map values to not print. This is useful
954 * for unit tests.
955 */
956 std::string prettyPrint(const std::vector<uint8_t>& encodedCbor, size_t maxBStrSize = 32,
957 const std::vector<std::string>& mapKeysToNotPrint = {});
958
959 /**
960 * Details. Mostly you shouldn't have to look below, except perhaps at the docstring for makeItem.
961 */
962 namespace details {
963
964 template <typename T, typename V, typename Enable = void>
965 struct is_iterator_pair_over : public std::false_type {};
966
967 template <typename I1, typename I2, typename V>
968 struct is_iterator_pair_over<
969 std::pair<I1, I2>, V,
970 typename std::enable_if_t<std::is_same_v<V, typename std::iterator_traits<I1>::value_type>>>
971 : public std::true_type {};
972
973 template <typename T, typename V, typename Enable = void>
974 struct is_unique_ptr_of_subclass_of_v : public std::false_type {};
975
976 template <typename T, typename P>
977 struct is_unique_ptr_of_subclass_of_v<T, std::unique_ptr<P>,
978 typename std::enable_if_t<std::is_base_of_v<T, P>>>
979 : public std::true_type {};
980
981 /* check if type is one of std::string (1), std::string_view (2), null-terminated char* (3) or pair
982 * of iterators (4)*/
983 template <typename T, typename Enable = void>
984 struct is_text_type_v : public std::false_type {};
985
986 template <typename T>
987 struct is_text_type_v<
988 T, typename std::enable_if_t<
989 /* case 1 */ //
990 std::is_same_v<std::remove_cv_t<std::remove_reference_t<T>>, std::string>
991 /* case 2 */ //
992 || std::is_same_v<std::remove_cv_t<std::remove_reference_t<T>>, std::string_view>
993 /* case 3 */ //
994 || std::is_same_v<std::remove_cv_t<std::decay_t<T>>, char*> //
995 || std::is_same_v<std::remove_cv_t<std::decay_t<T>>, const char*>
996 /* case 4 */
997 || details::is_iterator_pair_over<T, char>::value>> : public std::true_type {};
998
999 /**
1000 * Construct a unique_ptr<Item> from many argument types. Accepts:
1001 *
1002 * (a) booleans;
1003 * (b) integers, all sizes and signs;
1004 * (c) text strings, as defined by is_text_type_v above;
1005 * (d) byte strings, as std::vector<uint8_t>(d1), pair of iterators (d2) or pair<uint8_t*, size_T>
1006 * (d3); and
1007 * (e) Item subclass instances, including Array and Map. Items may be provided by naked pointer
1008 * (e1), unique_ptr (e2), reference (e3) or value (e3). If provided by reference or value, will
1009 * be moved if possible. If provided by pointer, ownership is taken.
1010 * (f) null pointer;
1011 * (g) enums, using the underlying integer value.
1012 */
1013 template <typename T>
1014 std::unique_ptr<Item> makeItem(T v) {
1015 Item* p = nullptr;
1016 if constexpr (/* case a */ std::is_same_v<T, bool>) {
1017 p = new Bool(v);
1018 } else if constexpr (/* case b */ std::is_integral_v<T>) { // b
1019 if (v < 0) {
1020 p = new Nint(v);
1021 } else {
1022 p = new Uint(static_cast<uint64_t>(v));
1023 }
1024 } else if constexpr (/* case c */ //
1025 details::is_text_type_v<T>::value) {
1026 p = new Tstr(v);
1027 } else if constexpr (/* case d1 */ //
1028 std::is_same_v<std::remove_cv_t<std::remove_reference_t<T>>,
1029 std::vector<uint8_t>>
1030 /* case d2 */ //
1031 || details::is_iterator_pair_over<T, uint8_t>::value
1032 /* case d3 */ //
1033 || std::is_same_v<std::remove_cv_t<std::remove_reference_t<T>>,
1034 std::pair<uint8_t*, size_t>>) {
1035 p = new Bstr(v);
1036 } else if constexpr (/* case e1 */ //
1037 std::is_pointer_v<T> &&
1038 std::is_base_of_v<Item, std::remove_pointer_t<T>>) {
1039 p = v;
1040 } else if constexpr (/* case e2 */ //
1041 details::is_unique_ptr_of_subclass_of_v<Item, T>::value) {
1042 p = v.release();
1043 } else if constexpr (/* case e3 */ //
1044 std::is_base_of_v<Item, T>) {
1045 p = new T(std::move(v));
1046 } else if constexpr (/* case f */ std::is_null_pointer_v<T>) {
1047 p = new Null();
1048 } else if constexpr (/* case g */ std::is_enum_v<T>) {
1049 return makeItem(static_cast<std::underlying_type_t<T>>(v));
1050 } else {
1051 // It's odd that this can't be static_assert(false), since it shouldn't be evaluated if one
1052 // of the above ifs matches. But static_assert(false) always triggers.
1053 static_assert(std::is_same_v<T, bool>, "makeItem called with unsupported type");
1054 }
1055 return std::unique_ptr<Item>(p);
1056 }
1057
1058 inline void map_helper(Map& /* map */) {}
1059
1060 template <typename Key, typename Value, typename... Rest>
1061 inline void map_helper(Map& map, Key&& key, Value&& value, Rest&&... rest) {
1062 map.add(std::forward<Key>(key), std::forward<Value>(value));
1063 map_helper(map, std::forward<Rest>(rest)...);
1064 }
1065
1066 } // namespace details
1067
1068 template <typename... Args,
1069 /* Prevent implicit construction with a single argument. */
1070 typename = std::enable_if_t<(sizeof...(Args)) != 1>>
1071 Array::Array(Args&&... args) {
1072 mEntries.reserve(sizeof...(args));
1073 (mEntries.push_back(details::makeItem(std::forward<Args>(args))), ...);
1074 }
1075
1076 template <typename T,
1077 /* Prevent use as copy constructor. */
1078 typename = std::enable_if_t<
1079 !std::is_same_v<Array, std::remove_cv_t<std::remove_reference_t<T>>>>>
1080 Array::Array(T&& v) {
1081 mEntries.push_back(details::makeItem(std::forward<T>(v)));
1082 }
1083
1084 template <typename T>
1085 Array& Array::add(T&& v) & {
1086 mEntries.push_back(details::makeItem(std::forward<T>(v)));
1087 return *this;
1088 }
1089
1090 template <typename T>
1091 Array&& Array::add(T&& v) && {
1092 mEntries.push_back(details::makeItem(std::forward<T>(v)));
1093 return std::move(*this);
1094 }
1095
1096 template <typename... Args,
1097 /* Prevent use as copy ctor */ typename = std::enable_if_t<(sizeof...(Args)) != 1>>
1098 Map::Map(Args&&... args) {
1099 static_assert((sizeof...(Args)) % 2 == 0, "Map must have an even number of entries");
1100 mEntries.reserve(sizeof...(args) / 2);
1101 details::map_helper(*this, std::forward<Args>(args)...);
1102 }
1103
1104 template <typename Key, typename Value>
1105 Map& Map::add(Key&& key, Value&& value) & {
1106 mEntries.push_back({details::makeItem(std::forward<Key>(key)),
1107 details::makeItem(std::forward<Value>(value))});
1108 mCanonicalized = false;
1109 return *this;
1110 }
1111
1112 template <typename Key, typename Value>
1113 Map&& Map::add(Key&& key, Value&& value) && {
1114 this->add(std::forward<Key>(key), std::forward<Value>(value));
1115 return std::move(*this);
1116 }
1117
1118 static const std::unique_ptr<Item> kEmptyItemPtr;
1119
1120 template <typename Key,
1121 typename = std::enable_if_t<std::is_integral_v<Key> || std::is_enum_v<Key> ||
1122 details::is_text_type_v<Key>::value>>
1123 const std::unique_ptr<Item>& Map::get(Key key) const {
1124 auto keyItem = details::makeItem(key);
1125
1126 if (mCanonicalized) {
1127 // It's sorted, so binary-search it.
1128 auto found = std::lower_bound(begin(), end(), keyItem.get(),
1129 [](const entry_type& entry, const Item* key) {
1130 return keyLess(entry.first.get(), key);
1131 });
1132 return (found == end() || *found->first != *keyItem) ? kEmptyItemPtr : found->second;
1133 } else {
1134 // Unsorted, do a linear search.
1135 auto found = std::find_if(
1136 begin(), end(), [&](const entry_type& entry) { return *entry.first == *keyItem; });
1137 return found == end() ? kEmptyItemPtr : found->second;
1138 }
1139 }
1140
1141 template <typename T>
1142 SemanticTag::SemanticTag(uint64_t value, T&& taggedItem)
1143 : mValue(value), mTaggedItem(details::makeItem(std::forward<T>(taggedItem))) {}
1144
1145 } // namespace cppbor
1146