169 lines
		
	
	
		
			6.6 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
		
		
			
		
	
	
			169 lines
		
	
	
		
			6.6 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
|   | // ---------------------------------------------------------------------------- | ||
|  | // 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/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); | ||
|  |         stream << std::endl; | ||
|  |         if (!stream.good()) | ||
|  |             BOOST_PROPERTY_TREE_THROW(json_parser_error("write error", filename, 0)); | ||
|  |     } | ||
|  | 
 | ||
|  | } } } | ||
|  | 
 | ||
|  | #endif |