1
// Copyright 2014 BitPay Inc.
2
// Copyright 2015 Bitcoin Core Developers
3
// Distributed under the MIT software license, see the accompanying
4
// file COPYING or https://opensource.org/licenses/mit-license.php.
5

            
6
#ifndef BITCOIN_UNIVALUE_INCLUDE_UNIVALUE_H
7
#define BITCOIN_UNIVALUE_INCLUDE_UNIVALUE_H
8

            
9
#include <charconv>
10
#include <cstdint>
11
#include <cstring>
12
#include <map>
13
#include <stdexcept>
14
#include <string>
15
#include <type_traits>
16
#include <vector>
17

            
18
class UniValue {
19
public:
20
    enum VType { VNULL, VOBJ, VARR, VSTR, VNUM, VBOOL, };
21

            
22
1
    UniValue() { typ = VNULL; }
23
    UniValue(UniValue::VType initialType, const std::string& initialStr = "") {
24
        typ = initialType;
25
        val = initialStr;
26
    }
27
    UniValue(uint64_t val_) {
28
        setInt(val_);
29
    }
30
    UniValue(int64_t val_) {
31
        setInt(val_);
32
    }
33
    UniValue(bool val_) {
34
        setBool(val_);
35
    }
36
    UniValue(int val_) {
37
        setInt(val_);
38
    }
39
    UniValue(double val_) {
40
        setFloat(val_);
41
    }
42
    UniValue(const std::string& val_) {
43
        setStr(val_);
44
    }
45
    UniValue(const char *val_) {
46
        std::string s(val_);
47
        setStr(s);
48
    }
49

            
50
    void clear();
51

            
52
    bool setNull();
53
    bool setBool(bool val);
54
    bool setNumStr(const std::string& val);
55
    bool setInt(uint64_t val);
56
    bool setInt(int64_t val);
57
    bool setInt(int val_) { return setInt((int64_t)val_); }
58
    bool setFloat(double val);
59
    bool setStr(const std::string& val);
60
    bool setArray();
61
    bool setObject();
62

            
63
    enum VType getType() const { return typ; }
64
    const std::string& getValStr() const { return val; }
65
    bool empty() const { return (values.size() == 0); }
66

            
67
    size_t size() const { return values.size(); }
68

            
69
    bool getBool() const { return isTrue(); }
70
    void getObjMap(std::map<std::string,UniValue>& kv) const;
71
    bool checkObject(const std::map<std::string,UniValue::VType>& memberTypes) const;
72
    const UniValue& operator[](const std::string& key) const;
73
    const UniValue& operator[](size_t index) const;
74
    bool exists(const std::string& key) const { size_t i; return findKey(key, i); }
75

            
76
    bool isNull() const { return (typ == VNULL); }
77
    bool isTrue() const { return (typ == VBOOL) && (val == "1"); }
78
    bool isFalse() const { return (typ == VBOOL) && (val != "1"); }
79
    bool isBool() const { return (typ == VBOOL); }
80
    bool isStr() const { return (typ == VSTR); }
81
    bool isNum() const { return (typ == VNUM); }
82
    bool isArray() const { return (typ == VARR); }
83
    bool isObject() const { return (typ == VOBJ); }
84

            
85
    bool push_back(const UniValue& val);
86
    bool push_backV(const std::vector<UniValue>& vec);
87

            
88
    void __pushKV(const std::string& key, const UniValue& val);
89
    bool pushKV(const std::string& key, const UniValue& val);
90
    bool pushKVs(const UniValue& obj);
91

            
92
    std::string write(unsigned int prettyIndent = 0,
93
                      unsigned int indentLevel = 0) const;
94

            
95
    bool read(const char *raw, size_t len);
96
    bool read(const char *raw) { return read(raw, strlen(raw)); }
97
    bool read(const std::string& rawStr) {
98
        return read(rawStr.data(), rawStr.size());
99
    }
100

            
101
private:
102
    UniValue::VType typ;
103
    std::string val;                       // numbers are stored as C++ strings
104
    std::vector<std::string> keys;
105
    std::vector<UniValue> values;
106

            
107
    bool findKey(const std::string& key, size_t& retIdx) const;
108
    void writeArray(unsigned int prettyIndent, unsigned int indentLevel, std::string& s) const;
109
    void writeObject(unsigned int prettyIndent, unsigned int indentLevel, std::string& s) const;
110

            
111
public:
112
    // Strict type-specific getters, these throw std::runtime_error if the
113
    // value is of unexpected type
114
    const std::vector<std::string>& getKeys() const;
115
    const std::vector<UniValue>& getValues() const;
116
    template <typename Int>
117
    auto getInt() const
118
    {
119
        static_assert(std::is_integral<Int>::value);
120
        if (typ != VNUM) {
121
            throw std::runtime_error("JSON value is not an integer as expected");
122
        }
123
        Int result;
124
        const auto [first_nonmatching, error_condition] = std::from_chars(val.data(), val.data() + val.size(), result);
125
        if (first_nonmatching != val.data() + val.size() || error_condition != std::errc{}) {
126
            throw std::runtime_error("JSON integer out of range");
127
        }
128
        return result;
129
    }
130
    bool get_bool() const;
131
    const std::string& get_str() const;
132
    double get_real() const;
133
    const UniValue& get_obj() const;
134
    const UniValue& get_array() const;
135

            
136
    enum VType type() const { return getType(); }
137
    friend const UniValue& find_value( const UniValue& obj, const std::string& name);
138
};
139

            
140
enum jtokentype {
141
    JTOK_ERR        = -1,
142
    JTOK_NONE       = 0,                           // eof
143
    JTOK_OBJ_OPEN,
144
    JTOK_OBJ_CLOSE,
145
    JTOK_ARR_OPEN,
146
    JTOK_ARR_CLOSE,
147
    JTOK_COLON,
148
    JTOK_COMMA,
149
    JTOK_KW_NULL,
150
    JTOK_KW_TRUE,
151
    JTOK_KW_FALSE,
152
    JTOK_NUMBER,
153
    JTOK_STRING,
154
};
155

            
156
extern enum jtokentype getJsonToken(std::string& tokenVal,
157
                                    unsigned int& consumed, const char *raw, const char *end);
158
extern const char *uvTypeName(UniValue::VType t);
159

            
160
static inline bool jsonTokenIsValue(enum jtokentype jtt)
161
{
162
    switch (jtt) {
163
    case JTOK_KW_NULL:
164
    case JTOK_KW_TRUE:
165
    case JTOK_KW_FALSE:
166
    case JTOK_NUMBER:
167
    case JTOK_STRING:
168
        return true;
169

            
170
    default:
171
        return false;
172
    }
173

            
174
    // not reached
175
}
176

            
177
static inline bool json_isspace(int ch)
178
{
179
    switch (ch) {
180
    case 0x20:
181
    case 0x09:
182
    case 0x0a:
183
    case 0x0d:
184
        return true;
185

            
186
    default:
187
        return false;
188
    }
189

            
190
    // not reached
191
}
192

            
193
extern const UniValue NullUniValue;
194

            
195
const UniValue& find_value( const UniValue& obj, const std::string& name);
196

            
197
#endif // BITCOIN_UNIVALUE_INCLUDE_UNIVALUE_H