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