summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--libjsonpp/jsonpp.h9
-rw-r--r--libjsonpp/serialize.cpp230
-rw-r--r--libjsonpp/testParse.cpp2
-rw-r--r--libjsonpp/testSerialise.cpp15
4 files changed, 120 insertions, 136 deletions
diff --git a/libjsonpp/jsonpp.h b/libjsonpp/jsonpp.h
index 45c7415..df628ae 100644
--- a/libjsonpp/jsonpp.h
+++ b/libjsonpp/jsonpp.h
@@ -32,21 +32,12 @@ namespace json {
Value(const X & x) : VT(x) { }
};
- Object parseObject(Glib::ustring::const_iterator &);
- Object parseObject(const Glib::ustring &);
Value parseValue(std::istream &);
Value parseValue(std::istream &, const std::string & encoding);
Value parseValue(const Glib::ustring & s);
Value parseValue(Glib::ustring::const_iterator & s);
- 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);
}
#pragma GCC visibility pop
diff --git a/libjsonpp/serialize.cpp b/libjsonpp/serialize.cpp
index 97cf7ba..7c5cd06 100644
--- a/libjsonpp/serialize.cpp
+++ b/libjsonpp/serialize.cpp
@@ -1,149 +1,127 @@
#include "jsonpp.h"
#include <glibmm/convert.h>
#include <ios>
+#include <iomanip>
namespace json {
+ const std::string null("null");
+ const std::string utf8("utf-8");
+
class JsonSerialize : public boost::static_visitor<> {
public:
JsonSerialize(std::ostream & out, const std::string & encoding) :
- o(out),
+ s(out),
e(encoding) {
+ s << std::boolalpha // for Boolean
+ << std::defaultfloat // for Number
+ << std::setfill('0') // for String \uNNNN
+ ;
+ }
+ void operator()(const Value & v) const {
+ boost::apply_visitor(*this, v);
}
- 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 std::string & str) const {
+ (*this)(str, e);
}
- void operator()(const Object & s) const {
- serializeObject(s, o, e);
+ void operator()(const String & str) const {
+ (*this)(str, e);
}
- void operator()(const Null & s) const {
- serializeNull(s, o, e);
+ void operator()(const String & str, const std::string & enc) const {
+ if (!enc.empty()) {
+ serializeString(Glib::convert(str, enc, utf8));
+ }
+ else {
+ serializeString(str);
+ }
}
- void operator()(const Boolean & s) const {
- serializeBoolean(s, o, e);
+ void serializeString(const String & str) const {
+ s << '"';
+ for (auto i = str.begin(); i != str.end(); ) {
+ const 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 == '\\')) {
+ const 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:
+ s << "\\u" << std::setw(4) << std::hex << c << std::setw(1);
+ break;
+ }
+ i++;
+ }
+ }
+ s << '"';
}
- 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 << '{';
- for (const Object::value_type & v : o) {
- if (&v != &*o.begin()) {
- s << ',';
+ void operator()(const Number & n) const {
+ s << std::dec << n;
}
- 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 << '[';
- for (const Array::value_type & v : a) {
- if (&v != &*a.begin()) {
- s << ',';
+ void operator()(const Array & a) const {
+ s << '[';
+ for (const Array::value_type & v : a) {
+ if (&v != &*a.begin()) {
+ s << ',';
+ }
+ (*this)(*v);
+ }
+ 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++;
+ void operator()(const Object & o) const {
+ s << '{';
+ for (const Object::value_type & v : o) {
+ if (&v != &*o.begin()) {
+ s << ',';
+ }
+ (*this)(v.first);
+ s << ':';
+ (*this)(*v.second);
+ }
+ s << '}';
}
- if (start == str.begin() && i == str.end()) {
- s << str.raw();
- break;
+ void operator()(const Null &) const {
+ s << null;
}
- else if (start != i) {
- s << Glib::ustring(start, i).raw();
+ void operator()(const Boolean & b) const {
+ s << b;
}
- 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.unsetf(std::ios::fixed);
- s << n;
- }
-
- void serializeBoolean(const Boolean & b, std::ostream & s, const std::string & ) {
- s << (b ? "true" : "false");
- }
-
- void serializeNull(const Null &, std::ostream & s, const std::string & ) {
- s << "null";
- }
+ private:
+ std::ostream & s;
+ const std::string & e;
+ };
- Glib::ustring serializeObject(const Object & o, const std::string & enc) {
- std::stringstream out;
- serializeObject(o, out, enc);
- return out.str();
+ void serializeValue(const Value & v, std::ostream & s, const std::string & enc) {
+ JsonSerialize(s, enc)(v);
}
}
diff --git a/libjsonpp/testParse.cpp b/libjsonpp/testParse.cpp
index 77fe975..30cf85e 100644
--- a/libjsonpp/testParse.cpp
+++ b/libjsonpp/testParse.cpp
@@ -127,7 +127,7 @@ BOOST_AUTO_TEST_CASE( parse_string_simple )
BOOST_AUTO_TEST_CASE( parse_object_withStringContainingQuote )
{
const Glib::ustring val(" { \"key1\": \"value1\", \"key2\": \"value\\\"2\\\"\", \"key3\": 3 } ");
- auto obj = json::parseObject(val);
+ auto obj = boost::get<json::Object>(json::parseValue(val));
BOOST_REQUIRE_EQUAL(3, obj.size());
BOOST_REQUIRE_EQUAL("value1", boost::get<json::String>(*obj["key1"]));
BOOST_REQUIRE_EQUAL("value\"2\"", boost::get<json::String>(*obj["key2"]));
diff --git a/libjsonpp/testSerialise.cpp b/libjsonpp/testSerialise.cpp
index fb90930..e1d7af2 100644
--- a/libjsonpp/testSerialise.cpp
+++ b/libjsonpp/testSerialise.cpp
@@ -81,6 +81,21 @@ BOOST_AUTO_TEST_CASE( serialise_whitespace )
BOOST_REQUIRE_EQUAL("\"\\r\\n\\t\"", writeString(Glib::ustring("\r\n\t")));
}
+BOOST_AUTO_TEST_CASE( serialise_control )
+{
+ BOOST_REQUIRE_EQUAL("\"\\b\\f\"", writeString(Glib::ustring("\b\f")));
+}
+
+BOOST_AUTO_TEST_CASE( serialise_slashes )
+{
+ BOOST_REQUIRE_EQUAL("\"\\\\\\/\"", writeString(Glib::ustring("\\/")));
+}
+
+BOOST_AUTO_TEST_CASE( serialise_other )
+{
+ BOOST_REQUIRE_EQUAL("\"\\u000b\\u0007\"", writeString(Glib::ustring("\v\a")));
+}
+
BOOST_AUTO_TEST_CASE( serialise_quotes )
{
BOOST_REQUIRE_EQUAL("\"string with \\\" in\"", writeString(Glib::ustring("string with \" in")));