Branch data 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 <cstddef>
11 : : #include <cstdint>
12 : : #include <map>
13 : : #include <stdexcept>
14 : : #include <string>
15 : : #include <string_view>
16 : : #include <system_error>
17 : : #include <type_traits>
18 : : #include <utility>
19 : : #include <vector>
20 : :
21 [ - + ]: 143 : class UniValue {
22 : : public:
23 : : enum VType { VNULL, VOBJ, VARR, VSTR, VNUM, VBOOL, };
24 : :
25 : 0 : class type_error : public std::runtime_error
26 : : {
27 : 0 : using std::runtime_error::runtime_error;
28 : : };
29 : :
30 : 8824 : UniValue() { typ = VNULL; }
31 : 2 : UniValue(UniValue::VType type, std::string str = {}) : typ{type}, val{std::move(str)} {}
32 : : template <typename Ref, typename T = std::remove_cv_t<std::remove_reference_t<Ref>>,
33 : : std::enable_if_t<std::is_floating_point_v<T> || // setFloat
34 : : std::is_same_v<bool, T> || // setBool
35 : : std::is_signed_v<T> || std::is_unsigned_v<T> || // setInt
36 : : std::is_constructible_v<std::string, T>, // setStr
37 : : bool> = true>
38 : 117 : UniValue(Ref&& val)
39 : : {
40 : : if constexpr (std::is_floating_point_v<T>) {
41 [ + - ][ # # ]: 2 : setFloat(val);
42 : : } else if constexpr (std::is_same_v<bool, T>) {
43 [ + - ][ # # ]: 47 : setBool(val);
[ # # ]
44 : : } else if constexpr (std::is_signed_v<T>) {
45 [ # # ][ + - ]: 30 : setInt(int64_t{val});
[ # # ][ # # ]
[ # # ][ # # ]
46 : : } else if constexpr (std::is_unsigned_v<T>) {
47 [ # # ][ # # ]: 4 : setInt(uint64_t{val});
[ # # ][ + - ]
[ # # ]
48 : : } else {
49 [ + - ][ + + ]: 34 : setStr(std::string{std::forward<Ref>(val)});
[ - + ][ + - ]
[ - + ][ # # ]
[ # # ][ + - ]
[ - + ][ # # ]
[ + - ][ - + ]
[ + - ][ - + ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
50 : : }
51 : 117 : }
52 : :
53 : : void clear();
54 : :
55 : : void setNull();
56 : : void setBool(bool val);
57 : : void setNumStr(std::string str);
58 : : void setInt(uint64_t val);
59 : : void setInt(int64_t val);
60 : : void setInt(int val_) { return setInt(int64_t{val_}); }
61 : : void setFloat(double val);
62 : : void setStr(std::string str);
63 : : void setArray();
64 : : void setObject();
65 : :
66 : 88 : enum VType getType() const { return typ; }
67 : 11 : const std::string& getValStr() const { return val; }
68 : 0 : bool empty() const { return (values.size() == 0); }
69 : :
70 : 0 : size_t size() const { return values.size(); }
71 : :
72 : : void getObjMap(std::map<std::string,UniValue>& kv) const;
73 : : bool checkObject(const std::map<std::string,UniValue::VType>& memberTypes) const;
74 : : const UniValue& operator[](const std::string& key) const;
75 : : const UniValue& operator[](size_t index) const;
76 : 0 : bool exists(const std::string& key) const { size_t i; return findKey(key, i); }
77 : :
78 : 8814 : bool isNull() const { return (typ == VNULL); }
79 [ + - ]: 7 : bool isTrue() const { return (typ == VBOOL) && (val == "1"); }
80 [ + + ]: 59 : bool isFalse() const { return (typ == VBOOL) && (val != "1"); }
81 : 4 : bool isBool() const { return (typ == VBOOL); }
82 : 0 : bool isStr() const { return (typ == VSTR); }
83 : 4 : bool isNum() const { return (typ == VNUM); }
84 : 3 : bool isArray() const { return (typ == VARR); }
85 : 0 : bool isObject() const { return (typ == VOBJ); }
86 : :
87 : : void push_back(UniValue val);
88 : : void push_backV(const std::vector<UniValue>& vec);
89 : : template <class It>
90 : : void push_backV(It first, It last);
91 : :
92 : : void pushKVEnd(std::string key, UniValue val);
93 : : void pushKV(std::string key, UniValue val);
94 : : void pushKVs(UniValue obj);
95 : :
96 : : std::string write(unsigned int prettyIndent = 0,
97 : : unsigned int indentLevel = 0) const;
98 : :
99 : : bool read(std::string_view raw);
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 : 0 : 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 : 0 : Int UniValue::getInt() const
138 : : {
139 : : static_assert(std::is_integral<Int>::value);
140 : 0 : checkType(VNUM);
141 : : Int result;
142 : 0 : const auto [first_nonmatching, error_condition] = std::from_chars(val.data(), val.data() + val.size(), result);
143 [ # # ][ # # ]: 0 : if (first_nonmatching != val.data() + val.size() || error_condition != std::errc{}) {
[ # # ]
144 [ # # ][ # # ]: 0 : throw std::runtime_error("JSON integer out of range");
[ # # ]
145 : : }
146 : 0 : 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 : 0 : static inline bool jsonTokenIsValue(enum jtokentype jtt)
170 : : {
171 [ # # ]: 0 : 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 : 0 : return true;
178 : :
179 : : default:
180 : 0 : return false;
181 : : }
182 : :
183 : : // not reached
184 : 0 : }
185 : :
186 : 36 : static inline bool json_isspace(int ch)
187 : : {
188 [ + - ]: 36 : switch (ch) {
189 : : case 0x20:
190 : : case 0x09:
191 : : case 0x0a:
192 : : case 0x0d:
193 : 0 : return true;
194 : :
195 : : default:
196 : 36 : return false;
197 : : }
198 : :
199 : : // not reached
200 : 36 : }
201 : :
202 : : extern const UniValue NullUniValue;
203 : :
204 : : #endif // BITCOIN_UNIVALUE_INCLUDE_UNIVALUE_H
|