From 0917306fdf39b12556b95fe91be2e7b44d34bb9f Mon Sep 17 00:00:00 2001 From: Jonas Schnelli Date: Fri, 4 Sep 2015 16:59:04 +0200 Subject: [PATCH 1/4] remove univalue, prepare for subtree --- src/univalue/gen.cpp | 77 ------- src/univalue/univalue.cpp | 303 ------------------------- src/univalue/univalue.h | 248 -------------------- src/univalue/univalue_escapes.h | 262 --------------------- src/univalue/univalue_read.cpp | 389 -------------------------------- src/univalue/univalue_write.cpp | 127 ----------- 6 files changed, 1406 deletions(-) delete mode 100644 src/univalue/gen.cpp delete mode 100644 src/univalue/univalue.cpp delete mode 100644 src/univalue/univalue.h delete mode 100644 src/univalue/univalue_escapes.h delete mode 100644 src/univalue/univalue_read.cpp delete mode 100644 src/univalue/univalue_write.cpp diff --git a/src/univalue/gen.cpp b/src/univalue/gen.cpp deleted file mode 100644 index 5e5a4d4ae..000000000 --- a/src/univalue/gen.cpp +++ /dev/null @@ -1,77 +0,0 @@ -// Copyright 2014 BitPay Inc. -// Distributed under the MIT software license, see the accompanying -// file COPYING or http://www.opensource.org/licenses/mit-license.php. - -// -// To re-create univalue_escapes.h: -// $ g++ -o gen gen.cpp -// $ ./gen > univalue_escapes.h -// - -#include -#include -#include -#include "univalue.h" - -using namespace std; - -static bool initEscapes; -static const char *escapes[256]; - -static void initJsonEscape() -{ - escapes[(int)'"'] = "\\\""; - escapes[(int)'\\'] = "\\\\"; - escapes[(int)'\b'] = "\\b"; - escapes[(int)'\f'] = "\\f"; - escapes[(int)'\n'] = "\\n"; - escapes[(int)'\r'] = "\\r"; - escapes[(int)'\t'] = "\\t"; - - initEscapes = true; -} - -static void outputEscape() -{ - printf( "// Automatically generated file. Do not modify.\n" - "#ifndef BITCOIN_UNIVALUE_UNIVALUE_ESCAPES_H\n" - "#define BITCOIN_UNIVALUE_UNIVALUE_ESCAPES_H\n" - "static const char *escapes[256] = {\n"); - - for (unsigned int i = 0; i < 256; i++) { - if (!escapes[i]) { - printf("\tNULL,\n"); - } else { - printf("\t\""); - - unsigned int si; - for (si = 0; si < strlen(escapes[i]); si++) { - char ch = escapes[i][si]; - switch (ch) { - case '"': - printf("\\\""); - break; - case '\\': - printf("\\\\"); - break; - default: - printf("%c", escapes[i][si]); - break; - } - } - - printf("\",\n"); - } - } - - printf( "};\n" - "#endif // BITCOIN_UNIVALUE_UNIVALUE_ESCAPES_H\n"); -} - -int main (int argc, char *argv[]) -{ - initJsonEscape(); - outputEscape(); - return 0; -} - diff --git a/src/univalue/univalue.cpp b/src/univalue/univalue.cpp deleted file mode 100644 index 1d49a2cfc..000000000 --- a/src/univalue/univalue.cpp +++ /dev/null @@ -1,303 +0,0 @@ -// Copyright 2014 BitPay Inc. -// Distributed under the MIT software license, see the accompanying -// file COPYING or http://www.opensource.org/licenses/mit-license.php. - -#include -#include -#include -#include -#include // std::runtime_error - -#include "univalue.h" - -#include "utilstrencodings.h" // ParseXX - -using namespace std; - -const UniValue NullUniValue; - -void UniValue::clear() -{ - typ = VNULL; - val.clear(); - keys.clear(); - values.clear(); -} - -bool UniValue::setNull() -{ - clear(); - return true; -} - -bool UniValue::setBool(bool val_) -{ - clear(); - typ = VBOOL; - if (val_) - val = "1"; - return true; -} - -static bool validNumStr(const string& s) -{ - string tokenVal; - unsigned int consumed; - enum jtokentype tt = getJsonToken(tokenVal, consumed, s.c_str()); - return (tt == JTOK_NUMBER); -} - -bool UniValue::setNumStr(const string& val_) -{ - if (!validNumStr(val_)) - return false; - - clear(); - typ = VNUM; - val = val_; - return true; -} - -bool UniValue::setInt(uint64_t val) -{ - string s; - ostringstream oss; - - oss << val; - - return setNumStr(oss.str()); -} - -bool UniValue::setInt(int64_t val) -{ - string s; - ostringstream oss; - - oss << val; - - return setNumStr(oss.str()); -} - -bool UniValue::setFloat(double val) -{ - string s; - ostringstream oss; - - oss << std::setprecision(16) << val; - - bool ret = setNumStr(oss.str()); - typ = VNUM; - return ret; -} - -bool UniValue::setStr(const string& val_) -{ - clear(); - typ = VSTR; - val = val_; - return true; -} - -bool UniValue::setArray() -{ - clear(); - typ = VARR; - return true; -} - -bool UniValue::setObject() -{ - clear(); - typ = VOBJ; - return true; -} - -bool UniValue::push_back(const UniValue& val) -{ - if (typ != VARR) - return false; - - values.push_back(val); - return true; -} - -bool UniValue::push_backV(const std::vector& vec) -{ - if (typ != VARR) - return false; - - values.insert(values.end(), vec.begin(), vec.end()); - - return true; -} - -bool UniValue::pushKV(const std::string& key, const UniValue& val) -{ - if (typ != VOBJ) - return false; - - keys.push_back(key); - values.push_back(val); - return true; -} - -bool UniValue::pushKVs(const UniValue& obj) -{ - if (typ != VOBJ || obj.typ != VOBJ) - return false; - - for (unsigned int i = 0; i < obj.keys.size(); i++) { - keys.push_back(obj.keys[i]); - values.push_back(obj.values[i]); - } - - return true; -} - -int UniValue::findKey(const std::string& key) const -{ - for (unsigned int i = 0; i < keys.size(); i++) { - if (keys[i] == key) - return (int) i; - } - - return -1; -} - -bool UniValue::checkObject(const std::map& t) -{ - for (std::map::const_iterator it = t.begin(); - it != t.end(); it++) { - int idx = findKey(it->first); - if (idx < 0) - return false; - - if (values[idx].getType() != it->second) - return false; - } - - return true; -} - -const UniValue& UniValue::operator[](const std::string& key) const -{ - if (typ != VOBJ) - return NullUniValue; - - int index = findKey(key); - if (index < 0) - return NullUniValue; - - return values[index]; -} - -const UniValue& UniValue::operator[](unsigned int index) const -{ - if (typ != VOBJ && typ != VARR) - return NullUniValue; - if (index >= values.size()) - return NullUniValue; - - return values[index]; -} - -const char *uvTypeName(UniValue::VType t) -{ - switch (t) { - case UniValue::VNULL: return "null"; - case UniValue::VBOOL: return "bool"; - case UniValue::VOBJ: return "object"; - case UniValue::VARR: return "array"; - case UniValue::VSTR: return "string"; - case UniValue::VNUM: return "number"; - } - - // not reached - return NULL; -} - -const UniValue& find_value( const UniValue& obj, const std::string& name) -{ - for (unsigned int i = 0; i < obj.keys.size(); i++) - { - if( obj.keys[i] == name ) - { - return obj.values[i]; - } - } - - return NullUniValue; -} - -std::vector UniValue::getKeys() const -{ - if (typ != VOBJ) - throw std::runtime_error("JSON value is not an object as expected"); - return keys; -} - -std::vector UniValue::getValues() const -{ - if (typ != VOBJ && typ != VARR) - throw std::runtime_error("JSON value is not an object or array as expected"); - return values; -} - -bool UniValue::get_bool() const -{ - if (typ != VBOOL) - throw std::runtime_error("JSON value is not a boolean as expected"); - return getBool(); -} - -std::string UniValue::get_str() const -{ - if (typ != VSTR) - throw std::runtime_error("JSON value is not a string as expected"); - return getValStr(); -} - -int UniValue::get_int() const -{ - if (typ != VNUM) - throw std::runtime_error("JSON value is not an integer as expected"); - int32_t retval; - if (!ParseInt32(getValStr(), &retval)) - throw std::runtime_error("JSON integer out of range"); - return retval; -} - -int64_t UniValue::get_int64() const -{ - if (typ != VNUM) - throw std::runtime_error("JSON value is not an integer as expected"); - int64_t retval; - if (!ParseInt64(getValStr(), &retval)) - throw std::runtime_error("JSON integer out of range"); - return retval; -} - -double UniValue::get_real() const -{ - if (typ != VNUM) - throw std::runtime_error("JSON value is not a number as expected"); - double retval; - if (!ParseDouble(getValStr(), &retval)) - throw std::runtime_error("JSON double out of range"); - return retval; -} - -const UniValue& UniValue::get_obj() const -{ - if (typ != VOBJ) - throw std::runtime_error("JSON value is not an object as expected"); - return *this; -} - -const UniValue& UniValue::get_array() const -{ - if (typ != VARR) - throw std::runtime_error("JSON value is not an array as expected"); - return *this; -} - diff --git a/src/univalue/univalue.h b/src/univalue/univalue.h deleted file mode 100644 index 4742b56f3..000000000 --- a/src/univalue/univalue.h +++ /dev/null @@ -1,248 +0,0 @@ -// Copyright 2014 BitPay Inc. -// Distributed under the MIT software license, see the accompanying -// file COPYING or http://www.opensource.org/licenses/mit-license.php. - -#ifndef BITCOIN_UNIVALUE_UNIVALUE_H -#define BITCOIN_UNIVALUE_UNIVALUE_H - -#include -#include -#include -#include -#include - -#include // .get_int64() -#include // 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(); } - bool checkObject(const std::map& memberTypes); - const UniValue& operator[](const std::string& key) const; - const UniValue& operator[](unsigned int index) const; - bool exists(const std::string& key) const { return (findKey(key) >= 0); } - - 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_backV(const std::vector& vec); - - 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, 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); - bool read(const std::string& rawStr) { - return read(rawStr.c_str()); - } - -private: - UniValue::VType typ; - std::string val; // numbers are stored as C++ strings - std::vector keys; - std::vector values; - - int findKey(const std::string& key) 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 - std::vector getKeys() const; - std::vector getValues() const; - bool get_bool() 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 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 Pair(const char *cKey, const char *cVal) -{ - std::string key(cKey); - UniValue uVal(cVal); - return std::make_pair(key, uVal); -} - -static inline std::pair Pair(const char *cKey, std::string strVal) -{ - std::string key(cKey); - UniValue uVal(strVal); - return std::make_pair(key, uVal); -} - -static inline std::pair Pair(const char *cKey, uint64_t u64Val) -{ - std::string key(cKey); - UniValue uVal(u64Val); - return std::make_pair(key, uVal); -} - -static inline std::pair Pair(const char *cKey, int64_t i64Val) -{ - std::string key(cKey); - UniValue uVal(i64Val); - return std::make_pair(key, uVal); -} - -static inline std::pair Pair(const char *cKey, bool iVal) -{ - std::string key(cKey); - UniValue uVal(iVal); - return std::make_pair(key, uVal); -} - -static inline std::pair Pair(const char *cKey, int iVal) -{ - std::string key(cKey); - UniValue uVal(iVal); - return std::make_pair(key, uVal); -} - -static inline std::pair Pair(const char *cKey, double dVal) -{ - std::string key(cKey); - UniValue uVal(dVal); - return std::make_pair(key, uVal); -} - -static inline std::pair Pair(const char *cKey, const UniValue& uVal) -{ - std::string key(cKey); - return std::make_pair(key, uVal); -} - -static inline std::pair 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); -extern const char *uvTypeName(UniValue::VType t); - -extern const UniValue NullUniValue; - -const UniValue& find_value( const UniValue& obj, const std::string& name); - -#endif // BITCOIN_UNIVALUE_UNIVALUE_H diff --git a/src/univalue/univalue_escapes.h b/src/univalue/univalue_escapes.h deleted file mode 100644 index 4133b24ca..000000000 --- a/src/univalue/univalue_escapes.h +++ /dev/null @@ -1,262 +0,0 @@ -// Automatically generated file. Do not modify. -#ifndef BITCOIN_UNIVALUE_UNIVALUE_ESCAPES_H -#define BITCOIN_UNIVALUE_UNIVALUE_ESCAPES_H -static const char *escapes[256] = { - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - "\\b", - "\\t", - "\\n", - NULL, - "\\f", - "\\r", - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - "\\\"", - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - "\\\\", - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, -}; -#endif // BITCOIN_UNIVALUE_UNIVALUE_ESCAPES_H diff --git a/src/univalue/univalue_read.cpp b/src/univalue/univalue_read.cpp deleted file mode 100644 index 64591234c..000000000 --- a/src/univalue/univalue_read.cpp +++ /dev/null @@ -1,389 +0,0 @@ -// Copyright 2014 BitPay Inc. -// Distributed under the MIT software license, see the accompanying -// file COPYING or http://www.opensource.org/licenses/mit-license.php. - -#include -#include -#include -#include "univalue.h" - -using namespace std; - -// convert hexadecimal string to unsigned integer -static const char *hatoui(const char *first, const char *last, - unsigned int& out) -{ - unsigned int result = 0; - for (; first != last; ++first) - { - int digit; - if (isdigit(*first)) - digit = *first - '0'; - - else if (*first >= 'a' && *first <= 'f') - digit = *first - 'a' + 10; - - else if (*first >= 'A' && *first <= 'F') - digit = *first - 'A' + 10; - - else - break; - - result = 16 * result + digit; - } - out = result; - - return first; -} - -enum jtokentype getJsonToken(string& tokenVal, unsigned int& consumed, - const char *raw) -{ - tokenVal.clear(); - consumed = 0; - - const char *rawStart = raw; - - while ((*raw) && (isspace(*raw))) // skip whitespace - raw++; - - switch (*raw) { - - case 0: - return JTOK_NONE; - - case '{': - raw++; - consumed = (raw - rawStart); - return JTOK_OBJ_OPEN; - case '}': - raw++; - consumed = (raw - rawStart); - return JTOK_OBJ_CLOSE; - case '[': - raw++; - consumed = (raw - rawStart); - return JTOK_ARR_OPEN; - case ']': - raw++; - consumed = (raw - rawStart); - return JTOK_ARR_CLOSE; - - case ':': - raw++; - consumed = (raw - rawStart); - return JTOK_COLON; - case ',': - raw++; - consumed = (raw - rawStart); - return JTOK_COMMA; - - case 'n': - case 't': - case 'f': - if (!strncmp(raw, "null", 4)) { - raw += 4; - consumed = (raw - rawStart); - return JTOK_KW_NULL; - } else if (!strncmp(raw, "true", 4)) { - raw += 4; - consumed = (raw - rawStart); - return JTOK_KW_TRUE; - } else if (!strncmp(raw, "false", 5)) { - raw += 5; - consumed = (raw - rawStart); - return JTOK_KW_FALSE; - } else - return JTOK_ERR; - - case '-': - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': { - // part 1: int - string numStr; - - const char *first = raw; - - const char *firstDigit = first; - if (!isdigit(*firstDigit)) - firstDigit++; - if ((*firstDigit == '0') && isdigit(firstDigit[1])) - return JTOK_ERR; - - numStr += *raw; // copy first char - raw++; - - if ((*first == '-') && (!isdigit(*raw))) - return JTOK_ERR; - - while ((*raw) && isdigit(*raw)) { // copy digits - numStr += *raw; - raw++; - } - - // part 2: frac - if (*raw == '.') { - numStr += *raw; // copy . - raw++; - - if (!isdigit(*raw)) - return JTOK_ERR; - while ((*raw) && isdigit(*raw)) { // copy digits - numStr += *raw; - raw++; - } - } - - // part 3: exp - if (*raw == 'e' || *raw == 'E') { - numStr += *raw; // copy E - raw++; - - if (*raw == '-' || *raw == '+') { // copy +/- - numStr += *raw; - raw++; - } - - if (!isdigit(*raw)) - return JTOK_ERR; - while ((*raw) && isdigit(*raw)) { // copy digits - numStr += *raw; - raw++; - } - } - - tokenVal = numStr; - consumed = (raw - rawStart); - return JTOK_NUMBER; - } - - case '"': { - raw++; // skip " - - string valStr; - - while (*raw) { - if (*raw < 0x20) - return JTOK_ERR; - - else if (*raw == '\\') { - raw++; // skip backslash - - switch (*raw) { - case '"': valStr += "\""; break; - case '\\': valStr += "\\"; break; - case '/': valStr += "/"; break; - case 'b': valStr += "\b"; break; - case 'f': valStr += "\f"; break; - case 'n': valStr += "\n"; break; - case 'r': valStr += "\r"; break; - case 't': valStr += "\t"; break; - - case 'u': { - unsigned int codepoint; - if (hatoui(raw + 1, raw + 1 + 4, codepoint) != - raw + 1 + 4) - return JTOK_ERR; - - if (codepoint <= 0x7f) - valStr.push_back((char)codepoint); - else if (codepoint <= 0x7FF) { - valStr.push_back((char)(0xC0 | (codepoint >> 6))); - valStr.push_back((char)(0x80 | (codepoint & 0x3F))); - } else if (codepoint <= 0xFFFF) { - valStr.push_back((char)(0xE0 | (codepoint >> 12))); - valStr.push_back((char)(0x80 | ((codepoint >> 6) & 0x3F))); - valStr.push_back((char)(0x80 | (codepoint & 0x3F))); - } - - raw += 4; - break; - } - default: - return JTOK_ERR; - - } - - raw++; // skip esc'd char - } - - else if (*raw == '"') { - raw++; // skip " - break; // stop scanning - } - - else { - valStr += *raw; - raw++; - } - } - - tokenVal = valStr; - consumed = (raw - rawStart); - return JTOK_STRING; - } - - default: - return JTOK_ERR; - } -} - -bool UniValue::read(const char *raw) -{ - clear(); - - bool expectName = false; - bool expectColon = false; - vector stack; - - string tokenVal; - unsigned int consumed; - enum jtokentype tok = JTOK_NONE; - enum jtokentype last_tok = JTOK_NONE; - do { - last_tok = tok; - - tok = getJsonToken(tokenVal, consumed, raw); - if (tok == JTOK_NONE || tok == JTOK_ERR) - return false; - raw += consumed; - - switch (tok) { - - case JTOK_OBJ_OPEN: - case JTOK_ARR_OPEN: { - VType utyp = (tok == JTOK_OBJ_OPEN ? VOBJ : VARR); - if (!stack.size()) { - if (utyp == VOBJ) - setObject(); - else - setArray(); - stack.push_back(this); - } else { - UniValue tmpVal(utyp); - UniValue *top = stack.back(); - top->values.push_back(tmpVal); - - UniValue *newTop = &(top->values.back()); - stack.push_back(newTop); - } - - if (utyp == VOBJ) - expectName = true; - break; - } - - case JTOK_OBJ_CLOSE: - case JTOK_ARR_CLOSE: { - if (!stack.size() || expectColon || (last_tok == JTOK_COMMA)) - return false; - - VType utyp = (tok == JTOK_OBJ_CLOSE ? VOBJ : VARR); - UniValue *top = stack.back(); - if (utyp != top->getType()) - return false; - - stack.pop_back(); - expectName = false; - break; - } - - case JTOK_COLON: { - if (!stack.size() || expectName || !expectColon) - return false; - - UniValue *top = stack.back(); - if (top->getType() != VOBJ) - return false; - - expectColon = false; - break; - } - - case JTOK_COMMA: { - if (!stack.size() || expectName || expectColon || - (last_tok == JTOK_COMMA) || (last_tok == JTOK_ARR_OPEN)) - return false; - - UniValue *top = stack.back(); - if (top->getType() == VOBJ) - expectName = true; - break; - } - - case JTOK_KW_NULL: - case JTOK_KW_TRUE: - case JTOK_KW_FALSE: { - if (!stack.size() || expectName || expectColon) - return false; - - UniValue tmpVal; - switch (tok) { - case JTOK_KW_NULL: - // do nothing more - break; - case JTOK_KW_TRUE: - tmpVal.setBool(true); - break; - case JTOK_KW_FALSE: - tmpVal.setBool(false); - break; - default: /* impossible */ break; - } - - UniValue *top = stack.back(); - top->values.push_back(tmpVal); - - break; - } - - case JTOK_NUMBER: { - if (!stack.size() || expectName || expectColon) - return false; - - UniValue tmpVal(VNUM, tokenVal); - UniValue *top = stack.back(); - top->values.push_back(tmpVal); - - break; - } - - case JTOK_STRING: { - if (!stack.size()) - return false; - - UniValue *top = stack.back(); - - if (expectName) { - top->keys.push_back(tokenVal); - expectName = false; - expectColon = true; - } else { - UniValue tmpVal(VSTR, tokenVal); - top->values.push_back(tmpVal); - } - - break; - } - - default: - return false; - } - } while (!stack.empty ()); - - /* Check that nothing follows the initial construct (parsed above). */ - tok = getJsonToken(tokenVal, consumed, raw); - if (tok != JTOK_NONE) - return false; - - return true; -} - diff --git a/src/univalue/univalue_write.cpp b/src/univalue/univalue_write.cpp deleted file mode 100644 index bce3997af..000000000 --- a/src/univalue/univalue_write.cpp +++ /dev/null @@ -1,127 +0,0 @@ -// Copyright 2014 BitPay Inc. -// Distributed under the MIT software license, see the accompanying -// file COPYING or http://www.opensource.org/licenses/mit-license.php. - -#include -#include -#include -#include -#include "univalue.h" -#include "univalue_escapes.h" - -// TODO: Using UTF8 - -using namespace std; - -static string json_escape(const string& inS) -{ - string outS; - outS.reserve(inS.size() * 2); - - for (unsigned int i = 0; i < inS.size(); i++) { - unsigned char ch = inS[i]; - const char *escStr = escapes[ch]; - - if (escStr) - outS += escStr; - - else if (isprint(ch)) - outS += ch; - - else { - char tmpesc[16]; - sprintf(tmpesc, "\\u%04x", ch); - outS += tmpesc; - } - } - - return outS; -} - -string UniValue::write(unsigned int prettyIndent, - unsigned int indentLevel) const -{ - string s; - s.reserve(1024); - - unsigned int modIndent = indentLevel; - if (modIndent == 0) - modIndent = 1; - - switch (typ) { - case VNULL: - s += "null"; - break; - case VOBJ: - writeObject(prettyIndent, modIndent, s); - break; - case VARR: - writeArray(prettyIndent, modIndent, s); - break; - case VSTR: - s += "\"" + json_escape(val) + "\""; - break; - case VNUM: - s += val; - break; - case VBOOL: - s += (val == "1" ? "true" : "false"); - break; - } - - return s; -} - -static void indentStr(unsigned int prettyIndent, unsigned int indentLevel, string& s) -{ - s.append(prettyIndent * indentLevel, ' '); -} - -void UniValue::writeArray(unsigned int prettyIndent, unsigned int indentLevel, string& s) const -{ - s += "["; - if (prettyIndent) - s += "\n"; - - for (unsigned int i = 0; i < values.size(); i++) { - if (prettyIndent) - indentStr(prettyIndent, indentLevel, s); - s += values[i].write(prettyIndent, indentLevel + 1); - if (i != (values.size() - 1)) { - s += ","; - if (prettyIndent) - s += " "; - } - if (prettyIndent) - s += "\n"; - } - - if (prettyIndent) - indentStr(prettyIndent, indentLevel - 1, s); - s += "]"; -} - -void UniValue::writeObject(unsigned int prettyIndent, unsigned int indentLevel, string& s) const -{ - s += "{"; - if (prettyIndent) - s += "\n"; - - for (unsigned int i = 0; i < keys.size(); i++) { - if (prettyIndent) - indentStr(prettyIndent, indentLevel, s); - s += "\"" + json_escape(keys[i]) + "\":"; - if (prettyIndent) - s += " "; - s += values[i].write(prettyIndent, indentLevel + 1); - if (i != (values.size() - 1)) - s += ","; - if (prettyIndent) - s += "\n"; - } - - if (prettyIndent) - indentStr(prettyIndent, indentLevel - 1, s); - s += "}"; -} - From 2f9f082b5ef3c495c70598ef23383effef675f9a Mon Sep 17 00:00:00 2001 From: Jonas Schnelli Date: Thu, 1 Oct 2015 10:37:19 +0200 Subject: [PATCH 2/4] Squashed 'src/univalue/' content from commit 87d9045 git-subtree-dir: src/univalue git-subtree-split: 87d90455ff5e87dedc304353aa23ace47ffb6c1c --- .gitignore | 22 ++ .travis.yml | 52 +++++ COPYING | 19 ++ Makefile.am | 84 +++++++ README | 7 + TODO | 10 + autogen.sh | 9 + build-aux/m4/.empty | 0 configure.ac | 69 ++++++ gen/gen.cpp | 77 ++++++ include/univalue.h | 250 ++++++++++++++++++++ lib/.gitignore | 10 + lib/univalue.cpp | 365 +++++++++++++++++++++++++++++ lib/univalue_escapes.h | 262 +++++++++++++++++++++ lib/univalue_read.cpp | 389 +++++++++++++++++++++++++++++++ lib/univalue_write.cpp | 127 ++++++++++ pc/libunivalue-uninstalled.pc.in | 9 + pc/libunivalue.pc.in | 10 + test/.gitignore | 7 + test/fail1.json | 1 + test/fail10.json | 1 + test/fail11.json | 1 + test/fail12.json | 1 + test/fail13.json | 1 + test/fail14.json | 1 + test/fail15.json | 1 + test/fail16.json | 1 + test/fail17.json | 1 + test/fail18.json | 1 + test/fail19.json | 1 + test/fail2.json | 1 + test/fail20.json | 1 + test/fail21.json | 1 + test/fail22.json | 1 + test/fail23.json | 1 + test/fail24.json | 1 + test/fail25.json | 1 + test/fail26.json | 1 + test/fail27.json | 2 + test/fail28.json | 2 + test/fail29.json | 1 + test/fail3.json | 1 + test/fail30.json | 1 + test/fail31.json | 1 + test/fail32.json | 1 + test/fail33.json | 1 + test/fail34.json | 1 + test/fail4.json | 1 + test/fail5.json | 1 + test/fail6.json | 1 + test/fail7.json | 1 + test/fail8.json | 1 + test/fail9.json | 1 + test/pass1.json | 58 +++++ test/pass2.json | 1 + test/pass3.json | 6 + test/unitester.cpp | 115 +++++++++ 57 files changed, 1994 insertions(+) create mode 100644 .gitignore create mode 100644 .travis.yml create mode 100644 COPYING create mode 100644 Makefile.am create mode 100644 README create mode 100644 TODO create mode 100755 autogen.sh create mode 100644 build-aux/m4/.empty create mode 100644 configure.ac create mode 100644 gen/gen.cpp create mode 100644 include/univalue.h create mode 100644 lib/.gitignore create mode 100644 lib/univalue.cpp create mode 100644 lib/univalue_escapes.h create mode 100644 lib/univalue_read.cpp create mode 100644 lib/univalue_write.cpp create mode 100644 pc/libunivalue-uninstalled.pc.in create mode 100644 pc/libunivalue.pc.in create mode 100644 test/.gitignore create mode 100644 test/fail1.json create mode 100644 test/fail10.json create mode 100644 test/fail11.json create mode 100644 test/fail12.json create mode 100644 test/fail13.json create mode 100644 test/fail14.json create mode 100644 test/fail15.json create mode 100644 test/fail16.json create mode 100644 test/fail17.json create mode 100644 test/fail18.json create mode 100644 test/fail19.json create mode 100644 test/fail2.json create mode 100644 test/fail20.json create mode 100644 test/fail21.json create mode 100644 test/fail22.json create mode 100644 test/fail23.json create mode 100644 test/fail24.json create mode 100644 test/fail25.json create mode 100644 test/fail26.json create mode 100644 test/fail27.json create mode 100644 test/fail28.json create mode 100644 test/fail29.json create mode 100644 test/fail3.json create mode 100644 test/fail30.json create mode 100644 test/fail31.json create mode 100644 test/fail32.json create mode 100644 test/fail33.json create mode 100644 test/fail34.json create mode 100644 test/fail4.json create mode 100644 test/fail5.json create mode 100644 test/fail6.json create mode 100644 test/fail7.json create mode 100644 test/fail8.json create mode 100644 test/fail9.json create mode 100644 test/pass1.json create mode 100644 test/pass2.json create mode 100644 test/pass3.json create mode 100644 test/unitester.cpp diff --git a/.gitignore b/.gitignore new file mode 100644 index 000000000..ca9e84234 --- /dev/null +++ b/.gitignore @@ -0,0 +1,22 @@ +.deps/ +INSTALL +Makefile +Makefile.in +aclocal.m4 +autom4te.cache/ +compile +config.log +config.status +config.guess +config.sub +configure +depcomp +install-sh +missing +stamp-h1 +univalue-config.h* +test-driver +libtool +ltmain.sh + +*.o diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 000000000..af632c78d --- /dev/null +++ b/.travis.yml @@ -0,0 +1,52 @@ + +language: cpp + +compiler: + - clang + - gcc + +os: + - linux + - osx + +sudo: false + +env: + global: + - MAKEJOBS=-j3 + - RUN_TESTS=true + - BASE_OUTDIR=$TRAVIS_BUILD_DIR/out + +cache: + apt: true + +addons: + apt: + packages: + - pkg-config + +before_script: + - if [ -n "$USE_SHELL" ]; then export CONFIG_SHELL="$USE_SHELL"; fi + - test -n "$USE_SHELL" && eval '"$USE_SHELL" -c "./autogen.sh"' || ./autogen.sh + +script: + - if [ -n "$UNIVALUE_CONFIG" ]; then unset CC; unset CXX; fi + - OUTDIR=$BASE_OUTDIR/$TRAVIS_PULL_REQUEST/$TRAVIS_JOB_NUMBER-$HOST + - UNIVALUE_CONFIG_ALL="--prefix=$TRAVIS_BUILD_DIR/depends/$HOST --bindir=$OUTDIR/bin --libdir=$OUTDIR/lib" + - ./configure --cache-file=config.cache $UNIVALUE_CONFIG_ALL $UNIVALUE_CONFIG || ( cat config.log && false) + - make -s $MAKEJOBS $GOAL || ( echo "Build failure. Verbose build follows." && make $GOAL ; false ) + - export LD_LIBRARY_PATH=$TRAVIS_BUILD_DIR/depends/$HOST/lib + - if [ "$RUN_TESTS" = "true" ]; then make check; fi + +matrix: + fast_finish: true + include: + - os: linux + compiler: gcc + env: UNIVALUE_CONFIG=--host=x86_64-w64-mingw32 RUN_TESTS=false + addons: + apt: + packages: + - g++-mingw-w64-x86-64 + - gcc-mingw-w64-x86-64 + - binutils-mingw-w64-x86-64 diff --git a/COPYING b/COPYING new file mode 100644 index 000000000..1fb429f35 --- /dev/null +++ b/COPYING @@ -0,0 +1,19 @@ + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + diff --git a/Makefile.am b/Makefile.am new file mode 100644 index 000000000..2800f466d --- /dev/null +++ b/Makefile.am @@ -0,0 +1,84 @@ +ACLOCAL_AMFLAGS = -I build-aux/m4 +.PHONY: gen +.INTERMEDIATE: $(GENBIN) + +include_HEADERS = include/univalue.h +noinst_HEADERS = lib/univalue_escapes.h + +lib_LTLIBRARIES = lib/libunivalue.la + +pkgconfigdir = $(libdir)/pkgconfig +pkgconfig_DATA = pc/libunivalue.pc + +lib_libunivalue_la_SOURCES = \ + lib/univalue.cpp \ + lib/univalue_read.cpp \ + lib/univalue_write.cpp + +lib_libunivalue_la_LDFLAGS = \ + -version-info $(LIBUNIVALUE_CURRENT):$(LIBUNIVALUE_REVISION):$(LIBUNIVALUE_AGE) \ + -no-undefined +lib_libunivalue_la_CXXFLAGS = -I$(top_srcdir)/include + +TESTS = test/unitester + +GENBIN = gen/gen$(BUILD_EXEEXT) +GEN_SRCS = gen/gen.cpp + +$(GENBIN): $(GEN_SRCS) + @echo Building $@ + $(AM_V_at)c++ -I$(top_srcdir)/include -o $@ $< + +gen: lib/univalue_escapes.h $(GENBIN) + @echo Updating $< + $(AM_V_at)$(GENBIN) > lib/univalue_escapes.h + +noinst_PROGRAMS = $(TESTS) + +TEST_DATA_DIR=test + +test_unitester_SOURCES = test/unitester.cpp +test_unitester_LDADD = lib/libunivalue.la +test_unitester_CXXFLAGS = -I$(top_srcdir)/include -DJSON_TEST_SRC=\"$(srcdir)/$(TEST_DATA_DIR)\" +test_unitester_LDFLAGS = -static $(LIBTOOL_APP_LDFLAGS) + +TEST_FILES = \ + $(TEST_DATA_DIR)/fail10.json \ + $(TEST_DATA_DIR)/fail11.json \ + $(TEST_DATA_DIR)/fail12.json \ + $(TEST_DATA_DIR)/fail13.json \ + $(TEST_DATA_DIR)/fail14.json \ + $(TEST_DATA_DIR)/fail15.json \ + $(TEST_DATA_DIR)/fail16.json \ + $(TEST_DATA_DIR)/fail17.json \ + $(TEST_DATA_DIR)/fail18.json \ + $(TEST_DATA_DIR)/fail19.json \ + $(TEST_DATA_DIR)/fail1.json \ + $(TEST_DATA_DIR)/fail20.json \ + $(TEST_DATA_DIR)/fail21.json \ + $(TEST_DATA_DIR)/fail22.json \ + $(TEST_DATA_DIR)/fail23.json \ + $(TEST_DATA_DIR)/fail24.json \ + $(TEST_DATA_DIR)/fail25.json \ + $(TEST_DATA_DIR)/fail26.json \ + $(TEST_DATA_DIR)/fail27.json \ + $(TEST_DATA_DIR)/fail28.json \ + $(TEST_DATA_DIR)/fail29.json \ + $(TEST_DATA_DIR)/fail2.json \ + $(TEST_DATA_DIR)/fail30.json \ + $(TEST_DATA_DIR)/fail31.json \ + $(TEST_DATA_DIR)/fail32.json \ + $(TEST_DATA_DIR)/fail33.json \ + $(TEST_DATA_DIR)/fail34.json \ + $(TEST_DATA_DIR)/fail3.json \ + $(TEST_DATA_DIR)/fail4.json \ + $(TEST_DATA_DIR)/fail5.json \ + $(TEST_DATA_DIR)/fail6.json \ + $(TEST_DATA_DIR)/fail7.json \ + $(TEST_DATA_DIR)/fail8.json \ + $(TEST_DATA_DIR)/fail9.json \ + $(TEST_DATA_DIR)/pass1.json \ + $(TEST_DATA_DIR)/pass2.json \ + $(TEST_DATA_DIR)/pass3.json + +EXTRA_DIST=$(TEST_FILES) $(GEN_SRCS) diff --git a/README b/README new file mode 100644 index 000000000..48167b083 --- /dev/null +++ b/README @@ -0,0 +1,7 @@ + + UniValue + +A universal value object, with JSON encoding (output) and decoding (input). + +Built as a single dynamic RAII C++ object class, and no templates. + diff --git a/TODO b/TODO new file mode 100644 index 000000000..5530048e9 --- /dev/null +++ b/TODO @@ -0,0 +1,10 @@ + +Rearrange tree for easier 'git subtree' style use + +Move towards C++11 etc. + +Namespace support - must come up with useful shorthand, avoiding +long Univalue::Univalue::Univalue usages forced upon library users. + +Improve test suite + diff --git a/autogen.sh b/autogen.sh new file mode 100755 index 000000000..4b38721fa --- /dev/null +++ b/autogen.sh @@ -0,0 +1,9 @@ +#!/bin/sh +set -e +srcdir="$(dirname $0)" +cd "$srcdir" +if [ -z ${LIBTOOLIZE} ] && GLIBTOOLIZE="`which glibtoolize 2>/dev/null`"; then + LIBTOOLIZE="${GLIBTOOLIZE}" + export LIBTOOLIZE +fi +autoreconf --install --force diff --git a/build-aux/m4/.empty b/build-aux/m4/.empty new file mode 100644 index 000000000..e69de29bb diff --git a/configure.ac b/configure.ac new file mode 100644 index 000000000..6cd951622 --- /dev/null +++ b/configure.ac @@ -0,0 +1,69 @@ +m4_define([libunivalue_major_version], [1]) +m4_define([libunivalue_minor_version], [1]) +m4_define([libunivalue_micro_version], [1]) +m4_define([libunivalue_interface_age], [1]) +# If you need a modifier for the version number. +# Normally empty, but can be used to make "fixup" releases. +m4_define([libunivalue_extraversion], []) + +dnl libtool versioning from libunivalue +m4_define([libunivalue_current], [m4_eval(100 * libunivalue_minor_version + libunivalue_micro_version - libunivalue_interface_age)]) +m4_define([libunivalue_binary_age], [m4_eval(100 * libunivalue_minor_version + libunivalue_micro_version)]) +m4_define([libunivalue_revision], [libunivalue_interface_age]) +m4_define([libunivalue_age], [m4_eval(libunivalue_binary_age - libunivalue_interface_age)]) +m4_define([libunivalue_version], [libunivalue_major_version().libunivalue_minor_version().libunivalue_micro_version()libunivalue_extraversion()]) + + +AC_INIT([univalue], [1.0.0], + [http://github.com/jgarzik/univalue/]) + +dnl make the compilation flags quiet unless V=1 is used +m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])]) + +AC_PREREQ(2.60) +AC_CONFIG_SRCDIR([lib/univalue.cpp]) +AC_CONFIG_AUX_DIR([build-aux]) +AC_CONFIG_MACRO_DIR([build-aux/m4]) +AC_CONFIG_HEADERS([univalue-config.h]) +AM_INIT_AUTOMAKE([subdir-objects foreign]) + +LIBUNIVALUE_MAJOR_VERSION=libunivalue_major_version +LIBUNIVALUE_MINOR_VERSION=libunivalue_minor_version +LIBUNIVALUE_MICRO_VERSION=libunivalue_micro_version +LIBUNIVALUE_INTERFACE_AGE=libunivalue_interface_age + +# ABI version +# http://www.gnu.org/software/libtool/manual/html_node/Updating-version-info.html +LIBUNIVALUE_CURRENT=libunivalue_current +LIBUNIVALUE_REVISION=libunivalue_revision +LIBUNIVALUE_AGE=libunivalue_age + +AC_SUBST(LIBUNIVALUE_CURRENT) +AC_SUBST(LIBUNIVALUE_REVISION) +AC_SUBST(LIBUNIVALUE_AGE) + +LT_INIT +LT_LANG([C++]) + +case $host in + *mingw*) + LIBTOOL_APP_LDFLAGS="$LIBTOOL_APP_LDFLAGS -all-static" + ;; +esac + +BUILD_EXEEXT= +case $build in + *mingw*) + BUILD_EXEEXT=".exe" + ;; +esac + +AC_CONFIG_FILES([ + Makefile + pc/libunivalue.pc + pc/libunivalue-uninstalled.pc]) + +AC_SUBST(LIBTOOL_APP_LDFLAGS) +AC_SUBST(BUILD_EXEEXT) +AC_OUTPUT + diff --git a/gen/gen.cpp b/gen/gen.cpp new file mode 100644 index 000000000..5e5a4d4ae --- /dev/null +++ b/gen/gen.cpp @@ -0,0 +1,77 @@ +// Copyright 2014 BitPay Inc. +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +// +// To re-create univalue_escapes.h: +// $ g++ -o gen gen.cpp +// $ ./gen > univalue_escapes.h +// + +#include +#include +#include +#include "univalue.h" + +using namespace std; + +static bool initEscapes; +static const char *escapes[256]; + +static void initJsonEscape() +{ + escapes[(int)'"'] = "\\\""; + escapes[(int)'\\'] = "\\\\"; + escapes[(int)'\b'] = "\\b"; + escapes[(int)'\f'] = "\\f"; + escapes[(int)'\n'] = "\\n"; + escapes[(int)'\r'] = "\\r"; + escapes[(int)'\t'] = "\\t"; + + initEscapes = true; +} + +static void outputEscape() +{ + printf( "// Automatically generated file. Do not modify.\n" + "#ifndef BITCOIN_UNIVALUE_UNIVALUE_ESCAPES_H\n" + "#define BITCOIN_UNIVALUE_UNIVALUE_ESCAPES_H\n" + "static const char *escapes[256] = {\n"); + + for (unsigned int i = 0; i < 256; i++) { + if (!escapes[i]) { + printf("\tNULL,\n"); + } else { + printf("\t\""); + + unsigned int si; + for (si = 0; si < strlen(escapes[i]); si++) { + char ch = escapes[i][si]; + switch (ch) { + case '"': + printf("\\\""); + break; + case '\\': + printf("\\\\"); + break; + default: + printf("%c", escapes[i][si]); + break; + } + } + + printf("\",\n"); + } + } + + printf( "};\n" + "#endif // BITCOIN_UNIVALUE_UNIVALUE_ESCAPES_H\n"); +} + +int main (int argc, char *argv[]) +{ + initJsonEscape(); + outputEscape(); + return 0; +} + diff --git a/include/univalue.h b/include/univalue.h new file mode 100644 index 000000000..ac0511601 --- /dev/null +++ b/include/univalue.h @@ -0,0 +1,250 @@ +// 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 + +#include +#include +#include +#include + +#include // .get_int64() +#include // 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(); } + bool checkObject(const std::map& memberTypes); + const UniValue& operator[](const std::string& key) const; + const UniValue& operator[](unsigned int index) const; + bool exists(const std::string& key) const { return (findKey(key) >= 0); } + + 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_backV(const std::vector& vec); + + 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, 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); + bool read(const std::string& rawStr) { + return read(rawStr.c_str()); + } + +private: + UniValue::VType typ; + std::string val; // numbers are stored as C++ strings + std::vector keys; + std::vector values; + + int findKey(const std::string& key) 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 + std::vector getKeys() const; + std::vector getValues() const; + bool get_bool() 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 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 Pair(const char *cKey, const char *cVal) +{ + std::string key(cKey); + UniValue uVal(cVal); + return std::make_pair(key, uVal); +} + +static inline std::pair Pair(const char *cKey, std::string strVal) +{ + std::string key(cKey); + UniValue uVal(strVal); + return std::make_pair(key, uVal); +} + +static inline std::pair Pair(const char *cKey, uint64_t u64Val) +{ + std::string key(cKey); + UniValue uVal(u64Val); + return std::make_pair(key, uVal); +} + +static inline std::pair Pair(const char *cKey, int64_t i64Val) +{ + std::string key(cKey); + UniValue uVal(i64Val); + return std::make_pair(key, uVal); +} + +static inline std::pair Pair(const char *cKey, bool iVal) +{ + std::string key(cKey); + UniValue uVal(iVal); + return std::make_pair(key, uVal); +} + +static inline std::pair Pair(const char *cKey, int iVal) +{ + std::string key(cKey); + UniValue uVal(iVal); + return std::make_pair(key, uVal); +} + +static inline std::pair Pair(const char *cKey, double dVal) +{ + std::string key(cKey); + UniValue uVal(dVal); + return std::make_pair(key, uVal); +} + +static inline std::pair Pair(const char *cKey, const UniValue& uVal) +{ + std::string key(cKey); + return std::make_pair(key, uVal); +} + +static inline std::pair 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); +extern const char *uvTypeName(UniValue::VType t); + +extern const UniValue NullUniValue; + +const UniValue& find_value( const UniValue& obj, const std::string& name); + +#endif // __UNIVALUE_H__ \ No newline at end of file diff --git a/lib/.gitignore b/lib/.gitignore new file mode 100644 index 000000000..ca8c16dcd --- /dev/null +++ b/lib/.gitignore @@ -0,0 +1,10 @@ + +libunivalue-uninstalled.pc +libunivalue.pc +libunivalue.a +gen + +.libs +*.lo +*.la + diff --git a/lib/univalue.cpp b/lib/univalue.cpp new file mode 100644 index 000000000..883e8651f --- /dev/null +++ b/lib/univalue.cpp @@ -0,0 +1,365 @@ +// 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. + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "univalue.h" + +namespace +{ +static bool ParsePrechecks(const std::string& str) +{ + if (str.empty()) // No empty string allowed + return false; + if (str.size() >= 1 && (isspace(str[0]) || isspace(str[str.size()-1]))) // No padding allowed + return false; + if (str.size() != strlen(str.c_str())) // No embedded NUL characters allowed + return false; + return true; +} + +bool ParseInt32(const std::string& str, int32_t *out) +{ + if (!ParsePrechecks(str)) + return false; + char *endp = NULL; + errno = 0; // strtol will not set errno if valid + long int n = strtol(str.c_str(), &endp, 10); + if(out) *out = (int32_t)n; + // Note that strtol returns a *long int*, so even if strtol doesn't report a over/underflow + // we still have to check that the returned value is within the range of an *int32_t*. On 64-bit + // platforms the size of these types may be different. + return endp && *endp == 0 && !errno && + n >= std::numeric_limits::min() && + n <= std::numeric_limits::max(); +} + +bool ParseInt64(const std::string& str, int64_t *out) +{ + if (!ParsePrechecks(str)) + return false; + char *endp = NULL; + errno = 0; // strtoll will not set errno if valid + long long int n = strtoll(str.c_str(), &endp, 10); + if(out) *out = (int64_t)n; + // Note that strtoll returns a *long long int*, so even if strtol doesn't report a over/underflow + // we still have to check that the returned value is within the range of an *int64_t*. + return endp && *endp == 0 && !errno && + n >= std::numeric_limits::min() && + n <= std::numeric_limits::max(); +} + +bool ParseDouble(const std::string& str, double *out) +{ + if (!ParsePrechecks(str)) + return false; + if (str.size() >= 2 && str[0] == '0' && str[1] == 'x') // No hexadecimal floats allowed + return false; + std::istringstream text(str); + text.imbue(std::locale::classic()); + double result; + text >> result; + if(out) *out = result; + return text.eof() && !text.fail(); +} +} + +using namespace std; + +const UniValue NullUniValue; + +void UniValue::clear() +{ + typ = VNULL; + val.clear(); + keys.clear(); + values.clear(); +} + +bool UniValue::setNull() +{ + clear(); + return true; +} + +bool UniValue::setBool(bool val_) +{ + clear(); + typ = VBOOL; + if (val_) + val = "1"; + return true; +} + +static bool validNumStr(const string& s) +{ + string tokenVal; + unsigned int consumed; + enum jtokentype tt = getJsonToken(tokenVal, consumed, s.c_str()); + return (tt == JTOK_NUMBER); +} + +bool UniValue::setNumStr(const string& val_) +{ + if (!validNumStr(val_)) + return false; + + clear(); + typ = VNUM; + val = val_; + return true; +} + +bool UniValue::setInt(uint64_t val) +{ + string s; + ostringstream oss; + + oss << val; + + return setNumStr(oss.str()); +} + +bool UniValue::setInt(int64_t val) +{ + string s; + ostringstream oss; + + oss << val; + + return setNumStr(oss.str()); +} + +bool UniValue::setFloat(double val) +{ + string s; + ostringstream oss; + + oss << std::setprecision(16) << val; + + bool ret = setNumStr(oss.str()); + typ = VNUM; + return ret; +} + +bool UniValue::setStr(const string& val_) +{ + clear(); + typ = VSTR; + val = val_; + return true; +} + +bool UniValue::setArray() +{ + clear(); + typ = VARR; + return true; +} + +bool UniValue::setObject() +{ + clear(); + typ = VOBJ; + return true; +} + +bool UniValue::push_back(const UniValue& val) +{ + if (typ != VARR) + return false; + + values.push_back(val); + return true; +} + +bool UniValue::push_backV(const std::vector& vec) +{ + if (typ != VARR) + return false; + + values.insert(values.end(), vec.begin(), vec.end()); + + return true; +} + +bool UniValue::pushKV(const std::string& key, const UniValue& val) +{ + if (typ != VOBJ) + return false; + + keys.push_back(key); + values.push_back(val); + return true; +} + +bool UniValue::pushKVs(const UniValue& obj) +{ + if (typ != VOBJ || obj.typ != VOBJ) + return false; + + for (unsigned int i = 0; i < obj.keys.size(); i++) { + keys.push_back(obj.keys[i]); + values.push_back(obj.values[i]); + } + + return true; +} + +int UniValue::findKey(const std::string& key) const +{ + for (unsigned int i = 0; i < keys.size(); i++) { + if (keys[i] == key) + return (int) i; + } + + return -1; +} + +bool UniValue::checkObject(const std::map& t) +{ + for (std::map::const_iterator it = t.begin(); + it != t.end(); it++) { + int idx = findKey(it->first); + if (idx < 0) + return false; + + if (values[idx].getType() != it->second) + return false; + } + + return true; +} + +const UniValue& UniValue::operator[](const std::string& key) const +{ + if (typ != VOBJ) + return NullUniValue; + + int index = findKey(key); + if (index < 0) + return NullUniValue; + + return values[index]; +} + +const UniValue& UniValue::operator[](unsigned int index) const +{ + if (typ != VOBJ && typ != VARR) + return NullUniValue; + if (index >= values.size()) + return NullUniValue; + + return values[index]; +} + +const char *uvTypeName(UniValue::VType t) +{ + switch (t) { + case UniValue::VNULL: return "null"; + case UniValue::VBOOL: return "bool"; + case UniValue::VOBJ: return "object"; + case UniValue::VARR: return "array"; + case UniValue::VSTR: return "string"; + case UniValue::VNUM: return "number"; + } + + // not reached + return NULL; +} + +const UniValue& find_value( const UniValue& obj, const std::string& name) +{ + for (unsigned int i = 0; i < obj.keys.size(); i++) + { + if( obj.keys[i] == name ) + { + return obj.values[i]; + } + } + + return NullUniValue; +} + +std::vector UniValue::getKeys() const +{ + if (typ != VOBJ) + throw std::runtime_error("JSON value is not an object as expected"); + return keys; +} + +std::vector UniValue::getValues() const +{ + if (typ != VOBJ && typ != VARR) + throw std::runtime_error("JSON value is not an object or array as expected"); + return values; +} + +bool UniValue::get_bool() const +{ + if (typ != VBOOL) + throw std::runtime_error("JSON value is not a boolean as expected"); + return getBool(); +} + +std::string UniValue::get_str() const +{ + if (typ != VSTR) + throw std::runtime_error("JSON value is not a string as expected"); + return getValStr(); +} + +int UniValue::get_int() const +{ + if (typ != VNUM) + throw std::runtime_error("JSON value is not an integer as expected"); + int32_t retval; + if (!ParseInt32(getValStr(), &retval)) + throw std::runtime_error("JSON integer out of range"); + return retval; +} + +int64_t UniValue::get_int64() const +{ + if (typ != VNUM) + throw std::runtime_error("JSON value is not an integer as expected"); + int64_t retval; + if (!ParseInt64(getValStr(), &retval)) + throw std::runtime_error("JSON integer out of range"); + return retval; +} + +double UniValue::get_real() const +{ + if (typ != VNUM) + throw std::runtime_error("JSON value is not a number as expected"); + double retval; + if (!ParseDouble(getValStr(), &retval)) + throw std::runtime_error("JSON double out of range"); + return retval; +} + +const UniValue& UniValue::get_obj() const +{ + if (typ != VOBJ) + throw std::runtime_error("JSON value is not an object as expected"); + return *this; +} + +const UniValue& UniValue::get_array() const +{ + if (typ != VARR) + throw std::runtime_error("JSON value is not an array as expected"); + return *this; +} + diff --git a/lib/univalue_escapes.h b/lib/univalue_escapes.h new file mode 100644 index 000000000..4133b24ca --- /dev/null +++ b/lib/univalue_escapes.h @@ -0,0 +1,262 @@ +// Automatically generated file. Do not modify. +#ifndef BITCOIN_UNIVALUE_UNIVALUE_ESCAPES_H +#define BITCOIN_UNIVALUE_UNIVALUE_ESCAPES_H +static const char *escapes[256] = { + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + "\\b", + "\\t", + "\\n", + NULL, + "\\f", + "\\r", + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + "\\\"", + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + "\\\\", + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, +}; +#endif // BITCOIN_UNIVALUE_UNIVALUE_ESCAPES_H diff --git a/lib/univalue_read.cpp b/lib/univalue_read.cpp new file mode 100644 index 000000000..64591234c --- /dev/null +++ b/lib/univalue_read.cpp @@ -0,0 +1,389 @@ +// Copyright 2014 BitPay Inc. +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include +#include +#include +#include "univalue.h" + +using namespace std; + +// convert hexadecimal string to unsigned integer +static const char *hatoui(const char *first, const char *last, + unsigned int& out) +{ + unsigned int result = 0; + for (; first != last; ++first) + { + int digit; + if (isdigit(*first)) + digit = *first - '0'; + + else if (*first >= 'a' && *first <= 'f') + digit = *first - 'a' + 10; + + else if (*first >= 'A' && *first <= 'F') + digit = *first - 'A' + 10; + + else + break; + + result = 16 * result + digit; + } + out = result; + + return first; +} + +enum jtokentype getJsonToken(string& tokenVal, unsigned int& consumed, + const char *raw) +{ + tokenVal.clear(); + consumed = 0; + + const char *rawStart = raw; + + while ((*raw) && (isspace(*raw))) // skip whitespace + raw++; + + switch (*raw) { + + case 0: + return JTOK_NONE; + + case '{': + raw++; + consumed = (raw - rawStart); + return JTOK_OBJ_OPEN; + case '}': + raw++; + consumed = (raw - rawStart); + return JTOK_OBJ_CLOSE; + case '[': + raw++; + consumed = (raw - rawStart); + return JTOK_ARR_OPEN; + case ']': + raw++; + consumed = (raw - rawStart); + return JTOK_ARR_CLOSE; + + case ':': + raw++; + consumed = (raw - rawStart); + return JTOK_COLON; + case ',': + raw++; + consumed = (raw - rawStart); + return JTOK_COMMA; + + case 'n': + case 't': + case 'f': + if (!strncmp(raw, "null", 4)) { + raw += 4; + consumed = (raw - rawStart); + return JTOK_KW_NULL; + } else if (!strncmp(raw, "true", 4)) { + raw += 4; + consumed = (raw - rawStart); + return JTOK_KW_TRUE; + } else if (!strncmp(raw, "false", 5)) { + raw += 5; + consumed = (raw - rawStart); + return JTOK_KW_FALSE; + } else + return JTOK_ERR; + + case '-': + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': { + // part 1: int + string numStr; + + const char *first = raw; + + const char *firstDigit = first; + if (!isdigit(*firstDigit)) + firstDigit++; + if ((*firstDigit == '0') && isdigit(firstDigit[1])) + return JTOK_ERR; + + numStr += *raw; // copy first char + raw++; + + if ((*first == '-') && (!isdigit(*raw))) + return JTOK_ERR; + + while ((*raw) && isdigit(*raw)) { // copy digits + numStr += *raw; + raw++; + } + + // part 2: frac + if (*raw == '.') { + numStr += *raw; // copy . + raw++; + + if (!isdigit(*raw)) + return JTOK_ERR; + while ((*raw) && isdigit(*raw)) { // copy digits + numStr += *raw; + raw++; + } + } + + // part 3: exp + if (*raw == 'e' || *raw == 'E') { + numStr += *raw; // copy E + raw++; + + if (*raw == '-' || *raw == '+') { // copy +/- + numStr += *raw; + raw++; + } + + if (!isdigit(*raw)) + return JTOK_ERR; + while ((*raw) && isdigit(*raw)) { // copy digits + numStr += *raw; + raw++; + } + } + + tokenVal = numStr; + consumed = (raw - rawStart); + return JTOK_NUMBER; + } + + case '"': { + raw++; // skip " + + string valStr; + + while (*raw) { + if (*raw < 0x20) + return JTOK_ERR; + + else if (*raw == '\\') { + raw++; // skip backslash + + switch (*raw) { + case '"': valStr += "\""; break; + case '\\': valStr += "\\"; break; + case '/': valStr += "/"; break; + case 'b': valStr += "\b"; break; + case 'f': valStr += "\f"; break; + case 'n': valStr += "\n"; break; + case 'r': valStr += "\r"; break; + case 't': valStr += "\t"; break; + + case 'u': { + unsigned int codepoint; + if (hatoui(raw + 1, raw + 1 + 4, codepoint) != + raw + 1 + 4) + return JTOK_ERR; + + if (codepoint <= 0x7f) + valStr.push_back((char)codepoint); + else if (codepoint <= 0x7FF) { + valStr.push_back((char)(0xC0 | (codepoint >> 6))); + valStr.push_back((char)(0x80 | (codepoint & 0x3F))); + } else if (codepoint <= 0xFFFF) { + valStr.push_back((char)(0xE0 | (codepoint >> 12))); + valStr.push_back((char)(0x80 | ((codepoint >> 6) & 0x3F))); + valStr.push_back((char)(0x80 | (codepoint & 0x3F))); + } + + raw += 4; + break; + } + default: + return JTOK_ERR; + + } + + raw++; // skip esc'd char + } + + else if (*raw == '"') { + raw++; // skip " + break; // stop scanning + } + + else { + valStr += *raw; + raw++; + } + } + + tokenVal = valStr; + consumed = (raw - rawStart); + return JTOK_STRING; + } + + default: + return JTOK_ERR; + } +} + +bool UniValue::read(const char *raw) +{ + clear(); + + bool expectName = false; + bool expectColon = false; + vector stack; + + string tokenVal; + unsigned int consumed; + enum jtokentype tok = JTOK_NONE; + enum jtokentype last_tok = JTOK_NONE; + do { + last_tok = tok; + + tok = getJsonToken(tokenVal, consumed, raw); + if (tok == JTOK_NONE || tok == JTOK_ERR) + return false; + raw += consumed; + + switch (tok) { + + case JTOK_OBJ_OPEN: + case JTOK_ARR_OPEN: { + VType utyp = (tok == JTOK_OBJ_OPEN ? VOBJ : VARR); + if (!stack.size()) { + if (utyp == VOBJ) + setObject(); + else + setArray(); + stack.push_back(this); + } else { + UniValue tmpVal(utyp); + UniValue *top = stack.back(); + top->values.push_back(tmpVal); + + UniValue *newTop = &(top->values.back()); + stack.push_back(newTop); + } + + if (utyp == VOBJ) + expectName = true; + break; + } + + case JTOK_OBJ_CLOSE: + case JTOK_ARR_CLOSE: { + if (!stack.size() || expectColon || (last_tok == JTOK_COMMA)) + return false; + + VType utyp = (tok == JTOK_OBJ_CLOSE ? VOBJ : VARR); + UniValue *top = stack.back(); + if (utyp != top->getType()) + return false; + + stack.pop_back(); + expectName = false; + break; + } + + case JTOK_COLON: { + if (!stack.size() || expectName || !expectColon) + return false; + + UniValue *top = stack.back(); + if (top->getType() != VOBJ) + return false; + + expectColon = false; + break; + } + + case JTOK_COMMA: { + if (!stack.size() || expectName || expectColon || + (last_tok == JTOK_COMMA) || (last_tok == JTOK_ARR_OPEN)) + return false; + + UniValue *top = stack.back(); + if (top->getType() == VOBJ) + expectName = true; + break; + } + + case JTOK_KW_NULL: + case JTOK_KW_TRUE: + case JTOK_KW_FALSE: { + if (!stack.size() || expectName || expectColon) + return false; + + UniValue tmpVal; + switch (tok) { + case JTOK_KW_NULL: + // do nothing more + break; + case JTOK_KW_TRUE: + tmpVal.setBool(true); + break; + case JTOK_KW_FALSE: + tmpVal.setBool(false); + break; + default: /* impossible */ break; + } + + UniValue *top = stack.back(); + top->values.push_back(tmpVal); + + break; + } + + case JTOK_NUMBER: { + if (!stack.size() || expectName || expectColon) + return false; + + UniValue tmpVal(VNUM, tokenVal); + UniValue *top = stack.back(); + top->values.push_back(tmpVal); + + break; + } + + case JTOK_STRING: { + if (!stack.size()) + return false; + + UniValue *top = stack.back(); + + if (expectName) { + top->keys.push_back(tokenVal); + expectName = false; + expectColon = true; + } else { + UniValue tmpVal(VSTR, tokenVal); + top->values.push_back(tmpVal); + } + + break; + } + + default: + return false; + } + } while (!stack.empty ()); + + /* Check that nothing follows the initial construct (parsed above). */ + tok = getJsonToken(tokenVal, consumed, raw); + if (tok != JTOK_NONE) + return false; + + return true; +} + diff --git a/lib/univalue_write.cpp b/lib/univalue_write.cpp new file mode 100644 index 000000000..bce3997af --- /dev/null +++ b/lib/univalue_write.cpp @@ -0,0 +1,127 @@ +// Copyright 2014 BitPay Inc. +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include +#include +#include +#include +#include "univalue.h" +#include "univalue_escapes.h" + +// TODO: Using UTF8 + +using namespace std; + +static string json_escape(const string& inS) +{ + string outS; + outS.reserve(inS.size() * 2); + + for (unsigned int i = 0; i < inS.size(); i++) { + unsigned char ch = inS[i]; + const char *escStr = escapes[ch]; + + if (escStr) + outS += escStr; + + else if (isprint(ch)) + outS += ch; + + else { + char tmpesc[16]; + sprintf(tmpesc, "\\u%04x", ch); + outS += tmpesc; + } + } + + return outS; +} + +string UniValue::write(unsigned int prettyIndent, + unsigned int indentLevel) const +{ + string s; + s.reserve(1024); + + unsigned int modIndent = indentLevel; + if (modIndent == 0) + modIndent = 1; + + switch (typ) { + case VNULL: + s += "null"; + break; + case VOBJ: + writeObject(prettyIndent, modIndent, s); + break; + case VARR: + writeArray(prettyIndent, modIndent, s); + break; + case VSTR: + s += "\"" + json_escape(val) + "\""; + break; + case VNUM: + s += val; + break; + case VBOOL: + s += (val == "1" ? "true" : "false"); + break; + } + + return s; +} + +static void indentStr(unsigned int prettyIndent, unsigned int indentLevel, string& s) +{ + s.append(prettyIndent * indentLevel, ' '); +} + +void UniValue::writeArray(unsigned int prettyIndent, unsigned int indentLevel, string& s) const +{ + s += "["; + if (prettyIndent) + s += "\n"; + + for (unsigned int i = 0; i < values.size(); i++) { + if (prettyIndent) + indentStr(prettyIndent, indentLevel, s); + s += values[i].write(prettyIndent, indentLevel + 1); + if (i != (values.size() - 1)) { + s += ","; + if (prettyIndent) + s += " "; + } + if (prettyIndent) + s += "\n"; + } + + if (prettyIndent) + indentStr(prettyIndent, indentLevel - 1, s); + s += "]"; +} + +void UniValue::writeObject(unsigned int prettyIndent, unsigned int indentLevel, string& s) const +{ + s += "{"; + if (prettyIndent) + s += "\n"; + + for (unsigned int i = 0; i < keys.size(); i++) { + if (prettyIndent) + indentStr(prettyIndent, indentLevel, s); + s += "\"" + json_escape(keys[i]) + "\":"; + if (prettyIndent) + s += " "; + s += values[i].write(prettyIndent, indentLevel + 1); + if (i != (values.size() - 1)) + s += ","; + if (prettyIndent) + s += "\n"; + } + + if (prettyIndent) + indentStr(prettyIndent, indentLevel - 1, s); + s += "}"; +} + diff --git a/pc/libunivalue-uninstalled.pc.in b/pc/libunivalue-uninstalled.pc.in new file mode 100644 index 000000000..b7f53e875 --- /dev/null +++ b/pc/libunivalue-uninstalled.pc.in @@ -0,0 +1,9 @@ +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ +includedir=@includedir@ + +Name: libunivalue +Description: libunivalue, C++ universal value object and JSON library +Version: @VERSION@ +Libs: ${pc_top_builddir}/${pcfiledir}/libunivalue.la diff --git a/pc/libunivalue.pc.in b/pc/libunivalue.pc.in new file mode 100644 index 000000000..358a2d5f7 --- /dev/null +++ b/pc/libunivalue.pc.in @@ -0,0 +1,10 @@ +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ +includedir=@includedir@ + +Name: libunivalue +Description: libunivalue, C++ universal value object and JSON library +Version: @VERSION@ +Libs: -L${libdir} -lunivalue +Cflags: -I${includedir} diff --git a/test/.gitignore b/test/.gitignore new file mode 100644 index 000000000..e4dea0df7 --- /dev/null +++ b/test/.gitignore @@ -0,0 +1,7 @@ + +unitester + +*.log +*.trs + +.libs diff --git a/test/fail1.json b/test/fail1.json new file mode 100644 index 000000000..6216b865f --- /dev/null +++ b/test/fail1.json @@ -0,0 +1 @@ +"A JSON payload should be an object or array, not a string." \ No newline at end of file diff --git a/test/fail10.json b/test/fail10.json new file mode 100644 index 000000000..5d8c0047b --- /dev/null +++ b/test/fail10.json @@ -0,0 +1 @@ +{"Extra value after close": true} "misplaced quoted value" \ No newline at end of file diff --git a/test/fail11.json b/test/fail11.json new file mode 100644 index 000000000..76eb95b45 --- /dev/null +++ b/test/fail11.json @@ -0,0 +1 @@ +{"Illegal expression": 1 + 2} \ No newline at end of file diff --git a/test/fail12.json b/test/fail12.json new file mode 100644 index 000000000..77580a452 --- /dev/null +++ b/test/fail12.json @@ -0,0 +1 @@ +{"Illegal invocation": alert()} \ No newline at end of file diff --git a/test/fail13.json b/test/fail13.json new file mode 100644 index 000000000..379406b59 --- /dev/null +++ b/test/fail13.json @@ -0,0 +1 @@ +{"Numbers cannot have leading zeroes": 013} \ No newline at end of file diff --git a/test/fail14.json b/test/fail14.json new file mode 100644 index 000000000..0ed366b38 --- /dev/null +++ b/test/fail14.json @@ -0,0 +1 @@ +{"Numbers cannot be hex": 0x14} \ No newline at end of file diff --git a/test/fail15.json b/test/fail15.json new file mode 100644 index 000000000..fc8376b60 --- /dev/null +++ b/test/fail15.json @@ -0,0 +1 @@ +["Illegal backslash escape: \x15"] \ No newline at end of file diff --git a/test/fail16.json b/test/fail16.json new file mode 100644 index 000000000..3fe21d4b5 --- /dev/null +++ b/test/fail16.json @@ -0,0 +1 @@ +[\naked] \ No newline at end of file diff --git a/test/fail17.json b/test/fail17.json new file mode 100644 index 000000000..62b9214ae --- /dev/null +++ b/test/fail17.json @@ -0,0 +1 @@ +["Illegal backslash escape: \017"] \ No newline at end of file diff --git a/test/fail18.json b/test/fail18.json new file mode 100644 index 000000000..edac92716 --- /dev/null +++ b/test/fail18.json @@ -0,0 +1 @@ +[[[[[[[[[[[[[[[[[[[["Too deep"]]]]]]]]]]]]]]]]]]]] \ No newline at end of file diff --git a/test/fail19.json b/test/fail19.json new file mode 100644 index 000000000..3b9c46fa9 --- /dev/null +++ b/test/fail19.json @@ -0,0 +1 @@ +{"Missing colon" null} \ No newline at end of file diff --git a/test/fail2.json b/test/fail2.json new file mode 100644 index 000000000..6b7c11e5a --- /dev/null +++ b/test/fail2.json @@ -0,0 +1 @@ +["Unclosed array" \ No newline at end of file diff --git a/test/fail20.json b/test/fail20.json new file mode 100644 index 000000000..27c1af3e7 --- /dev/null +++ b/test/fail20.json @@ -0,0 +1 @@ +{"Double colon":: null} \ No newline at end of file diff --git a/test/fail21.json b/test/fail21.json new file mode 100644 index 000000000..62474573b --- /dev/null +++ b/test/fail21.json @@ -0,0 +1 @@ +{"Comma instead of colon", null} \ No newline at end of file diff --git a/test/fail22.json b/test/fail22.json new file mode 100644 index 000000000..a7752581b --- /dev/null +++ b/test/fail22.json @@ -0,0 +1 @@ +["Colon instead of comma": false] \ No newline at end of file diff --git a/test/fail23.json b/test/fail23.json new file mode 100644 index 000000000..494add1ca --- /dev/null +++ b/test/fail23.json @@ -0,0 +1 @@ +["Bad value", truth] \ No newline at end of file diff --git a/test/fail24.json b/test/fail24.json new file mode 100644 index 000000000..caff239bf --- /dev/null +++ b/test/fail24.json @@ -0,0 +1 @@ +['single quote'] \ No newline at end of file diff --git a/test/fail25.json b/test/fail25.json new file mode 100644 index 000000000..8b7ad23e0 --- /dev/null +++ b/test/fail25.json @@ -0,0 +1 @@ +[" tab character in string "] \ No newline at end of file diff --git a/test/fail26.json b/test/fail26.json new file mode 100644 index 000000000..845d26a6a --- /dev/null +++ b/test/fail26.json @@ -0,0 +1 @@ +["tab\ character\ in\ string\ "] \ No newline at end of file diff --git a/test/fail27.json b/test/fail27.json new file mode 100644 index 000000000..6b01a2ca4 --- /dev/null +++ b/test/fail27.json @@ -0,0 +1,2 @@ +["line +break"] \ No newline at end of file diff --git a/test/fail28.json b/test/fail28.json new file mode 100644 index 000000000..621a0101c --- /dev/null +++ b/test/fail28.json @@ -0,0 +1,2 @@ +["line\ +break"] \ No newline at end of file diff --git a/test/fail29.json b/test/fail29.json new file mode 100644 index 000000000..47ec421bb --- /dev/null +++ b/test/fail29.json @@ -0,0 +1 @@ +[0e] \ No newline at end of file diff --git a/test/fail3.json b/test/fail3.json new file mode 100644 index 000000000..168c81eb7 --- /dev/null +++ b/test/fail3.json @@ -0,0 +1 @@ +{unquoted_key: "keys must be quoted"} \ No newline at end of file diff --git a/test/fail30.json b/test/fail30.json new file mode 100644 index 000000000..8ab0bc4b8 --- /dev/null +++ b/test/fail30.json @@ -0,0 +1 @@ +[0e+] \ No newline at end of file diff --git a/test/fail31.json b/test/fail31.json new file mode 100644 index 000000000..1cce602b5 --- /dev/null +++ b/test/fail31.json @@ -0,0 +1 @@ +[0e+-1] \ No newline at end of file diff --git a/test/fail32.json b/test/fail32.json new file mode 100644 index 000000000..45cba7396 --- /dev/null +++ b/test/fail32.json @@ -0,0 +1 @@ +{"Comma instead if closing brace": true, \ No newline at end of file diff --git a/test/fail33.json b/test/fail33.json new file mode 100644 index 000000000..ca5eb19dc --- /dev/null +++ b/test/fail33.json @@ -0,0 +1 @@ +["mismatch"} \ No newline at end of file diff --git a/test/fail34.json b/test/fail34.json new file mode 100644 index 000000000..3f8be1728 --- /dev/null +++ b/test/fail34.json @@ -0,0 +1 @@ +{} garbage \ No newline at end of file diff --git a/test/fail4.json b/test/fail4.json new file mode 100644 index 000000000..9de168bf3 --- /dev/null +++ b/test/fail4.json @@ -0,0 +1 @@ +["extra comma",] \ No newline at end of file diff --git a/test/fail5.json b/test/fail5.json new file mode 100644 index 000000000..ddf3ce3d2 --- /dev/null +++ b/test/fail5.json @@ -0,0 +1 @@ +["double extra comma",,] \ No newline at end of file diff --git a/test/fail6.json b/test/fail6.json new file mode 100644 index 000000000..ed91580e1 --- /dev/null +++ b/test/fail6.json @@ -0,0 +1 @@ +[ , "<-- missing value"] \ No newline at end of file diff --git a/test/fail7.json b/test/fail7.json new file mode 100644 index 000000000..8a96af3e4 --- /dev/null +++ b/test/fail7.json @@ -0,0 +1 @@ +["Comma after the close"], \ No newline at end of file diff --git a/test/fail8.json b/test/fail8.json new file mode 100644 index 000000000..b28479c6e --- /dev/null +++ b/test/fail8.json @@ -0,0 +1 @@ +["Extra close"]] \ No newline at end of file diff --git a/test/fail9.json b/test/fail9.json new file mode 100644 index 000000000..5815574f3 --- /dev/null +++ b/test/fail9.json @@ -0,0 +1 @@ +{"Extra comma": true,} \ No newline at end of file diff --git a/test/pass1.json b/test/pass1.json new file mode 100644 index 000000000..70e268543 --- /dev/null +++ b/test/pass1.json @@ -0,0 +1,58 @@ +[ + "JSON Test Pattern pass1", + {"object with 1 member":["array with 1 element"]}, + {}, + [], + -42, + true, + false, + null, + { + "integer": 1234567890, + "real": -9876.543210, + "e": 0.123456789e-12, + "E": 1.234567890E+34, + "": 23456789012E66, + "zero": 0, + "one": 1, + "space": " ", + "quote": "\"", + "backslash": "\\", + "controls": "\b\f\n\r\t", + "slash": "/ & \/", + "alpha": "abcdefghijklmnopqrstuvwyz", + "ALPHA": "ABCDEFGHIJKLMNOPQRSTUVWYZ", + "digit": "0123456789", + "0123456789": "digit", + "special": "`1~!@#$%^&*()_+-={':[,]}|;.?", + "hex": "\u0123\u4567\u89AB\uCDEF\uabcd\uef4A", + "true": true, + "false": false, + "null": null, + "array":[ ], + "object":{ }, + "address": "50 St. James Street", + "url": "http://www.JSON.org/", + "comment": "// /* */": " ", + " s p a c e d " :[1,2 , 3 + +, + +4 , 5 , 6 ,7 ],"compact":[1,2,3,4,5,6,7], + "jsontext": "{\"object with 1 member\":[\"array with 1 element\"]}", + "quotes": "" \u0022 %22 0x22 034 "", + "\/\\\"\uCAFE\uBABE\uAB98\uFCDE\ubcda\uef4A\b\f\n\r\t`1~!@#$%^&*()_+-=[]{}|;:',./<>?" +: "A key can be any string" + }, + 0.5 ,98.6 +, +99.44 +, + +1066, +1e1, +0.1e1, +1e-1, +1e00,2e+00,2e-00 +,"rosebud"] \ No newline at end of file diff --git a/test/pass2.json b/test/pass2.json new file mode 100644 index 000000000..d3c63c7ad --- /dev/null +++ b/test/pass2.json @@ -0,0 +1 @@ +[[[[[[[[[[[[[[[[[[["Not too deep"]]]]]]]]]]]]]]]]]]] \ No newline at end of file diff --git a/test/pass3.json b/test/pass3.json new file mode 100644 index 000000000..4528d51f1 --- /dev/null +++ b/test/pass3.json @@ -0,0 +1,6 @@ +{ + "JSON Test Pattern pass3": { + "The outermost value": "must be an object or array.", + "In this test": "It is an object." + } +} diff --git a/test/unitester.cpp b/test/unitester.cpp new file mode 100644 index 000000000..835556e03 --- /dev/null +++ b/test/unitester.cpp @@ -0,0 +1,115 @@ +// Copyright 2014 BitPay Inc. +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include +#include +#include +#include +#include +#include "univalue.h" + +#ifndef JSON_TEST_SRC +#error JSON_TEST_SRC must point to test source directory +#endif + +#ifndef ARRAY_SIZE +#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0])) +#endif + +using namespace std; +string srcdir(JSON_TEST_SRC); + +static void runtest(string filename, const string& jdata) +{ + fprintf(stderr, "test %s\n", filename.c_str()); + + string prefix = filename.substr(0, 4); + + bool wantPass = (prefix == "pass"); + bool wantFail = (prefix == "fail"); + assert(wantPass || wantFail); + + UniValue val; + bool testResult = val.read(jdata); + + if (wantPass) { + assert(testResult == true); + } else { + assert(testResult == false); + } +} + +static void runtest_file(const char *filename_) +{ + string basename(filename_); + string filename = srcdir + "/" + basename; + FILE *f = fopen(filename.c_str(), "r"); + assert(f != NULL); + + string jdata; + + char buf[4096]; + while (!feof(f)) { + int bread = fread(buf, 1, sizeof(buf), f); + assert(!ferror(f)); + + string s(buf, bread); + jdata += s; + } + + assert(!ferror(f)); + fclose(f); + + runtest(basename, jdata); +} + +static const char *filenames[] = { + "fail10.json", + "fail11.json", + "fail12.json", + "fail13.json", + "fail14.json", + "fail15.json", + "fail16.json", + "fail17.json", + //"fail18.json", // investigate + "fail19.json", + "fail1.json", + "fail20.json", + "fail21.json", + "fail22.json", + "fail23.json", + "fail24.json", + "fail25.json", + "fail26.json", + "fail27.json", + "fail28.json", + "fail29.json", + "fail2.json", + "fail30.json", + "fail31.json", + "fail32.json", + "fail33.json", + "fail34.json", + "fail3.json", + "fail4.json", // extra comma + "fail5.json", + "fail6.json", + "fail7.json", + "fail8.json", + "fail9.json", // extra comma + "pass1.json", + "pass2.json", + "pass3.json", +}; + +int main (int argc, char *argv[]) +{ + for (unsigned int fidx = 0; fidx < ARRAY_SIZE(filenames); fidx++) { + runtest_file(filenames[fidx]); + } + + return 0; +} + From 9623e934732ba0f0a5176cd3d993ebcda327b413 Mon Sep 17 00:00:00 2001 From: Jonas Schnelli Date: Fri, 4 Sep 2015 16:11:34 +0200 Subject: [PATCH 3/4] [Univalue] add univalue over subtree similar to secp256k1 include and compile univalue over a subtree --- configure.ac | 2 +- src/Makefile.am | 23 +++++++++-------------- src/Makefile.qt.include | 2 +- src/Makefile.qttest.include | 2 +- src/Makefile.test.include | 3 ++- src/bitcoin-cli.cpp | 2 +- src/bitcoin-tx.cpp | 2 +- src/core_read.cpp | 2 +- src/core_write.cpp | 2 +- src/qt/rpcconsole.cpp | 2 +- src/rest.cpp | 2 +- src/rpcblockchain.cpp | 2 +- src/rpcclient.cpp | 2 +- src/rpcclient.h | 2 +- src/rpcmining.cpp | 2 +- src/rpcmisc.cpp | 2 +- src/rpcnet.cpp | 2 +- src/rpcprotocol.h | 2 +- src/rpcrawtransaction.cpp | 2 +- src/rpcserver.cpp | 2 +- src/rpcserver.h | 2 +- src/test/base58_tests.cpp | 2 +- src/test/rpc_tests.cpp | 2 +- src/test/rpc_wallet_tests.cpp | 2 +- src/test/script_tests.cpp | 2 +- src/test/sighash_tests.cpp | 2 +- src/test/transaction_tests.cpp | 2 +- src/test/univalue_tests.cpp | 2 +- src/wallet/rpcdump.cpp | 2 +- src/wallet/rpcwallet.cpp | 2 +- 30 files changed, 39 insertions(+), 43 deletions(-) diff --git a/configure.ac b/configure.ac index d530f8c26..dbdc356f5 100644 --- a/configure.ac +++ b/configure.ac @@ -940,7 +940,7 @@ unset PKG_CONFIG_LIBDIR PKG_CONFIG_LIBDIR="$PKGCONFIG_LIBDIR_TEMP" ac_configure_args="${ac_configure_args} --disable-shared --with-pic --with-bignum=no" -AC_CONFIG_SUBDIRS([src/secp256k1]) +AC_CONFIG_SUBDIRS([src/secp256k1 src/univalue]) AC_OUTPUT diff --git a/src/Makefile.am b/src/Makefile.am index 7fdc766e1..301880dbc 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1,4 +1,4 @@ -DIST_SUBDIRS = secp256k1 +DIST_SUBDIRS = secp256k1 univalue AM_LDFLAGS = $(PTHREAD_CFLAGS) $(LIBTOOL_LDFLAGS) @@ -21,6 +21,7 @@ BITCOIN_CONFIG_INCLUDES=-I$(builddir)/config BITCOIN_INCLUDES=-I$(builddir) -I$(builddir)/obj $(BOOST_CPPFLAGS) $(LEVELDB_CPPFLAGS) $(CRYPTO_CFLAGS) $(SSL_CFLAGS) BITCOIN_INCLUDES += -I$(srcdir)/secp256k1/include +BITCOIN_INCLUDES += -I$(srcdir)/univalue/include LIBBITCOIN_SERVER=libbitcoin_server.a LIBBITCOIN_WALLET=libbitcoin_wallet.a @@ -28,12 +29,15 @@ LIBBITCOIN_COMMON=libbitcoin_common.a LIBBITCOIN_CLI=libbitcoin_cli.a LIBBITCOIN_UTIL=libbitcoin_util.a LIBBITCOIN_CRYPTO=crypto/libbitcoin_crypto.a -LIBBITCOIN_UNIVALUE=univalue/libbitcoin_univalue.a LIBBITCOINQT=qt/libbitcoinqt.a LIBSECP256K1=secp256k1/libsecp256k1.la +LIBUNIVALUE=univalue/lib/libunivalue.la $(LIBSECP256K1): $(wildcard secp256k1/src/*) $(wildcard secp256k1/include/*) $(AM_V_at)$(MAKE) $(AM_MAKEFLAGS) -C $(@D) $(@F) + +$(LIBUNIVALUE): $(wildcard univalue/lib/*) $(wildcard univalue/include/*) + $(AM_V_at)$(MAKE) $(AM_MAKEFLAGS) -C $(@D) $(@F) # Make is not made aware of per-object dependencies to avoid limiting building parallelization # But to build the less dependent modules first, we manually select their order here: @@ -41,7 +45,6 @@ EXTRA_LIBRARIES = \ crypto/libbitcoin_crypto.a \ libbitcoin_util.a \ libbitcoin_common.a \ - univalue/libbitcoin_univalue.a \ libbitcoin_server.a \ libbitcoin_cli.a if ENABLE_WALLET @@ -248,14 +251,6 @@ crypto_libbitcoin_crypto_a_SOURCES = \ crypto/sha512.cpp \ crypto/sha512.h -# univalue JSON library -univalue_libbitcoin_univalue_a_SOURCES = \ - univalue/univalue.cpp \ - univalue/univalue.h \ - univalue/univalue_escapes.h \ - univalue/univalue_read.cpp \ - univalue/univalue_write.cpp - # common: shared between bitcoind, and bitcoin-qt and non-server tools libbitcoin_common_a_CPPFLAGS = $(BITCOIN_INCLUDES) libbitcoin_common_a_SOURCES = \ @@ -332,7 +327,7 @@ endif bitcoind_LDADD = \ $(LIBBITCOIN_SERVER) \ $(LIBBITCOIN_COMMON) \ - $(LIBBITCOIN_UNIVALUE) \ + $(LIBUNIVALUE) \ $(LIBBITCOIN_UTIL) \ $(LIBBITCOIN_CRYPTO) \ $(LIBLEVELDB) \ @@ -360,7 +355,7 @@ endif bitcoin_cli_LDADD = \ $(LIBBITCOIN_CLI) \ - $(LIBBITCOIN_UNIVALUE) \ + $(LIBUNIVALUE) \ $(LIBBITCOIN_UTIL) bitcoin_cli_LDADD += $(BOOST_LIBS) $(SSL_LIBS) $(CRYPTO_LIBS) $(EVENT_LIBS) @@ -376,7 +371,7 @@ bitcoin_tx_SOURCES += bitcoin-tx-res.rc endif bitcoin_tx_LDADD = \ - $(LIBBITCOIN_UNIVALUE) \ + $(LIBUNIVALUE) \ $(LIBBITCOIN_COMMON) \ $(LIBBITCOIN_UTIL) \ $(LIBBITCOIN_CRYPTO) \ diff --git a/src/Makefile.qt.include b/src/Makefile.qt.include index 3330ed289..67fd7c107 100644 --- a/src/Makefile.qt.include +++ b/src/Makefile.qt.include @@ -367,7 +367,7 @@ endif if ENABLE_ZMQ qt_bitcoin_qt_LDADD += $(LIBBITCOIN_ZMQ) $(ZMQ_LIBS) endif -qt_bitcoin_qt_LDADD += $(LIBBITCOIN_CLI) $(LIBBITCOIN_COMMON) $(LIBBITCOIN_UTIL) $(LIBBITCOIN_CRYPTO) $(LIBBITCOIN_UNIVALUE) $(LIBLEVELDB) $(LIBMEMENV) \ +qt_bitcoin_qt_LDADD += $(LIBBITCOIN_CLI) $(LIBBITCOIN_COMMON) $(LIBBITCOIN_UTIL) $(LIBBITCOIN_CRYPTO) $(LIBUNIVALUE) $(LIBLEVELDB) $(LIBMEMENV) \ $(BOOST_LIBS) $(QT_LIBS) $(QT_DBUS_LIBS) $(QR_LIBS) $(PROTOBUF_LIBS) $(BDB_LIBS) $(SSL_LIBS) $(CRYPTO_LIBS) $(MINIUPNPC_LIBS) $(LIBSECP256K1) \ $(EVENT_PTHREADS_LIBS) $(EVENT_LIBS) qt_bitcoin_qt_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(QT_LDFLAGS) $(LIBTOOL_APP_LDFLAGS) diff --git a/src/Makefile.qttest.include b/src/Makefile.qttest.include index 6554580be..b8725c872 100644 --- a/src/Makefile.qttest.include +++ b/src/Makefile.qttest.include @@ -33,7 +33,7 @@ endif if ENABLE_ZMQ qt_test_test_bitcoin_qt_LDADD += $(LIBBITCOIN_ZMQ) $(ZMQ_LIBS) endif -qt_test_test_bitcoin_qt_LDADD += $(LIBBITCOIN_CLI) $(LIBBITCOIN_COMMON) $(LIBBITCOIN_UTIL) $(LIBBITCOIN_CRYPTO) $(LIBBITCOIN_UNIVALUE) $(LIBLEVELDB) \ +qt_test_test_bitcoin_qt_LDADD += $(LIBBITCOIN_CLI) $(LIBBITCOIN_COMMON) $(LIBBITCOIN_UTIL) $(LIBBITCOIN_CRYPTO) $(LIBUNIVALUE) $(LIBLEVELDB) \ $(LIBMEMENV) $(BOOST_LIBS) $(QT_DBUS_LIBS) $(QT_TEST_LIBS) $(QT_LIBS) \ $(QR_LIBS) $(PROTOBUF_LIBS) $(BDB_LIBS) $(SSL_LIBS) $(CRYPTO_LIBS) $(MINIUPNPC_LIBS) $(LIBSECP256K1) \ $(EVENT_PTHREADS_LIBS) $(EVENT_LIBS) diff --git a/src/Makefile.test.include b/src/Makefile.test.include index cee35926a..9a6e43631 100644 --- a/src/Makefile.test.include +++ b/src/Makefile.test.include @@ -91,7 +91,7 @@ endif test_test_bitcoin_SOURCES = $(BITCOIN_TESTS) $(JSON_TEST_FILES) $(RAW_TEST_FILES) test_test_bitcoin_CPPFLAGS = $(BITCOIN_INCLUDES) -I$(builddir)/test/ $(TESTDEFS) -test_test_bitcoin_LDADD = $(LIBBITCOIN_SERVER) $(LIBBITCOIN_CLI) $(LIBBITCOIN_COMMON) $(LIBBITCOIN_UTIL) $(LIBBITCOIN_CRYPTO) $(LIBBITCOIN_UNIVALUE) $(LIBLEVELDB) $(LIBMEMENV) \ +test_test_bitcoin_LDADD = $(LIBBITCOIN_SERVER) $(LIBBITCOIN_CLI) $(LIBBITCOIN_COMMON) $(LIBBITCOIN_UTIL) $(LIBBITCOIN_CRYPTO) $(LIBUNIVALUE) $(LIBLEVELDB) $(LIBMEMENV) \ $(BOOST_LIBS) $(BOOST_UNIT_TEST_FRAMEWORK_LIB) $(LIBSECP256K1) if ENABLE_WALLET test_test_bitcoin_LDADD += $(LIBBITCOIN_WALLET) @@ -124,6 +124,7 @@ check-local: @echo "Running test/bitcoin-util-test.py..." $(AM_V_at)srcdir=$(srcdir) PYTHONPATH=$(builddir)/test $(srcdir)/test/bitcoin-util-test.py $(AM_V_at)$(MAKE) $(AM_MAKEFLAGS) -C secp256k1 check + $(AM_V_at)$(MAKE) $(AM_MAKEFLAGS) -C univalue check %.json.h: %.json @$(MKDIR_P) $(@D) diff --git a/src/bitcoin-cli.cpp b/src/bitcoin-cli.cpp index 7839b3b6b..e0fe6aa5b 100644 --- a/src/bitcoin-cli.cpp +++ b/src/bitcoin-cli.cpp @@ -18,7 +18,7 @@ #include #include -#include "univalue/univalue.h" +#include using namespace std; diff --git a/src/bitcoin-tx.cpp b/src/bitcoin-tx.cpp index 5beab265b..f7518fab5 100644 --- a/src/bitcoin-tx.cpp +++ b/src/bitcoin-tx.cpp @@ -12,7 +12,7 @@ #include "primitives/transaction.h" #include "script/script.h" #include "script/sign.h" -#include "univalue/univalue.h" +#include #include "util.h" #include "utilmoneystr.h" #include "utilstrencodings.h" diff --git a/src/core_read.cpp b/src/core_read.cpp index f762f2c3b..4be24f8e0 100644 --- a/src/core_read.cpp +++ b/src/core_read.cpp @@ -9,7 +9,7 @@ #include "script/script.h" #include "serialize.h" #include "streams.h" -#include "univalue/univalue.h" +#include #include "util.h" #include "utilstrencodings.h" #include "version.h" diff --git a/src/core_write.cpp b/src/core_write.cpp index 2ad42badd..533fedfe7 100644 --- a/src/core_write.cpp +++ b/src/core_write.cpp @@ -10,7 +10,7 @@ #include "script/standard.h" #include "serialize.h" #include "streams.h" -#include "univalue/univalue.h" +#include #include "util.h" #include "utilmoneystr.h" #include "utilstrencodings.h" diff --git a/src/qt/rpcconsole.cpp b/src/qt/rpcconsole.cpp index 72a3023c9..f387a3ec8 100644 --- a/src/qt/rpcconsole.cpp +++ b/src/qt/rpcconsole.cpp @@ -18,7 +18,7 @@ #include -#include "univalue/univalue.h" +#include #ifdef ENABLE_WALLET #include diff --git a/src/rest.cpp b/src/rest.cpp index 226e237fc..c46d7a8bd 100644 --- a/src/rest.cpp +++ b/src/rest.cpp @@ -18,7 +18,7 @@ #include #include -#include "univalue/univalue.h" +#include using namespace std; diff --git a/src/rpcblockchain.cpp b/src/rpcblockchain.cpp index 1c201ef99..545ac1289 100644 --- a/src/rpcblockchain.cpp +++ b/src/rpcblockchain.cpp @@ -20,7 +20,7 @@ #include -#include "univalue/univalue.h" +#include using namespace std; diff --git a/src/rpcclient.cpp b/src/rpcclient.cpp index 0c8e6d6d6..4064c2fee 100644 --- a/src/rpcclient.cpp +++ b/src/rpcclient.cpp @@ -12,7 +12,7 @@ #include #include // for to_lower() -#include "univalue/univalue.h" +#include using namespace std; diff --git a/src/rpcclient.h b/src/rpcclient.h index d68b4ed6a..8937a56f0 100644 --- a/src/rpcclient.h +++ b/src/rpcclient.h @@ -6,7 +6,7 @@ #ifndef BITCOIN_RPCCLIENT_H #define BITCOIN_RPCCLIENT_H -#include "univalue/univalue.h" +#include UniValue RPCConvertValues(const std::string& strMethod, const std::vector& strParams); /** Non-RFC4627 JSON parser, accepts internal values (such as numbers, true, false, null) diff --git a/src/rpcmining.cpp b/src/rpcmining.cpp index 8dd0ff2f7..c49c3e519 100644 --- a/src/rpcmining.cpp +++ b/src/rpcmining.cpp @@ -25,7 +25,7 @@ #include #include -#include "univalue/univalue.h" +#include using namespace std; diff --git a/src/rpcmisc.cpp b/src/rpcmisc.cpp index e2b6d5826..0f0457c5c 100644 --- a/src/rpcmisc.cpp +++ b/src/rpcmisc.cpp @@ -22,7 +22,7 @@ #include -#include "univalue/univalue.h" +#include using namespace std; diff --git a/src/rpcnet.cpp b/src/rpcnet.cpp index 5d490c70c..7746be25f 100644 --- a/src/rpcnet.cpp +++ b/src/rpcnet.cpp @@ -19,7 +19,7 @@ #include -#include "univalue/univalue.h" +#include using namespace std; diff --git a/src/rpcprotocol.h b/src/rpcprotocol.h index 5381e4bcf..9cf1ab6d9 100644 --- a/src/rpcprotocol.h +++ b/src/rpcprotocol.h @@ -12,7 +12,7 @@ #include #include -#include "univalue/univalue.h" +#include //! HTTP status codes enum HTTPStatusCode diff --git a/src/rpcrawtransaction.cpp b/src/rpcrawtransaction.cpp index fa3150cd7..4dec53396 100644 --- a/src/rpcrawtransaction.cpp +++ b/src/rpcrawtransaction.cpp @@ -31,7 +31,7 @@ #include -#include "univalue/univalue.h" +#include using namespace std; diff --git a/src/rpcserver.cpp b/src/rpcserver.cpp index dbee61efc..fa60f8c83 100644 --- a/src/rpcserver.cpp +++ b/src/rpcserver.cpp @@ -13,7 +13,7 @@ #include "util.h" #include "utilstrencodings.h" -#include "univalue/univalue.h" +#include #include #include diff --git a/src/rpcserver.h b/src/rpcserver.h index 83cc37918..dde8dfdcc 100644 --- a/src/rpcserver.h +++ b/src/rpcserver.h @@ -17,7 +17,7 @@ #include -#include "univalue/univalue.h" +#include class CRPCCommand; diff --git a/src/test/base58_tests.cpp b/src/test/base58_tests.cpp index 9e74f5f42..9845df697 100644 --- a/src/test/base58_tests.cpp +++ b/src/test/base58_tests.cpp @@ -18,7 +18,7 @@ #include #include -#include "univalue/univalue.h" +#include extern UniValue read_json(const std::string& jsondata); diff --git a/src/test/rpc_tests.cpp b/src/test/rpc_tests.cpp index 1bd59497f..2a486f08e 100644 --- a/src/test/rpc_tests.cpp +++ b/src/test/rpc_tests.cpp @@ -13,7 +13,7 @@ #include #include -#include "univalue/univalue.h" +#include using namespace std; diff --git a/src/test/rpc_wallet_tests.cpp b/src/test/rpc_wallet_tests.cpp index 52f41be8a..2e652f76e 100644 --- a/src/test/rpc_wallet_tests.cpp +++ b/src/test/rpc_wallet_tests.cpp @@ -14,7 +14,7 @@ #include #include -#include "univalue/univalue.h" +#include using namespace std; diff --git a/src/test/script_tests.cpp b/src/test/script_tests.cpp index 225da0801..882f9eb19 100644 --- a/src/test/script_tests.cpp +++ b/src/test/script_tests.cpp @@ -27,7 +27,7 @@ #include #include -#include "univalue/univalue.h" +#include using namespace std; diff --git a/src/test/sighash_tests.cpp b/src/test/sighash_tests.cpp index 4b9646156..6fca64d5d 100644 --- a/src/test/sighash_tests.cpp +++ b/src/test/sighash_tests.cpp @@ -20,7 +20,7 @@ #include -#include "univalue/univalue.h" +#include extern UniValue read_json(const std::string& jsondata); diff --git a/src/test/transaction_tests.cpp b/src/test/transaction_tests.cpp index e70ebddc2..beec39667 100644 --- a/src/test/transaction_tests.cpp +++ b/src/test/transaction_tests.cpp @@ -26,7 +26,7 @@ #include #include -#include "univalue/univalue.h" +#include using namespace std; diff --git a/src/test/univalue_tests.cpp b/src/test/univalue_tests.cpp index ee31c0955..945c1acbe 100644 --- a/src/test/univalue_tests.cpp +++ b/src/test/univalue_tests.cpp @@ -6,7 +6,7 @@ #include #include #include -#include "univalue/univalue.h" +#include #include "test/test_bitcoin.h" #include diff --git a/src/wallet/rpcdump.cpp b/src/wallet/rpcdump.cpp index 7e22faac3..c431fc401 100644 --- a/src/wallet/rpcdump.cpp +++ b/src/wallet/rpcdump.cpp @@ -20,7 +20,7 @@ #include #include -#include "univalue/univalue.h" +#include #include diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index 5d182f3d4..30b854477 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -22,7 +22,7 @@ #include -#include "univalue/univalue.h" +#include using namespace std; From 95acf3cc6d90d9406030ce897efdee8be0550a53 Mon Sep 17 00:00:00 2001 From: Jonas Schnelli Date: Thu, 1 Oct 2015 13:01:58 +0200 Subject: [PATCH 4/4] remove $(@F) and subdirs from univalue make --- src/Makefile.am | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Makefile.am b/src/Makefile.am index 301880dbc..462774389 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -36,8 +36,8 @@ LIBUNIVALUE=univalue/lib/libunivalue.la $(LIBSECP256K1): $(wildcard secp256k1/src/*) $(wildcard secp256k1/include/*) $(AM_V_at)$(MAKE) $(AM_MAKEFLAGS) -C $(@D) $(@F) -$(LIBUNIVALUE): $(wildcard univalue/lib/*) $(wildcard univalue/include/*) - $(AM_V_at)$(MAKE) $(AM_MAKEFLAGS) -C $(@D) $(@F) +$(LIBUNIVALUE): $(wildcard univalue/lib/*) + $(AM_V_at)$(MAKE) $(AM_MAKEFLAGS) -C univalue/ # Make is not made aware of per-object dependencies to avoid limiting building parallelization # But to build the less dependent modules first, we manually select their order here: