summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--libjsonpp/Jamfile.jam20
-rw-r--r--libjsonpp/jsonpp.h48
-rw-r--r--libjsonpp/parse.cpp223
-rw-r--r--libjsonpp/pch.hpp12
-rw-r--r--libjsonpp/serialize.cpp149
5 files changed, 452 insertions, 0 deletions
diff --git a/libjsonpp/Jamfile.jam b/libjsonpp/Jamfile.jam
new file mode 100644
index 0000000..f3d0c6c
--- /dev/null
+++ b/libjsonpp/Jamfile.jam
@@ -0,0 +1,20 @@
+import package ;
+
+alias glibmm : : : :
+ <cflags>"`pkg-config --cflags glibmm-2.4`"
+ <linkflags>"`pkg-config --libs glibmm-2.4`"
+ ;
+
+cpp-pch pch : pch.hpp :
+ <library>glibmm
+ ;
+lib jsonpp :
+ pch [ glob *.cpp ]
+ :
+ <include>.
+ <library>glibmm
+ : :
+ <include>.
+ ;
+
+package.install install : <install-source-root>. : : jsonpp : [ glob *.h ] ;
diff --git a/libjsonpp/jsonpp.h b/libjsonpp/jsonpp.h
new file mode 100644
index 0000000..33f5dab
--- /dev/null
+++ b/libjsonpp/jsonpp.h
@@ -0,0 +1,48 @@
+#ifndef JSON_H
+#define JSON_H
+
+#include <glibmm/ustring.h>
+#include <boost/shared_ptr.hpp>
+#include <boost/variant.hpp>
+#include <map>
+#include <list>
+
+namespace json {
+ typedef Glib::ustring String;
+ typedef double Number;
+ typedef bool Boolean;
+ class Null { };
+ class Value;
+ typedef boost::shared_ptr<Value> ValuePtr;
+ typedef std::map<std::string, ValuePtr> Object;
+ typedef std::list<ValuePtr> Array;
+ typedef boost::variant<Null, String, Number, Object, Array, Boolean> VT;
+ class Value : public VT {
+ public:
+ Value() : VT(Null()) { }
+
+ template <class X>
+ Value(const X & x) : VT(x) { }
+ };
+
+ Object parseObject(Glib::ustring::const_iterator &);
+ Object parseObject(const Glib::ustring &);
+ String parseString(Glib::ustring::const_iterator & s);
+ Number parseNumber(Glib::ustring::const_iterator & s);
+ Boolean parseBoolean(Glib::ustring::const_iterator & s);
+ Null parseNull(Glib::ustring::const_iterator & s);
+ Value parseValue(Glib::ustring::const_iterator & s);
+ Array parseArray(Glib::ustring::const_iterator &);
+
+ void serializeObject(const Object &, std::ostream & s, const std::string & encoding);
+ void serializeValue(const Value &, std::ostream & s, const std::string & encoding);
+ void serializeArray(const Array &, std::ostream & s, const std::string & encoding);
+ void serializeString(const String &, std::ostream & s, const std::string & encoding);
+ void serializeNumber(const Number &, std::ostream & s, const std::string & encoding);
+ void serializeBoolean(const Boolean &, std::ostream & s, const std::string & encoding);
+ void serializeNull(const Null &, std::ostream & s, const std::string & encoding);
+ Glib::ustring serializeObject(const Object &, const std::string & encoding);
+}
+
+#endif
+
diff --git a/libjsonpp/parse.cpp b/libjsonpp/parse.cpp
new file mode 100644
index 0000000..565c9e1
--- /dev/null
+++ b/libjsonpp/parse.cpp
@@ -0,0 +1,223 @@
+#include <pch.hpp>
+#include "jsonpp.h"
+
+namespace json {
+ class ParseError { };
+ String parseString(Glib::ustring::const_iterator & s) {
+ while (Glib::Unicode::isspace(*s)) s++;
+ if (*s++ != '"') throw ParseError();
+ String str;
+ while (*s != '"') {
+ if (*s == '\\') {
+ switch (*s) {
+ case '"':
+ str += '"';
+ break;
+ case '\\':
+ str += '\\';
+ break;
+ case '/':
+ str += '/';
+ break;
+ case 'b':
+ str += gunichar(8);
+ break;
+ case 'f':
+ str += gunichar(12);
+ break;
+ case 'n':
+ str += gunichar(10);
+ break;
+ case 'r':
+ str += gunichar(13);
+ break;
+ case 't':
+ str += gunichar(9);
+ break;
+ case 'u':
+ {
+ unsigned int c = 0;
+ for (int n = 0; n < 4; n += 1) {
+ c *= 16;
+ if (*s >= '0' && *s <= '9') {
+ c += (*s - '0');
+ }
+ else if (*s >= 'a' && *s <= 'f') {
+ c += (*s - 'a');
+ }
+ else if (*s >= 'A' && *s <= 'F') {
+ c += (*s - 'A');
+ }
+ else {
+ throw ParseError();
+ }
+ s++;
+ }
+ str += gunichar(c);
+ s--;
+ }
+ break;
+ default:
+ throw ParseError();
+ }
+ }
+ else {
+ str += *s;
+ }
+ s++;
+ }
+ if (*s++ != '"') throw ParseError();
+ return str;
+ }
+ Number parseNumber(Glib::ustring::const_iterator & s) {
+ while (Glib::Unicode::isspace(*s)) s++;
+ bool neg = false;
+ double v = 0;
+ if (*s == '-') {
+ neg = true;
+ s++;
+ }
+ bool dot = false, e = false;
+ double frac = 1;
+ unsigned int digits = 0;
+ while (true) {
+ if (Glib::Unicode::isdigit(*s)) {
+ if (dot) {
+ frac /= 10;
+ v += (frac * (*s - '0'));
+ }
+ else {
+ v *= 10;
+ v += (*s - '0');
+ digits += 1;
+ }
+ }
+ else if (*s == '.') {
+ if (dot || e) throw ParseError();
+ dot = true;
+ }
+ else if (*s == 'e' || *s == 'E') {
+ e = true;
+ s++;
+ bool eneg = false;
+ if (*s == '+') {
+ }
+ else if (*s == '-') {
+ eneg = true;
+ s++;
+ }
+ int ev = 0;
+ while (Glib::Unicode::isdigit(*s)) {
+ ev *= 10;
+ ev += (*s - '0');
+ s++;
+ }
+ while (ev--) {
+ if (eneg) {
+ v /= 10;
+ }
+ else {
+ v *= 10;
+ }
+ }
+ break;
+ }
+ else {
+ break;
+ }
+ s++;
+ }
+ if (digits < 1) throw ParseError();
+ return neg ? -v : v;
+ }
+ Value parseValue(Glib::ustring::const_iterator & s) {
+ while (Glib::Unicode::isspace(*s)) s++;
+ switch (*s) {
+ case '"':
+ return parseString(s);
+ case '{':
+ return parseObject(s);
+ case '[':
+ return parseArray(s);
+ case 'n':
+ return parseNull(s);
+ case 't':
+ case 'f':
+ return parseBoolean(s);
+ default:
+ return parseNumber(s);
+ }
+ }
+ Object parseObject(const Glib::ustring & s) {
+ Glib::ustring::const_iterator i = s.begin();
+ Object o = parseObject(i);
+ if (i != s.end()) throw ParseError();
+ return o;
+ }
+ Object parseObject(Glib::ustring::const_iterator & s) {
+ Object o;
+ while (Glib::Unicode::isspace(*s)) s++;
+ if (*s != '{') throw ParseError();
+ do {
+ s++;
+ while (Glib::Unicode::isspace(*s)) s++;
+ if (*s == '}') return o;
+ String key = parseString(s);
+ while (Glib::Unicode::isspace(*s)) s++;
+ if (*s++ != ':') throw ParseError();
+ if (!o.insert(Object::value_type(key, ValuePtr(new Value(parseValue(s))))).second) throw ParseError();
+ while (Glib::Unicode::isspace(*s)) s++;
+ } while (*s == ',');
+ if (*s == '}') {
+ s++;
+ while (Glib::Unicode::isspace(*s)) s++;
+ return o;
+ }
+ throw ParseError();
+ }
+ Array parseArray(Glib::ustring::const_iterator & s) {
+ Array a;
+ while (Glib::Unicode::isspace(*s)) s++;
+ if (*s != '[') throw ParseError();
+ do {
+ s++;
+ while (Glib::Unicode::isspace(*s)) s++;
+ if (*s == ']') {
+ s++;
+ return a;
+ }
+ a.push_back(ValuePtr(new Value(parseValue(s))));
+ while (Glib::Unicode::isspace(*s)) s++;
+ } while (*s == ',');
+ if (*s == ']') {
+ s++;
+ return a;
+ }
+ throw ParseError();
+ }
+ Null parseNull(Glib::ustring::const_iterator & s) {
+ if (*s++ != 'n') throw ParseError();
+ if (*s++ != 'u') throw ParseError();
+ if (*s++ != 'l') throw ParseError();
+ if (*s++ != 'l') throw ParseError();
+ return Null();
+ }
+ Boolean parseBoolean(Glib::ustring::const_iterator & s) {
+ if (*s == 't') {
+ s++;
+ if (*s++ != 'r') throw ParseError();
+ if (*s++ != 'u') throw ParseError();
+ if (*s++ != 'e') throw ParseError();
+ return true;
+ }
+ else if (*s == 'f') {
+ s++;
+ if (*s++ != 'a') throw ParseError();
+ if (*s++ != 'l') throw ParseError();
+ if (*s++ != 's') throw ParseError();
+ if (*s++ != 'e') throw ParseError();
+ return false;
+ }
+ throw ParseError();
+ }
+}
diff --git a/libjsonpp/pch.hpp b/libjsonpp/pch.hpp
new file mode 100644
index 0000000..c0123d3
--- /dev/null
+++ b/libjsonpp/pch.hpp
@@ -0,0 +1,12 @@
+#ifdef BOOST_BUILD_PCH_ENABLED
+#ifndef JSON_PCH
+#define JSON_PCH
+
+#include <boost/variant.hpp>
+#include <glibmm/ustring.h>
+#include <map>
+#include <list>
+
+#endif
+#endif
+
diff --git a/libjsonpp/serialize.cpp b/libjsonpp/serialize.cpp
new file mode 100644
index 0000000..1b542e4
--- /dev/null
+++ b/libjsonpp/serialize.cpp
@@ -0,0 +1,149 @@
+#include <pch.hpp>
+#include "jsonpp.h"
+#include <boost/foreach.hpp>
+#include <glibmm/convert.h>
+
+namespace json {
+ class JsonSerialize : public boost::static_visitor<> {
+ public:
+ JsonSerialize(std::ostream & out, const std::string & encoding) :
+ o(out),
+ e(encoding) {
+ }
+ void operator()(const String & s) const {
+ serializeString(s, o, e);
+ }
+ void operator()(const Number & s) const {
+ serializeNumber(s, o, e);
+ }
+ void operator()(const Array & s) const {
+ serializeArray(s, o, e);
+ }
+ void operator()(const Object & s) const {
+ serializeObject(s, o, e);
+ }
+ void operator()(const Null & s) const {
+ serializeNull(s, o, e);
+ }
+ void operator()(const Boolean & s) const {
+ serializeBoolean(s, o, e);
+ }
+ private:
+ std::ostream & o;
+ std::string e;
+ };
+
+ void serializeObject(const Object & o, std::ostream & s, const std::string & renc) {
+ std::string enc(renc == "utf-8" ? std::string() : renc);
+ s << std::boolalpha;
+ s << std::fixed;
+ s << '{';
+ BOOST_FOREACH(const Object::value_type & v, o) {
+ if (&v != &*o.begin()) {
+ s << ',';
+ }
+ serializeString(v.first, s, enc);
+ s << ':';
+ serializeValue(*v.second, s, enc);
+ }
+ s << '}';
+ }
+
+ void serializeValue(const Value & v, std::ostream & s, const std::string & enc) {
+ boost::apply_visitor(JsonSerialize(s, enc), v);
+ }
+
+ void serializeArray(const Array & a, std::ostream & s, const std::string & enc) {
+ s << '[';
+ BOOST_FOREACH(const Array::value_type & v, a) {
+ if (&v != &*a.begin()) {
+ s << ',';
+ }
+ serializeValue(*v, s, enc);
+ }
+ s << ']';
+ }
+
+ void serializeString(const String & str, std::ostream & s) {
+ s << '"';
+ for (auto i = str.begin(); i != str.end(); ) {
+ auto start = i;
+ while (i != str.end() && *i >= 32 && *i != '/' && *i != '"' && *i != '\\') {
+ i++;
+ }
+ if (start == str.begin() && i == str.end()) {
+ s << str.raw();
+ break;
+ }
+ else if (start != i) {
+ s << Glib::ustring(start, i).raw();
+ }
+ while (i != str.end() && (*i < 32 || *i == '/' || *i == '"' || *i == '\\')) {
+ gunichar c = *i;
+ switch (c) {
+ case '\f':
+ s << "\\f";
+ break;
+ case '\t':
+ s << "\\t";
+ break;
+ case '\n':
+ s << "\\n";
+ break;
+ case '\b':
+ s << "\\b";
+ break;
+ case '\r':
+ s << "\\r";
+ break;
+ case '/':
+ s << "\\/";
+ break;
+ case '\\':
+ s << "\\\\";
+ break;
+ case '"':
+ s << "\\\"";
+ break;
+ default:
+ char buf[7];
+ snprintf(buf, sizeof(buf), "\\u%04x", c);
+ s << buf;
+ break;
+ }
+ i++;
+ }
+ }
+ s << '"';
+ }
+
+ void serializeString(const String & str, std::ostream & o, const std::string & encoding) {
+ if (!encoding.empty()) {
+ std::stringstream s;
+ serializeString(str, s);
+ o << Glib::convert(s.str(), encoding, "utf-8");
+ }
+ else {
+ serializeString(str, o);
+ }
+ }
+
+ void serializeNumber(const Number & n, std::ostream & s, const std::string & ) {
+ s << n;
+ }
+
+ void serializeBoolean(const Boolean & b, std::ostream & s, const std::string & ) {
+ s << b;
+ }
+
+ void serializeNull(const Null &, std::ostream & s, const std::string & ) {
+ s << "null";
+ }
+
+ Glib::ustring serializeObject(const Object & o, const std::string & enc) {
+ std::stringstream out;
+ serializeObject(o, out, enc);
+ return out.str();
+ }
+}
+