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>
19 namespace boost
{ namespace property_tree
{ namespace json_parser
22 // Create necessary escape sequences from illegal characters
24 std::basic_string
<Ch
> create_escapes(const std::basic_string
<Ch
> &s
,
25 const std::locale
&loc
)
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 if (*b
== Ch('\0')) result
+= Ch('\\'), result
+= Ch('0');
33 else if (*b
== Ch('\b')) result
+= Ch('\\'), result
+= Ch('b');
34 else if (*b
== Ch('\f')) result
+= Ch('\\'), result
+= Ch('f');
35 else if (*b
== Ch('\n')) result
+= Ch('\\'), result
+= Ch('n');
36 else if (*b
== Ch('\r')) result
+= Ch('\\'), result
+= Ch('r');
37 else if (*b
== Ch('"')) result
+= Ch('\\'), result
+= Ch('"');
38 else if (*b
== Ch('\\')) result
+= Ch('\\'), result
+= Ch('\\');
41 if (std::isprint(*b
, loc
))
45 const char *hexdigits
= "0123456789ABCDEF";
46 unsigned long u
= (std::min
)(static_cast<unsigned long>(*b
), 0xFFFFul
);
47 int d1
= u
/ 4096; u
-= d1
* 4096;
48 int d2
= u
/ 256; u
-= d2
* 256;
49 int d3
= u
/ 16; u
-= d3
* 16;
51 result
+= Ch('\\'); result
+= Ch('u');
52 result
+= Ch(hexdigits
[d1
]); result
+= Ch(hexdigits
[d2
]);
53 result
+= Ch(hexdigits
[d3
]); result
+= Ch(hexdigits
[d4
]);
62 void write_json_helper(std::basic_ostream
<typename
Ptree::key_type::value_type
> &stream
,
67 typedef typename
Ptree::key_type::value_type Ch
;
68 typedef typename
std::basic_string
<Ch
> Str
;
70 // Value or object or array
71 if (indent
> 0 && pt
.empty())
75 Str data
= create_escapes(pt
.template get_value
<Str
>(), stream
.getloc());
76 stream
<< Ch('"') << data
<< Ch('"');
79 else if (indent
> 0 && pt
.count(Str()) == pt
.size())
83 stream
<< Ch('[') << Ch('\n');
84 typename
Ptree::const_iterator it
= pt
.begin();
85 for (; it
!= pt
.end(); ++it
)
87 stream
<< Str(4 * (indent
+ 1), Ch(' '));
88 write_json_helper(stream
, it
->second
, indent
+ 1);
89 if (boost::next(it
) != pt
.end())
93 stream
<< Str(4 * indent
, Ch(' ')) << Ch(']');
100 stream
<< Ch('{') << Ch('\n');
101 typename
Ptree::const_iterator it
= pt
.begin();
102 for (; it
!= pt
.end(); ++it
)
104 stream
<< Str(4 * (indent
+ 1), Ch(' '));
105 stream
<< Ch('"') << create_escapes(it
->first
, stream
.getloc()) << Ch('"') << Ch(':');
106 if (it
->second
.empty())
109 stream
<< Ch('\n') << Str(4 * (indent
+ 1), Ch(' '));
110 write_json_helper(stream
, it
->second
, indent
+ 1);
111 if (boost::next(it
) != pt
.end())
115 stream
<< Str(4 * indent
, Ch(' ')) << Ch('}');
121 // Verify if ptree does not contain information that cannot be written to json
122 template<class Ptree
>
123 bool verify_json(const Ptree
&pt
, int depth
)
126 typedef typename
Ptree::key_type::value_type Ch
;
127 typedef typename
std::basic_string
<Ch
> Str
;
129 // Root ptree cannot have data
130 if (depth
== 0 && !pt
.template get_value
<Str
>().empty())
133 // Ptree cannot have both children and data
134 if (!pt
.template get_value
<Str
>().empty() && !pt
.empty())
138 typename
Ptree::const_iterator it
= pt
.begin();
139 for (; it
!= pt
.end(); ++it
)
140 if (!verify_json(it
->second
, depth
+ 1))
148 // Write ptree to json stream
149 template<class Ptree
>
150 void write_json_internal(std::basic_ostream
<typename
Ptree::key_type::value_type
> &stream
,
152 const std::string
&filename
)
154 if (!verify_json(pt
, 0))
155 BOOST_PROPERTY_TREE_THROW(json_parser_error("ptree contains data that cannot be represented in JSON format", filename
, 0));
156 write_json_helper(stream
, pt
, 0);
159 BOOST_PROPERTY_TREE_THROW(json_parser_error("write error", filename
, 0));