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