1 // ----------------------------------------------------------------------------
2 // Copyright (C) 2002-2006 Marcin Kalicinski
4 // Distributed under the Boost Software License, Version 1.0.
5 // (See accompanying file LICENSE_1_0.txt or copy at
6 // http://www.boost.org/LICENSE_1_0.txt)
8 // For more information, see www.boost.org
9 // ----------------------------------------------------------------------------
10 #ifndef BOOST_PROPERTY_TREE_DETAIL_JSON_PARSER_WRITE_HPP_INCLUDED
11 #define BOOST_PROPERTY_TREE_DETAIL_JSON_PARSER_WRITE_HPP_INCLUDED
13 #include <boost/property_tree/ptree.hpp>
14 #include <boost/next_prior.hpp>
15 #include <boost/type_traits/make_unsigned.hpp>
20 namespace boost { namespace property_tree { namespace json_parser
23 // Create necessary escape sequences from illegal characters
25 std::basic_string<Ch> create_escapes(const std::basic_string<Ch> &s)
27 std::basic_string<Ch> result;
28 typename std::basic_string<Ch>::const_iterator b = s.begin();
29 typename std::basic_string<Ch>::const_iterator e = s.end();
32 typedef typename make_unsigned<Ch>::type UCh;
34 // This assumes an ASCII superset. But so does everything in PTree.
35 // We escape everything outside ASCII, because this code can't
36 // handle high unicode characters.
37 if (c == 0x20 || c == 0x21 || (c >= 0x23 && c <= 0x2E) ||
38 (c >= 0x30 && c <= 0x5B) || (c >= 0x5D && c <= 0xFF))
40 else if (*b == Ch('\b')) result += Ch('\\'), result += Ch('b');
41 else if (*b == Ch('\f')) result += Ch('\\'), result += Ch('f');
42 else if (*b == Ch('\n')) result += Ch('\\'), result += Ch('n');
43 else if (*b == Ch('\r')) result += Ch('\\'), result += Ch('r');
44 else if (*b == Ch('\t')) result += Ch('\\'), result += Ch('t');
45 else if (*b == Ch('/')) result += Ch('\\'), result += Ch('/');
46 else if (*b == Ch('"')) result += Ch('\\'), result += Ch('"');
47 else if (*b == Ch('\\')) result += Ch('\\'), result += Ch('\\');
50 const char *hexdigits = "0123456789ABCDEF";
51 unsigned long u = (std::min)(static_cast<unsigned long>(
52 static_cast<UCh>(*b)),
54 unsigned long d1 = u / 4096; u -= d1 * 4096;
55 unsigned long d2 = u / 256; u -= d2 * 256;
56 unsigned long d3 = u / 16; u -= d3 * 16;
58 result += Ch('\\'); result += Ch('u');
59 result += Ch(hexdigits[d1]); result += Ch(hexdigits[d2]);
60 result += Ch(hexdigits[d3]); result += Ch(hexdigits[d4]);
68 void write_json_helper(std::basic_ostream<typename Ptree::key_type::value_type> &stream,
70 int indent, bool pretty)
73 typedef typename Ptree::key_type::value_type Ch;
74 typedef typename std::basic_string<Ch> Str;
76 // Value or object or array
77 if (indent > 0 && pt.empty())
80 Str data = create_escapes(pt.template get_value<Str>());
81 stream << Ch('"') << data << Ch('"');
84 else if (indent > 0 && pt.count(Str()) == pt.size())
88 if (pretty) stream << Ch('\n');
89 typename Ptree::const_iterator it = pt.begin();
90 for (; it != pt.end(); ++it)
92 if (pretty) stream << Str(4 * (indent + 1), Ch(' '));
93 write_json_helper(stream, it->second, indent + 1, pretty);
94 if (boost::next(it) != pt.end())
96 if (pretty) stream << Ch('\n');
98 if (pretty) stream << Str(4 * indent, Ch(' '));
106 if (pretty) stream << Ch('\n');
107 typename Ptree::const_iterator it = pt.begin();
108 for (; it != pt.end(); ++it)
110 if (pretty) stream << Str(4 * (indent + 1), Ch(' '));
111 stream << Ch('"') << create_escapes(it->first) << Ch('"') << Ch(':');
112 if (pretty) stream << Ch(' ');
113 write_json_helper(stream, it->second, indent + 1, pretty);
114 if (boost::next(it) != pt.end())
116 if (pretty) stream << Ch('\n');
118 if (pretty) stream << Str(4 * indent, Ch(' '));
124 // Verify if ptree does not contain information that cannot be written to json
125 template<class Ptree>
126 bool verify_json(const Ptree &pt, int depth)
129 typedef typename Ptree::key_type::value_type Ch;
130 typedef typename std::basic_string<Ch> Str;
132 // Root ptree cannot have data
133 if (depth == 0 && !pt.template get_value<Str>().empty())
136 // Ptree cannot have both children and data
137 if (!pt.template get_value<Str>().empty() && !pt.empty())
141 typename Ptree::const_iterator it = pt.begin();
142 for (; it != pt.end(); ++it)
143 if (!verify_json(it->second, depth + 1))
151 // Write ptree to json stream
152 template<class Ptree>
153 void write_json_internal(std::basic_ostream<typename Ptree::key_type::value_type> &stream,
155 const std::string &filename,
158 if (!verify_json(pt, 0))
159 BOOST_PROPERTY_TREE_THROW(json_parser_error("ptree contains data that cannot be represented in JSON format", filename, 0));
160 write_json_helper(stream, pt, 0, pretty);
163 BOOST_PROPERTY_TREE_THROW(json_parser_error("write error", filename, 0));