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 <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