univalue.cpp raw
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 #include <univalue.h>
7
8 #include <iomanip>
9 #include <map>
10 #include <sstream>
11 #include <string>
12 #include <utility>
13 #include <vector>
14
15 const UniValue NullUniValue;
16
17 void UniValue::clear()
18 {
19 typ = VNULL;
20 val.clear();
21 keys.clear();
22 values.clear();
23 }
24
25 void UniValue::setNull()
26 {
27 clear();
28 }
29
30 void UniValue::setBool(bool val_)
31 {
32 clear();
33 typ = VBOOL;
34 if (val_)
35 val = "1";
36 }
37
38 static bool validNumStr(const std::string& s)
39 {
40 std::string tokenVal;
41 unsigned int consumed;
42 enum jtokentype tt = getJsonToken(tokenVal, consumed, s.data(), s.data() + s.size());
43 return (tt == JTOK_NUMBER);
44 }
45
46 void UniValue::setNumStr(std::string str)
47 {
48 if (!validNumStr(str)) {
49 throw std::runtime_error{"The string '" + str + "' is not a valid JSON number"};
50 }
51
52 clear();
53 typ = VNUM;
54 val = std::move(str);
55 }
56
57 void UniValue::setInt(uint64_t val_)
58 {
59 std::ostringstream oss;
60
61 oss << val_;
62
63 return setNumStr(oss.str());
64 }
65
66 void UniValue::setInt(int64_t val_)
67 {
68 std::ostringstream oss;
69
70 oss << val_;
71
72 return setNumStr(oss.str());
73 }
74
75 void UniValue::setFloat(double val_)
76 {
77 std::ostringstream oss;
78
79 oss << std::setprecision(16) << val_;
80
81 return setNumStr(oss.str());
82 }
83
84 void UniValue::setStr(std::string str)
85 {
86 clear();
87 typ = VSTR;
88 val = std::move(str);
89 }
90
91 void UniValue::setArray()
92 {
93 clear();
94 typ = VARR;
95 }
96
97 void UniValue::setObject()
98 {
99 clear();
100 typ = VOBJ;
101 }
102
103 void UniValue::push_back(UniValue val)
104 {
105 checkType(VARR);
106
107 values.push_back(std::move(val));
108 }
109
110 void UniValue::push_backV(const std::vector<UniValue>& vec)
111 {
112 checkType(VARR);
113
114 values.insert(values.end(), vec.begin(), vec.end());
115 }
116
117 void UniValue::pushKVEnd(std::string key, UniValue val)
118 {
119 checkType(VOBJ);
120
121 keys.push_back(std::move(key));
122 values.push_back(std::move(val));
123 }
124
125 void UniValue::pushKV(std::string key, UniValue val)
126 {
127 checkType(VOBJ);
128
129 size_t idx;
130 if (findKey(key, idx))
131 values[idx] = std::move(val);
132 else
133 pushKVEnd(std::move(key), std::move(val));
134 }
135
136 void UniValue::pushKVs(UniValue obj)
137 {
138 checkType(VOBJ);
139 obj.checkType(VOBJ);
140
141 for (size_t i = 0; i < obj.keys.size(); i++)
142 pushKVEnd(std::move(obj.keys.at(i)), std::move(obj.values.at(i)));
143 }
144
145 void UniValue::getObjMap(std::map<std::string,UniValue>& kv) const
146 {
147 if (typ != VOBJ)
148 return;
149
150 kv.clear();
151 for (size_t i = 0; i < keys.size(); i++)
152 kv[keys[i]] = values[i];
153 }
154
155 bool UniValue::findKey(const std::string& key, size_t& retIdx) const
156 {
157 for (size_t i = 0; i < keys.size(); i++) {
158 if (keys[i] == key) {
159 retIdx = i;
160 return true;
161 }
162 }
163
164 return false;
165 }
166
167 bool UniValue::checkObject(const std::map<std::string,UniValue::VType>& t) const
168 {
169 if (typ != VOBJ) {
170 return false;
171 }
172
173 for (const auto& object: t) {
174 size_t idx = 0;
175 if (!findKey(object.first, idx)) {
176 return false;
177 }
178
179 if (values.at(idx).getType() != object.second) {
180 return false;
181 }
182 }
183
184 return true;
185 }
186
187 const UniValue& UniValue::operator[](const std::string& key) const
188 {
189 if (typ != VOBJ)
190 return NullUniValue;
191
192 size_t index = 0;
193 if (!findKey(key, index))
194 return NullUniValue;
195
196 return values.at(index);
197 }
198
199 const UniValue& UniValue::operator[](size_t index) const
200 {
201 if (typ != VOBJ && typ != VARR)
202 return NullUniValue;
203 if (index >= values.size())
204 return NullUniValue;
205
206 return values.at(index);
207 }
208
209 void UniValue::checkType(const VType& expected) const
210 {
211 if (typ != expected) {
212 throw type_error{"JSON value of type " + std::string{uvTypeName(typ)} + " is not of expected type " +
213 std::string{uvTypeName(expected)}};
214 }
215 }
216
217 const char *uvTypeName(UniValue::VType t)
218 {
219 switch (t) {
220 case UniValue::VNULL: return "null";
221 case UniValue::VBOOL: return "bool";
222 case UniValue::VOBJ: return "object";
223 case UniValue::VARR: return "array";
224 case UniValue::VSTR: return "string";
225 case UniValue::VNUM: return "number";
226 }
227
228 // not reached
229 return nullptr;
230 }
231
232 const UniValue& UniValue::find_value(std::string_view key) const
233 {
234 for (unsigned int i = 0; i < keys.size(); ++i) {
235 if (keys[i] == key) {
236 return values.at(i);
237 }
238 }
239 return NullUniValue;
240 }
241
242 void UniValue::reserve(size_t new_cap)
243 {
244 values.reserve(new_cap);
245 if (typ == VOBJ) {
246 keys.reserve(new_cap);
247 }
248 }
249