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