123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172 |
- // ----------------------------------------------------------------------------
- // Copyright (C) 2002-2006 Marcin Kalicinski
- //
- // Distributed under the Boost Software License, Version 1.0.
- // (See accompanying file LICENSE_1_0.txt or copy at
- // http://www.boost.org/LICENSE_1_0.txt)
- //
- // For more information, see www.boost.org
- // ----------------------------------------------------------------------------
- #ifndef BOOST_PROPERTY_TREE_DETAIL_JSON_PARSER_WRITE_HPP_INCLUDED
- #define BOOST_PROPERTY_TREE_DETAIL_JSON_PARSER_WRITE_HPP_INCLUDED
- #include <boost/property_tree/json_parser/error.hpp>
- #include <boost/property_tree/ptree.hpp>
- #include <boost/next_prior.hpp>
- #include <boost/type_traits/make_unsigned.hpp>
- #include <string>
- #include <ostream>
- #include <iomanip>
- namespace boost { namespace property_tree { namespace json_parser
- {
- // Create necessary escape sequences from illegal characters
- template<class Ch>
- std::basic_string<Ch> create_escapes(const std::basic_string<Ch> &s)
- {
- std::basic_string<Ch> result;
- typename std::basic_string<Ch>::const_iterator b = s.begin();
- typename std::basic_string<Ch>::const_iterator e = s.end();
- while (b != e)
- {
- typedef typename make_unsigned<Ch>::type UCh;
- UCh c(*b);
- // This assumes an ASCII superset. But so does everything in PTree.
- // We escape everything outside ASCII, because this code can't
- // handle high unicode characters.
- if (c == 0x20 || c == 0x21 || (c >= 0x23 && c <= 0x2E) ||
- (c >= 0x30 && c <= 0x5B) || (c >= 0x5D && c <= 0xFF))
- result += *b;
- else if (*b == Ch('\b')) result += Ch('\\'), result += Ch('b');
- else if (*b == Ch('\f')) result += Ch('\\'), result += Ch('f');
- else if (*b == Ch('\n')) result += Ch('\\'), result += Ch('n');
- else if (*b == Ch('\r')) result += Ch('\\'), result += Ch('r');
- else if (*b == Ch('\t')) result += Ch('\\'), result += Ch('t');
- else if (*b == Ch('/')) result += Ch('\\'), result += Ch('/');
- else if (*b == Ch('"')) result += Ch('\\'), result += Ch('"');
- else if (*b == Ch('\\')) result += Ch('\\'), result += Ch('\\');
- else
- {
- const char *hexdigits = "0123456789ABCDEF";
- unsigned long u = (std::min)(static_cast<unsigned long>(
- static_cast<UCh>(*b)),
- 0xFFFFul);
- unsigned long d1 = u / 4096; u -= d1 * 4096;
- unsigned long d2 = u / 256; u -= d2 * 256;
- unsigned long d3 = u / 16; u -= d3 * 16;
- unsigned long d4 = u;
- result += Ch('\\'); result += Ch('u');
- result += Ch(hexdigits[d1]); result += Ch(hexdigits[d2]);
- result += Ch(hexdigits[d3]); result += Ch(hexdigits[d4]);
- }
- ++b;
- }
- return result;
- }
- template<class Ptree>
- void write_json_helper(std::basic_ostream<typename Ptree::key_type::value_type> &stream,
- const Ptree &pt,
- int indent, bool pretty)
- {
- typedef typename Ptree::key_type::value_type Ch;
- typedef typename std::basic_string<Ch> Str;
- // Value or object or array
- if (indent > 0 && pt.empty())
- {
- // Write value
- Str data = create_escapes(pt.template get_value<Str>());
- stream << Ch('"') << data << Ch('"');
- }
- else if (indent > 0 && pt.count(Str()) == pt.size())
- {
- // Write array
- stream << Ch('[');
- if (pretty) stream << Ch('\n');
- typename Ptree::const_iterator it = pt.begin();
- for (; it != pt.end(); ++it)
- {
- if (pretty) stream << Str(4 * (indent + 1), Ch(' '));
- write_json_helper(stream, it->second, indent + 1, pretty);
- if (boost::next(it) != pt.end())
- stream << Ch(',');
- if (pretty) stream << Ch('\n');
- }
- if (pretty) stream << Str(4 * indent, Ch(' '));
- stream << Ch(']');
- }
- else
- {
- // Write object
- stream << Ch('{');
- if (pretty) stream << Ch('\n');
- typename Ptree::const_iterator it = pt.begin();
- for (; it != pt.end(); ++it)
- {
- if (pretty) stream << Str(4 * (indent + 1), Ch(' '));
- stream << Ch('"') << create_escapes(it->first) << Ch('"') << Ch(':');
- if (pretty) stream << Ch(' ');
- write_json_helper(stream, it->second, indent + 1, pretty);
- if (boost::next(it) != pt.end())
- stream << Ch(',');
- if (pretty) stream << Ch('\n');
- }
- if (pretty) stream << Str(4 * indent, Ch(' '));
- stream << Ch('}');
- }
- }
- // Verify if ptree does not contain information that cannot be written to json
- template<class Ptree>
- bool verify_json(const Ptree &pt, int depth)
- {
- typedef typename Ptree::key_type::value_type Ch;
- typedef typename std::basic_string<Ch> Str;
- // Root ptree cannot have data
- if (depth == 0 && !pt.template get_value<Str>().empty())
- return false;
-
- // Ptree cannot have both children and data
- if (!pt.template get_value<Str>().empty() && !pt.empty())
- return false;
- // Check children
- typename Ptree::const_iterator it = pt.begin();
- for (; it != pt.end(); ++it)
- if (!verify_json(it->second, depth + 1))
- return false;
- // Success
- return true;
- }
-
- // Write ptree to json stream
- template<class Ptree>
- void write_json_internal(std::basic_ostream<typename Ptree::key_type::value_type> &stream,
- const Ptree &pt,
- const std::string &filename,
- bool pretty)
- {
- if (!verify_json(pt, 0))
- BOOST_PROPERTY_TREE_THROW(json_parser_error("ptree contains data that cannot be represented in JSON format", filename, 0));
- write_json_helper(stream, pt, 0, pretty);
- if (pretty) stream << std::endl;
- else stream << std::flush;
- if (!stream.good())
- BOOST_PROPERTY_TREE_THROW(json_parser_error("write error", filename, 0));
- }
- } } }
- #endif
|