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
 |