1
// Copyright © 2017-2020 Trust Wallet.
2
//
3
// This file is part of Trust. The full Trust copyright notice, including
4
// terms governing use, modification, and redistribution, is contained in the
5
// file LICENSE at the root of the source code distribution tree.
6

7
#pragma once
8

9
#include "Data.h"
10

11
#include <string>
12
#include <memory>
13

14
namespace TW::Cbor {
15

16
/*
17
 * CBOR (Concise Binary Object Representation) encoding and decoding.
18
 * See  http://cbor.io  and   RFC 7049 https://tools.ietf.org/html/rfc7049
19
 */
20

21
/// CBOR Encoder, and container for data being encoded.
22
/// See CborTests.cpp for usage.
23 1
class Encode {
24
public:
25
    /// Return encoded bytes
26
    TW::Data encoded() const;
27

28
    // Static state-less encoder methods:
29
    /// encode an unsigned int
30
    static Encode uint(uint64_t value);
31
    /// encode a negative int (positive is given)
32
    static Encode negInt(uint64_t value);
33
    /// encode a string
34
    static Encode string(const std::string& str);
35
    /// encode a byte array
36
    static Encode bytes(const Data& str);
37
    /// encode an array of elements (of different types)
38
    static Encode array(const std::vector<Encode>& elems);
39
    /// encode a map
40
    static Encode map(const std::vector<std::pair<Encode, Encode>>& elems);
41
    /// encode a tag and following element
42
    static Encode tag(uint64_t value, const Encode& elem);
43

44
    /// Stateful building (for indefinite length)
45
    /// Start an indefinite-length array
46
    static Encode indefArray();
47
    /// Add an element to indefinite-length array
48
    Encode addIndefArrayElem(const Encode& elem);
49
    /// Close an indefinite-length array
50
    Encode closeIndefArray();
51

52
    /// Create from raw content, must be valid CBOR data, may throw
53
    static Encode fromRaw(const TW::Data& rawData);
54

55
private:
56 1
    Encode() {}
57 1
    Encode(const TW::Data& rawData) : data(rawData) {}
58
    /// Append types + value, on variable number of bytes (1..8). Return object to support chain syntax.
59
    Encode appendValue(byte majorType, uint64_t value);
60 1
    inline Encode append(const TW::Data& data) { TW::append(this->data, data); return *this; }
61
    void appendIndefinite(byte majorType);
62

63
private:
64
    /// Encoded data is stored here, always well-formed, but my be partial.
65
    TW::Data data;
66
    /// number of currently open indefinite buildingds (0, 1, or more for nested)
67 1
    int openIndefCount = 0;
68
};
69

70
/// CBOR Decoder and container for data for decoding.  Contains reference to read-only CBOR data.
71
/// See CborTests.cpp for usage.
72 1
class Decode {
73
public:
74
    /// Constructor, create from CBOR byte stream
75
    Decode(const Data& input);
76

77
public: // decoding
78
    /// Check if contains a valid CBOR byte stream.
79
    bool isValid() const;
80
    /// Get the value of a simple type
81
    uint64_t getValue() const;
82
    /// Get the value of a string/bytes as string
83
    std::string getString() const;
84
    /// Get the value of a string/bytes as Data
85
    TW::Data getBytes() const;
86
    /// Get all elements of array
87 1
    std::vector<Decode> getArrayElements() const { return getCompoundElements(1, MT_array); }
88
    /// Get all elements of map
89
    std::vector<std::pair<Decode, Decode>> getMapElements() const;
90
    /// Get the tag number
91
    uint64_t getTagValue() const;
92
    /// Get the tag element
93
    Decode getTagElement() const;
94
    /// Dump to a JSON-like string (debugging)
95
    std::string dumpToString() const;
96 1
    uint32_t length() const { return subLen; }
97
    /// Return encoded form (useful e.g for parsed out sub-parts)
98
    Data encoded() const;
99

100
    enum MajorType {
101
        MT_uint = 0,
102
        MT_negint = 1,
103
        MT_bytes = 2,
104
        MT_string = 3,
105
        MT_array = 4,
106
        MT_map = 5,
107
        MT_tag = 6,
108
        MT_special = 7,
109
    };
110
    
111
private:
112
    /// Struct used to keep reference to original data
113 1
    struct OrigDataRef {
114
        Data origData;
115 1
        OrigDataRef(const Data& o) : origData(o) {}
116
    };
117
    Decode(const std::shared_ptr<OrigDataRef>& nData, uint32_t nSubIdx, uint32_t nSubLen);
118
    /// Skip ahead: form other Decode data with offset
119
    Decode skipClone(uint32_t offset) const;
120
    /// Get the Nth byte
121 1
    inline TW::byte getByte(uint32_t idx) const {
122 1
        if (subStart + idx >= data->origData.size()) { throw std::invalid_argument("CBOR data too short"); }
123 1
        return data->origData[subStart + idx];
124
    }
125 1
    struct TypeDesc {
126 1
        MajorType majorType = MT_uint;
127 1
        TW::byte byteCount = 0;
128 1
        uint64_t value = 0;
129 1
        bool isIndefiniteValue = false;
130
    };
131
    /// Parse out type sepcifiers
132
    TypeDesc getTypeDesc() const;
133
    uint32_t getTotalLen() const;
134
    uint32_t getCompoundLength(uint32_t countMultiplier) const;
135
    std::vector<Decode> getCompoundElements(uint32_t countMultiplier, TW::byte expectedType) const;
136
    bool isBreak() const;
137
    std::string dumpToStringInternal() const;
138

139
private:
140
    /// Reference to raw data, to the whole orginal, smart ptr
141
    std::shared_ptr<OrigDataRef> data;
142
    // Additional substring start and len, to make skip ahead possible without touching the base data pointer
143
    uint32_t subStart;
144
    uint32_t subLen;
145
};
146

147
} // namespace TW::Cbor

Read our documentation on viewing source code .

Loading