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