From ab7081676adf140cc8967c5ef49641b9a37bae2b Mon Sep 17 00:00:00 2001 From: Vegard Storheil Eriksen Date: Mon, 10 Jan 2011 04:25:45 +0100 Subject: Add JSON parser/generator. --- json.cpp | 131 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ json.h | 32 ++++++++++++++++ 2 files changed, 163 insertions(+) create mode 100644 json.cpp create mode 100644 json.h 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 +#include +#include + +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 bool_p = qi::lit("false")[qi::_val = false] | qi::lit("true")[qi::_val = true]; + + qi::rule()> number_p = (qi::int_ >> !(qi::lit('.') | 'e' | 'E')) | qi::float_; + + qi::rule 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 string_p = '\"' >> *(char_p) >> '\"'; + + qi::rule value_p; + + qi::rule array_p = '[' >> -(value_p % ',') >> ']'; + + qi::rule()> key_value_p = string_p >> ":" >> value_p; + qi::rule 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& 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); +} diff --git a/json.h b/json.h new file mode 100644 index 0000000..0e18911 --- /dev/null +++ b/json.h @@ -0,0 +1,32 @@ +#ifndef JSON_H +#define JSON_H + +#include +#include +#include +#include + +#include + +namespace JSON { + // TODO: Support null. + typedef boost::make_recursive_variant< + bool, + int, + float, + std::string, + std::vector, + std::map + >::type Value; + + typedef std::vector Array; + typedef std::map 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 -- cgit v1.2.3