text: // Copyright 2014 BitPay Inc.
  // Copyright 2015 Bitcoin Core Developers
  // Distributed under the MIT software license, see the accompanying
  // file COPYING or http://www.opensource.org/licenses/mit-license.php.
  
  #ifndef __UNIVALUE_H__
  #define __UNIVALUE_H__
  
  #include <stdint.h>
  #include <string.h>
  
  #include <string>
  #include <vector>
  #include <map>
  #include <cassert>
  
  #include <sstream>        // .get_int64()
  #include <utility>        // std::pair
  
  class UniValue {
  public:
      enum VType { VNULL, VOBJ, VARR, VSTR, VNUM, VBOOL, };
  
      UniValue() { typ = VNULL; }
      UniValue(UniValue::VType initialType, const std::string& initialStr = "") {
          typ = initialType;
          val = initialStr;
      }
      UniValue(uint64_t val_) {
          setInt(val_);
      }
      UniValue(int64_t val_) {
          setInt(val_);
      }
      UniValue(bool val_) {
          setBool(val_);
      }
      UniValue(int val_) {
          setInt(val_);
      }
      UniValue(double val_) {
          setFloat(val_);
      }
      UniValue(const std::string& val_) {
          setStr(val_);
      }
      UniValue(const char *val_) {
          std::string s(val_);
          setStr(s);
      }
      ~UniValue() {}
  
      void clear();
  
      bool setNull();
      bool setBool(bool val);
      bool setNumStr(const std::string& val);
      bool setInt(uint64_t val);
      bool setInt(int64_t val);
      bool setInt(int val_) { return setInt((int64_t)val_); }
      bool setFloat(double val);
      bool setStr(const std::string& val);
      bool setArray();
      bool setObject();
  
      enum VType getType() const { return typ; }
      const std::string& getValStr() const { return val; }
      bool empty() const { return (values.size() == 0); }
  
      size_t size() const { return values.size(); }
  
      bool getBool() const { return isTrue(); }
      void getObjMap(std::map<std::string,UniValue>& kv) const;
      bool checkObject(const std::map<std::string,UniValue::VType>& memberTypes) const;
      const UniValue& operator[](const std::string& key) const;
      const UniValue& operator[](size_t index) const;
      bool exists(const std::string& key) const { size_t i; return findKey(key, i); }
  
      bool isNull() const { return (typ == VNULL); }
      bool isTrue() const { return (typ == VBOOL) && (val == "1"); }
      bool isFalse() const { return (typ == VBOOL) && (val != "1"); }
      bool isBool() const { return (typ == VBOOL); }
      bool isStr() const { return (typ == VSTR); }
      bool isNum() const { return (typ == VNUM); }
      bool isArray() const { return (typ == VARR); }
      bool isObject() const { return (typ == VOBJ); }
  
      bool push_back(const UniValue& val);
      bool push_back(const std::string& val_) {
          UniValue tmpVal(VSTR, val_);
          return push_back(tmpVal);
      }
      bool push_back(const char *val_) {
          std::string s(val_);
          return push_back(s);
      }
      bool push_back(uint64_t val_) {
          UniValue tmpVal(val_);
          return push_back(tmpVal);
      }
      bool push_back(int64_t val_) {
          UniValue tmpVal(val_);
          return push_back(tmpVal);
      }
      bool push_back(int val_) {
          UniValue tmpVal(val_);
          return push_back(tmpVal);
      }
      bool push_back(double val_) {
          UniValue tmpVal(val_);
          return push_back(tmpVal);
      }
      bool push_backV(const std::vector<UniValue>& vec);
  
      void __pushKV(const std::string& key, const UniValue& val);
      bool pushKV(const std::string& key, const UniValue& val);
      bool pushKV(const std::string& key, const std::string& val_) {
          UniValue tmpVal(VSTR, val_);
          return pushKV(key, tmpVal);
      }
      bool pushKV(const std::string& key, const char *val_) {
          std::string _val(val_);
          return pushKV(key, _val);
      }
      bool pushKV(const std::string& key, int64_t val_) {
          UniValue tmpVal(val_);
          return pushKV(key, tmpVal);
      }
      bool pushKV(const std::string& key, uint64_t val_) {
          UniValue tmpVal(val_);
          return pushKV(key, tmpVal);
      }
      bool pushKV(const std::string& key, bool val_) {
          UniValue tmpVal((bool)val_);
          return pushKV(key, tmpVal);
      }
      bool pushKV(const std::string& key, int val_) {
          UniValue tmpVal((int64_t)val_);
          return pushKV(key, tmpVal);
      }
      bool pushKV(const std::string& key, double val_) {
          UniValue tmpVal(val_);
          return pushKV(key, tmpVal);
      }
      bool pushKVs(const UniValue& obj);
  
      std::string write(unsigned int prettyIndent = 0,
                        unsigned int indentLevel = 0) const;
  
      bool read(const char *raw, size_t len);
      bool read(const char *raw) { return read(raw, strlen(raw)); }
      bool read(const std::string& rawStr) {
          return read(rawStr.data(), rawStr.size());
      }
  
  private:
      UniValue::VType typ;
      std::string val;                       // numbers are stored as C++ strings
      std::vector<std::string> keys;
      std::vector<UniValue> values;
  
      bool findKey(const std::string& key, size_t& retIdx) const;
      void writeArray(unsigned int prettyIndent, unsigned int indentLevel, std::string& s) const;
      void writeObject(unsigned int prettyIndent, unsigned int indentLevel, std::string& s) const;
  
  public:
      // Strict type-specific getters, these throw std::runtime_error if the
      // value is of unexpected type
      const std::vector<std::string>& getKeys() const;
      const std::vector<UniValue>& getValues() const;
      bool get_bool() const;
      const std::string& get_str() const;
      int get_int() const;
      int64_t get_int64() const;
      double get_real() const;
      const UniValue& get_obj() const;
      const UniValue& get_array() const;
  
      enum VType type() const { return getType(); }
      bool push_back(std::pair<std::string,UniValue> pear) {
          return pushKV(pear.first, pear.second);
      }
      friend const UniValue& find_value( const UniValue& obj, const std::string& name);
  };
  
  //
  // The following were added for compatibility with json_spirit.
  // Most duplicate other methods, and should be removed.
  //
  static inline std::pair<std::string,UniValue> Pair(const char *cKey, const char *cVal)
  {
      std::string key(cKey);
      UniValue uVal(cVal);
      return std::make_pair(key, uVal);
  }
  
  static inline std::pair<std::string,UniValue> Pair(const char *cKey, std::string strVal)
  {
      std::string key(cKey);
      UniValue uVal(strVal);
      return std::make_pair(key, uVal);
  }
  
  static inline std::pair<std::string,UniValue> Pair(const char *cKey, uint64_t u64Val)
  {
      std::string key(cKey);
      UniValue uVal(u64Val);
      return std::make_pair(key, uVal);
  }
  
  static inline std::pair<std::string,UniValue> Pair(const char *cKey, int64_t i64Val)
  {
      std::string key(cKey);
      UniValue uVal(i64Val);
      return std::make_pair(key, uVal);
  }
  
  static inline std::pair<std::string,UniValue> Pair(const char *cKey, bool iVal)
  {
      std::string key(cKey);
      UniValue uVal(iVal);
      return std::make_pair(key, uVal);
  }
  
  static inline std::pair<std::string,UniValue> Pair(const char *cKey, int iVal)
  {
      std::string key(cKey);
      UniValue uVal(iVal);
      return std::make_pair(key, uVal);
  }
  
  static inline std::pair<std::string,UniValue> Pair(const char *cKey, double dVal)
  {
      std::string key(cKey);
      UniValue uVal(dVal);
      return std::make_pair(key, uVal);
  }
  
  static inline std::pair<std::string,UniValue> Pair(const char *cKey, const UniValue& uVal)
  {
      std::string key(cKey);
      return std::make_pair(key, uVal);
  }
  
  static inline std::pair<std::string,UniValue> Pair(std::string key, const UniValue& uVal)
  {
      return std::make_pair(key, uVal);
  }
  
  enum jtokentype {
      JTOK_ERR        = -1,
      JTOK_NONE       = 0,                           // eof
      JTOK_OBJ_OPEN,
      JTOK_OBJ_CLOSE,
      JTOK_ARR_OPEN,
      JTOK_ARR_CLOSE,
      JTOK_COLON,
      JTOK_COMMA,
      JTOK_KW_NULL,
      JTOK_KW_TRUE,
      JTOK_KW_FALSE,
      JTOK_NUMBER,
      JTOK_STRING,
  };
  
  extern enum jtokentype getJsonToken(std::string& tokenVal,
                                      unsigned int& consumed, const char *raw, const char *end);
  extern const char *uvTypeName(UniValue::VType t);
  
  static inline bool jsonTokenIsValue(enum jtokentype jtt)
  {
      switch (jtt) {
      case JTOK_KW_NULL:
      case JTOK_KW_TRUE:
      case JTOK_KW_FALSE:
      case JTOK_NUMBER:
      case JTOK_STRING:
          return true;
  
      default:
          return false;
      }
  
      // not reached
  }
  
  static inline bool json_isspace(int ch)
  {
      switch (ch) {
      case 0x20:
      case 0x09:
      case 0x0a:
      case 0x0d:
          return true;
  
      default:
          return false;
      }
  
      // not reached
  }
  
  extern const UniValue NullUniValue;
  
  const UniValue& find_value( const UniValue& obj, const std::string& name);
  
  /**
   * Verifies whether a given string consists only of valid UTF-8 code points
   * as per the JSONUTF8StringFilter.
   *
   * This method is exposed for Xaya to validate names.
   */
  bool IsValidUtf8String(const std::string& str);
  
  #endif // __UNIVALUE_H__
  