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