[Pkg-bitcoin-commits] [libunivalue] 01/76: Initial revision of the universal value and JSON library

Jonas Smedegaard dr at jones.dk
Mon Apr 4 09:18:26 UTC 2016


This is an automated email from the git hooks/post-receive script.

js pushed a commit to branch master
in repository libunivalue.

commit 55ef0b01d7b82cfef801219256fb88edb417afc2
Author: Jeff Garzik <jgarzik at bitpay.com>
Date:   Thu Jun 12 16:04:04 2014 -0400

    Initial revision of the universal value and JSON library
---
 .gitignore         |  18 ++++
 AUTHORS            |   1 +
 COPYING            |  19 ++++
 ChangeLog          |   1 +
 Makefile.am        |  10 +++
 NEWS               |   1 +
 README             |   1 +
 autogen.sh         |   5 ++
 configure.ac       |  28 ++++++
 univalue.cpp       | 133 ++++++++++++++++++++++++++++
 univalue.h         |  79 +++++++++++++++++
 univalue_read.cpp  | 253 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 univalue_write.cpp | 145 ++++++++++++++++++++++++++++++
 13 files changed, 694 insertions(+)

diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..e14b9d9
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,18 @@
+.deps/
+INSTALL
+Makefile
+Makefile.in
+aclocal.m4
+autom4te.cache/
+compile
+config.log
+config.status
+configure
+depcomp
+install-sh
+missing
+stamp-h1
+univalue-config.h*
+
+*.o
+libunivalue.a
diff --git a/AUTHORS b/AUTHORS
new file mode 100644
index 0000000..53315d7
--- /dev/null
+++ b/AUTHORS
@@ -0,0 +1 @@
+Jeff Garzik
diff --git a/COPYING b/COPYING
new file mode 100644
index 0000000..1fb429f
--- /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/ChangeLog b/ChangeLog
new file mode 100644
index 0000000..f853f9d
--- /dev/null
+++ b/ChangeLog
@@ -0,0 +1 @@
+See git changelog
diff --git a/Makefile.am b/Makefile.am
new file mode 100644
index 0000000..7d7bc3d
--- /dev/null
+++ b/Makefile.am
@@ -0,0 +1,10 @@
+
+include_HEADERS = univalue.h
+
+lib_LIBRARIES = libunivalue.a
+
+libunivalue_a_SOURCES = \
+	univalue.cpp \
+	univalue_read.cpp \
+	univalue_write.cpp
+
diff --git a/NEWS b/NEWS
new file mode 100644
index 0000000..6c2f9bb
--- /dev/null
+++ b/NEWS
@@ -0,0 +1 @@
+No news is good news.
diff --git a/README b/README
new file mode 100644
index 0000000..e6902c6
--- /dev/null
+++ b/README
@@ -0,0 +1 @@
+univalue library
diff --git a/autogen.sh b/autogen.sh
new file mode 100755
index 0000000..5b883a6
--- /dev/null
+++ b/autogen.sh
@@ -0,0 +1,5 @@
+#!/bin/sh
+set -e
+srcdir="$(dirname $0)"
+cd "$srcdir"
+autoreconf --install --force
diff --git a/configure.ac b/configure.ac
new file mode 100644
index 0000000..618c368
--- /dev/null
+++ b/configure.ac
@@ -0,0 +1,28 @@
+AC_INIT([univalue], [0.0.1],
+        [http://github.com/jgarzik/univalue/])
+
+AC_PREREQ(2.52)
+AC_CONFIG_SRCDIR([univalue.cpp])
+AM_INIT_AUTOMAKE([gnu])
+AC_CONFIG_HEADERS([univalue-config.h])
+
+
+AC_PROG_CXX
+AC_PROG_CC
+AC_PROG_CPP
+AC_PROG_CXXCPP
+AC_PROG_INSTALL
+AC_PROG_OBJC
+AC_PROG_LN_S
+AC_PROG_MKDIR_P
+AC_PROG_SED
+AC_PATH_TOOL(AR, ar)
+AC_PATH_TOOL(RANLIB, ranlib)
+AC_PATH_TOOL(STRIP, strip)
+PKG_PROG_PKG_CONFIG
+
+AC_LANG_PUSH([C++])
+
+AC_CONFIG_FILES([Makefile])
+AC_OUTPUT
+
diff --git a/univalue.cpp b/univalue.cpp
new file mode 100644
index 0000000..45b21e9
--- /dev/null
+++ b/univalue.cpp
@@ -0,0 +1,133 @@
+
+#include <stdint.h>
+#include <ctype.h>
+#include <sstream>
+#include "univalue.h"
+
+using namespace std;
+
+void UniValue::clear()
+{
+    typ = VNULL;
+    val.clear();
+    keys.clear();
+    values.clear();
+}
+
+bool UniValue::setNull()
+{
+    clear();
+    return true;
+}
+
+bool UniValue::setBool(bool val)
+{
+    clear();
+    typ = (val ? VTRUE : VFALSE);
+    return true;
+}
+
+static bool validNumStr(const string& s)
+{
+    bool seenDec = false;
+    for (unsigned int i = 0; i < s.size(); i++) {
+        switch (s[i]) {
+        case '0':
+        case '1':
+        case '2':
+        case '3':
+        case '4':
+        case '5':
+        case '6':
+        case '7':
+        case '8':
+        case '9':
+            // do nothing
+            break;
+
+        case '.':
+            if (seenDec)
+                return false;
+            seenDec = true;
+            break;
+
+        default:
+            return false;
+        }
+    }
+
+    return true;
+}
+
+bool UniValue::setNumStr(string val_)
+{
+    if (!validNumStr(val))
+        return false;
+
+    clear();
+    typ = VNUM;
+    val = val_;
+    return true;
+}
+
+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 << val;
+
+    return setNumStr(oss.str());
+}
+
+bool UniValue::setStr(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(UniValue& val)
+{
+    if (typ != VARR)
+        return false;
+
+    values.push_back(val);
+    return true;
+}
+
+bool UniValue::pushKV(string key, UniValue& val)
+{
+    if (typ != VOBJ)
+        return false;
+
+    keys.push_back(key);
+    values.push_back(val);
+    return true;
+}
+
diff --git a/univalue.h b/univalue.h
new file mode 100644
index 0000000..5260f71
--- /dev/null
+++ b/univalue.h
@@ -0,0 +1,79 @@
+#ifndef __BITCOIN_UNIVALUE_H__
+#define __BITCOIN_UNIVALUE_H__
+
+#include <stdint.h>
+#include <string>
+#include <vector>
+#include <cassert>
+
+class UniValue {
+public:
+    enum VType { VNULL, VOBJ, VARR, VSTR, VNUM, VTRUE, VFALSE, };
+
+    UniValue() { typ = VNULL; }
+    UniValue(UniValue::VType initialType, const std::string& initialStr = "") {
+        typ = initialType;
+        val = initialStr;
+    }
+    UniValue(int64_t val_) {
+        setInt(val_);
+    }
+    ~UniValue() {}
+
+    void clear();
+
+    bool setNull();
+    bool setBool(bool val);
+    bool setNumStr(std::string val);
+    bool setInt(int64_t val);
+    bool setFloat(double val);
+    bool setStr(std::string val);
+    bool setArray();
+    bool setObject();
+
+    enum VType getType() { return typ; }
+    std::string getValStr() { return val; }
+
+    bool isNull() { return (typ == VNULL); }
+    bool isTrue() { return (typ == VTRUE); }
+    bool isFalse() { return (typ == VFALSE); }
+    bool isBool() { return (typ == VTRUE || typ == VFALSE); }
+    bool isStr() { return (typ == VSTR); }
+    bool isNum() { return (typ == VNUM); }
+    bool isArray() { return (typ == VARR); }
+    bool isObject() { return (typ == VOBJ); }
+
+    bool push(UniValue& val);
+    bool push(const std::string& val_) {
+        UniValue tmpVal(VSTR, val_);
+        return push(tmpVal);
+    }
+
+    bool pushKV(std::string key, UniValue& val);
+    bool pushKV(std::string key, const std::string val) {
+        UniValue tmpVal(VSTR, val);
+        return pushKV(key, tmpVal);
+    }
+    bool pushKV(std::string key, int64_t val) {
+        UniValue tmpVal(val);
+        return pushKV(key, tmpVal);
+    }
+
+    std::string write(unsigned int prettyIndent = 0,
+                      unsigned int indentLevel = 0);
+
+    void read(const char *raw);
+
+private:
+    UniValue::VType typ;
+    std::string val;                       // numbers are stored as C++ strings
+    std::vector<std::string> keys;
+    std::vector<UniValue> values;
+
+    void writeOpen(unsigned int prettyIndent, unsigned int indentLevel, std::string& s);
+    void writeClose(unsigned int prettyIndent, unsigned int indentLevel, std::string& s);
+    void writeArray(unsigned int prettyIndent, unsigned int indentLevel, std::string& s);
+    void writeObject(unsigned int prettyIndent, unsigned int indentLevel, std::string& s);
+};
+
+#endif // __BITCOIN_UNIVALUE_H__
diff --git a/univalue_read.cpp b/univalue_read.cpp
new file mode 100644
index 0000000..63d5f9b
--- /dev/null
+++ b/univalue_read.cpp
@@ -0,0 +1,253 @@
+
+#include <string.h>
+#include <vector>
+#include <stdio.h>
+#include <cassert>
+#include <stdexcept>
+#include "univalue.h"
+
+using namespace std;
+
+void UniValue::read(const char *raw)
+{
+    clear();
+
+    bool expectName = false;
+    vector<UniValue*> stack;
+
+    while (*raw) {
+        switch (*raw) {
+
+        case '{':
+        case '[': {
+            VType utyp = (*raw == '{' ? VOBJ : VARR);
+            if (!stack.size()) {
+                setObject();
+                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;
+
+            raw++;
+            break;
+            }
+
+        case '}':
+        case ']': {
+            if (!stack.size())
+                throw runtime_error("json parse: unexpected }]");
+
+            VType utyp = (*raw == '}' ? VOBJ : VARR);
+            UniValue *top = stack.back();
+            if (utyp != top->getType())
+                throw runtime_error("json parse: mismatched }]");
+
+            stack.pop_back();
+            expectName = false;
+
+            raw++;
+            break;
+            }
+
+        case ':': {
+            if (!stack.size() || expectName)
+                throw runtime_error("json parse: : stack empty or want name");
+
+            UniValue *top = stack.back();
+            if (top->getType() != VOBJ)
+                throw runtime_error("json parse: : parent not object");
+
+            raw++;
+            break;
+            }
+
+        case ',': {
+            if (!stack.size() || expectName)
+                throw runtime_error("json parse: , stack empty or want name");
+
+            UniValue *top = stack.back();
+            if (top->getType() == VOBJ)
+                expectName = true;
+
+            raw++;
+            break;
+            }
+
+        case 'n':
+        case 't':
+        case 'f': {
+            if (!stack.size() || expectName)
+                throw runtime_error("json parse: ntf stack empty or want name");
+
+            VType utyp;
+            if (!strncmp(raw, "null", 4)) {
+                utyp = VNULL;
+                raw += 4;
+            } else if (!strncmp(raw, "true", 4)) {
+                utyp = VTRUE;
+                raw += 4;
+            } else if (!strncmp(raw, "false", 5)) {
+                utyp = VFALSE;
+                raw += 5;
+            } else
+                throw runtime_error("json parse: ntf unknown keyword");
+
+            UniValue tmpVal(utyp);
+            UniValue *top = stack.back();
+            top->values.push_back(tmpVal);
+
+            break;
+            }
+
+        case '-':
+        case '0':
+        case '1':
+        case '2':
+        case '3':
+        case '4':
+        case '5':
+        case '6':
+        case '7':
+        case '8':
+        case '9': {
+            if (!stack.size() || expectName)
+                throw runtime_error("json parse digits: stack empty or want name");
+
+            // part 1: int
+            string numStr;
+
+            const char *first = raw;
+            numStr += *raw;                       // copy first char
+            raw++;
+
+            if ((*first == '-') && (!isdigit(*raw)))
+                throw runtime_error("json parse digits 2: first char bad");
+
+            while ((*raw) && isdigit(*raw)) {     // copy digits
+                numStr += *raw;
+                raw++;
+            }
+
+            // part 2: frac
+            if (*raw == '.') {
+                numStr += *raw;                   // copy .
+                raw++;
+
+                if (!isdigit(*raw))
+                    throw runtime_error("json parse digits 3: want digit");
+                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))
+                    throw runtime_error("json parse digits 4: want digit");
+                while ((*raw) && isdigit(*raw)) { // copy digits
+                    numStr += *raw;
+                    raw++;
+                }
+            }
+
+            UniValue tmpVal(VNUM, numStr);
+            UniValue *top = stack.back();
+            top->values.push_back(tmpVal);
+
+            break;
+            }
+
+        case '"': {
+            if (!stack.size())
+                throw runtime_error("json parse string: stack empty");
+
+            raw++;                                // skip "
+
+            string valStr;
+
+            while (*raw) {
+                if (*raw < 0x20)
+                    throw runtime_error("json parse string: have ctl chars");
+
+                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':
+                        // TODO: not supported yet
+                        assert(0);
+                        break;
+                    default:
+                        throw runtime_error("json parse string: unknown escape");
+
+                    }
+
+                    raw++;                        // skip esc'd char
+                }
+
+                else if (*raw == '"') {
+                    raw++;                        // skip "
+                    break;                        // stop scanning
+                }
+
+                else {
+                    valStr += *raw;
+                    raw++;
+                }
+            }
+
+            UniValue *top = stack.back();
+
+            if (expectName) {
+                top->keys.push_back(valStr);
+                expectName = false;
+            } else {
+                UniValue tmpVal(VSTR, valStr);
+                top->values.push_back(tmpVal);
+            }
+
+            break;
+            }
+
+        case ' ':
+        case '\t':
+        case '\f':
+        case '\r':
+        case '\n':
+            raw++;                                // skip whitespace
+            break;
+        }
+    }
+
+    if (stack.size() != 0) {
+        char msg[64];
+        sprintf(msg, "json parse: too many toplevel obj, %lu", stack.size());
+        throw runtime_error(msg);
+    }
+}
+
diff --git a/univalue_write.cpp b/univalue_write.cpp
new file mode 100644
index 0000000..7641784
--- /dev/null
+++ b/univalue_write.cpp
@@ -0,0 +1,145 @@
+
+#include <ctype.h>
+#include <stdio.h>
+#include "univalue.h"
+
+// TODO: Using UTF8
+
+using namespace std;
+
+static bool initEscapes;
+static const char *escapes[256];
+
+static void initJsonEscape()
+{
+    escapes['"'] = "\\\"";
+    escapes['\\'] = "\\\\";
+    escapes['/'] = "\\/";
+    escapes['\b'] = "\\b";
+    escapes['\f'] = "\\f";
+    escapes['\n'] = "\\n";
+    escapes['\r'] = "\\r";
+    escapes['\t'] = "\\t";
+
+    initEscapes = true;
+}
+
+static string json_escape(const string& inS)
+{
+    if (!initEscapes)
+        initJsonEscape();
+
+    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)
+{
+    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 VTRUE:
+        s += "true";
+        break;
+    case VFALSE:
+        s += "false";
+        break;
+    }
+
+    return s;
+}
+
+static string spaceStr;
+
+static string indentStr(unsigned int prettyIndent, unsigned int indentLevel)
+{
+    unsigned int spaces = prettyIndent * indentLevel;
+    while (spaceStr.size() < spaces)
+        spaceStr += "                ";
+
+    return spaceStr.substr(0, spaces);
+}
+
+void UniValue::writeArray(unsigned int prettyIndent, unsigned int indentLevel, string& s)
+{
+    s += "[";
+    if (prettyIndent)
+        s += "\n";
+
+    for (unsigned int i = 0; i < values.size(); i++) {
+        if (prettyIndent)
+            s += indentStr(prettyIndent, indentLevel);
+        s += values[i].write(prettyIndent, indentLevel + 1);
+        if (i != (values.size() - 1))
+            s += ", ";
+        if (prettyIndent)
+            s += "\n";
+    }
+
+    if (prettyIndent)
+        s += indentStr(prettyIndent, indentLevel - 1);
+    s += "]";
+}
+
+void UniValue::writeObject(unsigned int prettyIndent, unsigned int indentLevel, string& s)
+{
+    s += "{";
+    if (prettyIndent)
+        s += "\n";
+
+    for (unsigned int i = 0; i < keys.size(); i++) {
+        if (prettyIndent)
+            s += indentStr(prettyIndent, indentLevel);
+        s += "\"" + json_escape(keys[i]) + "\": ";
+        s += values[i].write(prettyIndent, indentLevel + 1);
+        if (i != (values.size() - 1))
+            s += ",";
+        if (prettyIndent)
+            s += "\n";
+    }
+
+    if (prettyIndent)
+        s += indentStr(prettyIndent, indentLevel - 1);
+    s += "}";
+}
+

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-bitcoin/libunivalue.git



More information about the Pkg-bitcoin-commits mailing list