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