1// ----------------------------------------------------------------------------
2// Copyright (C) 2002-2006 Marcin Kalicinski
3//
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)
7//
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
12
13#include <boost/property_tree/json_parser/error.hpp>
14#include <boost/property_tree/ptree.hpp>
15#include <boost/next_prior.hpp>
16#include <boost/type_traits/make_unsigned.hpp>
17#include <string>
18#include <ostream>
19#include <iomanip>
20
21namespace boost { namespace property_tree { namespace json_parser
22{
23
24 // Create necessary escape sequences from illegal characters
25 template<class Ch>
26 std::basic_string<Ch> create_escapes(const std::basic_string<Ch> &s)
27 {
28 std::basic_string<Ch> result;
29 typename std::basic_string<Ch>::const_iterator b = s.begin();
30 typename std::basic_string<Ch>::const_iterator e = s.end();
31 while (b != e)
32 {
33 typedef typename make_unsigned<Ch>::type UCh;
34 UCh c(*b);
35 // This assumes an ASCII superset. But so does everything in PTree.
36 // We escape everything outside ASCII, because this code can't
37 // handle high unicode characters.
38 if (c == 0x20 || c == 0x21 || (c >= 0x23 && c <= 0x2E) ||
39 (c >= 0x30 && c <= 0x5B) || (c >= 0x5D && c <= 0xFF))
40 result += *b;
41 else if (*b == Ch('\b')) result += Ch('\\'), result += Ch('b');
42 else if (*b == Ch('\f')) result += Ch('\\'), result += Ch('f');
43 else if (*b == Ch('\n')) result += Ch('\\'), result += Ch('n');
44 else if (*b == Ch('\r')) result += Ch('\\'), result += Ch('r');
45 else if (*b == Ch('\t')) result += Ch('\\'), result += Ch('t');
46 else if (*b == Ch('/')) result += Ch('\\'), result += Ch('/');
47 else if (*b == Ch('"')) result += Ch('\\'), result += Ch('"');
48 else if (*b == Ch('\\')) result += Ch('\\'), result += Ch('\\');
49 else
50 {
51 const char *hexdigits = "0123456789ABCDEF";
52 unsigned long u = (std::min)(a: static_cast<unsigned long>(
53 static_cast<UCh>(*b)),
54 b: 0xFFFFul);
55 unsigned long d1 = u / 4096; u -= d1 * 4096;
56 unsigned long d2 = u / 256; u -= d2 * 256;
57 unsigned long d3 = u / 16; u -= d3 * 16;
58 unsigned long d4 = u;
59 result += Ch('\\'); result += Ch('u');
60 result += Ch(hexdigits[d1]); result += Ch(hexdigits[d2]);
61 result += Ch(hexdigits[d3]); result += Ch(hexdigits[d4]);
62 }
63 ++b;
64 }
65 return result;
66 }
67
68 template<class Ptree>
69 void write_json_helper(std::basic_ostream<typename Ptree::key_type::value_type> &stream,
70 const Ptree &pt,
71 int indent, bool pretty)
72 {
73
74 typedef typename Ptree::key_type::value_type Ch;
75 typedef typename std::basic_string<Ch> Str;
76
77 // Value or object or array
78 if (indent > 0 && pt.empty())
79 {
80 // Write value
81 Str data = create_escapes(pt.template get_value<Str>());
82 stream << Ch('"') << data << Ch('"');
83
84 }
85 else if (indent > 0 && pt.count(Str()) == pt.size())
86 {
87 // Write array
88 stream << Ch('[');
89 if (pretty) stream << Ch('\n');
90 typename Ptree::const_iterator it = pt.begin();
91 for (; it != pt.end(); ++it)
92 {
93 if (pretty) stream << Str(4 * (indent + 1), Ch(' '));
94 write_json_helper(stream, it->second, indent + 1, pretty);
95 if (boost::next(it) != pt.end())
96 stream << Ch(',');
97 if (pretty) stream << Ch('\n');
98 }
99 if (pretty) stream << Str(4 * indent, Ch(' '));
100 stream << Ch(']');
101
102 }
103 else
104 {
105 // Write object
106 stream << Ch('{');
107 if (pretty) stream << Ch('\n');
108 typename Ptree::const_iterator it = pt.begin();
109 for (; it != pt.end(); ++it)
110 {
111 if (pretty) stream << Str(4 * (indent + 1), Ch(' '));
112 stream << Ch('"') << create_escapes(it->first) << Ch('"') << Ch(':');
113 if (pretty) stream << Ch(' ');
114 write_json_helper(stream, it->second, indent + 1, pretty);
115 if (boost::next(it) != pt.end())
116 stream << Ch(',');
117 if (pretty) stream << Ch('\n');
118 }
119 if (pretty) stream << Str(4 * indent, Ch(' '));
120 stream << Ch('}');
121 }
122
123 }
124
125 // Verify if ptree does not contain information that cannot be written to json
126 template<class Ptree>
127 bool verify_json(const Ptree &pt, int depth)
128 {
129
130 typedef typename Ptree::key_type::value_type Ch;
131 typedef typename std::basic_string<Ch> Str;
132
133 // Root ptree cannot have data
134 if (depth == 0 && !pt.template get_value<Str>().empty())
135 return false;
136
137 // Ptree cannot have both children and data
138 if (!pt.template get_value<Str>().empty() && !pt.empty())
139 return false;
140
141 // Check children
142 typename Ptree::const_iterator it = pt.begin();
143 for (; it != pt.end(); ++it)
144 if (!verify_json(it->second, depth + 1))
145 return false;
146
147 // Success
148 return true;
149
150 }
151
152 // Write ptree to json stream
153 template<class Ptree>
154 void write_json_internal(std::basic_ostream<typename Ptree::key_type::value_type> &stream,
155 const Ptree &pt,
156 const std::string &filename,
157 bool pretty)
158 {
159 if (!verify_json(pt, 0))
160 BOOST_PROPERTY_TREE_THROW(json_parser_error("ptree contains data that cannot be represented in JSON format", filename, 0));
161 write_json_helper(stream, pt, 0, pretty);
162
163 if (pretty) stream << std::endl;
164 else stream << std::flush;
165
166 if (!stream.good())
167 BOOST_PROPERTY_TREE_THROW(json_parser_error("write error", filename, 0));
168 }
169
170} } }
171
172#endif
173

source code of boost/libs/property_tree/include/boost/property_tree/json_parser/detail/write.hpp