univalue.cpp raw

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