[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