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
							 |