Line data Source code
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 <string_view>
16 : #include <type_traits>
17 : #include <vector>
18 :
19 297062 : class UniValue {
20 : public:
21 : enum VType { VNULL, VOBJ, VARR, VSTR, VNUM, VBOOL, };
22 :
23 : class type_error : public std::runtime_error
24 : {
25 : using std::runtime_error::runtime_error;
26 : };
27 :
28 1357354 : UniValue() { typ = VNULL; }
29 48784 : UniValue(UniValue::VType type, std::string str = {}) : typ{type}, val{std::move(str)} {}
30 : template <typename Ref, typename T = std::remove_cv_t<std::remove_reference_t<Ref>>,
31 : std::enable_if_t<std::is_floating_point_v<T> || // setFloat
32 : std::is_same_v<bool, T> || // setBool
33 : std::is_signed_v<T> || std::is_unsigned_v<T> || // setInt
34 : std::is_constructible_v<std::string, T>, // setStr
35 : bool> = true>
36 552926 : UniValue(Ref&& val)
37 276463 : {
38 : if constexpr (std::is_floating_point_v<T>) {
39 96 : setFloat(val);
40 : } else if constexpr (std::is_same_v<bool, T>) {
41 98202 : setBool(val);
42 : } else if constexpr (std::is_signed_v<T>) {
43 2961 : setInt(int64_t{val});
44 : } else if constexpr (std::is_unsigned_v<T>) {
45 259 : setInt(uint64_t{val});
46 : } else {
47 174945 : setStr(std::string{std::forward<Ref>(val)});
48 : }
49 552926 : }
50 :
51 : void clear();
52 :
53 : void setNull();
54 : void setBool(bool val);
55 : void setNumStr(std::string str);
56 : void setInt(uint64_t val);
57 : void setInt(int64_t val);
58 4 : void setInt(int val_) { return setInt(int64_t{val_}); }
59 : void setFloat(double val);
60 : void setStr(std::string str);
61 : void setArray();
62 : void setObject();
63 :
64 37098 : enum VType getType() const { return typ; }
65 97283 : const std::string& getValStr() const { return val; }
66 37 : bool empty() const { return (values.size() == 0); }
67 :
68 13679 : size_t size() const { return values.size(); }
69 :
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 67 : bool exists(const std::string& key) const { size_t i; return findKey(key, i); }
75 :
76 625575 : bool isNull() const { return (typ == VNULL); }
77 71455 : bool isTrue() const { return (typ == VBOOL) && (val == "1"); }
78 817805 : bool isFalse() const { return (typ == VBOOL) && (val != "1"); }
79 4810 : bool isBool() const { return (typ == VBOOL); }
80 461 : bool isStr() const { return (typ == VSTR); }
81 23980 : bool isNum() const { return (typ == VNUM); }
82 50822 : bool isArray() const { return (typ == VARR); }
83 178 : bool isObject() const { return (typ == VOBJ); }
84 :
85 : void push_back(UniValue val);
86 : void push_backV(const std::vector<UniValue>& vec);
87 : template <class It>
88 : void push_backV(It first, It last);
89 :
90 : void __pushKV(std::string key, UniValue val);
91 : void pushKV(std::string key, UniValue val);
92 : void pushKVs(UniValue obj);
93 :
94 : std::string write(unsigned int prettyIndent = 0,
95 : unsigned int indentLevel = 0) const;
96 :
97 : bool read(const char *raw, size_t len);
98 32 : bool read(const char *raw) { return read(raw, strlen(raw)); }
99 239 : bool read(std::string_view raw) { return read(raw.data(), raw.size()); }
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 : void checkType(const VType& expected) const;
108 : bool findKey(const std::string& key, size_t& retIdx) const;
109 : void writeArray(unsigned int prettyIndent, unsigned int indentLevel, std::string& s) const;
110 : void writeObject(unsigned int prettyIndent, unsigned int indentLevel, std::string& s) const;
111 :
112 : public:
113 : // Strict type-specific getters, these throw std::runtime_error if the
114 : // value is of unexpected type
115 : const std::vector<std::string>& getKeys() const;
116 : const std::vector<UniValue>& getValues() const;
117 : template <typename Int>
118 : Int getInt() const;
119 : bool get_bool() const;
120 : const std::string& get_str() const;
121 : double get_real() const;
122 : const UniValue& get_obj() const;
123 : const UniValue& get_array() const;
124 :
125 29 : enum VType type() const { return getType(); }
126 : const UniValue& find_value(std::string_view key) const;
127 : };
128 :
129 : template <class It>
130 0 : void UniValue::push_backV(It first, It last)
131 : {
132 0 : checkType(VARR);
133 0 : values.insert(values.end(), first, last);
134 0 : }
135 :
136 : template <typename Int>
137 1316 : Int UniValue::getInt() const
138 : {
139 : static_assert(std::is_integral<Int>::value);
140 1316 : checkType(VNUM);
141 : Int result;
142 1316 : const auto [first_nonmatching, error_condition] = std::from_chars(val.data(), val.data() + val.size(), result);
143 1316 : if (first_nonmatching != val.data() + val.size() || error_condition != std::errc{}) {
144 4 : throw std::runtime_error("JSON integer out of range");
145 : }
146 1312 : return result;
147 0 : }
148 :
149 : enum jtokentype {
150 : JTOK_ERR = -1,
151 : JTOK_NONE = 0, // eof
152 : JTOK_OBJ_OPEN,
153 : JTOK_OBJ_CLOSE,
154 : JTOK_ARR_OPEN,
155 : JTOK_ARR_CLOSE,
156 : JTOK_COLON,
157 : JTOK_COMMA,
158 : JTOK_KW_NULL,
159 : JTOK_KW_TRUE,
160 : JTOK_KW_FALSE,
161 : JTOK_NUMBER,
162 : JTOK_STRING,
163 : };
164 :
165 : extern enum jtokentype getJsonToken(std::string& tokenVal,
166 : unsigned int& consumed, const char *raw, const char *end);
167 : extern const char *uvTypeName(UniValue::VType t);
168 :
169 46651 : static inline bool jsonTokenIsValue(enum jtokentype jtt)
170 : {
171 46651 : switch (jtt) {
172 : case JTOK_KW_NULL:
173 : case JTOK_KW_TRUE:
174 : case JTOK_KW_FALSE:
175 : case JTOK_NUMBER:
176 : case JTOK_STRING:
177 18070 : return true;
178 :
179 : default:
180 28581 : return false;
181 : }
182 :
183 : // not reached
184 46651 : }
185 :
186 85134 : static inline bool json_isspace(int ch)
187 : {
188 85134 : switch (ch) {
189 : case 0x20:
190 : case 0x09:
191 : case 0x0a:
192 : case 0x0d:
193 35040 : return true;
194 :
195 : default:
196 50094 : return false;
197 : }
198 :
199 : // not reached
200 85134 : }
201 :
202 : extern const UniValue NullUniValue;
203 :
204 : #endif // BITCOIN_UNIVALUE_INCLUDE_UNIVALUE_H
|