summaryrefslogtreecommitdiff
path: root/boost/property_tree/json_parser/detail/write.hpp
diff options
context:
space:
mode:
Diffstat (limited to 'boost/property_tree/json_parser/detail/write.hpp')
-rw-r--r--boost/property_tree/json_parser/detail/write.hpp168
1 files changed, 168 insertions, 0 deletions
diff --git a/boost/property_tree/json_parser/detail/write.hpp b/boost/property_tree/json_parser/detail/write.hpp
new file mode 100644
index 0000000000..bba10038bb
--- /dev/null
+++ b/boost/property_tree/json_parser/detail/write.hpp
@@ -0,0 +1,168 @@
+// ----------------------------------------------------------------------------
+// Copyright (C) 2002-2006 Marcin Kalicinski
+//
+// Distributed under the Boost Software License, Version 1.0.
+// (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+//
+// For more information, see www.boost.org
+// ----------------------------------------------------------------------------
+#ifndef BOOST_PROPERTY_TREE_DETAIL_JSON_PARSER_WRITE_HPP_INCLUDED
+#define BOOST_PROPERTY_TREE_DETAIL_JSON_PARSER_WRITE_HPP_INCLUDED
+
+#include <boost/property_tree/ptree.hpp>
+#include <boost/next_prior.hpp>
+#include <boost/type_traits/make_unsigned.hpp>
+#include <string>
+#include <ostream>
+#include <iomanip>
+
+namespace boost { namespace property_tree { namespace json_parser
+{
+
+ // Create necessary escape sequences from illegal characters
+ template<class Ch>
+ std::basic_string<Ch> create_escapes(const std::basic_string<Ch> &s)
+ {
+ std::basic_string<Ch> result;
+ typename std::basic_string<Ch>::const_iterator b = s.begin();
+ typename std::basic_string<Ch>::const_iterator e = s.end();
+ while (b != e)
+ {
+ typedef typename make_unsigned<Ch>::type UCh;
+ UCh c(*b);
+ // This assumes an ASCII superset. But so does everything in PTree.
+ // We escape everything outside ASCII, because this code can't
+ // handle high unicode characters.
+ if (c == 0x20 || c == 0x21 || (c >= 0x23 && c <= 0x2E) ||
+ (c >= 0x30 && c <= 0x5B) || (c >= 0x5D && c <= 0xFF))
+ result += *b;
+ else if (*b == Ch('\b')) result += Ch('\\'), result += Ch('b');
+ else if (*b == Ch('\f')) result += Ch('\\'), result += Ch('f');
+ else if (*b == Ch('\n')) result += Ch('\\'), result += Ch('n');
+ else if (*b == Ch('\r')) result += Ch('\\'), result += Ch('r');
+ else if (*b == Ch('\t')) result += Ch('\\'), result += Ch('t');
+ else if (*b == Ch('/')) result += Ch('\\'), result += Ch('/');
+ else if (*b == Ch('"')) result += Ch('\\'), result += Ch('"');
+ else if (*b == Ch('\\')) result += Ch('\\'), result += Ch('\\');
+ else
+ {
+ const char *hexdigits = "0123456789ABCDEF";
+ unsigned long u = (std::min)(static_cast<unsigned long>(
+ static_cast<UCh>(*b)),
+ 0xFFFFul);
+ unsigned long d1 = u / 4096; u -= d1 * 4096;
+ unsigned long d2 = u / 256; u -= d2 * 256;
+ unsigned long d3 = u / 16; u -= d3 * 16;
+ unsigned long d4 = u;
+ result += Ch('\\'); result += Ch('u');
+ result += Ch(hexdigits[d1]); result += Ch(hexdigits[d2]);
+ result += Ch(hexdigits[d3]); result += Ch(hexdigits[d4]);
+ }
+ ++b;
+ }
+ return result;
+ }
+
+ template<class Ptree>
+ void write_json_helper(std::basic_ostream<typename Ptree::key_type::value_type> &stream,
+ const Ptree &pt,
+ int indent, bool pretty)
+ {
+
+ typedef typename Ptree::key_type::value_type Ch;
+ typedef typename std::basic_string<Ch> Str;
+
+ // Value or object or array
+ if (indent > 0 && pt.empty())
+ {
+ // Write value
+ Str data = create_escapes(pt.template get_value<Str>());
+ stream << Ch('"') << data << Ch('"');
+
+ }
+ else if (indent > 0 && pt.count(Str()) == pt.size())
+ {
+ // Write array
+ stream << Ch('[');
+ if (pretty) stream << Ch('\n');
+ typename Ptree::const_iterator it = pt.begin();
+ for (; it != pt.end(); ++it)
+ {
+ if (pretty) stream << Str(4 * (indent + 1), Ch(' '));
+ write_json_helper(stream, it->second, indent + 1, pretty);
+ if (boost::next(it) != pt.end())
+ stream << Ch(',');
+ if (pretty) stream << Ch('\n');
+ }
+ if (pretty) stream << Str(4 * indent, Ch(' '));
+ stream << Ch(']');
+
+ }
+ else
+ {
+ // Write object
+ stream << Ch('{');
+ if (pretty) stream << Ch('\n');
+ typename Ptree::const_iterator it = pt.begin();
+ for (; it != pt.end(); ++it)
+ {
+ if (pretty) stream << Str(4 * (indent + 1), Ch(' '));
+ stream << Ch('"') << create_escapes(it->first) << Ch('"') << Ch(':');
+ if (pretty) stream << Ch(' ');
+ write_json_helper(stream, it->second, indent + 1, pretty);
+ if (boost::next(it) != pt.end())
+ stream << Ch(',');
+ if (pretty) stream << Ch('\n');
+ }
+ if (pretty) stream << Str(4 * indent, Ch(' '));
+ stream << Ch('}');
+ }
+
+ }
+
+ // Verify if ptree does not contain information that cannot be written to json
+ template<class Ptree>
+ bool verify_json(const Ptree &pt, int depth)
+ {
+
+ typedef typename Ptree::key_type::value_type Ch;
+ typedef typename std::basic_string<Ch> Str;
+
+ // Root ptree cannot have data
+ if (depth == 0 && !pt.template get_value<Str>().empty())
+ return false;
+
+ // Ptree cannot have both children and data
+ if (!pt.template get_value<Str>().empty() && !pt.empty())
+ return false;
+
+ // Check children
+ typename Ptree::const_iterator it = pt.begin();
+ for (; it != pt.end(); ++it)
+ if (!verify_json(it->second, depth + 1))
+ return false;
+
+ // Success
+ return true;
+
+ }
+
+ // Write ptree to json stream
+ template<class Ptree>
+ void write_json_internal(std::basic_ostream<typename Ptree::key_type::value_type> &stream,
+ const Ptree &pt,
+ const std::string &filename,
+ bool pretty)
+ {
+ if (!verify_json(pt, 0))
+ BOOST_PROPERTY_TREE_THROW(json_parser_error("ptree contains data that cannot be represented in JSON format", filename, 0));
+ write_json_helper(stream, pt, 0, pretty);
+ stream << std::endl;
+ if (!stream.good())
+ BOOST_PROPERTY_TREE_THROW(json_parser_error("write error", filename, 0));
+ }
+
+} } }
+
+#endif