]> git.proxmox.com Git - ceph.git/blob - ceph/src/boost/boost/property_tree/json_parser/detail/write.hpp
update sources to v12.2.3
[ceph.git] / ceph / src / boost / boost / property_tree / json_parser / detail / write.hpp
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/ptree.hpp>
14 #include <boost/next_prior.hpp>
15 #include <boost/type_traits/make_unsigned.hpp>
16 #include <string>
17 #include <ostream>
18 #include <iomanip>
19
20 namespace boost { namespace property_tree { namespace json_parser
21 {
22
23 // Create necessary escape sequences from illegal characters
24 template<class Ch>
25 std::basic_string<Ch> create_escapes(const std::basic_string<Ch> &s)
26 {
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();
30 while (b != e)
31 {
32 typedef typename make_unsigned<Ch>::type UCh;
33 UCh c(*b);
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))
39 result += *b;
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('\\');
48 else
49 {
50 const char *hexdigits = "0123456789ABCDEF";
51 unsigned long u = (std::min)(static_cast<unsigned long>(
52 static_cast<UCh>(*b)),
53 0xFFFFul);
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;
57 unsigned long d4 = u;
58 result += Ch('\\'); result += Ch('u');
59 result += Ch(hexdigits[d1]); result += Ch(hexdigits[d2]);
60 result += Ch(hexdigits[d3]); result += Ch(hexdigits[d4]);
61 }
62 ++b;
63 }
64 return result;
65 }
66
67 template<class Ptree>
68 void write_json_helper(std::basic_ostream<typename Ptree::key_type::value_type> &stream,
69 const Ptree &pt,
70 int indent, bool pretty)
71 {
72
73 typedef typename Ptree::key_type::value_type Ch;
74 typedef typename std::basic_string<Ch> Str;
75
76 // Value or object or array
77 if (indent > 0 && pt.empty())
78 {
79 // Write value
80 Str data = create_escapes(pt.template get_value<Str>());
81 stream << Ch('"') << data << Ch('"');
82
83 }
84 else if (indent > 0 && pt.count(Str()) == pt.size())
85 {
86 // Write array
87 stream << Ch('[');
88 if (pretty) stream << Ch('\n');
89 typename Ptree::const_iterator it = pt.begin();
90 for (; it != pt.end(); ++it)
91 {
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())
95 stream << Ch(',');
96 if (pretty) stream << Ch('\n');
97 }
98 if (pretty) stream << Str(4 * indent, Ch(' '));
99 stream << Ch(']');
100
101 }
102 else
103 {
104 // Write object
105 stream << Ch('{');
106 if (pretty) stream << Ch('\n');
107 typename Ptree::const_iterator it = pt.begin();
108 for (; it != pt.end(); ++it)
109 {
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())
115 stream << Ch(',');
116 if (pretty) stream << Ch('\n');
117 }
118 if (pretty) stream << Str(4 * indent, Ch(' '));
119 stream << Ch('}');
120 }
121
122 }
123
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)
127 {
128
129 typedef typename Ptree::key_type::value_type Ch;
130 typedef typename std::basic_string<Ch> Str;
131
132 // Root ptree cannot have data
133 if (depth == 0 && !pt.template get_value<Str>().empty())
134 return false;
135
136 // Ptree cannot have both children and data
137 if (!pt.template get_value<Str>().empty() && !pt.empty())
138 return false;
139
140 // Check children
141 typename Ptree::const_iterator it = pt.begin();
142 for (; it != pt.end(); ++it)
143 if (!verify_json(it->second, depth + 1))
144 return false;
145
146 // Success
147 return true;
148
149 }
150
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,
154 const Ptree &pt,
155 const std::string &filename,
156 bool pretty)
157 {
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);
161 stream << std::endl;
162 if (!stream.good())
163 BOOST_PROPERTY_TREE_THROW(json_parser_error("write error", filename, 0));
164 }
165
166 } } }
167
168 #endif