diff options
author | Vegard Storheil Eriksen <zyp@jvnv.net> | 2011-01-10 04:25:45 +0100 |
---|---|---|
committer | Vegard Storheil Eriksen <zyp@jvnv.net> | 2011-01-10 04:25:45 +0100 |
commit | ab7081676adf140cc8967c5ef49641b9a37bae2b (patch) | |
tree | 48c7da25061db1c0f486699bba384c2475680c70 | |
parent | 9abc3cad022da793ae16912d7feced8eef58be3d (diff) |
Add JSON parser/generator.
-rw-r--r-- | json.cpp | 131 | ||||
-rw-r--r-- | json.h | 32 |
2 files changed, 163 insertions, 0 deletions
diff --git a/json.cpp b/json.cpp new file mode 100644 index 0000000..0277cce --- /dev/null +++ b/json.cpp @@ -0,0 +1,131 @@ +#include "json.h" + +#include <boost/spirit/include/qi.hpp> +#include <boost/spirit/include/phoenix_operator.hpp> +#include <boost/fusion/include/std_pair.hpp> + +namespace qi = boost::spirit::qi; + +using namespace JSON; + +bool JSON::parse(const std::string& s, Value& v) { + typedef std::string::const_iterator Iterator; + + qi::rule<Iterator, bool()> bool_p = qi::lit("false")[qi::_val = false] | qi::lit("true")[qi::_val = true]; + + qi::rule<Iterator, boost::variant<int, float>()> number_p = (qi::int_ >> !(qi::lit('.') | 'e' | 'E')) | qi::float_; + + qi::rule<Iterator, char()> char_p = (qi::char_ - '\"' - '\\') | '\\' >> ( + qi::char_('\"') | + qi::char_('\\') | + qi::char_('/') | + 'b' >> qi::attr('\b') | + 'f' >> qi::attr('\f') | + 'n' >> qi::attr('\n') | + 'r' >> qi::attr('\r') | + 't' >> qi::attr('\t') + ); + + qi::rule<Iterator, std::string()> string_p = '\"' >> *(char_p) >> '\"'; + + qi::rule<Iterator, Value()> value_p; + + qi::rule<Iterator, Array()> array_p = '[' >> -(value_p % ',') >> ']'; + + qi::rule<Iterator, std::pair<std::string, Value>()> key_value_p = string_p >> ":" >> value_p; + qi::rule<Iterator, Object()> object_p = '{' >> -(key_value_p % ',') >> '}'; + + value_p = qi::omit[*qi::space] >> (bool_p | number_p | string_p | array_p | object_p) >> qi::omit[*qi::space]; + + return qi::parse(s.begin(), s.end(), value_p, v); +} + +struct generate : public boost::static_visitor<std::ostream&> { + std::ostream& stream; + generate(std::ostream& s) : stream(s) {} + + std::ostream& operator()(const bool& x) const { + return stream << (x ? "true" : "false"); + } + + std::ostream& operator()(const int& x) const { + return stream << x; + } + + std::ostream& operator()(const float& x) const { + return stream << x; + } + + std::ostream& operator()(const std::string& x) const { + stream << '\"'; + for(std::string::const_iterator it = x.begin(); it != x.end(); it++) { + switch(*it) { + case '\"': + case '\\': + case '/': + stream << '\\' << *it; + break; + + case '\b': + stream << "\\b"; + break; + + case '\f': + stream << "\\f"; + break; + + case '\n': + stream << "\\n"; + break; + + case '\r': + stream << "\\r"; + break; + + case '\t': + stream << "\\t"; + break; + + default: + stream << *it; + } + } + return stream << '\"'; + } + + std::ostream& operator()(const Array& x) const { + stream << "["; + for(Array::const_iterator it = x.begin();;) { + boost::apply_visitor(generate(stream), *it); + + if(++it == x.end()) { + break; + } + + stream << ", "; + } + return stream << "]"; + } + + std::ostream& operator()(const Object& x) const { + stream << "{"; + for(Object::const_iterator it = x.begin();;) { + (*this)(it->first); + + stream << ": "; + + boost::apply_visitor(generate(stream), it->second); + + if(++it == x.end()) { + break; + } + + stream << ", "; + } + return stream << "}"; + } +}; + +std::ostream& operator<<(std::ostream& s, const Value& v) { + return boost::apply_visitor(generate(s), v); +} @@ -0,0 +1,32 @@ +#ifndef JSON_H +#define JSON_H + +#include <string> +#include <vector> +#include <map> +#include <iostream> + +#include <boost/variant.hpp> + +namespace JSON { + // TODO: Support null. + typedef boost::make_recursive_variant< + bool, + int, + float, + std::string, + std::vector<boost::recursive_variant_ >, + std::map<std::string, boost::recursive_variant_ > + >::type Value; + + typedef std::vector<Value> Array; + typedef std::map<std::string, Value> Object; + + //! Parse JSON string into value-tree. + bool parse(const std::string& s, Value& v); +}; + +//! Write JSON to stream. +std::ostream& operator<<(std::ostream& s, const JSON::Value& v); + +#endif |