diff options
-rw-r--r-- | libjsonpp/Jamfile.jam | 20 | ||||
-rw-r--r-- | libjsonpp/jsonpp.h | 48 | ||||
-rw-r--r-- | libjsonpp/parse.cpp | 223 | ||||
-rw-r--r-- | libjsonpp/pch.hpp | 12 | ||||
-rw-r--r-- | libjsonpp/serialize.cpp | 149 |
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(); + } +} + |