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(); +	} +} +  | 
