univalue.cpp
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 }