• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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