File indexing completed on 2025-07-12 08:28:43
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010 #ifndef BOOST_PROPERTY_TREE_DETAIL_JSON_PARSER_WRITE_HPP_INCLUDED
0011 #define BOOST_PROPERTY_TREE_DETAIL_JSON_PARSER_WRITE_HPP_INCLUDED
0012
0013 #include <boost/property_tree/json_parser/error.hpp>
0014 #include <boost/property_tree/ptree.hpp>
0015 #include <boost/next_prior.hpp>
0016 #include <boost/type_traits/make_unsigned.hpp>
0017 #include <string>
0018 #include <ostream>
0019 #include <iomanip>
0020
0021 namespace boost { namespace property_tree { namespace json_parser
0022 {
0023
0024
0025 template<class Ch>
0026 std::basic_string<Ch> create_escapes(const std::basic_string<Ch> &s)
0027 {
0028 std::basic_string<Ch> result;
0029 typename std::basic_string<Ch>::const_iterator b = s.begin();
0030 typename std::basic_string<Ch>::const_iterator e = s.end();
0031 while (b != e)
0032 {
0033 typedef typename make_unsigned<Ch>::type UCh;
0034 UCh c(*b);
0035
0036
0037
0038 if (c == 0x20 || c == 0x21 || (c >= 0x23 && c <= 0x2E) ||
0039 (c >= 0x30 && c <= 0x5B) || (c >= 0x5D && c <= 0xFF))
0040 result += *b;
0041 else if (*b == Ch('\b')) result += Ch('\\'), result += Ch('b');
0042 else if (*b == Ch('\f')) result += Ch('\\'), result += Ch('f');
0043 else if (*b == Ch('\n')) result += Ch('\\'), result += Ch('n');
0044 else if (*b == Ch('\r')) result += Ch('\\'), result += Ch('r');
0045 else if (*b == Ch('\t')) result += Ch('\\'), result += Ch('t');
0046 else if (*b == Ch('/')) result += Ch('\\'), result += Ch('/');
0047 else if (*b == Ch('"')) result += Ch('\\'), result += Ch('"');
0048 else if (*b == Ch('\\')) result += Ch('\\'), result += Ch('\\');
0049 else
0050 {
0051 const char *hexdigits = "0123456789ABCDEF";
0052 unsigned long u = (std::min)(static_cast<unsigned long>(
0053 static_cast<UCh>(*b)),
0054 0xFFFFul);
0055 unsigned long d1 = u / 4096; u -= d1 * 4096;
0056 unsigned long d2 = u / 256; u -= d2 * 256;
0057 unsigned long d3 = u / 16; u -= d3 * 16;
0058 unsigned long d4 = u;
0059 result += Ch('\\'); result += Ch('u');
0060 result += Ch(hexdigits[d1]); result += Ch(hexdigits[d2]);
0061 result += Ch(hexdigits[d3]); result += Ch(hexdigits[d4]);
0062 }
0063 ++b;
0064 }
0065 return result;
0066 }
0067
0068 template<class Ptree>
0069 void write_json_helper(std::basic_ostream<typename Ptree::key_type::value_type> &stream,
0070 const Ptree &pt,
0071 int indent, bool pretty)
0072 {
0073
0074 typedef typename Ptree::key_type::value_type Ch;
0075 typedef typename std::basic_string<Ch> Str;
0076
0077
0078 if (indent > 0 && pt.empty())
0079 {
0080
0081 Str data = create_escapes(pt.template get_value<Str>());
0082 stream << Ch('"') << data << Ch('"');
0083
0084 }
0085 else if (indent > 0 && pt.count(Str()) == pt.size())
0086 {
0087
0088 stream << Ch('[');
0089 if (pretty) stream << Ch('\n');
0090 typename Ptree::const_iterator it = pt.begin();
0091 for (; it != pt.end(); ++it)
0092 {
0093 if (pretty) stream << Str(4 * (indent + 1), Ch(' '));
0094 write_json_helper(stream, it->second, indent + 1, pretty);
0095 if (boost::next(it) != pt.end())
0096 stream << Ch(',');
0097 if (pretty) stream << Ch('\n');
0098 }
0099 if (pretty) stream << Str(4 * indent, Ch(' '));
0100 stream << Ch(']');
0101
0102 }
0103 else
0104 {
0105
0106 stream << Ch('{');
0107 if (pretty) stream << Ch('\n');
0108 typename Ptree::const_iterator it = pt.begin();
0109 for (; it != pt.end(); ++it)
0110 {
0111 if (pretty) stream << Str(4 * (indent + 1), Ch(' '));
0112 stream << Ch('"') << create_escapes(it->first) << Ch('"') << Ch(':');
0113 if (pretty) stream << Ch(' ');
0114 write_json_helper(stream, it->second, indent + 1, pretty);
0115 if (boost::next(it) != pt.end())
0116 stream << Ch(',');
0117 if (pretty) stream << Ch('\n');
0118 }
0119 if (pretty) stream << Str(4 * indent, Ch(' '));
0120 stream << Ch('}');
0121 }
0122
0123 }
0124
0125
0126 template<class Ptree>
0127 bool verify_json(const Ptree &pt, int depth)
0128 {
0129
0130 typedef typename Ptree::key_type::value_type Ch;
0131 typedef typename std::basic_string<Ch> Str;
0132
0133
0134 if (depth == 0 && !pt.template get_value<Str>().empty())
0135 return false;
0136
0137
0138 if (!pt.template get_value<Str>().empty() && !pt.empty())
0139 return false;
0140
0141
0142 typename Ptree::const_iterator it = pt.begin();
0143 for (; it != pt.end(); ++it)
0144 if (!verify_json(it->second, depth + 1))
0145 return false;
0146
0147
0148 return true;
0149
0150 }
0151
0152
0153 template<class Ptree>
0154 void write_json_internal(std::basic_ostream<typename Ptree::key_type::value_type> &stream,
0155 const Ptree &pt,
0156 const std::string &filename,
0157 bool pretty)
0158 {
0159 if (!verify_json(pt, 0))
0160 BOOST_PROPERTY_TREE_THROW(json_parser_error("ptree contains data that cannot be represented in JSON format", filename, 0));
0161 write_json_helper(stream, pt, 0, pretty);
0162
0163 if (pretty) stream << std::endl;
0164 else stream << std::flush;
0165
0166 if (!stream.good())
0167 BOOST_PROPERTY_TREE_THROW(json_parser_error("write error", filename, 0));
0168 }
0169
0170 } } }
0171
0172 #endif