Squashed 'third_party/boostorg/property_tree/' content from commit bdfe275

Change-Id: I075a5e242aaddc356ecc81e756c4a0907fc38130
git-subtree-dir: third_party/boostorg/property_tree
git-subtree-split: bdfe275d172ac30bc5e89a6375a5a64dea20b3c0
diff --git a/include/boost/property_tree/detail/exception_implementation.hpp b/include/boost/property_tree/detail/exception_implementation.hpp
new file mode 100644
index 0000000..bb39135
--- /dev/null
+++ b/include/boost/property_tree/detail/exception_implementation.hpp
@@ -0,0 +1,83 @@
+// ----------------------------------------------------------------------------
+// Copyright (C) 2002-2006 Marcin Kalicinski
+// Copyright (C) 2009 Sebastian Redl
+//
+// 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_EXCEPTIONS_IMPLEMENTATION_HPP_INCLUDED
+#define BOOST_PROPERTY_TREE_DETAIL_EXCEPTIONS_IMPLEMENTATION_HPP_INCLUDED
+
+namespace boost { namespace property_tree
+{
+
+    namespace detail
+    {
+
+        // Helper for preparing what string in ptree_bad_path exception
+        template<class P> inline
+        std::string prepare_bad_path_what(const std::string &what,
+                                          const P &path)
+        {
+            return what + " (" + path.dump() + ")";
+        }
+
+    }
+
+    ///////////////////////////////////////////////////////////////////////////
+    // ptree_error
+
+    inline ptree_error::ptree_error(const std::string &w): 
+        std::runtime_error(w) 
+    {
+    }
+
+    inline ptree_error::~ptree_error() throw()
+    {
+    }
+
+    ///////////////////////////////////////////////////////////////////////////
+    // ptree_bad_data
+
+    template<class D> inline
+    ptree_bad_data::ptree_bad_data(const std::string &w, const D &d):
+        ptree_error(w), m_data(d)
+    {
+    }
+
+    inline ptree_bad_data::~ptree_bad_data() throw()
+    {
+    }
+
+    template<class D> inline
+    D ptree_bad_data::data() const
+    {
+        return boost::any_cast<D>(m_data);
+    }
+
+    ///////////////////////////////////////////////////////////////////////////
+    // ptree_bad_path
+
+    template<class P> inline
+    ptree_bad_path::ptree_bad_path(const std::string &w, const P &p):
+        ptree_error(detail::prepare_bad_path_what(w, p)), m_path(p)
+    {
+
+    }
+
+    inline ptree_bad_path::~ptree_bad_path() throw()
+    {
+    }
+
+    template<class P> inline
+    P ptree_bad_path::path() const
+    {
+        return boost::any_cast<P>(m_path);
+    }
+
+}}
+
+#endif
diff --git a/include/boost/property_tree/detail/file_parser_error.hpp b/include/boost/property_tree/detail/file_parser_error.hpp
new file mode 100644
index 0000000..ff90583
--- /dev/null
+++ b/include/boost/property_tree/detail/file_parser_error.hpp
@@ -0,0 +1,88 @@
+// ----------------------------------------------------------------------------
+// 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_FILE_PARSER_ERROR_HPP_INCLUDED
+#define BOOST_PROPERTY_TREE_DETAIL_FILE_PARSER_ERROR_HPP_INCLUDED
+
+#include <boost/property_tree/ptree.hpp>
+#include <string>
+
+namespace boost { namespace property_tree
+{
+
+    //! File parse error
+    class file_parser_error: public ptree_error
+    {
+
+    public:
+
+        ///////////////////////////////////////////////////////////////////////
+        // Construction & destruction
+
+        // Construct error
+        file_parser_error(const std::string &msg,
+                          const std::string &file,
+                          unsigned long l) :
+            ptree_error(format_what(msg, file, l)),
+            m_message(msg), m_filename(file), m_line(l)
+        {
+        }
+
+        ~file_parser_error() throw()
+            // gcc 3.4.2 complains about lack of throw specifier on compiler
+            // generated dtor
+        {
+        }
+
+        ///////////////////////////////////////////////////////////////////////
+        // Data access
+
+        // Get error message (without line and file - use what() to get
+        // full message)
+        std::string message() const
+        {
+            return m_message;
+        }
+
+        // Get error filename
+        std::string filename() const
+        {
+            return m_filename;
+        }
+
+        // Get error line number
+        unsigned long line() const
+        {
+            return m_line;
+        }
+
+    private:
+
+        std::string m_message;
+        std::string m_filename;
+        unsigned long m_line;
+
+        // Format error message to be returned by std::runtime_error::what()
+        static std::string format_what(const std::string &msg,
+                                       const std::string &file,
+                                       unsigned long l)
+        {
+            std::stringstream stream;
+            stream << (file.empty() ? "<unspecified file>" : file.c_str());
+            if (l > 0)
+                stream << '(' << l << ')';
+            stream << ": " << msg;
+            return stream.str();
+        }
+
+    };
+
+} }
+
+#endif
diff --git a/include/boost/property_tree/detail/info_parser_error.hpp b/include/boost/property_tree/detail/info_parser_error.hpp
new file mode 100644
index 0000000..e7f06a1
--- /dev/null
+++ b/include/boost/property_tree/detail/info_parser_error.hpp
@@ -0,0 +1,32 @@
+// ----------------------------------------------------------------------------
+// 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_INFO_PARSER_ERROR_HPP_INCLUDED
+#define BOOST_PROPERTY_TREE_DETAIL_INFO_PARSER_ERROR_HPP_INCLUDED
+
+#include <boost/property_tree/detail/file_parser_error.hpp>
+#include <string>
+
+namespace boost { namespace property_tree { namespace info_parser
+{
+
+    class info_parser_error: public file_parser_error
+    {
+    public:
+        info_parser_error(const std::string &message,
+                          const std::string &filename,
+                          unsigned long line) :
+            file_parser_error(message, filename, line)
+        {
+        }
+    };
+
+} } }
+
+#endif
diff --git a/include/boost/property_tree/detail/info_parser_read.hpp b/include/boost/property_tree/detail/info_parser_read.hpp
new file mode 100644
index 0000000..87ef2cd
--- /dev/null
+++ b/include/boost/property_tree/detail/info_parser_read.hpp
@@ -0,0 +1,391 @@
+// ----------------------------------------------------------------------------
+// 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_INFO_PARSER_READ_HPP_INCLUDED
+#define BOOST_PROPERTY_TREE_DETAIL_INFO_PARSER_READ_HPP_INCLUDED
+
+#include "boost/property_tree/ptree.hpp"
+#include "boost/property_tree/detail/info_parser_error.hpp"
+#include "boost/property_tree/detail/info_parser_utils.hpp"
+#include <iterator>
+#include <string>
+#include <stack>
+#include <fstream>
+#include <cctype>
+
+namespace boost { namespace property_tree { namespace info_parser
+{
+
+    // Expand known escape sequences
+    template<class It>
+    std::basic_string<typename std::iterator_traits<It>::value_type>
+        expand_escapes(It b, It e)
+    {
+        typedef typename std::iterator_traits<It>::value_type Ch;
+        std::basic_string<Ch> result;
+        while (b != e)
+        {
+            if (*b == Ch('\\'))
+            {
+                ++b;
+                if (b == e)
+                {
+                    BOOST_PROPERTY_TREE_THROW(info_parser_error(
+                        "character expected after backslash", "", 0));
+                }
+                else if (*b == Ch('0')) result += Ch('\0');
+                else if (*b == Ch('a')) result += Ch('\a');
+                else if (*b == Ch('b')) result += Ch('\b');
+                else if (*b == Ch('f')) result += Ch('\f');
+                else if (*b == Ch('n')) result += Ch('\n');
+                else if (*b == Ch('r')) result += Ch('\r');
+                else if (*b == Ch('t')) result += Ch('\t');
+                else if (*b == Ch('v')) result += Ch('\v');
+                else if (*b == Ch('"')) result += Ch('"');
+                else if (*b == Ch('\'')) result += Ch('\'');
+                else if (*b == Ch('\\')) result += Ch('\\');
+                else
+                    BOOST_PROPERTY_TREE_THROW(info_parser_error(
+                        "unknown escape sequence", "", 0));
+            }
+            else
+                result += *b;
+            ++b;
+        }
+        return result;
+    }
+    
+    // Detect whitespace in a not very smart way.
+    template <class Ch>
+    bool is_ascii_space(Ch c)
+    {
+        // Everything outside ASCII is not space.
+        unsigned n = c;
+        if (n > 127)
+            return false;
+        return std::isspace(c) != 0;
+    }
+
+    // Advance pointer past whitespace
+    template<class Ch>
+    void skip_whitespace(const Ch *&text)
+    {
+        using namespace std;
+        while (is_ascii_space(*text))
+            ++text;
+    }
+
+    // Extract word (whitespace delimited) and advance pointer accordingly
+    template<class Ch>
+    std::basic_string<Ch> read_word(const Ch *&text)
+    {
+        using namespace std;
+        skip_whitespace(text);
+        const Ch *start = text;
+        while (!is_ascii_space(*text) && *text != Ch(';') && *text != Ch('\0'))
+            ++text;
+        return expand_escapes(start, text);
+    }
+
+    // Extract line (eol delimited) and advance pointer accordingly
+    template<class Ch>
+    std::basic_string<Ch> read_line(const Ch *&text)
+    {
+        using namespace std;
+        skip_whitespace(text);
+        const Ch *start = text;
+        while (*text != Ch('\0') && *text != Ch(';'))
+            ++text;
+        while (text > start && is_ascii_space(*(text - 1)))
+            --text;
+        return expand_escapes(start, text);
+    }
+
+    // Extract string (inside ""), and advance pointer accordingly
+    // Set need_more_lines to true if \ continuator found
+    template<class Ch>
+    std::basic_string<Ch> read_string(const Ch *&text, bool *need_more_lines)
+    {
+        skip_whitespace(text);
+        if (*text == Ch('\"'))
+        {
+
+            // Skip "
+            ++text;
+
+            // Find end of string, but skip escaped "
+            bool escaped = false;
+            const Ch *start = text;
+            while ((escaped || *text != Ch('\"')) && *text != Ch('\0'))
+            {
+                escaped = (!escaped && *text == Ch('\\'));
+                ++text;
+            }
+
+            // If end of string found
+            if (*text == Ch('\"'))
+            {
+                std::basic_string<Ch> result = expand_escapes(start, text++);
+                skip_whitespace(text);
+                if (*text == Ch('\\'))
+                {
+                    if (!need_more_lines)
+                        BOOST_PROPERTY_TREE_THROW(info_parser_error(
+                            "unexpected \\", "", 0));
+                    ++text;
+                    skip_whitespace(text);
+                    if (*text == Ch('\0') || *text == Ch(';'))
+                        *need_more_lines = true;
+                    else
+                        BOOST_PROPERTY_TREE_THROW(info_parser_error(
+                            "expected end of line after \\", "", 0));
+                }
+                else
+                    if (need_more_lines)
+                        *need_more_lines = false;
+                return result;
+            }
+            else
+                BOOST_PROPERTY_TREE_THROW(info_parser_error(
+                    "unexpected end of line", "", 0));
+
+        }
+        else
+            BOOST_PROPERTY_TREE_THROW(info_parser_error("expected \"", "", 0));
+    }
+
+    // Extract key
+    template<class Ch>
+    std::basic_string<Ch> read_key(const Ch *&text)
+    {
+        skip_whitespace(text);
+        if (*text == Ch('\"'))
+            return read_string(text, NULL);
+        else
+            return read_word(text);
+    }
+
+    // Extract data
+    template<class Ch>
+    std::basic_string<Ch> read_data(const Ch *&text, bool *need_more_lines)
+    {
+        skip_whitespace(text);
+        if (*text == Ch('\"'))
+            return read_string(text, need_more_lines);
+        else
+        {
+            *need_more_lines = false;
+            return read_word(text);
+        }
+    }
+
+    // Build ptree from info stream
+    template<class Ptree, class Ch>
+    void read_info_internal(std::basic_istream<Ch> &stream,
+                            Ptree &pt,
+                            const std::string &filename,
+                            int include_depth)
+    {
+        typedef std::basic_string<Ch> str_t;
+        // Possible parser states
+        enum state_t {
+            s_key,              // Parser expects key
+            s_data,             // Parser expects data
+            s_data_cont         // Parser expects data continuation
+        };
+
+        unsigned long line_no = 0;
+        state_t state = s_key;          // Parser state
+        Ptree *last = NULL;             // Pointer to last created ptree
+        // Define line here to minimize reallocations
+        str_t line;
+
+        // Initialize ptree stack (used to handle nesting)
+        std::stack<Ptree *> stack;
+        stack.push(&pt);                // Push root ptree on stack initially
+
+        try {
+            // While there are characters in the stream
+            while (stream.good()) {
+                // Read one line from stream
+                ++line_no;
+                std::getline(stream, line);
+                if (!stream.good() && !stream.eof())
+                    BOOST_PROPERTY_TREE_THROW(info_parser_error(
+                        "read error", filename, line_no));
+                const Ch *text = line.c_str();
+
+                // If directive found
+                skip_whitespace(text);
+                if (*text == Ch('#')) {
+                    // Determine directive type
+                    ++text;     // skip #
+                    std::basic_string<Ch> directive = read_word(text);
+                    if (directive == convert_chtype<Ch, char>("include")) {
+                        // #include
+                        if (include_depth > 100) {
+                            BOOST_PROPERTY_TREE_THROW(info_parser_error(
+                                "include depth too large, "
+                                "probably recursive include",
+                                filename, line_no));
+                        }
+                        str_t s = read_string(text, NULL);
+                        std::string inc_name =
+                            convert_chtype<char, Ch>(s.c_str());
+                        std::basic_ifstream<Ch> inc_stream(inc_name.c_str());
+                        if (!inc_stream.good())
+                            BOOST_PROPERTY_TREE_THROW(info_parser_error(
+                                "cannot open include file " + inc_name,
+                                filename, line_no));
+                        read_info_internal(inc_stream, *stack.top(),
+                                           inc_name, include_depth + 1);
+                    } else {   // Unknown directive
+                        BOOST_PROPERTY_TREE_THROW(info_parser_error(
+                            "unknown directive", filename, line_no));
+                    }
+
+                    // Directive must be followed by end of line
+                    skip_whitespace(text);
+                    if (*text != Ch('\0')) {
+                        BOOST_PROPERTY_TREE_THROW(info_parser_error(
+                            "expected end of line", filename, line_no));
+                    }
+
+                    // Go to next line
+                    continue;
+                }
+
+                // While there are characters left in line
+                while (1) {
+
+                    // Stop parsing on end of line or comment
+                    skip_whitespace(text);
+                    if (*text == Ch('\0') || *text == Ch(';')) {
+                        if (state == s_data)    // If there was no data set state to s_key
+                            state = s_key;
+                        break;
+                    }
+
+                    // Process according to current parser state
+                    switch (state)
+                    {
+
+                        // Parser expects key
+                        case s_key:
+                        {
+
+                            if (*text == Ch('{'))   // Brace opening found
+                            {
+                                if (!last)
+                                    BOOST_PROPERTY_TREE_THROW(info_parser_error("unexpected {", "", 0));
+                                stack.push(last);
+                                last = NULL;
+                                ++text;
+                            }
+                            else if (*text == Ch('}'))  // Brace closing found
+                            {
+                                if (stack.size() <= 1)
+                                    BOOST_PROPERTY_TREE_THROW(info_parser_error("unmatched }", "", 0));
+                                stack.pop();
+                                last = NULL;
+                                ++text;
+                            }
+                            else    // Key text found
+                            {
+                                std::basic_string<Ch> key = read_key(text);
+                                last = &stack.top()->push_back(
+                                    std::make_pair(key, Ptree()))->second;
+                                state = s_data;
+                            }
+
+                        }; break;
+
+                        // Parser expects data
+                        case s_data:
+                        {
+                            
+                            // Last ptree must be defined because we are going to add data to it
+                            BOOST_ASSERT(last);
+                            
+                            if (*text == Ch('{'))   // Brace opening found
+                            {
+                                stack.push(last);
+                                last = NULL;
+                                ++text;
+                                state = s_key;
+                            }
+                            else if (*text == Ch('}'))  // Brace closing found
+                            {
+                                if (stack.size() <= 1)
+                                    BOOST_PROPERTY_TREE_THROW(info_parser_error("unmatched }", "", 0));
+                                stack.pop();
+                                last = NULL;
+                                ++text;
+                                state = s_key;
+                            }
+                            else    // Data text found
+                            {
+                                bool need_more_lines;
+                                std::basic_string<Ch> data = read_data(text, &need_more_lines);
+                                last->data() = data;
+                                state = need_more_lines ? s_data_cont : s_key;
+                            }
+
+
+                        }; break;
+
+                        // Parser expects continuation of data after \ on previous line
+                        case s_data_cont:
+                        {
+                            
+                            // Last ptree must be defined because we are going to update its data
+                            BOOST_ASSERT(last);
+                            
+                            if (*text == Ch('\"'))  // Continuation must start with "
+                            {
+                                bool need_more_lines;
+                                std::basic_string<Ch> data = read_string(text, &need_more_lines);
+                                last->put_value(last->template get_value<std::basic_string<Ch> >() + data);
+                                state = need_more_lines ? s_data_cont : s_key;
+                            }
+                            else
+                                BOOST_PROPERTY_TREE_THROW(info_parser_error("expected \" after \\ in previous line", "", 0));
+
+                        }; break;
+
+                        // Should never happen
+                        default:
+                            BOOST_ASSERT(0);
+
+                    }
+                }
+            }
+
+            // Check if stack has initial size, otherwise some {'s have not been closed
+            if (stack.size() != 1)
+                BOOST_PROPERTY_TREE_THROW(info_parser_error("unmatched {", "", 0));
+
+        }
+        catch (info_parser_error &e)
+        {
+            // If line undefined rethrow error with correct filename and line
+            if (e.line() == 0)
+            {
+                BOOST_PROPERTY_TREE_THROW(info_parser_error(e.message(), filename, line_no));
+            }
+            else
+                BOOST_PROPERTY_TREE_THROW(e);
+
+        }
+
+    }
+
+} } }
+
+#endif
diff --git a/include/boost/property_tree/detail/info_parser_utils.hpp b/include/boost/property_tree/detail/info_parser_utils.hpp
new file mode 100644
index 0000000..f30010e
--- /dev/null
+++ b/include/boost/property_tree/detail/info_parser_utils.hpp
@@ -0,0 +1,32 @@
+// ----------------------------------------------------------------------------
+// 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_INFO_PARSER_CHCONV_HPP_INCLUDED
+#define BOOST_PROPERTY_TREE_DETAIL_INFO_PARSER_CHCONV_HPP_INCLUDED
+
+#include <string>
+
+namespace boost { namespace property_tree { namespace info_parser
+{
+
+    template<class ChDest, class ChSrc>
+    std::basic_string<ChDest> convert_chtype(const ChSrc *text)
+    {
+        std::basic_string<ChDest> result;
+        while (*text)
+        {
+            result += ChDest(*text);
+            ++text;
+        }
+        return result;
+    }
+
+} } }
+
+#endif
diff --git a/include/boost/property_tree/detail/info_parser_write.hpp b/include/boost/property_tree/detail/info_parser_write.hpp
new file mode 100644
index 0000000..6abd72c
--- /dev/null
+++ b/include/boost/property_tree/detail/info_parser_write.hpp
@@ -0,0 +1,147 @@
+// ----------------------------------------------------------------------------
+// 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_INFO_PARSER_WRITE_HPP_INCLUDED
+#define BOOST_PROPERTY_TREE_DETAIL_INFO_PARSER_WRITE_HPP_INCLUDED
+
+#include "boost/property_tree/ptree.hpp"
+#include "boost/property_tree/detail/info_parser_utils.hpp"
+#include <string>
+
+namespace boost { namespace property_tree { namespace info_parser
+{
+    template<class Ch>
+    void write_info_indent(std::basic_ostream<Ch> &stream,
+          int indent,
+          const info_writer_settings<Ch> &settings
+          )
+    {
+        stream << std::basic_string<Ch>(indent * settings.indent_count, settings.indent_char);
+    }
+    
+    // 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)
+        {
+            if (*b == Ch('\0')) result += Ch('\\'), result += Ch('0');
+            else if (*b == Ch('\a')) result += Ch('\\'), result += Ch('a');
+            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('\v')) result += Ch('\\'), result += Ch('v');
+            else if (*b == Ch('"')) result += Ch('\\'), result += Ch('"');
+            else if (*b == Ch('\\')) result += Ch('\\'), result += Ch('\\');
+            else
+                result += *b;
+            ++b;
+        }
+        return result;
+    }
+
+    template<class Ch>
+    bool is_simple_key(const std::basic_string<Ch> &key)
+    {
+        const static std::basic_string<Ch> chars = convert_chtype<Ch, char>(" \t{};\n\"");
+        return !key.empty() && key.find_first_of(chars) == key.npos;
+    }
+    
+    template<class Ch>
+    bool is_simple_data(const std::basic_string<Ch> &data)
+    {
+        const static std::basic_string<Ch> chars = convert_chtype<Ch, char>(" \t{};\n\"");
+        return !data.empty() && data.find_first_of(chars) == data.npos;
+    }
+
+    template<class Ptree>
+    void write_info_helper(std::basic_ostream<typename Ptree::key_type::value_type> &stream, 
+                           const Ptree &pt, 
+                           int indent,
+                           const info_writer_settings<typename Ptree::key_type::value_type> &settings)
+    {
+
+        // Character type
+        typedef typename Ptree::key_type::value_type Ch;
+        
+        // Write data
+        if (indent >= 0)
+        {
+            if (!pt.data().empty())
+            {
+                std::basic_string<Ch> data = create_escapes(pt.template get_value<std::basic_string<Ch> >());
+                if (is_simple_data(data))
+                    stream << Ch(' ') << data << Ch('\n');
+                else
+                    stream << Ch(' ') << Ch('\"') << data << Ch('\"') << Ch('\n');
+            }
+            else if (pt.empty())
+                stream << Ch(' ') << Ch('\"') << Ch('\"') << Ch('\n');
+            else
+                stream << Ch('\n');
+        }
+        
+        // Write keys
+        if (!pt.empty())
+        {
+            
+            // Open brace
+            if (indent >= 0)
+            {
+                write_info_indent( stream, indent, settings);
+                stream << Ch('{') << Ch('\n');
+            }
+            
+            // Write keys
+            typename Ptree::const_iterator it = pt.begin();
+            for (; it != pt.end(); ++it)
+            {
+
+                // Output key
+                std::basic_string<Ch> key = create_escapes(it->first);
+                write_info_indent( stream, indent+1, settings);
+                if (is_simple_key(key))
+                    stream << key;
+                else
+                    stream << Ch('\"') << key << Ch('\"');
+
+                // Output data and children  
+                write_info_helper(stream, it->second, indent + 1, settings);
+
+            }
+            
+            // Close brace
+            if (indent >= 0)
+            {
+                write_info_indent( stream, indent, settings);
+                stream << Ch('}') << Ch('\n');
+            }
+
+        }
+    }
+
+    // Write ptree to info stream
+    template<class Ptree>
+    void write_info_internal(std::basic_ostream<typename Ptree::key_type::value_type> &stream, 
+                             const Ptree &pt,
+                             const std::string &filename,
+                             const info_writer_settings<typename Ptree::key_type::value_type> &settings)
+    {
+        write_info_helper(stream, pt, -1, settings);
+        if (!stream.good())
+            BOOST_PROPERTY_TREE_THROW(info_parser_error("write error", filename, 0));
+    }
+
+} } }
+
+#endif
diff --git a/include/boost/property_tree/detail/info_parser_writer_settings.hpp b/include/boost/property_tree/detail/info_parser_writer_settings.hpp
new file mode 100644
index 0000000..a391dae
--- /dev/null
+++ b/include/boost/property_tree/detail/info_parser_writer_settings.hpp
@@ -0,0 +1,40 @@
+// ----------------------------------------------------------------------------
+// Copyright (C) 2002-2006 Marcin Kalicinski
+// Copyright (C) 2007 Alexey Baskakov
+//
+// 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_INFO_PARSER_WRITER_SETTINGS_HPP_INCLUDED
+#define BOOST_PROPERTY_TREE_DETAIL_INFO_PARSER_WRITER_SETTINGS_HPP_INCLUDED
+
+#include <string>
+
+namespace boost { namespace property_tree { namespace info_parser
+{
+
+    template <class Ch>
+    class info_writer_settings
+    {
+    public:
+        info_writer_settings(Ch indent_char = Ch(' '), unsigned indent_count = 4):
+            indent_char(indent_char),
+            indent_count(indent_count)
+        {
+        }
+        Ch indent_char;
+        int indent_count;
+    };
+
+    template <class Ch>
+    info_writer_settings<Ch> info_writer_make_settings(Ch indent_char = Ch(' '), unsigned indent_count = 4)
+    {
+        return info_writer_settings<Ch>(indent_char, indent_count);
+    }
+
+} } }
+
+#endif
diff --git a/include/boost/property_tree/detail/ptree_implementation.hpp b/include/boost/property_tree/detail/ptree_implementation.hpp
new file mode 100644
index 0000000..dd9fd37
--- /dev/null
+++ b/include/boost/property_tree/detail/ptree_implementation.hpp
@@ -0,0 +1,933 @@
+// ----------------------------------------------------------------------------
+// Copyright (C) 2002-2006 Marcin Kalicinski
+// Copyright (C) 2009 Sebastian Redl
+//
+// 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_PTREE_IMPLEMENTATION_HPP_INCLUDED
+#define BOOST_PROPERTY_TREE_DETAIL_PTREE_IMPLEMENTATION_HPP_INCLUDED
+
+#include <boost/iterator/iterator_adaptor.hpp>
+#include <boost/iterator/reverse_iterator.hpp>
+#include <boost/assert.hpp>
+#include <boost/utility/swap.hpp>
+#include <memory>
+
+#if (defined(BOOST_MSVC) && \
+     (_MSC_FULL_VER >= 160000000 && _MSC_FULL_VER < 170000000)) || \
+    (defined(BOOST_INTEL_WIN) && \
+     defined(BOOST_DINKUMWARE_STDLIB))
+#define BOOST_PROPERTY_TREE_PAIR_BUG
+#endif
+
+namespace boost { namespace property_tree
+{
+    template <class K, class D, class C>
+    struct basic_ptree<K, D, C>::subs
+    {
+        struct by_name {};
+        // The actual child container.
+#if defined(BOOST_PROPERTY_TREE_PAIR_BUG)
+        // MSVC 10 has moved std::pair's members to a base
+        // class. Unfortunately this does break the interface.
+        BOOST_STATIC_CONSTANT(unsigned,
+            first_offset = offsetof(value_type, first));
+#endif
+        typedef multi_index_container<value_type,
+            multi_index::indexed_by<
+                multi_index::sequenced<>,
+                multi_index::ordered_non_unique<multi_index::tag<by_name>,
+#if defined(BOOST_PROPERTY_TREE_PAIR_BUG)
+                    multi_index::member_offset<value_type, const key_type,
+                                        first_offset>,
+#else
+                    multi_index::member<value_type, const key_type,
+                                        &value_type::first>,
+#endif
+                    key_compare
+                >
+            >
+        > base_container;
+
+        // The by-name lookup index.
+        typedef typename base_container::template index<by_name>::type
+            by_name_index;
+
+        // Access functions for getting to the children of a tree.
+        static base_container& ch(self_type *s) {
+            return *static_cast<base_container*>(s->m_children);
+        }
+        static const base_container& ch(const self_type *s) {
+            return *static_cast<const base_container*>(s->m_children);
+        }
+        static by_name_index& assoc(self_type *s) {
+            return ch(s).BOOST_NESTED_TEMPLATE get<by_name>();
+        }
+        static const by_name_index& assoc(const self_type *s) {
+            return ch(s).BOOST_NESTED_TEMPLATE get<by_name>();
+        }
+    };
+    template <class K, class D, class C>
+    class basic_ptree<K, D, C>::iterator : public boost::iterator_adaptor<
+        iterator, typename subs::base_container::iterator, value_type>
+    {
+        friend class boost::iterator_core_access;
+        typedef boost::iterator_adaptor<
+            iterator, typename subs::base_container::iterator, value_type>
+            baset;
+    public:
+        typedef typename baset::reference reference;
+        iterator() {}
+        explicit iterator(typename iterator::base_type b)
+            : iterator::iterator_adaptor_(b)
+        {}
+        reference dereference() const
+        {
+            // multi_index doesn't allow modification of its values, because
+            // indexes could sort by anything, and modification screws that up.
+            // However, we only sort by the key, and it's protected against
+            // modification in the value_type, so this const_cast is safe.
+            return const_cast<reference>(*this->base_reference());
+        }
+    };
+    template <class K, class D, class C>
+    class basic_ptree<K, D, C>::const_iterator : public boost::iterator_adaptor<
+        const_iterator, typename subs::base_container::const_iterator>
+    {
+    public:
+        const_iterator() {}
+        explicit const_iterator(typename const_iterator::base_type b)
+            : const_iterator::iterator_adaptor_(b)
+        {}
+        const_iterator(iterator b)
+            : const_iterator::iterator_adaptor_(b.base())
+        {}
+    };
+    template <class K, class D, class C>
+    class basic_ptree<K, D, C>::reverse_iterator
+        : public boost::reverse_iterator<iterator>
+    {
+    public:
+        reverse_iterator() {}
+        explicit reverse_iterator(iterator b)
+            : boost::reverse_iterator<iterator>(b)
+        {}
+    };
+    template <class K, class D, class C>
+    class basic_ptree<K, D, C>::const_reverse_iterator
+        : public boost::reverse_iterator<const_iterator>
+    {
+    public:
+        const_reverse_iterator() {}
+        explicit const_reverse_iterator(const_iterator b)
+            : boost::reverse_iterator<const_iterator>(b)
+        {}
+        const_reverse_iterator(
+            typename basic_ptree<K, D, C>::reverse_iterator b)
+            : boost::reverse_iterator<const_iterator>(b)
+        {}
+    };
+    template <class K, class D, class C>
+    class basic_ptree<K, D, C>::assoc_iterator
+        : public boost::iterator_adaptor<assoc_iterator,
+                                         typename subs::by_name_index::iterator,
+                                         value_type>
+    {
+        friend class boost::iterator_core_access;
+        typedef boost::iterator_adaptor<assoc_iterator,
+                                         typename subs::by_name_index::iterator,
+                                         value_type>
+            baset;
+    public:
+        typedef typename baset::reference reference;
+        assoc_iterator() {}
+        explicit assoc_iterator(typename assoc_iterator::base_type b)
+            : assoc_iterator::iterator_adaptor_(b)
+        {}
+        reference dereference() const
+        {
+            return const_cast<reference>(*this->base_reference());
+        }
+    };
+    template <class K, class D, class C>
+    class basic_ptree<K, D, C>::const_assoc_iterator
+        : public boost::iterator_adaptor<const_assoc_iterator,
+                                   typename subs::by_name_index::const_iterator>
+    {
+    public:
+        const_assoc_iterator() {}
+        explicit const_assoc_iterator(
+            typename const_assoc_iterator::base_type b)
+            : const_assoc_iterator::iterator_adaptor_(b)
+        {}
+        const_assoc_iterator(assoc_iterator b)
+            : const_assoc_iterator::iterator_adaptor_(b.base())
+        {}
+    };
+
+
+    // Big five
+
+    // Perhaps the children collection could be created on-demand only, to
+    // reduce heap traffic. But that's a lot more work to implement.
+
+    template<class K, class D, class C> inline
+    basic_ptree<K, D, C>::basic_ptree()
+        : m_children(new typename subs::base_container)
+    {
+    }
+
+    template<class K, class D, class C> inline
+    basic_ptree<K, D, C>::basic_ptree(const data_type &d)
+        : m_data(d), m_children(new typename subs::base_container)
+    {
+    }
+
+    template<class K, class D, class C> inline
+    basic_ptree<K, D, C>::basic_ptree(const basic_ptree<K, D, C> &rhs)
+        : m_data(rhs.m_data),
+          m_children(new typename subs::base_container(subs::ch(&rhs)))
+    {
+    }
+
+    template<class K, class D, class C>
+    basic_ptree<K, D, C> &
+        basic_ptree<K, D, C>::operator =(const basic_ptree<K, D, C> &rhs)
+    {
+        self_type(rhs).swap(*this);
+        return *this;
+    }
+
+    template<class K, class D, class C>
+    basic_ptree<K, D, C>::~basic_ptree()
+    {
+        delete &subs::ch(this);
+    }
+
+    template<class K, class D, class C> inline
+    void basic_ptree<K, D, C>::swap(basic_ptree<K, D, C> &rhs)
+    {
+        boost::swap(m_data, rhs.m_data);
+        // Void pointers, no ADL necessary
+        std::swap(m_children, rhs.m_children);
+    }
+
+    // Container view
+
+    template<class K, class D, class C> inline
+    typename basic_ptree<K, D, C>::size_type
+        basic_ptree<K, D, C>::size() const
+    {
+        return subs::ch(this).size();
+    }
+
+    template<class K, class D, class C> inline
+    typename basic_ptree<K, D, C>::size_type
+        basic_ptree<K, D, C>::max_size() const
+    {
+        return subs::ch(this).max_size();
+    }
+
+    template<class K, class D, class C> inline
+    bool basic_ptree<K, D, C>::empty() const
+    {
+        return subs::ch(this).empty();
+    }
+
+    template<class K, class D, class C> inline
+    typename basic_ptree<K, D, C>::iterator
+        basic_ptree<K, D, C>::begin()
+    {
+        return iterator(subs::ch(this).begin());
+    }
+
+    template<class K, class D, class C> inline
+    typename basic_ptree<K, D, C>::const_iterator
+        basic_ptree<K, D, C>::begin() const
+    {
+        return const_iterator(subs::ch(this).begin());
+    }
+
+    template<class K, class D, class C> inline
+    typename basic_ptree<K, D, C>::iterator
+        basic_ptree<K, D, C>::end()
+    {
+        return iterator(subs::ch(this).end());
+    }
+
+    template<class K, class D, class C> inline
+    typename basic_ptree<K, D, C>::const_iterator
+        basic_ptree<K, D, C>::end() const
+    {
+        return const_iterator(subs::ch(this).end());
+    }
+
+    template<class K, class D, class C> inline
+    typename basic_ptree<K, D, C>::reverse_iterator
+        basic_ptree<K, D, C>::rbegin()
+    {
+        return reverse_iterator(this->end());
+    }
+
+    template<class K, class D, class C> inline
+    typename basic_ptree<K, D, C>::const_reverse_iterator
+        basic_ptree<K, D, C>::rbegin() const
+    {
+        return const_reverse_iterator(this->end());
+    }
+
+    template<class K, class D, class C> inline
+    typename basic_ptree<K, D, C>::reverse_iterator
+        basic_ptree<K, D, C>::rend()
+    {
+        return reverse_iterator(this->begin());
+    }
+
+    template<class K, class D, class C> inline
+    typename basic_ptree<K, D, C>::const_reverse_iterator
+        basic_ptree<K, D, C>::rend() const
+    {
+        return const_reverse_iterator(this->begin());
+    }
+
+    template<class K, class D, class C> inline
+    typename basic_ptree<K, D, C>::value_type &
+        basic_ptree<K, D, C>::front()
+    {
+        return const_cast<value_type&>(subs::ch(this).front());
+    }
+
+    template<class K, class D, class C> inline
+    const typename basic_ptree<K, D, C>::value_type &
+        basic_ptree<K, D, C>::front() const
+    {
+        return subs::ch(this).front();
+    }
+
+    template<class K, class D, class C> inline
+    typename basic_ptree<K, D, C>::value_type &
+        basic_ptree<K, D, C>::back()
+    {
+        return const_cast<value_type&>(subs::ch(this).back());
+    }
+
+    template<class K, class D, class C> inline
+    const typename basic_ptree<K, D, C>::value_type &
+        basic_ptree<K, D, C>::back() const
+    {
+        return subs::ch(this).back();
+    }
+
+    template<class K, class D, class C> inline
+    typename basic_ptree<K, D, C>::iterator
+    basic_ptree<K, D, C>::insert(iterator where, const value_type &value)
+    {
+        return iterator(subs::ch(this).insert(where.base(), value).first);
+    }
+
+    template<class K, class D, class C>
+    template<class It> inline
+    void basic_ptree<K, D, C>::insert(iterator where, It first, It last)
+    {
+        subs::ch(this).insert(where.base(), first, last);
+    }
+
+    template<class K, class D, class C> inline
+    typename basic_ptree<K, D, C>::iterator
+        basic_ptree<K, D, C>::erase(iterator where)
+    {
+        return iterator(subs::ch(this).erase(where.base()));
+    }
+
+    template<class K, class D, class C> inline
+    typename basic_ptree<K, D, C>::iterator
+        basic_ptree<K, D, C>::erase(iterator first, iterator last)
+    {
+        return iterator(subs::ch(this).erase(first.base(), last.base()));
+    }
+
+    template<class K, class D, class C> inline
+    typename basic_ptree<K, D, C>::iterator
+        basic_ptree<K, D, C>::push_front(const value_type &value)
+    {
+        return iterator(subs::ch(this).push_front(value).first);
+    }
+
+    template<class K, class D, class C> inline
+    typename basic_ptree<K, D, C>::iterator
+        basic_ptree<K, D, C>::push_back(const value_type &value)
+    {
+        return iterator(subs::ch(this).push_back(value).first);
+    }
+
+    template<class K, class D, class C> inline
+    void basic_ptree<K, D, C>::pop_front()
+    {
+        subs::ch(this).pop_front();
+    }
+
+    template<class K, class D, class C> inline
+    void basic_ptree<K, D, C>::pop_back()
+    {
+        subs::ch(this).pop_back();
+    }
+
+    template<class K, class D, class C> inline
+    void basic_ptree<K, D, C>::reverse()
+    {
+        subs::ch(this).reverse();
+    }
+
+    namespace impl
+    {
+        struct by_first
+        {
+            template <typename P>
+            bool operator ()(const P& lhs, const P& rhs) const {
+              return lhs.first < rhs.first;
+            }
+        };
+
+        template <typename C>
+        struct equal_pred
+        {
+            template <typename P>
+            bool operator ()(const P& lhs, const P& rhs) const {
+                C c;
+                return !c(lhs.first, rhs.first) &&
+                       !c(rhs.first, lhs.first) &&
+                       lhs.second == rhs.second;
+            }
+        };
+
+        template <typename C, typename MI>
+        bool equal_children(const MI& ch1, const MI& ch2) {
+            // Assumes ch1.size() == ch2.size()
+            return std::equal(ch1.begin(), ch1.end(),
+                ch2.begin(), equal_pred<C>());
+        }
+    }
+
+    template<class K, class D, class C> inline
+    void basic_ptree<K, D, C>::sort()
+    {
+        sort(impl::by_first());
+    }
+
+    template<class K, class D, class C>
+    template<class Compare> inline
+    void basic_ptree<K, D, C>::sort(Compare comp)
+    {
+        subs::ch(this).sort(comp);
+    }
+
+    // Equality
+
+    template<class K, class D, class C> inline
+    bool basic_ptree<K, D, C>::operator ==(
+                                  const basic_ptree<K, D, C> &rhs) const
+    {
+        // The size test is cheap, so add it as an optimization
+        return size() == rhs.size() && data() == rhs.data() &&
+            impl::equal_children<C>(subs::ch(this), subs::ch(&rhs));
+    }
+
+    template<class K, class D, class C> inline
+    bool basic_ptree<K, D, C>::operator !=(
+                                  const basic_ptree<K, D, C> &rhs) const
+    {
+        return !(*this == rhs);
+    }
+
+    // Associative view
+
+    template<class K, class D, class C> inline
+    typename basic_ptree<K, D, C>::assoc_iterator
+        basic_ptree<K, D, C>::ordered_begin()
+    {
+        return assoc_iterator(subs::assoc(this).begin());
+    }
+
+    template<class K, class D, class C> inline
+    typename basic_ptree<K, D, C>::const_assoc_iterator
+        basic_ptree<K, D, C>::ordered_begin() const
+    {
+        return const_assoc_iterator(subs::assoc(this).begin());
+    }
+
+    template<class K, class D, class C> inline
+    typename basic_ptree<K, D, C>::assoc_iterator
+        basic_ptree<K, D, C>::not_found()
+    {
+        return assoc_iterator(subs::assoc(this).end());
+    }
+
+    template<class K, class D, class C> inline
+    typename basic_ptree<K, D, C>::const_assoc_iterator
+        basic_ptree<K, D, C>::not_found() const
+    {
+        return const_assoc_iterator(subs::assoc(this).end());
+    }
+
+    template<class K, class D, class C> inline
+    typename basic_ptree<K, D, C>::assoc_iterator
+        basic_ptree<K, D, C>::find(const key_type &key)
+    {
+        return assoc_iterator(subs::assoc(this).find(key));
+    }
+
+    template<class K, class D, class C> inline
+    typename basic_ptree<K, D, C>::const_assoc_iterator
+        basic_ptree<K, D, C>::find(const key_type &key) const
+    {
+        return const_assoc_iterator(subs::assoc(this).find(key));
+    }
+
+    template<class K, class D, class C> inline
+    std::pair<
+        typename basic_ptree<K, D, C>::assoc_iterator,
+        typename basic_ptree<K, D, C>::assoc_iterator
+    > basic_ptree<K, D, C>::equal_range(const key_type &key)
+    {
+        std::pair<typename subs::by_name_index::iterator,
+                  typename subs::by_name_index::iterator> r(
+            subs::assoc(this).equal_range(key));
+        return std::pair<assoc_iterator, assoc_iterator>(
+          assoc_iterator(r.first), assoc_iterator(r.second));
+    }
+
+    template<class K, class D, class C> inline
+    std::pair<
+        typename basic_ptree<K, D, C>::const_assoc_iterator,
+        typename basic_ptree<K, D, C>::const_assoc_iterator
+    > basic_ptree<K, D, C>::equal_range(const key_type &key) const
+    {
+        std::pair<typename subs::by_name_index::const_iterator,
+                  typename subs::by_name_index::const_iterator> r(
+            subs::assoc(this).equal_range(key));
+        return std::pair<const_assoc_iterator, const_assoc_iterator>(
+            const_assoc_iterator(r.first), const_assoc_iterator(r.second));
+    }
+
+    template<class K, class D, class C> inline
+    typename basic_ptree<K, D, C>::size_type
+        basic_ptree<K, D, C>::count(const key_type &key) const
+    {
+        return subs::assoc(this).count(key);
+    }
+
+    template<class K, class D, class C> inline
+    typename basic_ptree<K, D, C>::size_type
+        basic_ptree<K, D, C>::erase(const key_type &key)
+    {
+        return subs::assoc(this).erase(key);
+    }
+
+    template<class K, class D, class C> inline
+    typename basic_ptree<K, D, C>::iterator
+        basic_ptree<K, D, C>::to_iterator(assoc_iterator ai)
+    {
+        return iterator(subs::ch(this).
+            BOOST_NESTED_TEMPLATE project<0>(ai.base()));
+    }
+
+    template<class K, class D, class C> inline
+    typename basic_ptree<K, D, C>::const_iterator
+        basic_ptree<K, D, C>::to_iterator(const_assoc_iterator ai) const
+    {
+        return const_iterator(subs::ch(this).
+            BOOST_NESTED_TEMPLATE project<0>(ai.base()));
+    }
+
+    // Property tree view
+
+    template<class K, class D, class C> inline
+    typename basic_ptree<K, D, C>::data_type &
+        basic_ptree<K, D, C>::data()
+    {
+        return m_data;
+    }
+
+    template<class K, class D, class C> inline
+    const typename basic_ptree<K, D, C>::data_type &
+        basic_ptree<K, D, C>::data() const
+    {
+        return m_data;
+    }
+
+    template<class K, class D, class C> inline
+    void basic_ptree<K, D, C>::clear()
+    {
+        m_data = data_type();
+        subs::ch(this).clear();
+    }
+
+    template<class K, class D, class C>
+    basic_ptree<K, D, C> &
+        basic_ptree<K, D, C>::get_child(const path_type &path)
+    {
+        path_type p(path);
+        self_type *n = walk_path(p);
+        if (!n) {
+            BOOST_PROPERTY_TREE_THROW(ptree_bad_path("No such node", path));
+        }
+        return *n;
+    }
+
+    template<class K, class D, class C> inline
+    const basic_ptree<K, D, C> &
+        basic_ptree<K, D, C>::get_child(const path_type &path) const
+    {
+        return const_cast<self_type*>(this)->get_child(path);
+    }
+
+    template<class K, class D, class C> inline
+    basic_ptree<K, D, C> &
+        basic_ptree<K, D, C>::get_child(const path_type &path,
+                                        self_type &default_value)
+    {
+        path_type p(path);
+        self_type *n = walk_path(p);
+        return n ? *n : default_value;
+    }
+
+    template<class K, class D, class C> inline
+    const basic_ptree<K, D, C> &
+        basic_ptree<K, D, C>::get_child(const path_type &path,
+                                        const self_type &default_value) const
+    {
+        return const_cast<self_type*>(this)->get_child(path,
+            const_cast<self_type&>(default_value));
+    }
+
+
+    template<class K, class D, class C>
+    optional<basic_ptree<K, D, C> &>
+        basic_ptree<K, D, C>::get_child_optional(const path_type &path)
+    {
+        path_type p(path);
+        self_type *n = walk_path(p);
+        if (!n) {
+            return optional<self_type&>();
+        }
+        return *n;
+    }
+
+    template<class K, class D, class C>
+    optional<const basic_ptree<K, D, C> &>
+        basic_ptree<K, D, C>::get_child_optional(const path_type &path) const
+    {
+        path_type p(path);
+        self_type *n = walk_path(p);
+        if (!n) {
+            return optional<const self_type&>();
+        }
+        return *n;
+    }
+
+    template<class K, class D, class C>
+    basic_ptree<K, D, C> &
+        basic_ptree<K, D, C>::put_child(const path_type &path,
+                                        const self_type &value)
+    {
+        path_type p(path);
+        self_type &parent = force_path(p);
+        // Got the parent. Now get the correct child.
+        key_type fragment = p.reduce();
+        assoc_iterator el = parent.find(fragment);
+        // If the new child exists, replace it.
+        if(el != parent.not_found()) {
+            return el->second = value;
+        } else {
+            return parent.push_back(value_type(fragment, value))->second;
+        }
+    }
+
+    template<class K, class D, class C>
+    basic_ptree<K, D, C> &
+        basic_ptree<K, D, C>::add_child(const path_type &path,
+                                        const self_type &value)
+    {
+        path_type p(path);
+        self_type &parent = force_path(p);
+        // Got the parent.
+        key_type fragment = p.reduce();
+        return parent.push_back(value_type(fragment, value))->second;
+    }
+
+    template<class K, class D, class C>
+    template<class Type, class Translator>
+    typename boost::enable_if<detail::is_translator<Translator>, Type>::type
+    basic_ptree<K, D, C>::get_value(Translator tr) const
+    {
+        if(boost::optional<Type> o = get_value_optional<Type>(tr)) {
+            return *o;
+        }
+        BOOST_PROPERTY_TREE_THROW(ptree_bad_data(
+            std::string("conversion of data to type \"") +
+            typeid(Type).name() + "\" failed", data()));
+    }
+
+    template<class K, class D, class C>
+    template<class Type> inline
+    Type basic_ptree<K, D, C>::get_value() const
+    {
+        return get_value<Type>(
+            typename translator_between<data_type, Type>::type());
+    }
+
+    template<class K, class D, class C>
+    template<class Type, class Translator> inline
+    Type basic_ptree<K, D, C>::get_value(const Type &default_value,
+                                         Translator tr) const
+    {
+        return get_value_optional<Type>(tr).get_value_or(default_value);
+    }
+
+    template<class K, class D, class C>
+    template <class Ch, class Translator>
+    typename boost::enable_if<
+        detail::is_character<Ch>,
+        std::basic_string<Ch>
+    >::type
+    basic_ptree<K, D, C>::get_value(const Ch *default_value, Translator tr)const
+    {
+        return get_value<std::basic_string<Ch>, Translator>(default_value, tr);
+    }
+
+    template<class K, class D, class C>
+    template<class Type> inline
+    typename boost::disable_if<detail::is_translator<Type>, Type>::type
+    basic_ptree<K, D, C>::get_value(const Type &default_value) const
+    {
+        return get_value(default_value,
+                         typename translator_between<data_type, Type>::type());
+    }
+
+    template<class K, class D, class C>
+    template <class Ch>
+    typename boost::enable_if<
+        detail::is_character<Ch>,
+        std::basic_string<Ch>
+    >::type
+    basic_ptree<K, D, C>::get_value(const Ch *default_value) const
+    {
+        return get_value< std::basic_string<Ch> >(default_value);
+    }
+
+    template<class K, class D, class C>
+    template<class Type, class Translator> inline
+    optional<Type> basic_ptree<K, D, C>::get_value_optional(
+                                                Translator tr) const
+    {
+        return tr.get_value(data());
+    }
+
+    template<class K, class D, class C>
+    template<class Type> inline
+    optional<Type> basic_ptree<K, D, C>::get_value_optional() const
+    {
+        return get_value_optional<Type>(
+            typename translator_between<data_type, Type>::type());
+    }
+
+    template<class K, class D, class C>
+    template<class Type, class Translator> inline
+    typename boost::enable_if<detail::is_translator<Translator>, Type>::type
+    basic_ptree<K, D, C>::get(const path_type &path,
+                              Translator tr) const
+    {
+        return get_child(path).BOOST_NESTED_TEMPLATE get_value<Type>(tr);
+    }
+
+    template<class K, class D, class C>
+    template<class Type> inline
+    Type basic_ptree<K, D, C>::get(const path_type &path) const
+    {
+        return get_child(path).BOOST_NESTED_TEMPLATE get_value<Type>();
+    }
+
+    template<class K, class D, class C>
+    template<class Type, class Translator> inline
+    Type basic_ptree<K, D, C>::get(const path_type &path,
+                                   const Type &default_value,
+                                   Translator tr) const
+    {
+        return get_optional<Type>(path, tr).get_value_or(default_value);
+    }
+
+    template<class K, class D, class C>
+    template <class Ch, class Translator>
+    typename boost::enable_if<
+        detail::is_character<Ch>,
+        std::basic_string<Ch>
+    >::type
+    basic_ptree<K, D, C>::get(
+        const path_type &path, const Ch *default_value, Translator tr) const
+    {
+        return get<std::basic_string<Ch>, Translator>(path, default_value, tr);
+    }
+
+    template<class K, class D, class C>
+    template<class Type> inline
+    typename boost::disable_if<detail::is_translator<Type>, Type>::type
+    basic_ptree<K, D, C>::get(const path_type &path,
+                              const Type &default_value) const
+    {
+        return get_optional<Type>(path).get_value_or(default_value);
+    }
+
+    template<class K, class D, class C>
+    template <class Ch>
+    typename boost::enable_if<
+        detail::is_character<Ch>,
+        std::basic_string<Ch>
+    >::type
+    basic_ptree<K, D, C>::get(
+        const path_type &path, const Ch *default_value) const
+    {
+        return get< std::basic_string<Ch> >(path, default_value);
+    }
+
+    template<class K, class D, class C>
+    template<class Type, class Translator>
+    optional<Type> basic_ptree<K, D, C>::get_optional(const path_type &path,
+                                                         Translator tr) const
+    {
+        if (optional<const self_type&> child = get_child_optional(path))
+            return child.get().
+                BOOST_NESTED_TEMPLATE get_value_optional<Type>(tr);
+        else
+            return optional<Type>();
+    }
+
+    template<class K, class D, class C>
+    template<class Type>
+    optional<Type> basic_ptree<K, D, C>::get_optional(
+                                                const path_type &path) const
+    {
+        if (optional<const self_type&> child = get_child_optional(path))
+            return child.get().BOOST_NESTED_TEMPLATE get_value_optional<Type>();
+        else
+            return optional<Type>();
+    }
+
+    template<class K, class D, class C>
+    template<class Type, class Translator>
+    void basic_ptree<K, D, C>::put_value(const Type &value, Translator tr)
+    {
+        if(optional<data_type> o = tr.put_value(value)) {
+            data() = *o;
+        } else {
+            BOOST_PROPERTY_TREE_THROW(ptree_bad_data(
+                std::string("conversion of type \"") + typeid(Type).name() +
+                "\" to data failed", boost::any()));
+        }
+    }
+
+    template<class K, class D, class C>
+    template<class Type> inline
+    void basic_ptree<K, D, C>::put_value(const Type &value)
+    {
+        put_value(value, typename translator_between<data_type, Type>::type());
+    }
+
+    template<class K, class D, class C>
+    template<class Type, typename Translator>
+    basic_ptree<K, D, C> & basic_ptree<K, D, C>::put(
+        const path_type &path, const Type &value, Translator tr)
+    {
+        if(optional<self_type &> child = get_child_optional(path)) {
+            child.get().put_value(value, tr);
+            return *child;
+        } else {
+            self_type &child2 = put_child(path, self_type());
+            child2.put_value(value, tr);
+            return child2;
+        }
+    }
+
+    template<class K, class D, class C>
+    template<class Type> inline
+    basic_ptree<K, D, C> & basic_ptree<K, D, C>::put(
+        const path_type &path, const Type &value)
+    {
+        return put(path, value,
+                   typename translator_between<data_type, Type>::type());
+    }
+
+    template<class K, class D, class C>
+    template<class Type, typename Translator> inline
+    basic_ptree<K, D, C> & basic_ptree<K, D, C>::add(
+        const path_type &path, const Type &value, Translator tr)
+    {
+        self_type &child = add_child(path, self_type());
+        child.put_value(value, tr);
+        return child;
+    }
+
+    template<class K, class D, class C>
+    template<class Type> inline
+    basic_ptree<K, D, C> & basic_ptree<K, D, C>::add(
+        const path_type &path, const Type &value)
+    {
+        return add(path, value,
+                   typename translator_between<data_type, Type>::type());
+    }
+
+
+    template<class K, class D, class C>
+    basic_ptree<K, D, C> *
+    basic_ptree<K, D, C>::walk_path(path_type &p) const
+    {
+        if(p.empty()) {
+            // I'm the child we're looking for.
+            return const_cast<basic_ptree*>(this);
+        }
+        // Recurse down the tree to find the path.
+        key_type fragment = p.reduce();
+        const_assoc_iterator el = find(fragment);
+        if(el == not_found()) {
+            // No such child.
+            return 0;
+        }
+        // Not done yet, recurse.
+        return el->second.walk_path(p);
+    }
+
+    template<class K, class D, class C>
+    basic_ptree<K, D, C> & basic_ptree<K, D, C>::force_path(path_type &p)
+    {
+        BOOST_ASSERT(!p.empty() && "Empty path not allowed for put_child.");
+        if(p.single()) {
+            // I'm the parent we're looking for.
+            return *this;
+        }
+        key_type fragment = p.reduce();
+        assoc_iterator el = find(fragment);
+        // If we've found an existing child, go down that path. Else
+        // create a new one.
+        self_type& child = el == not_found() ?
+            push_back(value_type(fragment, self_type()))->second : el->second;
+        return child.force_path(p);
+    }
+
+    // Free functions
+
+    template<class K, class D, class C>
+    inline void swap(basic_ptree<K, D, C> &pt1, basic_ptree<K, D, C> &pt2)
+    {
+        pt1.swap(pt2);
+    }
+
+} }
+
+#if defined(BOOST_PROPERTY_TREE_PAIR_BUG)
+#undef BOOST_PROPERTY_TREE_PAIR_BUG
+#endif
+
+#endif
diff --git a/include/boost/property_tree/detail/ptree_utils.hpp b/include/boost/property_tree/detail/ptree_utils.hpp
new file mode 100644
index 0000000..c353e08
--- /dev/null
+++ b/include/boost/property_tree/detail/ptree_utils.hpp
@@ -0,0 +1,105 @@
+// ----------------------------------------------------------------------------
+// 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_PTREE_UTILS_HPP_INCLUDED
+#define BOOST_PROPERTY_TREE_DETAIL_PTREE_UTILS_HPP_INCLUDED
+
+#include <boost/limits.hpp>
+#include <boost/type_traits/integral_constant.hpp>
+#include <boost/mpl/has_xxx.hpp>
+#include <boost/mpl/and.hpp>
+#include <string>
+#include <algorithm>
+#include <locale>
+
+namespace boost { namespace property_tree { namespace detail
+{
+
+    template<class T>
+    struct less_nocase
+    {
+        typedef typename T::value_type Ch;
+        std::locale m_locale;
+        inline bool operator()(Ch c1, Ch c2) const
+        {
+            return std::toupper(c1, m_locale) < std::toupper(c2, m_locale);
+        }
+        inline bool operator()(const T &t1, const T &t2) const
+        {
+            return std::lexicographical_compare(t1.begin(), t1.end(),
+                                                t2.begin(), t2.end(), *this);
+        }
+    };
+
+    template <typename Ch>
+    struct is_character : public boost::false_type {};
+    template <>
+    struct is_character<char> : public boost::true_type {};
+    template <>
+    struct is_character<wchar_t> : public boost::true_type {};
+
+
+    BOOST_MPL_HAS_XXX_TRAIT_DEF(internal_type)
+    BOOST_MPL_HAS_XXX_TRAIT_DEF(external_type)
+    template <typename T>
+    struct is_translator : public boost::mpl::and_<
+        has_internal_type<T>, has_external_type<T> > {};
+
+
+
+    // Naively convert narrow string to another character type
+    template<typename Str>
+    Str widen(const char *text)
+    {
+        Str result;
+        while (*text)
+        {
+            result += typename Str::value_type(*text);
+            ++text;
+        }
+        return result;
+    }
+
+    // Naively convert string to narrow character type
+    template<typename Str, typename char_type>
+    Str narrow(const char_type *text)
+    {
+        Str result;
+        while (*text)
+        {
+            if (*text < 0 || *text > (std::numeric_limits<char>::max)())
+                result += '*';
+            else
+                result += typename Str::value_type(*text);
+            ++text;
+        }
+        return result;
+    }
+
+    // Remove trailing and leading spaces
+    template<class Str>
+    Str trim(const Str &s, const std::locale &loc = std::locale())
+    {
+        typename Str::const_iterator first = s.begin();
+        typename Str::const_iterator end = s.end();
+        while (first != end && std::isspace(*first, loc))
+            ++first;
+        if (first == end)
+            return Str();
+        typename Str::const_iterator last = end;
+        do --last; while (std::isspace(*last, loc));
+        if (first != s.begin() || last + 1 != end)
+            return Str(first, last + 1);
+        else
+            return s;
+    }
+
+} } }
+
+#endif
diff --git a/include/boost/property_tree/detail/rapidxml.hpp b/include/boost/property_tree/detail/rapidxml.hpp
new file mode 100644
index 0000000..9e3d76a
--- /dev/null
+++ b/include/boost/property_tree/detail/rapidxml.hpp
@@ -0,0 +1,2595 @@
+// ----------------------------------------------------------------------------
+// Copyright (C) 2006, 2009 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_RAPIDXML_HPP_INCLUDED
+#define BOOST_PROPERTY_TREE_RAPIDXML_HPP_INCLUDED
+
+//! \file rapidxml.hpp This file contains rapidxml parser and DOM implementation
+
+#include <boost/assert.hpp>
+#include <cstdlib>      // For std::size_t
+#include <new>          // For placement new
+
+// On MSVC, disable "conditional expression is constant" warning (level 4). 
+// This warning is almost impossible to avoid with certain types of templated code
+#ifdef _MSC_VER
+    #pragma warning(push)
+    #pragma warning(disable:4127)   // Conditional expression is constant
+#endif
+
+///////////////////////////////////////////////////////////////////////////
+// BOOST_PROPERTY_TREE_RAPIDXML_PARSE_ERROR
+    
+#include <exception>    // For std::exception
+
+#define BOOST_PROPERTY_TREE_RAPIDXML_PARSE_ERROR(what, where) throw parse_error(what, where)
+
+namespace boost { namespace property_tree { namespace detail {namespace rapidxml
+{
+
+    //! Parse error exception. 
+    //! This exception is thrown by the parser when an error occurs. 
+    //! Use what() function to get human-readable error message. 
+    //! Use where() function to get a pointer to position within source text where error was detected.
+    //! <br><br>
+    //! If throwing exceptions by the parser is undesirable, 
+    //! it can be disabled by defining RAPIDXML_NO_EXCEPTIONS macro before rapidxml.hpp is included.
+    //! This will cause the parser to call rapidxml::parse_error_handler() function instead of throwing an exception.
+    //! This function must be defined by the user.
+    //! <br><br>
+    //! This class derives from <code>std::exception</code> class.
+    class parse_error: public std::exception
+    {
+    
+    public:
+    
+        //! Constructs parse error
+        parse_error(const char *wa, void *we)
+            : m_what(wa)
+            , m_where(we)
+        {
+        }
+
+        //! Gets human readable description of error.
+        //! \return Pointer to null terminated description of the error.
+        virtual const char *what() const throw()
+        {
+            return m_what;
+        }
+
+        //! Gets pointer to character data where error happened.
+        //! Ch should be the same as char type of xml_document that produced the error.
+        //! \return Pointer to location within the parsed string where error occurred.
+        template<class Ch>
+        Ch *where() const
+        {
+            return reinterpret_cast<Ch *>(m_where);
+        }
+
+    private:  
+
+        const char *m_what;
+        void *m_where;
+
+    };
+}}}}
+
+///////////////////////////////////////////////////////////////////////////
+// Pool sizes
+
+#ifndef BOOST_PROPERTY_TREE_RAPIDXML_STATIC_POOL_SIZE
+    // Size of static memory block of memory_pool.
+    // Define BOOST_PROPERTY_TREE_RAPIDXML_STATIC_POOL_SIZE before including rapidxml.hpp if you want to override the default value.
+    // No dynamic memory allocations are performed by memory_pool until static memory is exhausted.
+    #define BOOST_PROPERTY_TREE_RAPIDXML_STATIC_POOL_SIZE (64 * 1024)
+#endif
+
+#ifndef BOOST_PROPERTY_TREE_RAPIDXML_DYNAMIC_POOL_SIZE
+    // Size of dynamic memory block of memory_pool.
+    // Define BOOST_PROPERTY_TREE_RAPIDXML_DYNAMIC_POOL_SIZE before including rapidxml.hpp if you want to override the default value.
+    // After the static block is exhausted, dynamic blocks with approximately this size are allocated by memory_pool.
+    #define BOOST_PROPERTY_TREE_RAPIDXML_DYNAMIC_POOL_SIZE (64 * 1024)
+#endif
+
+#ifndef BOOST_PROPERTY_TREE_RAPIDXML_ALIGNMENT
+    // Memory allocation alignment.
+    // Define BOOST_PROPERTY_TREE_RAPIDXML_ALIGNMENT before including rapidxml.hpp if you want to override the default value, which is the size of pointer.
+    // All memory allocations for nodes, attributes and strings will be aligned to this value.
+    // This must be a power of 2 and at least 1, otherwise memory_pool will not work.
+    #define BOOST_PROPERTY_TREE_RAPIDXML_ALIGNMENT sizeof(void *)
+#endif
+
+namespace boost { namespace property_tree { namespace detail {namespace rapidxml
+{
+    // Forward declarations
+    template<class Ch> class xml_node;
+    template<class Ch> class xml_attribute;
+    template<class Ch> class xml_document;
+    
+    //! Enumeration listing all node types produced by the parser.
+    //! Use xml_node::type() function to query node type.
+    enum node_type
+    {
+        node_document,      //!< A document node. Name and value are empty.
+        node_element,       //!< An element node. Name contains element name. Value contains text of first data node.
+        node_data,          //!< A data node. Name is empty. Value contains data text.
+        node_cdata,         //!< A CDATA node. Name is empty. Value contains data text.
+        node_comment,       //!< A comment node. Name is empty. Value contains comment text.
+        node_declaration,   //!< A declaration node. Name and value are empty. Declaration parameters (version, encoding and standalone) are in node attributes.
+        node_doctype,       //!< A DOCTYPE node. Name is empty. Value contains DOCTYPE text.
+        node_pi             //!< A PI node. Name contains target. Value contains instructions.
+    };
+
+    ///////////////////////////////////////////////////////////////////////
+    // Parsing flags
+
+    //! Parse flag instructing the parser to not create data nodes. 
+    //! Text of first data node will still be placed in value of parent element, unless rapidxml::parse_no_element_values flag is also specified.
+    //! Can be combined with other flags by use of | operator.
+    //! <br><br>
+    //! See xml_document::parse() function.
+    const int parse_no_data_nodes = 0x1;            
+
+    //! Parse flag instructing the parser to not use text of first data node as a value of parent element.
+    //! Can be combined with other flags by use of | operator.
+    //! Note that child data nodes of element node take precendence over its value when printing. 
+    //! That is, if element has one or more child data nodes <em>and</em> a value, the value will be ignored.
+    //! Use rapidxml::parse_no_data_nodes flag to prevent creation of data nodes if you want to manipulate data using values of elements.
+    //! <br><br>
+    //! See xml_document::parse() function.
+    const int parse_no_element_values = 0x2;
+    
+    //! Parse flag instructing the parser to not place zero terminators after strings in the source text.
+    //! By default zero terminators are placed, modifying source text.
+    //! Can be combined with other flags by use of | operator.
+    //! <br><br>
+    //! See xml_document::parse() function.
+    const int parse_no_string_terminators = 0x4;
+    
+    //! Parse flag instructing the parser to not translate entities in the source text.
+    //! By default entities are translated, modifying source text.
+    //! Can be combined with other flags by use of | operator.
+    //! <br><br>
+    //! See xml_document::parse() function.
+    const int parse_no_entity_translation = 0x8;
+    
+    //! Parse flag instructing the parser to disable UTF-8 handling and assume plain 8 bit characters.
+    //! By default, UTF-8 handling is enabled.
+    //! Can be combined with other flags by use of | operator.
+    //! <br><br>
+    //! See xml_document::parse() function.
+    const int parse_no_utf8 = 0x10;
+    
+    //! Parse flag instructing the parser to create XML declaration node.
+    //! By default, declaration node is not created.
+    //! Can be combined with other flags by use of | operator.
+    //! <br><br>
+    //! See xml_document::parse() function.
+    const int parse_declaration_node = 0x20;
+    
+    //! Parse flag instructing the parser to create comments nodes.
+    //! By default, comment nodes are not created.
+    //! Can be combined with other flags by use of | operator.
+    //! <br><br>
+    //! See xml_document::parse() function.
+    const int parse_comment_nodes = 0x40;
+    
+    //! Parse flag instructing the parser to create DOCTYPE node.
+    //! By default, doctype node is not created.
+    //! Although W3C specification allows at most one DOCTYPE node, RapidXml will silently accept documents with more than one.
+    //! Can be combined with other flags by use of | operator.
+    //! <br><br>
+    //! See xml_document::parse() function.
+    const int parse_doctype_node = 0x80;
+    
+    //! Parse flag instructing the parser to create PI nodes.
+    //! By default, PI nodes are not created.
+    //! Can be combined with other flags by use of | operator.
+    //! <br><br>
+    //! See xml_document::parse() function.
+    const int parse_pi_nodes = 0x100;
+    
+    //! Parse flag instructing the parser to validate closing tag names. 
+    //! If not set, name inside closing tag is irrelevant to the parser.
+    //! By default, closing tags are not validated.
+    //! Can be combined with other flags by use of | operator.
+    //! <br><br>
+    //! See xml_document::parse() function.
+    const int parse_validate_closing_tags = 0x200;
+    
+    //! Parse flag instructing the parser to trim all leading and trailing whitespace of data nodes.
+    //! By default, whitespace is not trimmed. 
+    //! This flag does not cause the parser to modify source text.
+    //! Can be combined with other flags by use of | operator.
+    //! <br><br>
+    //! See xml_document::parse() function.
+    const int parse_trim_whitespace = 0x400;
+
+    //! Parse flag instructing the parser to condense all whitespace runs of data nodes to a single space character.
+    //! Trimming of leading and trailing whitespace of data is controlled by rapidxml::parse_trim_whitespace flag.
+    //! By default, whitespace is not normalized. 
+    //! If this flag is specified, source text will be modified.
+    //! Can be combined with other flags by use of | operator.
+    //! <br><br>
+    //! See xml_document::parse() function.
+    const int parse_normalize_whitespace = 0x800;
+
+    // Compound flags
+    
+    //! Parse flags which represent default behaviour of the parser. 
+    //! This is always equal to 0, so that all other flags can be simply ored together.
+    //! Normally there is no need to inconveniently disable flags by anding with their negated (~) values.
+    //! This also means that meaning of each flag is a <i>negation</i> of the default setting. 
+    //! For example, if flag name is rapidxml::parse_no_utf8, it means that utf-8 is <i>enabled</i> by default,
+    //! and using the flag will disable it.
+    //! <br><br>
+    //! See xml_document::parse() function.
+    const int parse_default = 0;
+    
+    //! A combination of parse flags that forbids any modifications of the source text. 
+    //! This also results in faster parsing. However, note that the following will occur:
+    //! <ul>
+    //! <li>names and values of nodes will not be zero terminated, you have to use xml_base::name_size() and xml_base::value_size() functions to determine where name and value ends</li>
+    //! <li>entities will not be translated</li>
+    //! <li>whitespace will not be normalized</li>
+    //! </ul>
+    //! See xml_document::parse() function.
+    const int parse_non_destructive = parse_no_string_terminators | parse_no_entity_translation;
+    
+    //! A combination of parse flags resulting in fastest possible parsing, without sacrificing important data.
+    //! <br><br>
+    //! See xml_document::parse() function.
+    const int parse_fastest = parse_non_destructive | parse_no_data_nodes;
+    
+    //! A combination of parse flags resulting in largest amount of data being extracted. 
+    //! This usually results in slowest parsing.
+    //! <br><br>
+    //! See xml_document::parse() function.
+    const int parse_full = parse_declaration_node | parse_comment_nodes | parse_doctype_node | parse_pi_nodes | parse_validate_closing_tags;
+
+    ///////////////////////////////////////////////////////////////////////
+    // Internals
+
+    //! \cond internal
+    namespace internal
+    {
+
+        // Struct that contains lookup tables for the parser
+        // It must be a template to allow correct linking (because it has static data members, which are defined in a header file).
+        template<int Dummy>
+        struct lookup_tables
+        {
+            static const unsigned char lookup_whitespace[256];              // Whitespace table
+            static const unsigned char lookup_node_name[256];               // Node name table
+            static const unsigned char lookup_text[256];                    // Text table
+            static const unsigned char lookup_text_pure_no_ws[256];         // Text table
+            static const unsigned char lookup_text_pure_with_ws[256];       // Text table
+            static const unsigned char lookup_attribute_name[256];          // Attribute name table
+            static const unsigned char lookup_attribute_data_1[256];        // Attribute data table with single quote
+            static const unsigned char lookup_attribute_data_1_pure[256];   // Attribute data table with single quote
+            static const unsigned char lookup_attribute_data_2[256];        // Attribute data table with double quotes
+            static const unsigned char lookup_attribute_data_2_pure[256];   // Attribute data table with double quotes
+            static const unsigned char lookup_digits[256];                  // Digits
+            static const unsigned char lookup_upcase[256];                  // To uppercase conversion table for ASCII characters
+        };
+
+        // Find length of the string
+        template<class Ch>
+        inline std::size_t measure(const Ch *p)
+        {
+            const Ch *tmp = p;
+            while (*tmp) 
+                ++tmp;
+            return tmp - p;
+        }
+
+        // Compare strings for equality
+        template<class Ch>
+        inline bool compare(const Ch *p1, std::size_t size1, const Ch *p2, std::size_t size2, bool case_sensitive)
+        {
+            if (size1 != size2)
+                return false;
+            if (case_sensitive)
+            {
+                for (const Ch *end = p1 + size1; p1 < end; ++p1, ++p2)
+                    if (*p1 != *p2)
+                        return false;
+            }
+            else
+            {
+                for (const Ch *end = p1 + size1; p1 < end; ++p1, ++p2)
+                    if (lookup_tables<0>::lookup_upcase[static_cast<unsigned char>(*p1)] != lookup_tables<0>::lookup_upcase[static_cast<unsigned char>(*p2)])
+                        return false;
+            }
+            return true;
+        }
+
+        template<class Ch>
+        inline size_t get_index(const Ch c)
+        {
+            // If not ASCII char, its semantic is same as plain 'z'.
+            // char could be signed, so first stretch and make unsigned.
+            unsigned n = c;
+            if (n > 127)
+            {
+                return 'z';
+            }
+            return c;
+        }
+    }
+    //! \endcond
+
+    ///////////////////////////////////////////////////////////////////////
+    // Memory pool
+    
+    //! This class is used by the parser to create new nodes and attributes, without overheads of dynamic memory allocation.
+    //! In most cases, you will not need to use this class directly. 
+    //! However, if you need to create nodes manually or modify names/values of nodes, 
+    //! you are encouraged to use memory_pool of relevant xml_document to allocate the memory. 
+    //! Not only is this faster than allocating them by using <code>new</code> operator, 
+    //! but also their lifetime will be tied to the lifetime of document, 
+    //! possibly simplyfing memory management. 
+    //! <br><br>
+    //! Call allocate_node() or allocate_attribute() functions to obtain new nodes or attributes from the pool. 
+    //! You can also call allocate_string() function to allocate strings.
+    //! Such strings can then be used as names or values of nodes without worrying about their lifetime.
+    //! Note that there is no <code>free()</code> function -- all allocations are freed at once when clear() function is called, 
+    //! or when the pool is destroyed.
+    //! <br><br>
+    //! It is also possible to create a standalone memory_pool, and use it 
+    //! to allocate nodes, whose lifetime will not be tied to any document.
+    //! <br><br>
+    //! Pool maintains <code>BOOST_PROPERTY_TREE_RAPIDXML_STATIC_POOL_SIZE</code> bytes of statically allocated memory. 
+    //! Until static memory is exhausted, no dynamic memory allocations are done.
+    //! When static memory is exhausted, pool allocates additional blocks of memory of size <code>BOOST_PROPERTY_TREE_RAPIDXML_DYNAMIC_POOL_SIZE</code> each,
+    //! by using global <code>new[]</code> and <code>delete[]</code> operators. 
+    //! This behaviour can be changed by setting custom allocation routines. 
+    //! Use set_allocator() function to set them.
+    //! <br><br>
+    //! Allocations for nodes, attributes and strings are aligned at <code>BOOST_PROPERTY_TREE_RAPIDXML_ALIGNMENT</code> bytes.
+    //! This value defaults to the size of pointer on target architecture.
+    //! <br><br>
+    //! To obtain absolutely top performance from the parser,
+    //! it is important that all nodes are allocated from a single, contiguous block of memory.
+    //! Otherwise, cache misses when jumping between two (or more) disjoint blocks of memory can slow down parsing quite considerably.
+    //! If required, you can tweak <code>BOOST_PROPERTY_TREE_RAPIDXML_STATIC_POOL_SIZE</code>, <code>BOOST_PROPERTY_TREE_RAPIDXML_DYNAMIC_POOL_SIZE</code> and <code>BOOST_PROPERTY_TREE_RAPIDXML_ALIGNMENT</code> 
+    //! to obtain best wasted memory to performance compromise.
+    //! To do it, define their values before rapidxml.hpp file is included.
+    //! \param Ch Character type of created nodes. 
+    template<class Ch = char>
+    class memory_pool
+    {
+        
+    public:
+
+        //! \cond internal
+        // Prefixed names to work around weird MSVC lookup bug.
+        typedef void *(boost_ptree_raw_alloc_func)(std::size_t);       // Type of user-defined function used to allocate memory
+        typedef void (boost_ptree_raw_free_func)(void *);              // Type of user-defined function used to free memory
+        //! \endcond
+        
+        //! Constructs empty pool with default allocator functions.
+        memory_pool()
+            : m_alloc_func(0)
+            , m_free_func(0)
+        {
+            init();
+        }
+
+        //! Destroys pool and frees all the memory. 
+        //! This causes memory occupied by nodes allocated by the pool to be freed.
+        //! Nodes allocated from the pool are no longer valid.
+        ~memory_pool()
+        {
+            clear();
+        }
+
+        //! Allocates a new node from the pool, and optionally assigns name and value to it. 
+        //! If the allocation request cannot be accomodated, this function will throw <code>std::bad_alloc</code>.
+        //! If exceptions are disabled by defining RAPIDXML_NO_EXCEPTIONS, this function
+        //! will call rapidxml::parse_error_handler() function.
+        //! \param type Type of node to create.
+        //! \param name Name to assign to the node, or 0 to assign no name.
+        //! \param value Value to assign to the node, or 0 to assign no value.
+        //! \param name_size Size of name to assign, or 0 to automatically calculate size from name string.
+        //! \param value_size Size of value to assign, or 0 to automatically calculate size from value string.
+        //! \return Pointer to allocated node. This pointer will never be NULL.
+        xml_node<Ch> *allocate_node(node_type type, 
+                                    const Ch *name = 0, const Ch *value = 0, 
+                                    std::size_t name_size = 0, std::size_t value_size = 0)
+        {
+            void *memory = allocate_aligned(sizeof(xml_node<Ch>));
+            xml_node<Ch> *node = new(memory) xml_node<Ch>(type);
+            if (name)
+            {
+                if (name_size > 0)
+                    node->name(name, name_size);
+                else
+                    node->name(name);
+            }
+            if (value)
+            {
+                if (value_size > 0)
+                    node->value(value, value_size);
+                else
+                    node->value(value);
+            }
+            return node;
+        }
+
+        //! Allocates a new attribute from the pool, and optionally assigns name and value to it.
+        //! If the allocation request cannot be accomodated, this function will throw <code>std::bad_alloc</code>.
+        //! If exceptions are disabled by defining RAPIDXML_NO_EXCEPTIONS, this function
+        //! will call rapidxml::parse_error_handler() function.
+        //! \param name Name to assign to the attribute, or 0 to assign no name.
+        //! \param value Value to assign to the attribute, or 0 to assign no value.
+        //! \param name_size Size of name to assign, or 0 to automatically calculate size from name string.
+        //! \param value_size Size of value to assign, or 0 to automatically calculate size from value string.
+        //! \return Pointer to allocated attribute. This pointer will never be NULL.
+        xml_attribute<Ch> *allocate_attribute(const Ch *name = 0, const Ch *value = 0, 
+                                              std::size_t name_size = 0, std::size_t value_size = 0)
+        {
+            void *memory = allocate_aligned(sizeof(xml_attribute<Ch>));
+            xml_attribute<Ch> *attribute = new(memory) xml_attribute<Ch>;
+            if (name)
+            {
+                if (name_size > 0)
+                    attribute->name(name, name_size);
+                else
+                    attribute->name(name);
+            }
+            if (value)
+            {
+                if (value_size > 0)
+                    attribute->value(value, value_size);
+                else
+                    attribute->value(value);
+            }
+            return attribute;
+        }
+
+        //! Allocates a char array of given size from the pool, and optionally copies a given string to it.
+        //! If the allocation request cannot be accomodated, this function will throw <code>std::bad_alloc</code>.
+        //! If exceptions are disabled by defining RAPIDXML_NO_EXCEPTIONS, this function
+        //! will call rapidxml::parse_error_handler() function.
+        //! \param source String to initialize the allocated memory with, or 0 to not initialize it.
+        //! \param size Number of characters to allocate, or zero to calculate it automatically from source string length; if size is 0, source string must be specified and null terminated.
+        //! \return Pointer to allocated char array. This pointer will never be NULL.
+        Ch *allocate_string(const Ch *source = 0, std::size_t size = 0)
+        {
+            BOOST_ASSERT(source || size);     // Either source or size (or both) must be specified
+            if (size == 0)
+                size = internal::measure(source) + 1;
+            Ch *result = static_cast<Ch *>(allocate_aligned(size * sizeof(Ch)));
+            if (source)
+                for (std::size_t i = 0; i < size; ++i)
+                    result[i] = source[i];
+            return result;
+        }
+
+        //! Clones an xml_node and its hierarchy of child nodes and attributes.
+        //! Nodes and attributes are allocated from this memory pool.
+        //! Names and values are not cloned, they are shared between the clone and the source.
+        //! Result node can be optionally specified as a second parameter, 
+        //! in which case its contents will be replaced with cloned source node.
+        //! This is useful when you want to clone entire document.
+        //! \param source Node to clone.
+        //! \param result Node to put results in, or 0 to automatically allocate result node
+        //! \return Pointer to cloned node. This pointer will never be NULL.
+        xml_node<Ch> *clone_node(const xml_node<Ch> *source, xml_node<Ch> *result = 0)
+        {
+            // Prepare result node
+            if (result)
+            {
+                result->remove_all_attributes();
+                result->remove_all_nodes();
+                result->type(source->type());
+            }
+            else
+                result = allocate_node(source->type());
+
+            // Clone name and value
+            result->name(source->name(), source->name_size());
+            result->value(source->value(), source->value_size());
+
+            // Clone child nodes and attributes
+            for (xml_node<Ch> *child = source->first_node(); child; child = child->next_sibling())
+                result->append_node(clone_node(child));
+            for (xml_attribute<Ch> *attr = source->first_attribute(); attr; attr = attr->next_attribute())
+                result->append_attribute(allocate_attribute(attr->name(), attr->value(), attr->name_size(), attr->value_size()));
+
+            return result;
+        }
+
+        //! Clears the pool. 
+        //! This causes memory occupied by nodes allocated by the pool to be freed.
+        //! Any nodes or strings allocated from the pool will no longer be valid.
+        void clear()
+        {
+            while (m_begin != m_static_memory)
+            {
+                char *previous_begin = reinterpret_cast<header *>(align(m_begin))->previous_begin;
+                if (m_free_func)
+                    m_free_func(m_begin);
+                else
+                    delete[] m_begin;
+                m_begin = previous_begin;
+            }
+            init();
+        }
+
+        //! Sets or resets the user-defined memory allocation functions for the pool.
+        //! This can only be called when no memory is allocated from the pool yet, otherwise results are undefined.
+        //! Allocation function must not return invalid pointer on failure. It should either throw,
+        //! stop the program, or use <code>longjmp()</code> function to pass control to other place of program. 
+        //! If it returns invalid pointer, results are undefined.
+        //! <br><br>
+        //! User defined allocation functions must have the following forms:
+        //! <br><code>
+        //! <br>void *allocate(std::size_t size);
+        //! <br>void free(void *pointer);
+        //! </code><br>
+        //! \param af Allocation function, or 0 to restore default function
+        //! \param ff Free function, or 0 to restore default function
+        void set_allocator(boost_ptree_raw_alloc_func *af, boost_ptree_raw_free_func *ff)
+        {
+            BOOST_ASSERT(m_begin == m_static_memory && m_ptr == align(m_begin));    // Verify that no memory is allocated yet
+            m_alloc_func = af;
+            m_free_func = ff;
+        }
+
+    private:
+
+        struct header
+        {
+            char *previous_begin;
+        };
+
+        void init()
+        {
+            m_begin = m_static_memory;
+            m_ptr = align(m_begin);
+            m_end = m_static_memory + sizeof(m_static_memory);
+        }
+        
+        char *align(char *ptr)
+        {
+            std::size_t alignment = ((BOOST_PROPERTY_TREE_RAPIDXML_ALIGNMENT - (std::size_t(ptr) & (BOOST_PROPERTY_TREE_RAPIDXML_ALIGNMENT - 1))) & (BOOST_PROPERTY_TREE_RAPIDXML_ALIGNMENT - 1));
+            return ptr + alignment;
+        }
+        
+        char *allocate_raw(std::size_t size)
+        {
+            // Allocate
+            void *memory;   
+            if (m_alloc_func)   // Allocate memory using either user-specified allocation function or global operator new[]
+            {
+                memory = m_alloc_func(size);
+                BOOST_ASSERT(memory); // Allocator is not allowed to return 0, on failure it must either throw, stop the program or use longjmp
+            }
+            else
+            {
+                memory = new char[size];
+            }
+            return static_cast<char *>(memory);
+        }
+        
+        void *allocate_aligned(std::size_t size)
+        {
+            // Calculate aligned pointer
+            char *result = align(m_ptr);
+
+            // If not enough memory left in current pool, allocate a new pool
+            if (result + size > m_end)
+            {
+                // Calculate required pool size (may be bigger than BOOST_PROPERTY_TREE_RAPIDXML_DYNAMIC_POOL_SIZE)
+                std::size_t pool_size = BOOST_PROPERTY_TREE_RAPIDXML_DYNAMIC_POOL_SIZE;
+                if (pool_size < size)
+                    pool_size = size;
+                
+                // Allocate
+                std::size_t alloc_size = sizeof(header) + (2 * BOOST_PROPERTY_TREE_RAPIDXML_ALIGNMENT - 2) + pool_size;     // 2 alignments required in worst case: one for header, one for actual allocation
+                char *raw_memory = allocate_raw(alloc_size);
+                    
+                // Setup new pool in allocated memory
+                char *pool = align(raw_memory);
+                header *new_header = reinterpret_cast<header *>(pool);
+                new_header->previous_begin = m_begin;
+                m_begin = raw_memory;
+                m_ptr = pool + sizeof(header);
+                m_end = raw_memory + alloc_size;
+
+                // Calculate aligned pointer again using new pool
+                result = align(m_ptr);
+            }
+
+            // Update pool and return aligned pointer
+            m_ptr = result + size;
+            return result;
+        }
+
+        char *m_begin;                                      // Start of raw memory making up current pool
+        char *m_ptr;                                        // First free byte in current pool
+        char *m_end;                                        // One past last available byte in current pool
+        char m_static_memory[BOOST_PROPERTY_TREE_RAPIDXML_STATIC_POOL_SIZE];    // Static raw memory
+        boost_ptree_raw_alloc_func *m_alloc_func;           // Allocator function, or 0 if default is to be used
+        boost_ptree_raw_free_func *m_free_func;             // Free function, or 0 if default is to be used
+    };
+
+    ///////////////////////////////////////////////////////////////////////////
+    // XML base
+
+    //! Base class for xml_node and xml_attribute implementing common functions: 
+    //! name(), name_size(), value(), value_size() and parent().
+    //! \param Ch Character type to use
+    template<class Ch = char>
+    class xml_base
+    {
+
+    public:
+        
+        ///////////////////////////////////////////////////////////////////////////
+        // Construction & destruction
+    
+        // Construct a base with empty name, value and parent
+        xml_base()
+            : m_name(0)
+            , m_value(0)
+            , m_parent(0)
+        {
+        }
+
+        ///////////////////////////////////////////////////////////////////////////
+        // Node data access
+    
+        //! Gets name of the node. 
+        //! Interpretation of name depends on type of node.
+        //! Note that name will not be zero-terminated if rapidxml::parse_no_string_terminators option was selected during parse.
+        //! <br><br>
+        //! Use name_size() function to determine length of the name.
+        //! \return Name of node, or empty string if node has no name.
+        Ch *name() const
+        {
+            return m_name ? m_name : nullstr();
+        }
+
+        //! Gets size of node name, not including terminator character.
+        //! This function works correctly irrespective of whether name is or is not zero terminated.
+        //! \return Size of node name, in characters.
+        std::size_t name_size() const
+        {
+            return m_name ? m_name_size : 0;
+        }
+
+        //! Gets value of node. 
+        //! Interpretation of value depends on type of node.
+        //! Note that value will not be zero-terminated if rapidxml::parse_no_string_terminators option was selected during parse.
+        //! <br><br>
+        //! Use value_size() function to determine length of the value.
+        //! \return Value of node, or empty string if node has no value.
+        Ch *value() const
+        {
+            return m_value ? m_value : nullstr();
+        }
+
+        //! Gets size of node value, not including terminator character.
+        //! This function works correctly irrespective of whether value is or is not zero terminated.
+        //! \return Size of node value, in characters.
+        std::size_t value_size() const
+        {
+            return m_value ? m_value_size : 0;
+        }
+
+        ///////////////////////////////////////////////////////////////////////////
+        // Node modification
+    
+        //! Sets name of node to a non zero-terminated string.
+        //! See \ref ownership_of_strings.
+        //! <br><br>
+        //! Note that node does not own its name or value, it only stores a pointer to it. 
+        //! It will not delete or otherwise free the pointer on destruction.
+        //! It is reponsibility of the user to properly manage lifetime of the string.
+        //! The easiest way to achieve it is to use memory_pool of the document to allocate the string -
+        //! on destruction of the document the string will be automatically freed.
+        //! <br><br>
+        //! Size of name must be specified separately, because name does not have to be zero terminated.
+        //! Use name(const Ch *) function to have the length automatically calculated (string must be zero terminated).
+        //! \param n Name of node to set. Does not have to be zero terminated.
+        //! \param size Size of name, in characters. This does not include zero terminator, if one is present.
+        void name(const Ch *n, std::size_t size)
+        {
+            m_name = const_cast<Ch *>(n);
+            m_name_size = size;
+        }
+
+        //! Sets name of node to a zero-terminated string.
+        //! See also \ref ownership_of_strings and xml_node::name(const Ch *, std::size_t).
+        //! \param n Name of node to set. Must be zero terminated.
+        void name(const Ch *n)
+        {
+            name(n, internal::measure(n));
+        }
+
+        //! Sets value of node to a non zero-terminated string.
+        //! See \ref ownership_of_strings.
+        //! <br><br>
+        //! Note that node does not own its name or value, it only stores a pointer to it. 
+        //! It will not delete or otherwise free the pointer on destruction.
+        //! It is reponsibility of the user to properly manage lifetime of the string.
+        //! The easiest way to achieve it is to use memory_pool of the document to allocate the string -
+        //! on destruction of the document the string will be automatically freed.
+        //! <br><br>
+        //! Size of value must be specified separately, because it does not have to be zero terminated.
+        //! Use value(const Ch *) function to have the length automatically calculated (string must be zero terminated).
+        //! <br><br>
+        //! If an element has a child node of type node_data, it will take precedence over element value when printing.
+        //! If you want to manipulate data of elements using values, use parser flag rapidxml::parse_no_data_nodes to prevent creation of data nodes by the parser.
+        //! \param val value of node to set. Does not have to be zero terminated.
+        //! \param size Size of value, in characters. This does not include zero terminator, if one is present.
+        void value(const Ch *val, std::size_t size)
+        {
+            m_value = const_cast<Ch *>(val);
+            m_value_size = size;
+        }
+
+        //! Sets value of node to a zero-terminated string.
+        //! See also \ref ownership_of_strings and xml_node::value(const Ch *, std::size_t).
+        //! \param val Vame of node to set. Must be zero terminated.
+        void value(const Ch *val)
+        {
+            this->value(val, internal::measure(val));
+        }
+
+        ///////////////////////////////////////////////////////////////////////////
+        // Related nodes access
+    
+        //! Gets node parent.
+        //! \return Pointer to parent node, or 0 if there is no parent.
+        xml_node<Ch> *parent() const
+        {
+            return m_parent;
+        }
+
+    protected:
+
+        // Return empty string
+        static Ch *nullstr()
+        {
+            static Ch zero = Ch('\0');
+            return &zero;
+        }
+
+        Ch *m_name;                         // Name of node, or 0 if no name
+        Ch *m_value;                        // Value of node, or 0 if no value
+        std::size_t m_name_size;            // Length of node name, or undefined of no name
+        std::size_t m_value_size;           // Length of node value, or undefined if no value
+        xml_node<Ch> *m_parent;             // Pointer to parent node, or 0 if none
+
+    };
+
+    //! Class representing attribute node of XML document. 
+    //! Each attribute has name and value strings, which are available through name() and value() functions (inherited from xml_base).
+    //! Note that after parse, both name and value of attribute will point to interior of source text used for parsing. 
+    //! Thus, this text must persist in memory for the lifetime of attribute.
+    //! \param Ch Character type to use.
+    template<class Ch = char>
+    class xml_attribute: public xml_base<Ch>
+    {
+
+        friend class xml_node<Ch>;
+    
+    public:
+
+        ///////////////////////////////////////////////////////////////////////////
+        // Construction & destruction
+    
+        //! Constructs an empty attribute with the specified type. 
+        //! Consider using memory_pool of appropriate xml_document if allocating attributes manually.
+        xml_attribute()
+        {
+        }
+
+        ///////////////////////////////////////////////////////////////////////////
+        // Related nodes access
+    
+        //! Gets document of which attribute is a child.
+        //! \return Pointer to document that contains this attribute, or 0 if there is no parent document.
+        xml_document<Ch> *document() const
+        {
+            if (xml_node<Ch> *node = this->parent())
+            {
+                while (node->parent())
+                    node = node->parent();
+                return node->type() == node_document ? static_cast<xml_document<Ch> *>(node) : 0;
+            }
+            else
+                return 0;
+        }
+
+        //! Gets previous attribute, optionally matching attribute name. 
+        //! \param n Name of attribute to find, or 0 to return previous attribute regardless of its name; this string doesn't have to be zero-terminated if nsize is non-zero
+        //! \param nsize Size of name, in characters, or 0 to have size calculated automatically from string
+        //! \param case_sensitive Should name comparison be case-sensitive; non case-sensitive comparison works properly only for ASCII characters
+        //! \return Pointer to found attribute, or 0 if not found.
+        xml_attribute<Ch> *previous_attribute(const Ch *n = 0, std::size_t nsize = 0, bool case_sensitive = true) const
+        {
+            if (n)
+            {
+                if (nsize == 0)
+                    nsize = internal::measure(n);
+                for (xml_attribute<Ch> *attribute = m_prev_attribute; attribute; attribute = attribute->m_prev_attribute)
+                    if (internal::compare(attribute->name(), attribute->name_size(), n, nsize, case_sensitive))
+                        return attribute;
+                return 0;
+            }
+            else
+                return this->m_parent ? m_prev_attribute : 0;
+        }
+
+        //! Gets next attribute, optionally matching attribute name. 
+        //! \param n Name of attribute to find, or 0 to return next attribute regardless of its name; this string doesn't have to be zero-terminated if nsize is non-zero
+        //! \param nsize Size of name, in characters, or 0 to have size calculated automatically from string
+        //! \param case_sensitive Should name comparison be case-sensitive; non case-sensitive comparison works properly only for ASCII characters
+        //! \return Pointer to found attribute, or 0 if not found.
+        xml_attribute<Ch> *next_attribute(const Ch *n = 0, std::size_t nsize = 0, bool case_sensitive = true) const
+        {
+            if (n)
+            {
+                if (nsize == 0)
+                    nsize = internal::measure(n);
+                for (xml_attribute<Ch> *attribute = m_next_attribute; attribute; attribute = attribute->m_next_attribute)
+                    if (internal::compare(attribute->name(), attribute->name_size(), n, nsize, case_sensitive))
+                        return attribute;
+                return 0;
+            }
+            else
+                return this->m_parent ? m_next_attribute : 0;
+        }
+
+    private:
+
+        xml_attribute<Ch> *m_prev_attribute;        // Pointer to previous sibling of attribute, or 0 if none; only valid if parent is non-zero
+        xml_attribute<Ch> *m_next_attribute;        // Pointer to next sibling of attribute, or 0 if none; only valid if parent is non-zero
+    
+    };
+
+    ///////////////////////////////////////////////////////////////////////////
+    // XML node
+
+    //! Class representing a node of XML document. 
+    //! Each node may have associated name and value strings, which are available through name() and value() functions. 
+    //! Interpretation of name and value depends on type of the node.
+    //! Type of node can be determined by using type() function.
+    //! <br><br>
+    //! Note that after parse, both name and value of node, if any, will point interior of source text used for parsing. 
+    //! Thus, this text must persist in the memory for the lifetime of node.
+    //! \param Ch Character type to use.
+    template<class Ch = char>
+    class xml_node: public xml_base<Ch>
+    {
+
+    public:
+
+        ///////////////////////////////////////////////////////////////////////////
+        // Construction & destruction
+    
+        //! Constructs an empty node with the specified type. 
+        //! Consider using memory_pool of appropriate document to allocate nodes manually.
+        //! \param t Type of node to construct.
+        xml_node(node_type t)
+            : m_type(t)
+            , m_first_node(0)
+            , m_first_attribute(0)
+        {
+        }
+
+        ///////////////////////////////////////////////////////////////////////////
+        // Node data access
+    
+        //! Gets type of node.
+        //! \return Type of node.
+        node_type type() const
+        {
+            return m_type;
+        }
+
+        ///////////////////////////////////////////////////////////////////////////
+        // Related nodes access
+    
+        //! Gets document of which node is a child.
+        //! \return Pointer to document that contains this node, or 0 if there is no parent document.
+        xml_document<Ch> *document() const
+        {
+            xml_node<Ch> *node = const_cast<xml_node<Ch> *>(this);
+            while (node->parent())
+                node = node->parent();
+            return node->type() == node_document ? static_cast<xml_document<Ch> *>(node) : 0;
+        }
+
+        //! Gets first child node, optionally matching node name.
+        //! \param n Name of child to find, or 0 to return first child regardless of its name; this string doesn't have to be zero-terminated if nsize is non-zero
+        //! \param nsize Size of name, in characters, or 0 to have size calculated automatically from string
+        //! \param case_sensitive Should name comparison be case-sensitive; non case-sensitive comparison works properly only for ASCII characters
+        //! \return Pointer to found child, or 0 if not found.
+        xml_node<Ch> *first_node(const Ch *n = 0, std::size_t nsize = 0, bool case_sensitive = true) const
+        {
+            if (n)
+            {
+                if (nsize == 0)
+                    nsize = internal::measure(n);
+                for (xml_node<Ch> *child = m_first_node; child; child = child->next_sibling())
+                    if (internal::compare(child->name(), child->name_size(), n, nsize, case_sensitive))
+                        return child;
+                return 0;
+            }
+            else
+                return m_first_node;
+        }
+
+        //! Gets last child node, optionally matching node name. 
+        //! Behaviour is undefined if node has no children.
+        //! Use first_node() to test if node has children.
+        //! \param n Name of child to find, or 0 to return last child regardless of its name; this string doesn't have to be zero-terminated if nsize is non-zero
+        //! \param nsize Size of name, in characters, or 0 to have size calculated automatically from string
+        //! \param case_sensitive Should name comparison be case-sensitive; non case-sensitive comparison works properly only for ASCII characters
+        //! \return Pointer to found child, or 0 if not found.
+        xml_node<Ch> *last_node(const Ch *n = 0, std::size_t nsize = 0, bool case_sensitive = true) const
+        {
+            BOOST_ASSERT(m_first_node);  // Cannot query for last child if node has no children
+            if (n)
+            {
+                if (nsize == 0)
+                    nsize = internal::measure(n);
+                for (xml_node<Ch> *child = m_last_node; child; child = child->previous_sibling())
+                    if (internal::compare(child->name(), child->name_size(), n, nsize, case_sensitive))
+                        return child;
+                return 0;
+            }
+            else
+                return m_last_node;
+        }
+
+        //! Gets previous sibling node, optionally matching node name. 
+        //! Behaviour is undefined if node has no parent.
+        //! Use parent() to test if node has a parent.
+        //! \param n Name of sibling to find, or 0 to return previous sibling regardless of its name; this string doesn't have to be zero-terminated if nsize is non-zero
+        //! \param nsize Size of name, in characters, or 0 to have size calculated automatically from string
+        //! \param case_sensitive Should name comparison be case-sensitive; non case-sensitive comparison works properly only for ASCII characters
+        //! \return Pointer to found sibling, or 0 if not found.
+        xml_node<Ch> *previous_sibling(const Ch *n = 0, std::size_t nsize = 0, bool case_sensitive = true) const
+        {
+            BOOST_ASSERT(this->m_parent);     // Cannot query for siblings if node has no parent
+            if (n)
+            {
+                if (nsize == 0)
+                    nsize = internal::measure(n);
+                for (xml_node<Ch> *sibling = m_prev_sibling; sibling; sibling = sibling->m_prev_sibling)
+                    if (internal::compare(sibling->name(), sibling->name_size(), n, nsize, case_sensitive))
+                        return sibling;
+                return 0;
+            }
+            else
+                return m_prev_sibling;
+        }
+
+        //! Gets next sibling node, optionally matching node name. 
+        //! Behaviour is undefined if node has no parent.
+        //! Use parent() to test if node has a parent.
+        //! \param n Name of sibling to find, or 0 to return next sibling regardless of its name; this string doesn't have to be zero-terminated if nsize is non-zero
+        //! \param nsize Size of name, in characters, or 0 to have size calculated automatically from string
+        //! \param case_sensitive Should name comparison be case-sensitive; non case-sensitive comparison works properly only for ASCII characters
+        //! \return Pointer to found sibling, or 0 if not found.
+        xml_node<Ch> *next_sibling(const Ch *n = 0, std::size_t nsize = 0, bool case_sensitive = true) const
+        {
+            BOOST_ASSERT(this->m_parent);     // Cannot query for siblings if node has no parent
+            if (n)
+            {
+                if (nsize == 0)
+                    nsize = internal::measure(n);
+                for (xml_node<Ch> *sibling = m_next_sibling; sibling; sibling = sibling->m_next_sibling)
+                    if (internal::compare(sibling->name(), sibling->name_size(), n, nsize, case_sensitive))
+                        return sibling;
+                return 0;
+            }
+            else
+                return m_next_sibling;
+        }
+
+        //! Gets first attribute of node, optionally matching attribute name.
+        //! \param n Name of attribute to find, or 0 to return first attribute regardless of its name; this string doesn't have to be zero-terminated if nsize is non-zero
+        //! \param nsize Size of name, in characters, or 0 to have size calculated automatically from string
+        //! \param case_sensitive Should name comparison be case-sensitive; non case-sensitive comparison works properly only for ASCII characters
+        //! \return Pointer to found attribute, or 0 if not found.
+        xml_attribute<Ch> *first_attribute(const Ch *n = 0, std::size_t nsize = 0, bool case_sensitive = true) const
+        {
+            if (n)
+            {
+                if (nsize == 0)
+                    nsize = internal::measure(n);
+                for (xml_attribute<Ch> *attribute = m_first_attribute; attribute; attribute = attribute->m_next_attribute)
+                    if (internal::compare(attribute->name(), attribute->name_size(), n, nsize, case_sensitive))
+                        return attribute;
+                return 0;
+            }
+            else
+                return m_first_attribute;
+        }
+
+        //! Gets last attribute of node, optionally matching attribute name.
+        //! \param n Name of attribute to find, or 0 to return last attribute regardless of its name; this string doesn't have to be zero-terminated if nsize is non-zero
+        //! \param nsize Size of name, in characters, or 0 to have size calculated automatically from string
+        //! \param case_sensitive Should name comparison be case-sensitive; non case-sensitive comparison works properly only for ASCII characters
+        //! \return Pointer to found attribute, or 0 if not found.
+        xml_attribute<Ch> *last_attribute(const Ch *n = 0, std::size_t nsize = 0, bool case_sensitive = true) const
+        {
+            if (n)
+            {
+                if (nsize == 0)
+                    nsize = internal::measure(n);
+                for (xml_attribute<Ch> *attribute = m_last_attribute; attribute; attribute = attribute->m_prev_attribute)
+                    if (internal::compare(attribute->name(), attribute->name_size(), n, nsize, case_sensitive))
+                        return attribute;
+                return 0;
+            }
+            else
+                return m_first_attribute ? m_last_attribute : 0;
+        }
+
+        ///////////////////////////////////////////////////////////////////////////
+        // Node modification
+    
+        //! Sets type of node.
+        //! \param t Type of node to set.
+        void type(node_type t)
+        {
+            m_type = t;
+        }
+
+        ///////////////////////////////////////////////////////////////////////////
+        // Node manipulation
+
+        //! Prepends a new child node.
+        //! The prepended child becomes the first child, and all existing children are moved one position back.
+        //! \param child Node to prepend.
+        void prepend_node(xml_node<Ch> *child)
+        {
+            BOOST_ASSERT(child && !child->parent() && child->type() != node_document);
+            if (first_node())
+            {
+                child->m_next_sibling = m_first_node;
+                m_first_node->m_prev_sibling = child;
+            }
+            else
+            {
+                child->m_next_sibling = 0;
+                m_last_node = child;
+            }
+            m_first_node = child;
+            child->m_parent = this;
+            child->m_prev_sibling = 0;
+        }
+
+        //! Appends a new child node. 
+        //! The appended child becomes the last child.
+        //! \param child Node to append.
+        void append_node(xml_node<Ch> *child)
+        {
+            BOOST_ASSERT(child && !child->parent() && child->type() != node_document);
+            if (first_node())
+            {
+                child->m_prev_sibling = m_last_node;
+                m_last_node->m_next_sibling = child;
+            }
+            else
+            {
+                child->m_prev_sibling = 0;
+                m_first_node = child;
+            }
+            m_last_node = child;
+            child->m_parent = this;
+            child->m_next_sibling = 0;
+        }
+
+        //! Inserts a new child node at specified place inside the node. 
+        //! All children after and including the specified node are moved one position back.
+        //! \param where Place where to insert the child, or 0 to insert at the back.
+        //! \param child Node to insert.
+        void insert_node(xml_node<Ch> *where, xml_node<Ch> *child)
+        {
+            BOOST_ASSERT(!where || where->parent() == this);
+            BOOST_ASSERT(child && !child->parent() && child->type() != node_document);
+            if (where == m_first_node)
+                prepend_node(child);
+            else if (where == 0)
+                append_node(child);
+            else
+            {
+                child->m_prev_sibling = where->m_prev_sibling;
+                child->m_next_sibling = where;
+                where->m_prev_sibling->m_next_sibling = child;
+                where->m_prev_sibling = child;
+                child->m_parent = this;
+            }
+        }
+
+        //! Removes first child node. 
+        //! If node has no children, behaviour is undefined.
+        //! Use first_node() to test if node has children.
+        void remove_first_node()
+        {
+            BOOST_ASSERT(first_node());
+            xml_node<Ch> *child = m_first_node;
+            m_first_node = child->m_next_sibling;
+            if (child->m_next_sibling)
+                child->m_next_sibling->m_prev_sibling = 0;
+            else
+                m_last_node = 0;
+            child->m_parent = 0;
+        }
+
+        //! Removes last child of the node. 
+        //! If node has no children, behaviour is undefined.
+        //! Use first_node() to test if node has children.
+        void remove_last_node()
+        {
+            BOOST_ASSERT(first_node());
+            xml_node<Ch> *child = m_last_node;
+            if (child->m_prev_sibling)
+            {
+                m_last_node = child->m_prev_sibling;
+                child->m_prev_sibling->m_next_sibling = 0;
+            }
+            else
+                m_first_node = 0;
+            child->m_parent = 0;
+        }
+
+        //! Removes specified child from the node
+        // \param where Pointer to child to be removed.
+        void remove_node(xml_node<Ch> *where)
+        {
+            BOOST_ASSERT(where && where->parent() == this);
+            BOOST_ASSERT(first_node());
+            if (where == m_first_node)
+                remove_first_node();
+            else if (where == m_last_node)
+                remove_last_node();
+            else
+            {
+                where->m_prev_sibling->m_next_sibling = where->m_next_sibling;
+                where->m_next_sibling->m_prev_sibling = where->m_prev_sibling;
+                where->m_parent = 0;
+            }
+        }
+
+        //! Removes all child nodes (but not attributes).
+        void remove_all_nodes()
+        {
+            for (xml_node<Ch> *node = first_node(); node; node = node->m_next_sibling)
+                node->m_parent = 0;
+            m_first_node = 0;
+        }
+
+        //! Prepends a new attribute to the node.
+        //! \param attribute Attribute to prepend.
+        void prepend_attribute(xml_attribute<Ch> *attribute)
+        {
+            BOOST_ASSERT(attribute && !attribute->parent());
+            if (first_attribute())
+            {
+                attribute->m_next_attribute = m_first_attribute;
+                m_first_attribute->m_prev_attribute = attribute;
+            }
+            else
+            {
+                attribute->m_next_attribute = 0;
+                m_last_attribute = attribute;
+            }
+            m_first_attribute = attribute;
+            attribute->m_parent = this;
+            attribute->m_prev_attribute = 0;
+        }
+
+        //! Appends a new attribute to the node.
+        //! \param attribute Attribute to append.
+        void append_attribute(xml_attribute<Ch> *attribute)
+        {
+            BOOST_ASSERT(attribute && !attribute->parent());
+            if (first_attribute())
+            {
+                attribute->m_prev_attribute = m_last_attribute;
+                m_last_attribute->m_next_attribute = attribute;
+            }
+            else
+            {
+                attribute->m_prev_attribute = 0;
+                m_first_attribute = attribute;
+            }
+            m_last_attribute = attribute;
+            attribute->m_parent = this;
+            attribute->m_next_attribute = 0;
+        }
+
+        //! Inserts a new attribute at specified place inside the node. 
+        //! All attributes after and including the specified attribute are moved one position back.
+        //! \param where Place where to insert the attribute, or 0 to insert at the back.
+        //! \param attribute Attribute to insert.
+        void insert_attribute(xml_attribute<Ch> *where, xml_attribute<Ch> *attribute)
+        {
+            BOOST_ASSERT(!where || where->parent() == this);
+            BOOST_ASSERT(attribute && !attribute->parent());
+            if (where == m_first_attribute)
+                prepend_attribute(attribute);
+            else if (where == 0)
+                append_attribute(attribute);
+            else
+            {
+                attribute->m_prev_attribute = where->m_prev_attribute;
+                attribute->m_next_attribute = where;
+                where->m_prev_attribute->m_next_attribute = attribute;
+                where->m_prev_attribute = attribute;
+                attribute->m_parent = this;
+            }
+        }
+
+        //! Removes first attribute of the node. 
+        //! If node has no attributes, behaviour is undefined.
+        //! Use first_attribute() to test if node has attributes.
+        void remove_first_attribute()
+        {
+            BOOST_ASSERT(first_attribute());
+            xml_attribute<Ch> *attribute = m_first_attribute;
+            if (attribute->m_next_attribute)
+            {
+                attribute->m_next_attribute->m_prev_attribute = 0;
+            }
+            else
+                m_last_attribute = 0;
+            attribute->m_parent = 0;
+            m_first_attribute = attribute->m_next_attribute;
+        }
+
+        //! Removes last attribute of the node. 
+        //! If node has no attributes, behaviour is undefined.
+        //! Use first_attribute() to test if node has attributes.
+        void remove_last_attribute()
+        {
+            BOOST_ASSERT(first_attribute());
+            xml_attribute<Ch> *attribute = m_last_attribute;
+            if (attribute->m_prev_attribute)
+            {
+                attribute->m_prev_attribute->m_next_attribute = 0;
+                m_last_attribute = attribute->m_prev_attribute;
+            }
+            else
+                m_first_attribute = 0;
+            attribute->m_parent = 0;
+        }
+
+        //! Removes specified attribute from node.
+        //! \param where Pointer to attribute to be removed.
+        void remove_attribute(xml_attribute<Ch> *where)
+        {
+            BOOST_ASSERT(first_attribute() && where->parent() == this);
+            if (where == m_first_attribute)
+                remove_first_attribute();
+            else if (where == m_last_attribute)
+                remove_last_attribute();
+            else
+            {
+                where->m_prev_attribute->m_next_attribute = where->m_next_attribute;
+                where->m_next_attribute->m_prev_attribute = where->m_prev_attribute;
+                where->m_parent = 0;
+            }
+        }
+
+        //! Removes all attributes of node.
+        void remove_all_attributes()
+        {
+            for (xml_attribute<Ch> *attribute = first_attribute(); attribute; attribute = attribute->m_next_attribute)
+                attribute->m_parent = 0;
+            m_first_attribute = 0;
+        }
+        
+    private:
+
+        ///////////////////////////////////////////////////////////////////////////
+        // Restrictions
+
+        // No copying
+        xml_node(const xml_node &);
+        void operator =(const xml_node &);
+    
+        ///////////////////////////////////////////////////////////////////////////
+        // Data members
+    
+        // Note that some of the pointers below have UNDEFINED values if certain other pointers are 0.
+        // This is required for maximum performance, as it allows the parser to omit initialization of 
+        // unneded/redundant values.
+        //
+        // The rules are as follows:
+        // 1. first_node and first_attribute contain valid pointers, or 0 if node has no children/attributes respectively
+        // 2. last_node and last_attribute are valid only if node has at least one child/attribute respectively, otherwise they contain garbage
+        // 3. prev_sibling and next_sibling are valid only if node has a parent, otherwise they contain garbage
+
+        node_type m_type;                       // Type of node; always valid
+        xml_node<Ch> *m_first_node;             // Pointer to first child node, or 0 if none; always valid
+        xml_node<Ch> *m_last_node;              // Pointer to last child node, or 0 if none; this value is only valid if m_first_node is non-zero
+        xml_attribute<Ch> *m_first_attribute;   // Pointer to first attribute of node, or 0 if none; always valid
+        xml_attribute<Ch> *m_last_attribute;    // Pointer to last attribute of node, or 0 if none; this value is only valid if m_first_attribute is non-zero
+        xml_node<Ch> *m_prev_sibling;           // Pointer to previous sibling of node, or 0 if none; this value is only valid if m_parent is non-zero
+        xml_node<Ch> *m_next_sibling;           // Pointer to next sibling of node, or 0 if none; this value is only valid if m_parent is non-zero
+
+    };
+
+    ///////////////////////////////////////////////////////////////////////////
+    // XML document
+    
+    //! This class represents root of the DOM hierarchy. 
+    //! It is also an xml_node and a memory_pool through public inheritance.
+    //! Use parse() function to build a DOM tree from a zero-terminated XML text string.
+    //! parse() function allocates memory for nodes and attributes by using functions of xml_document, 
+    //! which are inherited from memory_pool.
+    //! To access root node of the document, use the document itself, as if it was an xml_node.
+    //! \param Ch Character type to use.
+    template<class Ch = char>
+    class xml_document: public xml_node<Ch>, public memory_pool<Ch>
+    {
+    
+    public:
+
+        //! Constructs empty XML document
+        xml_document()
+            : xml_node<Ch>(node_document)
+        {
+        }
+
+        //! Parses zero-terminated XML string according to given flags.
+        //! Passed string will be modified by the parser, unless rapidxml::parse_non_destructive flag is used.
+        //! The string must persist for the lifetime of the document.
+        //! In case of error, rapidxml::parse_error exception will be thrown.
+        //! <br><br>
+        //! If you want to parse contents of a file, you must first load the file into the memory, and pass pointer to its beginning.
+        //! Make sure that data is zero-terminated.
+        //! <br><br>
+        //! Document can be parsed into multiple times. 
+        //! Each new call to parse removes previous nodes and attributes (if any), but does not clear memory pool.
+        //! \param text XML data to parse; pointer is non-const to denote fact that this data may be modified by the parser.
+        template<int Flags>
+        void parse(Ch *text)
+        {
+            BOOST_ASSERT(text);
+            
+            // Remove current contents
+            this->remove_all_nodes();
+            this->remove_all_attributes();
+            
+            // Parse BOM, if any
+            parse_bom<Flags>(text);
+            
+            // Parse children
+            while (1)
+            {
+                // Skip whitespace before node
+                skip<whitespace_pred, Flags>(text);
+                if (*text == 0)
+                    break;
+
+                // Parse and append new child
+                if (*text == Ch('<'))
+                {
+                    ++text;     // Skip '<'
+                    if (xml_node<Ch> *node = parse_node<Flags>(text))
+                        this->append_node(node);
+                }
+                else
+                    BOOST_PROPERTY_TREE_RAPIDXML_PARSE_ERROR("expected <", text);
+            }
+
+        }
+
+        //! Clears the document by deleting all nodes and clearing the memory pool.
+        //! All nodes owned by document pool are destroyed.
+        void clear()
+        {
+            this->remove_all_nodes();
+            this->remove_all_attributes();
+            memory_pool<Ch>::clear();
+        }
+        
+    private:
+
+        ///////////////////////////////////////////////////////////////////////
+        // Internal character utility functions
+        
+        // Detect whitespace character
+        struct whitespace_pred
+        {
+            static unsigned char test(Ch ch)
+            {
+                return internal::lookup_tables<0>::lookup_whitespace[internal::get_index(ch)];
+            }
+        };
+
+        // Detect node name character
+        struct node_name_pred
+        {
+            static unsigned char test(Ch ch)
+            {
+                return internal::lookup_tables<0>::lookup_node_name[internal::get_index(ch)];
+            }
+        };
+
+        // Detect attribute name character
+        struct attribute_name_pred
+        {
+            static unsigned char test(Ch ch)
+            {
+                return internal::lookup_tables<0>::lookup_attribute_name[internal::get_index(ch)];
+            }
+        };
+
+        // Detect text character (PCDATA)
+        struct text_pred
+        {
+            static unsigned char test(Ch ch)
+            {
+                return internal::lookup_tables<0>::lookup_text[internal::get_index(ch)];
+            }
+        };
+
+        // Detect text character (PCDATA) that does not require processing
+        struct text_pure_no_ws_pred
+        {
+            static unsigned char test(Ch ch)
+            {
+                return internal::lookup_tables<0>::lookup_text_pure_no_ws[internal::get_index(ch)];
+            }
+        };
+
+        // Detect text character (PCDATA) that does not require processing
+        struct text_pure_with_ws_pred
+        {
+            static unsigned char test(Ch ch)
+            {
+                return internal::lookup_tables<0>::lookup_text_pure_with_ws[internal::get_index(ch)];
+            }
+        };
+
+        // Detect attribute value character
+        template<Ch Quote>
+        struct attribute_value_pred
+        {
+            static unsigned char test(Ch ch)
+            {
+                if (Quote == Ch('\''))
+                    return internal::lookup_tables<0>::lookup_attribute_data_1[internal::get_index(ch)];
+                if (Quote == Ch('\"'))
+                    return internal::lookup_tables<0>::lookup_attribute_data_2[internal::get_index(ch)];
+                return 0;       // Should never be executed, to avoid warnings on Comeau
+            }
+        };
+
+        // Detect attribute value character
+        template<Ch Quote>
+        struct attribute_value_pure_pred
+        {
+            static unsigned char test(Ch ch)
+            {
+                if (Quote == Ch('\''))
+                    return internal::lookup_tables<0>::lookup_attribute_data_1_pure[internal::get_index(ch)];
+                if (Quote == Ch('\"'))
+                    return internal::lookup_tables<0>::lookup_attribute_data_2_pure[internal::get_index(ch)];
+                return 0;       // Should never be executed, to avoid warnings on Comeau
+            }
+        };
+
+        // Insert coded character, using UTF8 or 8-bit ASCII
+        template<int Flags>
+        static void insert_coded_character(Ch *&text, unsigned long code)
+        {
+            if (Flags & parse_no_utf8)
+            {
+                // Insert 8-bit ASCII character
+                // Todo: possibly verify that code is less than 256 and use replacement char otherwise?
+                text[0] = static_cast<unsigned char>(code);
+                text += 1;
+            }
+            else
+            {
+                // Insert UTF8 sequence
+                if (code < 0x80)    // 1 byte sequence
+                {
+                    text[0] = static_cast<unsigned char>(code);
+                    text += 1;
+                }
+                else if (code < 0x800)  // 2 byte sequence
+                {
+                    text[1] = static_cast<unsigned char>((code | 0x80) & 0xBF); code >>= 6;
+                    text[0] = static_cast<unsigned char>(code | 0xC0);
+                    text += 2;
+                }
+                else if (code < 0x10000)    // 3 byte sequence
+                {
+                    text[2] = static_cast<unsigned char>((code | 0x80) & 0xBF); code >>= 6;
+                    text[1] = static_cast<unsigned char>((code | 0x80) & 0xBF); code >>= 6;
+                    text[0] = static_cast<unsigned char>(code | 0xE0);
+                    text += 3;
+                }
+                else if (code < 0x110000)   // 4 byte sequence
+                {
+                    text[3] = static_cast<unsigned char>((code | 0x80) & 0xBF); code >>= 6;
+                    text[2] = static_cast<unsigned char>((code | 0x80) & 0xBF); code >>= 6;
+                    text[1] = static_cast<unsigned char>((code | 0x80) & 0xBF); code >>= 6;
+                    text[0] = static_cast<unsigned char>(code | 0xF0);
+                    text += 4;
+                }
+                else    // Invalid, only codes up to 0x10FFFF are allowed in Unicode
+                {
+                    BOOST_PROPERTY_TREE_RAPIDXML_PARSE_ERROR("invalid numeric character entity", text);
+                }
+            }
+        }
+
+        // Skip characters until predicate evaluates to true
+        template<class StopPred, int Flags>
+        static void skip(Ch *&text)
+        {
+            Ch *tmp = text;
+            while (StopPred::test(*tmp))
+                ++tmp;
+            text = tmp;
+        }
+
+        // Skip characters until predicate evaluates to true while doing the following:
+        // - replacing XML character entity references with proper characters (&apos; &amp; &quot; &lt; &gt; &#...;)
+        // - condensing whitespace sequences to single space character
+        template<class StopPred, class StopPredPure, int Flags>
+        static Ch *skip_and_expand_character_refs(Ch *&text)
+        {
+            // If entity translation, whitespace condense and whitespace trimming is disabled, use plain skip
+            if (Flags & parse_no_entity_translation && 
+                !(Flags & parse_normalize_whitespace) &&
+                !(Flags & parse_trim_whitespace))
+            {
+                skip<StopPred, Flags>(text);
+                return text;
+            }
+            
+            // Use simple skip until first modification is detected
+            skip<StopPredPure, Flags>(text);
+
+            // Use translation skip
+            Ch *src = text;
+            Ch *dest = src;
+            while (StopPred::test(*src))
+            {
+                // If entity translation is enabled    
+                if (!(Flags & parse_no_entity_translation))
+                {
+                    // Test if replacement is needed
+                    if (src[0] == Ch('&'))
+                    {
+                        switch (src[1])
+                        {
+
+                        // &amp; &apos;
+                        case Ch('a'): 
+                            if (src[2] == Ch('m') && src[3] == Ch('p') && src[4] == Ch(';'))
+                            {
+                                *dest = Ch('&');
+                                ++dest;
+                                src += 5;
+                                continue;
+                            }
+                            if (src[2] == Ch('p') && src[3] == Ch('o') && src[4] == Ch('s') && src[5] == Ch(';'))
+                            {
+                                *dest = Ch('\'');
+                                ++dest;
+                                src += 6;
+                                continue;
+                            }
+                            break;
+
+                        // &quot;
+                        case Ch('q'): 
+                            if (src[2] == Ch('u') && src[3] == Ch('o') && src[4] == Ch('t') && src[5] == Ch(';'))
+                            {
+                                *dest = Ch('"');
+                                ++dest;
+                                src += 6;
+                                continue;
+                            }
+                            break;
+
+                        // &gt;
+                        case Ch('g'): 
+                            if (src[2] == Ch('t') && src[3] == Ch(';'))
+                            {
+                                *dest = Ch('>');
+                                ++dest;
+                                src += 4;
+                                continue;
+                            }
+                            break;
+
+                        // &lt;
+                        case Ch('l'): 
+                            if (src[2] == Ch('t') && src[3] == Ch(';'))
+                            {
+                                *dest = Ch('<');
+                                ++dest;
+                                src += 4;
+                                continue;
+                            }
+                            break;
+
+                        // &#...; - assumes ASCII
+                        case Ch('#'): 
+                            if (src[2] == Ch('x'))
+                            {
+                                unsigned long code = 0;
+                                src += 3;   // Skip &#x
+                                while (1)
+                                {
+                                    unsigned char digit = internal::lookup_tables<0>::lookup_digits[static_cast<unsigned char>(*src)];
+                                    if (digit == 0xFF)
+                                        break;
+                                    code = code * 16 + digit;
+                                    ++src;
+                                }
+                                insert_coded_character<Flags>(dest, code);    // Put character in output
+                            }
+                            else
+                            {
+                                unsigned long code = 0;
+                                src += 2;   // Skip &#
+                                while (1)
+                                {
+                                    unsigned char digit = internal::lookup_tables<0>::lookup_digits[static_cast<unsigned char>(*src)];
+                                    if (digit == 0xFF)
+                                        break;
+                                    code = code * 10 + digit;
+                                    ++src;
+                                }
+                                insert_coded_character<Flags>(dest, code);    // Put character in output
+                            }
+                            if (*src == Ch(';'))
+                                ++src;
+                            else
+                                BOOST_PROPERTY_TREE_RAPIDXML_PARSE_ERROR("expected ;", src);
+                            continue;
+
+                        // Something else
+                        default:
+                            // Ignore, just copy '&' verbatim
+                            break;
+
+                        }
+                    }
+                }
+                
+                // If whitespace condensing is enabled
+                if (Flags & parse_normalize_whitespace)
+                {
+                    // Test if condensing is needed                 
+                    if (whitespace_pred::test(*src))
+                    {
+                        *dest = Ch(' '); ++dest;    // Put single space in dest
+                        ++src;                      // Skip first whitespace char
+                        // Skip remaining whitespace chars
+                        while (whitespace_pred::test(*src))
+                            ++src;
+                        continue;
+                    }
+                }
+
+                // No replacement, only copy character
+                *dest++ = *src++;
+
+            }
+
+            // Return new end
+            text = src;
+            return dest;
+
+        }
+
+        ///////////////////////////////////////////////////////////////////////
+        // Internal parsing functions
+        
+        // Parse UTF-8 BOM, if any
+        template<int Flags>
+        void parse_bom(char *&text)
+        {
+            if (static_cast<unsigned char>(text[0]) == 0xEF && 
+                static_cast<unsigned char>(text[1]) == 0xBB && 
+                static_cast<unsigned char>(text[2]) == 0xBF)
+            {
+                text += 3;
+            }
+        }
+        
+        // Parse UTF-16/32 BOM, if any
+        template<int Flags>
+        void parse_bom(wchar_t *&text)
+        {
+            const wchar_t bom = 0xFEFF;
+            if (text[0] == bom)
+            {
+                ++text;
+            }
+        }
+
+        // Parse XML declaration (<?xml...)
+        template<int Flags>
+        xml_node<Ch> *parse_xml_declaration(Ch *&text)
+        {
+            // If parsing of declaration is disabled
+            if (!(Flags & parse_declaration_node))
+            {
+                // Skip until end of declaration
+                while (text[0] != Ch('?') || text[1] != Ch('>'))
+                {
+                    if (!text[0])
+                        BOOST_PROPERTY_TREE_RAPIDXML_PARSE_ERROR("unexpected end of data", text);
+                    ++text;
+                }
+                text += 2;    // Skip '?>'
+                return 0;
+            }
+
+            // Create declaration
+            xml_node<Ch> *declaration = this->allocate_node(node_declaration);
+
+            // Skip whitespace before attributes or ?>
+            skip<whitespace_pred, Flags>(text);
+
+            // Parse declaration attributes
+            parse_node_attributes<Flags>(text, declaration);
+            
+            // Skip ?>
+            if (text[0] != Ch('?') || text[1] != Ch('>'))
+                BOOST_PROPERTY_TREE_RAPIDXML_PARSE_ERROR("expected ?>", text);
+            text += 2;
+            
+            return declaration;
+        }
+
+        // Parse XML comment (<!--...)
+        template<int Flags>
+        xml_node<Ch> *parse_comment(Ch *&text)
+        {
+            // If parsing of comments is disabled
+            if (!(Flags & parse_comment_nodes))
+            {
+                // Skip until end of comment
+                while (text[0] != Ch('-') || text[1] != Ch('-') || text[2] != Ch('>'))
+                {
+                    if (!text[0])
+                        BOOST_PROPERTY_TREE_RAPIDXML_PARSE_ERROR("unexpected end of data", text);
+                    ++text;
+                }
+                text += 3;     // Skip '-->'
+                return 0;      // Do not produce comment node
+            }
+
+            // Remember value start
+            Ch *val = text;
+
+            // Skip until end of comment
+            while (text[0] != Ch('-') || text[1] != Ch('-') || text[2] != Ch('>'))
+            {
+                if (!text[0])
+                    BOOST_PROPERTY_TREE_RAPIDXML_PARSE_ERROR("unexpected end of data", text);
+                ++text;
+            }
+
+            // Create comment node
+            xml_node<Ch> *comment = this->allocate_node(node_comment);
+            comment->value(val, text - val);
+            
+            // Place zero terminator after comment value
+            if (!(Flags & parse_no_string_terminators))
+                *text = Ch('\0');
+            
+            text += 3;     // Skip '-->'
+            return comment;
+        }
+
+        // Parse DOCTYPE
+        template<int Flags>
+        xml_node<Ch> *parse_doctype(Ch *&text)
+        {
+            // Remember value start
+            Ch *val = text;
+
+            // Skip to >
+            while (*text != Ch('>'))
+            {
+                // Determine character type
+                switch (*text)
+                {
+                
+                // If '[' encountered, scan for matching ending ']' using naive algorithm with depth
+                // This works for all W3C test files except for 2 most wicked
+                case Ch('['):
+                {
+                    ++text;     // Skip '['
+                    int depth = 1;
+                    while (depth > 0)
+                    {
+                        switch (*text)
+                        {
+                            case Ch('['): ++depth; break;
+                            case Ch(']'): --depth; break;
+                            case 0: BOOST_PROPERTY_TREE_RAPIDXML_PARSE_ERROR("unexpected end of data", text);
+                            default: break;
+                        }
+                        ++text;
+                    }
+                    break;
+                }
+                
+                // Error on end of text
+                case Ch('\0'):
+                    BOOST_PROPERTY_TREE_RAPIDXML_PARSE_ERROR("unexpected end of data", text);
+                
+                // Other character, skip it
+                default:
+                    ++text;
+
+                }
+            }
+            
+            // If DOCTYPE nodes enabled
+            if (Flags & parse_doctype_node)
+            {
+                // Create a new doctype node
+                xml_node<Ch> *doctype = this->allocate_node(node_doctype);
+                doctype->value(val, text - val);
+                
+                // Place zero terminator after value
+                if (!(Flags & parse_no_string_terminators))
+                    *text = Ch('\0');
+
+                text += 1;      // skip '>'
+                return doctype;
+            }
+            else
+            {
+                text += 1;      // skip '>'
+                return 0;
+            }
+
+        }
+
+        // Parse PI
+        template<int Flags>
+        xml_node<Ch> *parse_pi(Ch *&text)
+        {
+            // If creation of PI nodes is enabled
+            if (Flags & parse_pi_nodes)
+            {
+                // Create pi node
+                xml_node<Ch> *pi = this->allocate_node(node_pi);
+
+                // Extract PI target name
+                Ch *n = text;
+                skip<node_name_pred, Flags>(text);
+                if (text == n)
+                    BOOST_PROPERTY_TREE_RAPIDXML_PARSE_ERROR("expected PI target", text);
+                pi->name(n, text - n);
+                
+                // Skip whitespace between pi target and pi
+                skip<whitespace_pred, Flags>(text);
+
+                // Remember start of pi
+                Ch *val = text;
+                
+                // Skip to '?>'
+                while (text[0] != Ch('?') || text[1] != Ch('>'))
+                {
+                    if (*text == Ch('\0'))
+                        BOOST_PROPERTY_TREE_RAPIDXML_PARSE_ERROR("unexpected end of data", text);
+                    ++text;
+                }
+
+                // Set pi value (verbatim, no entity expansion or whitespace normalization)
+                pi->value(val, text - val);
+
+                // Place zero terminator after name and value
+                if (!(Flags & parse_no_string_terminators))
+                {
+                    pi->name()[pi->name_size()] = Ch('\0');
+                    pi->value()[pi->value_size()] = Ch('\0');
+                }
+                
+                text += 2;                          // Skip '?>'
+                return pi;
+            }
+            else
+            {
+                // Skip to '?>'
+                while (text[0] != Ch('?') || text[1] != Ch('>'))
+                {
+                    if (*text == Ch('\0'))
+                        BOOST_PROPERTY_TREE_RAPIDXML_PARSE_ERROR("unexpected end of data", text);
+                    ++text;
+                }
+                text += 2;    // Skip '?>'
+                return 0;
+            }
+        }
+
+        // Parse and append data
+        // Return character that ends data.
+        // This is necessary because this character might have been overwritten by a terminating 0
+        template<int Flags>
+        Ch parse_and_append_data(xml_node<Ch> *node, Ch *&text, Ch *contents_start)
+        {
+            // Backup to contents start if whitespace trimming is disabled
+            if (!(Flags & parse_trim_whitespace))
+                text = contents_start;     
+            
+            // Skip until end of data
+            Ch *val = text, *end;
+            if (Flags & parse_normalize_whitespace)
+                end = skip_and_expand_character_refs<text_pred, text_pure_with_ws_pred, Flags>(text);   
+            else
+                end = skip_and_expand_character_refs<text_pred, text_pure_no_ws_pred, Flags>(text);
+
+            // Trim trailing whitespace if flag is set; leading was already trimmed by whitespace skip after >
+            if (Flags & parse_trim_whitespace)
+            {
+                if (Flags & parse_normalize_whitespace)
+                {
+                    // Whitespace is already condensed to single space characters by skipping function, so just trim 1 char off the end
+                    if (*(end - 1) == Ch(' '))
+                        --end;
+                }
+                else
+                {
+                    // Backup until non-whitespace character is found
+                    while (whitespace_pred::test(*(end - 1)))
+                        --end;
+                }
+            }
+            
+            // If characters are still left between end and value (this test is only necessary if normalization is enabled)
+            // Create new data node
+            if (!(Flags & parse_no_data_nodes))
+            {
+                xml_node<Ch> *data = this->allocate_node(node_data);
+                data->value(val, end - val);
+                node->append_node(data);
+            }
+
+            // Add data to parent node if no data exists yet
+            if (!(Flags & parse_no_element_values)) 
+                if (*node->value() == Ch('\0'))
+                    node->value(val, end - val);
+
+            // Place zero terminator after value
+            if (!(Flags & parse_no_string_terminators))
+            {
+                Ch ch = *text;
+                *end = Ch('\0');
+                return ch;      // Return character that ends data; this is required because zero terminator overwritten it
+            }
+
+            // Return character that ends data
+            return *text;
+        }
+
+        // Parse CDATA
+        template<int Flags>
+        xml_node<Ch> *parse_cdata(Ch *&text)
+        {
+            // If CDATA is disabled
+            if (Flags & parse_no_data_nodes)
+            {
+                // Skip until end of cdata
+                while (text[0] != Ch(']') || text[1] != Ch(']') || text[2] != Ch('>'))
+                {
+                    if (!text[0])
+                        BOOST_PROPERTY_TREE_RAPIDXML_PARSE_ERROR("unexpected end of data", text);
+                    ++text;
+                }
+                text += 3;      // Skip ]]>
+                return 0;       // Do not produce CDATA node
+            }
+
+            // Skip until end of cdata
+            Ch *val = text;
+            while (text[0] != Ch(']') || text[1] != Ch(']') || text[2] != Ch('>'))
+            {
+                if (!text[0])
+                    BOOST_PROPERTY_TREE_RAPIDXML_PARSE_ERROR("unexpected end of data", text);
+                ++text;
+            }
+
+            // Create new cdata node
+            xml_node<Ch> *cdata = this->allocate_node(node_cdata);
+            cdata->value(val, text - val);
+
+            // Place zero terminator after value
+            if (!(Flags & parse_no_string_terminators))
+                *text = Ch('\0');
+
+            text += 3;      // Skip ]]>
+            return cdata;
+        }
+        
+        // Parse element node
+        template<int Flags>
+        xml_node<Ch> *parse_element(Ch *&text)
+        {
+            // Create element node
+            xml_node<Ch> *element = this->allocate_node(node_element);
+
+            // Extract element name
+            Ch *n = text;
+            skip<node_name_pred, Flags>(text);
+            if (text == n)
+                BOOST_PROPERTY_TREE_RAPIDXML_PARSE_ERROR("expected element name", text);
+            element->name(n, text - n);
+            
+            // Skip whitespace between element name and attributes or >
+            skip<whitespace_pred, Flags>(text);
+
+            // Parse attributes, if any
+            parse_node_attributes<Flags>(text, element);
+
+            // Determine ending type
+            if (*text == Ch('>'))
+            {
+                ++text;
+                parse_node_contents<Flags>(text, element);
+            }
+            else if (*text == Ch('/'))
+            {
+                ++text;
+                if (*text != Ch('>'))
+                    BOOST_PROPERTY_TREE_RAPIDXML_PARSE_ERROR("expected >", text);
+                ++text;
+            }
+            else
+                BOOST_PROPERTY_TREE_RAPIDXML_PARSE_ERROR("expected >", text);
+
+            // Place zero terminator after name
+            if (!(Flags & parse_no_string_terminators))
+                element->name()[element->name_size()] = Ch('\0');
+
+            // Return parsed element
+            return element;
+        }
+
+        // Determine node type, and parse it
+        template<int Flags>
+        xml_node<Ch> *parse_node(Ch *&text)
+        {
+            // Parse proper node type
+            switch (text[0])
+            {
+
+            // <...
+            default: 
+                // Parse and append element node
+                return parse_element<Flags>(text);
+
+            // <?...
+            case Ch('?'): 
+                ++text;     // Skip ?
+                if ((text[0] == Ch('x') || text[0] == Ch('X')) &&
+                    (text[1] == Ch('m') || text[1] == Ch('M')) && 
+                    (text[2] == Ch('l') || text[2] == Ch('L')) &&
+                    whitespace_pred::test(text[3]))
+                {
+                    // '<?xml ' - xml declaration
+                    text += 4;      // Skip 'xml '
+                    return parse_xml_declaration<Flags>(text);
+                }
+                else
+                {
+                    // Parse PI
+                    return parse_pi<Flags>(text);
+                }
+            
+            // <!...
+            case Ch('!'): 
+
+                // Parse proper subset of <! node
+                switch (text[1])    
+                {
+                
+                // <!-
+                case Ch('-'):
+                    if (text[2] == Ch('-'))
+                    {
+                        // '<!--' - xml comment
+                        text += 3;     // Skip '!--'
+                        return parse_comment<Flags>(text);
+                    }
+                    break;
+
+                // <![
+                case Ch('['):
+                    if (text[2] == Ch('C') && text[3] == Ch('D') && text[4] == Ch('A') && 
+                        text[5] == Ch('T') && text[6] == Ch('A') && text[7] == Ch('['))
+                    {
+                        // '<![CDATA[' - cdata
+                        text += 8;     // Skip '![CDATA['
+                        return parse_cdata<Flags>(text);
+                    }
+                    break;
+
+                // <!D
+                case Ch('D'):
+                    if (text[2] == Ch('O') && text[3] == Ch('C') && text[4] == Ch('T') && 
+                        text[5] == Ch('Y') && text[6] == Ch('P') && text[7] == Ch('E') && 
+                        whitespace_pred::test(text[8]))
+                    {
+                        // '<!DOCTYPE ' - doctype
+                        text += 9;      // skip '!DOCTYPE '
+                        return parse_doctype<Flags>(text);
+                    }
+                    break;
+
+                default: break;
+
+                }   // switch
+
+                // Attempt to skip other, unrecognized node types starting with <!
+                ++text;     // Skip !
+                while (*text != Ch('>'))
+                {
+                    if (*text == 0)
+                        BOOST_PROPERTY_TREE_RAPIDXML_PARSE_ERROR("unexpected end of data", text);
+                    ++text;
+                }
+                ++text;     // Skip '>'
+                return 0;   // No node recognized
+
+            }
+        }
+
+        // Parse contents of the node - children, data etc.
+        template<int Flags>
+        void parse_node_contents(Ch *&text, xml_node<Ch> *node)
+        {
+            // For all children and text
+            while (1)
+            {
+                // Skip whitespace between > and node contents
+                Ch *contents_start = text;      // Store start of node contents before whitespace is skipped
+                if (Flags & parse_trim_whitespace)
+                    skip<whitespace_pred, Flags>(text);
+                Ch next_char = *text;
+
+            // After data nodes, instead of continuing the loop, control jumps here.
+            // This is because zero termination inside parse_and_append_data() function
+            // would wreak havoc with the above code.
+            // Also, skipping whitespace after data nodes is unnecessary.
+            after_data_node:    
+                
+                // Determine what comes next: node closing, child node, data node, or 0?
+                switch (next_char)
+                {
+                
+                // Node closing or child node
+                case Ch('<'):
+                    if (text[1] == Ch('/'))
+                    {
+                        // Node closing
+                        text += 2;      // Skip '</'
+                        if (Flags & parse_validate_closing_tags)
+                        {
+                            // Skip and validate closing tag name
+                            Ch *closing_name = text;
+                            skip<node_name_pred, Flags>(text);
+                            if (!internal::compare(node->name(), node->name_size(), closing_name, text - closing_name, true))
+                                BOOST_PROPERTY_TREE_RAPIDXML_PARSE_ERROR("invalid closing tag name", text);
+                        }
+                        else
+                        {
+                            // No validation, just skip name
+                            skip<node_name_pred, Flags>(text);
+                        }
+                        // Skip remaining whitespace after node name
+                        skip<whitespace_pred, Flags>(text);
+                        if (*text != Ch('>'))
+                            BOOST_PROPERTY_TREE_RAPIDXML_PARSE_ERROR("expected >", text);
+                        ++text;     // Skip '>'
+                        return;     // Node closed, finished parsing contents
+                    }
+                    else
+                    {
+                        // Child node
+                        ++text;     // Skip '<'
+                        if (xml_node<Ch> *child = parse_node<Flags>(text))
+                            node->append_node(child);
+                    }
+                    break;
+
+                // End of data - error
+                case Ch('\0'):
+                    BOOST_PROPERTY_TREE_RAPIDXML_PARSE_ERROR("unexpected end of data", text);
+
+                // Data node
+                default:
+                    next_char = parse_and_append_data<Flags>(node, text, contents_start);
+                    goto after_data_node;   // Bypass regular processing after data nodes
+
+                }
+            }
+        }
+        
+        // Parse XML attributes of the node
+        template<int Flags>
+        void parse_node_attributes(Ch *&text, xml_node<Ch> *node)
+        {
+            // For all attributes 
+            while (attribute_name_pred::test(*text))
+            {
+                // Extract attribute name
+                Ch *n = text;
+                ++text;     // Skip first character of attribute name
+                skip<attribute_name_pred, Flags>(text);
+                if (text == n)
+                    BOOST_PROPERTY_TREE_RAPIDXML_PARSE_ERROR("expected attribute name", n);
+
+                // Create new attribute
+                xml_attribute<Ch> *attribute = this->allocate_attribute();
+                attribute->name(n, text - n);
+                node->append_attribute(attribute);
+
+                // Skip whitespace after attribute name
+                skip<whitespace_pred, Flags>(text);
+
+                // Skip =
+                if (*text != Ch('='))
+                    BOOST_PROPERTY_TREE_RAPIDXML_PARSE_ERROR("expected =", text);
+                ++text;
+
+                // Add terminating zero after name
+                if (!(Flags & parse_no_string_terminators))
+                    attribute->name()[attribute->name_size()] = 0;
+
+                // Skip whitespace after =
+                skip<whitespace_pred, Flags>(text);
+
+                // Skip quote and remember if it was ' or "
+                Ch quote = *text;
+                if (quote != Ch('\'') && quote != Ch('"'))
+                    BOOST_PROPERTY_TREE_RAPIDXML_PARSE_ERROR("expected ' or \"", text);
+                ++text;
+
+                // Extract attribute value and expand char refs in it
+                Ch *val = text, *end;
+                const int AttFlags = Flags & ~parse_normalize_whitespace;   // No whitespace normalization in attributes
+                if (quote == Ch('\''))
+                    end = skip_and_expand_character_refs<attribute_value_pred<Ch('\'')>, attribute_value_pure_pred<Ch('\'')>, AttFlags>(text);
+                else
+                    end = skip_and_expand_character_refs<attribute_value_pred<Ch('"')>, attribute_value_pure_pred<Ch('"')>, AttFlags>(text);
+                
+                // Set attribute value
+                attribute->value(val, end - val);
+                
+                // Make sure that end quote is present
+                if (*text != quote)
+                    BOOST_PROPERTY_TREE_RAPIDXML_PARSE_ERROR("expected ' or \"", text);
+                ++text;     // Skip quote
+
+                // Add terminating zero after value
+                if (!(Flags & parse_no_string_terminators))
+                    attribute->value()[attribute->value_size()] = 0;
+
+                // Skip whitespace after attribute value
+                skip<whitespace_pred, Flags>(text);
+            }
+        }
+
+    };
+
+    //! \cond internal
+    namespace internal
+    {
+
+        // Whitespace (space \n \r \t)
+        template<int Dummy>
+        const unsigned char lookup_tables<Dummy>::lookup_whitespace[256] = 
+        {
+          // 0   1   2   3   4   5   6   7   8   9   A   B   C   D   E   F
+             0,  0,  0,  0,  0,  0,  0,  0,  0,  1,  1,  0,  0,  1,  0,  0,  // 0
+             0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  // 1
+             1,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  // 2
+             0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  // 3
+             0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  // 4
+             0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  // 5
+             0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  // 6
+             0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  // 7
+             0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  // 8
+             0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  // 9
+             0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  // A
+             0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  // B
+             0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  // C
+             0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  // D
+             0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  // E
+             0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0   // F
+        };
+
+        // Node name (anything but space \n \r \t / > ? \0)
+        template<int Dummy>
+        const unsigned char lookup_tables<Dummy>::lookup_node_name[256] = 
+        {
+          // 0   1   2   3   4   5   6   7   8   9   A   B   C   D   E   F
+             0,  1,  1,  1,  1,  1,  1,  1,  1,  0,  0,  1,  1,  0,  1,  1,  // 0
+             1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 1
+             0,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  0,  // 2
+             1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  0,  0,  // 3
+             1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 4
+             1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 5
+             1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 6
+             1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 7
+             1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 8
+             1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 9
+             1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // A
+             1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // B
+             1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // C
+             1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // D
+             1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // E
+             1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1   // F
+        };
+
+        // Text (i.e. PCDATA) (anything but < \0)
+        template<int Dummy>
+        const unsigned char lookup_tables<Dummy>::lookup_text[256] = 
+        {
+          // 0   1   2   3   4   5   6   7   8   9   A   B   C   D   E   F
+             0,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 0
+             1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 1
+             1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 2
+             1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  0,  1,  1,  1,  // 3
+             1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 4
+             1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 5
+             1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 6
+             1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 7
+             1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 8
+             1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 9
+             1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // A
+             1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // B
+             1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // C
+             1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // D
+             1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // E
+             1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1   // F
+        };
+
+        // Text (i.e. PCDATA) that does not require processing when ws normalization is disabled 
+        // (anything but < \0 &)
+        template<int Dummy>
+        const unsigned char lookup_tables<Dummy>::lookup_text_pure_no_ws[256] = 
+        {
+          // 0   1   2   3   4   5   6   7   8   9   A   B   C   D   E   F
+             0,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 0
+             1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 1
+             1,  1,  1,  1,  1,  1,  0,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 2
+             1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  0,  1,  1,  1,  // 3
+             1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 4
+             1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 5
+             1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 6
+             1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 7
+             1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 8
+             1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 9
+             1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // A
+             1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // B
+             1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // C
+             1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // D
+             1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // E
+             1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1   // F
+        };
+
+        // Text (i.e. PCDATA) that does not require processing when ws normalizationis is enabled
+        // (anything but < \0 & space \n \r \t)
+        template<int Dummy>
+        const unsigned char lookup_tables<Dummy>::lookup_text_pure_with_ws[256] = 
+        {
+          // 0   1   2   3   4   5   6   7   8   9   A   B   C   D   E   F
+             0,  1,  1,  1,  1,  1,  1,  1,  1,  0,  0,  1,  1,  0,  1,  1,  // 0
+             1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 1
+             0,  1,  1,  1,  1,  1,  0,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 2
+             1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  0,  1,  1,  1,  // 3
+             1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 4
+             1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 5
+             1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 6
+             1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 7
+             1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 8
+             1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 9
+             1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // A
+             1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // B
+             1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // C
+             1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // D
+             1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // E
+             1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1   // F
+        };
+
+        // Attribute name (anything but space \n \r \t / < > = ? ! \0)
+        template<int Dummy>
+        const unsigned char lookup_tables<Dummy>::lookup_attribute_name[256] = 
+        {
+          // 0   1   2   3   4   5   6   7   8   9   A   B   C   D   E   F
+             0,  1,  1,  1,  1,  1,  1,  1,  1,  0,  0,  1,  1,  0,  1,  1,  // 0
+             1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 1
+             0,  0,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  0,  // 2
+             1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  0,  0,  0,  0,  // 3
+             1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 4
+             1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 5
+             1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 6
+             1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 7
+             1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 8
+             1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 9
+             1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // A
+             1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // B
+             1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // C
+             1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // D
+             1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // E
+             1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1   // F
+        };
+
+        // Attribute data with single quote (anything but ' \0)
+        template<int Dummy>
+        const unsigned char lookup_tables<Dummy>::lookup_attribute_data_1[256] = 
+        {
+          // 0   1   2   3   4   5   6   7   8   9   A   B   C   D   E   F
+             0,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 0
+             1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 1
+             1,  1,  1,  1,  1,  1,  1,  0,  1,  1,  1,  1,  1,  1,  1,  1,  // 2
+             1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 3
+             1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 4
+             1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 5
+             1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 6
+             1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 7
+             1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 8
+             1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 9
+             1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // A
+             1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // B
+             1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // C
+             1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // D
+             1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // E
+             1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1   // F
+        };
+
+        // Attribute data with single quote that does not require processing (anything but ' \0 &)
+        template<int Dummy>
+        const unsigned char lookup_tables<Dummy>::lookup_attribute_data_1_pure[256] = 
+        {
+          // 0   1   2   3   4   5   6   7   8   9   A   B   C   D   E   F
+             0,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 0
+             1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 1
+             1,  1,  1,  1,  1,  1,  0,  0,  1,  1,  1,  1,  1,  1,  1,  1,  // 2
+             1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 3
+             1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 4
+             1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 5
+             1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 6
+             1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 7
+             1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 8
+             1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 9
+             1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // A
+             1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // B
+             1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // C
+             1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // D
+             1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // E
+             1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1   // F
+        };
+
+        // Attribute data with double quote (anything but " \0)
+        template<int Dummy>
+        const unsigned char lookup_tables<Dummy>::lookup_attribute_data_2[256] = 
+        {
+          // 0   1   2   3   4   5   6   7   8   9   A   B   C   D   E   F
+             0,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 0
+             1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 1
+             1,  1,  0,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 2
+             1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 3
+             1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 4
+             1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 5
+             1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 6
+             1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 7
+             1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 8
+             1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 9
+             1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // A
+             1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // B
+             1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // C
+             1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // D
+             1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // E
+             1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1   // F
+        };
+
+        // Attribute data with double quote that does not require processing (anything but " \0 &)
+        template<int Dummy>
+        const unsigned char lookup_tables<Dummy>::lookup_attribute_data_2_pure[256] = 
+        {
+          // 0   1   2   3   4   5   6   7   8   9   A   B   C   D   E   F
+             0,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 0
+             1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 1
+             1,  1,  0,  1,  1,  1,  0,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 2
+             1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 3
+             1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 4
+             1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 5
+             1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 6
+             1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 7
+             1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 8
+             1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 9
+             1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // A
+             1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // B
+             1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // C
+             1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // D
+             1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // E
+             1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1   // F
+        };
+
+        // Digits (dec and hex, 255 denotes end of numeric character reference)
+        template<int Dummy>
+        const unsigned char lookup_tables<Dummy>::lookup_digits[256] = 
+        {
+          // 0   1   2   3   4   5   6   7   8   9   A   B   C   D   E   F
+           255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,  // 0
+           255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,  // 1
+           255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,  // 2
+             0,  1,  2,  3,  4,  5,  6,  7,  8,  9,255,255,255,255,255,255,  // 3
+           255, 10, 11, 12, 13, 14, 15,255,255,255,255,255,255,255,255,255,  // 4
+           255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,  // 5
+           255, 10, 11, 12, 13, 14, 15,255,255,255,255,255,255,255,255,255,  // 6
+           255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,  // 7
+           255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,  // 8
+           255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,  // 9
+           255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,  // A
+           255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,  // B
+           255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,  // C
+           255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,  // D
+           255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,  // E
+           255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255   // F
+        };
+    
+        // Upper case conversion
+        template<int Dummy>
+        const unsigned char lookup_tables<Dummy>::lookup_upcase[256] = 
+        {
+          // 0,  1,  2,  3,  4,  5,  6,  7,  8,  9,  A   B   C   D   E   F
+           0,  1,  2,  3,  4,  5,  6,  7,  8,  9,  10, 11, 12, 13, 14, 15,   // 0
+           16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,   // 1
+           32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,   // 2
+           48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,   // 3
+           64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,   // 4
+           80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95,   // 5
+           96, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,   // 6
+           80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 123,124,125,126,127,  // 7
+           128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,  // 8
+           144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,  // 9
+           160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175,  // A
+           176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191,  // B
+           192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,  // C
+           208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,  // D
+           224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,  // E
+           240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255   // F
+        };
+    }
+    //! \endcond
+
+}}}}
+
+// Undefine internal macros
+#undef BOOST_PROPERTY_TREE_RAPIDXML_PARSE_ERROR
+
+// On MSVC, restore warnings state
+#ifdef _MSC_VER
+    #pragma warning(pop)
+#endif
+
+#endif
diff --git a/include/boost/property_tree/detail/xml_parser_error.hpp b/include/boost/property_tree/detail/xml_parser_error.hpp
new file mode 100644
index 0000000..c79835c
--- /dev/null
+++ b/include/boost/property_tree/detail/xml_parser_error.hpp
@@ -0,0 +1,33 @@
+// ----------------------------------------------------------------------------
+// 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_XML_PARSER_ERROR_HPP_INCLUDED
+#define BOOST_PROPERTY_TREE_DETAIL_XML_PARSER_ERROR_HPP_INCLUDED
+
+#include <boost/property_tree/detail/file_parser_error.hpp>
+#include <string>
+
+namespace boost { namespace property_tree { namespace xml_parser
+{
+
+    //! Xml parser error
+    class xml_parser_error: public file_parser_error
+    {
+    public:
+        xml_parser_error(const std::string &msg,
+                         const std::string &file,
+                         unsigned long l):
+            file_parser_error(msg, file, l)
+        {
+        }
+    };
+
+} } }
+
+#endif
diff --git a/include/boost/property_tree/detail/xml_parser_flags.hpp b/include/boost/property_tree/detail/xml_parser_flags.hpp
new file mode 100644
index 0000000..9340fe2
--- /dev/null
+++ b/include/boost/property_tree/detail/xml_parser_flags.hpp
@@ -0,0 +1,31 @@
+// ----------------------------------------------------------------------------
+// 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_XML_PARSER_FLAGS_HPP_INCLUDED
+#define BOOST_PROPERTY_TREE_DETAIL_XML_PARSER_FLAGS_HPP_INCLUDED
+
+namespace boost { namespace property_tree { namespace xml_parser
+{
+
+    /// Text elements should be put in separate keys,
+    /// not concatenated in parent data.
+    static const int no_concat_text  = 0x1;
+    /// Comments should be omitted.
+    static const int no_comments     = 0x2;
+    /// Whitespace should be collapsed and trimmed.
+    static const int trim_whitespace = 0x4;
+
+    inline bool validate_flags(int flags)
+    {
+        return (flags & ~(no_concat_text | no_comments | trim_whitespace)) == 0;
+    }
+
+} } }
+
+#endif
diff --git a/include/boost/property_tree/detail/xml_parser_read_rapidxml.hpp b/include/boost/property_tree/detail/xml_parser_read_rapidxml.hpp
new file mode 100644
index 0000000..9c04219
--- /dev/null
+++ b/include/boost/property_tree/detail/xml_parser_read_rapidxml.hpp
@@ -0,0 +1,144 @@
+// ----------------------------------------------------------------------------
+// Copyright (C) 2007 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_XML_PARSER_READ_RAPIDXML_HPP_INCLUDED
+#define BOOST_PROPERTY_TREE_DETAIL_XML_PARSER_READ_RAPIDXML_HPP_INCLUDED
+
+#include <boost/property_tree/ptree.hpp>
+#include <boost/property_tree/detail/xml_parser_error.hpp>
+#include <boost/property_tree/detail/xml_parser_flags.hpp>
+#include <boost/property_tree/detail/xml_parser_utils.hpp>
+#include <boost/property_tree/detail/rapidxml.hpp>
+#include <vector>
+
+namespace boost { namespace property_tree { namespace xml_parser
+{
+
+    template<class Ptree, class Ch>
+    void read_xml_node(detail::rapidxml::xml_node<Ch> *node,
+                       Ptree &pt, int flags)
+    {
+        using namespace detail::rapidxml;
+        switch (node->type())
+        {
+            // Element nodes
+            case node_element: 
+            {
+                // Create node
+                Ptree &pt_node = pt.push_back(std::make_pair(node->name(),
+                                                             Ptree()))->second;
+
+                // Copy attributes
+                if (node->first_attribute())
+                {
+                    Ptree &pt_attr_root = pt_node.push_back(
+                        std::make_pair(xmlattr<typename Ptree::key_type>(), Ptree()))->second;
+                    for (xml_attribute<Ch> *attr = node->first_attribute();
+                         attr; attr = attr->next_attribute())
+                    {
+                        Ptree &pt_attr = pt_attr_root.push_back(
+                            std::make_pair(attr->name(), Ptree()))->second;
+                        pt_attr.data() = typename Ptree::key_type(attr->value(), attr->value_size());
+                    }
+                }
+
+                // Copy children
+                for (xml_node<Ch> *child = node->first_node();
+                     child; child = child->next_sibling())
+                    read_xml_node(child, pt_node, flags);
+            }
+            break;
+
+            // Data nodes
+            case node_data:
+            case node_cdata:
+            {
+                if (flags & no_concat_text)
+                    pt.push_back(std::make_pair(xmltext<typename Ptree::key_type>(),
+                                                Ptree(node->value())));
+                else
+                    pt.data() += typename Ptree::key_type(node->value(), node->value_size());
+            }
+            break;
+
+            // Comment nodes
+            case node_comment:
+            {
+                if (!(flags & no_comments))
+                    pt.push_back(std::make_pair(xmlcomment<typename Ptree::key_type>(),
+                                    Ptree(typename Ptree::key_type(node->value(), node->value_size()))));
+            }
+            break;
+
+            default:
+                // Skip other node types
+                break;
+        }
+    }
+
+    template<class Ptree>
+    void read_xml_internal(std::basic_istream<
+                               typename Ptree::key_type::value_type> &stream,
+                           Ptree &pt,
+                           int flags,
+                           const std::string &filename)
+    {
+        typedef typename Ptree::key_type::value_type Ch;
+        using namespace detail::rapidxml;
+
+        // Load data into vector
+        stream.unsetf(std::ios::skipws);
+        std::vector<Ch> v(std::istreambuf_iterator<Ch>(stream.rdbuf()),
+                          std::istreambuf_iterator<Ch>());
+        if (!stream.good())
+            BOOST_PROPERTY_TREE_THROW(
+                xml_parser_error("read error", filename, 0));
+        v.push_back(0); // zero-terminate
+
+        try {
+            // Parse using appropriate flags
+            const int f_tws = parse_normalize_whitespace
+                            | parse_trim_whitespace;
+            const int f_c = parse_comment_nodes;
+            // Some compilers don't like the bitwise or in the template arg.
+            const int f_tws_c = parse_normalize_whitespace
+                              | parse_trim_whitespace
+                              | parse_comment_nodes;
+            xml_document<Ch> doc;
+            if (flags & no_comments) {
+                if (flags & trim_whitespace)
+                    doc.BOOST_NESTED_TEMPLATE parse<f_tws>(&v.front());
+                else
+                    doc.BOOST_NESTED_TEMPLATE parse<0>(&v.front());
+            } else {
+                if (flags & trim_whitespace)
+                    doc.BOOST_NESTED_TEMPLATE parse<f_tws_c>(&v.front());
+                else
+                    doc.BOOST_NESTED_TEMPLATE parse<f_c>(&v.front());
+            }
+
+            // Create ptree from nodes
+            Ptree local;
+            for (xml_node<Ch> *child = doc.first_node();
+                 child; child = child->next_sibling())
+                read_xml_node(child, local, flags);
+
+            // Swap local and result ptrees
+            pt.swap(local);
+        } catch (parse_error &e) {
+            long line = static_cast<long>(
+                std::count(&v.front(), e.where<Ch>(), Ch('\n')) + 1);
+            BOOST_PROPERTY_TREE_THROW(
+                xml_parser_error(e.what(), filename, line));  
+        }
+    }
+
+} } }
+
+#endif
diff --git a/include/boost/property_tree/detail/xml_parser_utils.hpp b/include/boost/property_tree/detail/xml_parser_utils.hpp
new file mode 100644
index 0000000..fbbde01
--- /dev/null
+++ b/include/boost/property_tree/detail/xml_parser_utils.hpp
@@ -0,0 +1,139 @@
+// ----------------------------------------------------------------------------
+// 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_XML_PARSER_UTILS_HPP_INCLUDED
+#define BOOST_PROPERTY_TREE_DETAIL_XML_PARSER_UTILS_HPP_INCLUDED
+
+#include <boost/property_tree/detail/ptree_utils.hpp>
+#include <boost/property_tree/detail/xml_parser_error.hpp>
+#include <boost/property_tree/detail/xml_parser_writer_settings.hpp>
+#include <string>
+#include <algorithm>
+#include <locale>
+
+namespace boost { namespace property_tree { namespace xml_parser
+{
+
+    template<class Str>
+    Str condense(const Str &s)
+    {
+        typedef typename Str::value_type Ch;
+        Str r;
+        std::locale loc;
+        bool space = false;
+        typename Str::const_iterator end = s.end();
+        for (typename Str::const_iterator it = s.begin();
+             it != end; ++it)
+        {
+            if (isspace(*it, loc) || *it == Ch('\n'))
+            {
+                if (!space)
+                    r += Ch(' '), space = true;
+            }
+            else
+                r += *it, space = false;
+        }
+        return r;
+    }
+
+
+    template<class Str>
+    Str encode_char_entities(const Str &s)
+    {
+        // Don't do anything for empty strings.
+        if(s.empty()) return s;
+
+        typedef typename Str::value_type Ch;
+
+        Str r;
+        // To properly round-trip spaces and not uglify the XML beyond
+        // recognition, we have to encode them IF the text contains only spaces.
+        Str sp(1, Ch(' '));
+        if(s.find_first_not_of(sp) == Str::npos) {
+            // The first will suffice.
+            r = detail::widen<Str>("&#32;");
+            r += Str(s.size() - 1, Ch(' '));
+        } else {
+            typename Str::const_iterator end = s.end();
+            for (typename Str::const_iterator it = s.begin(); it != end; ++it)
+            {
+                switch (*it)
+                {
+                    case Ch('<'): r += detail::widen<Str>("&lt;"); break;
+                    case Ch('>'): r += detail::widen<Str>("&gt;"); break;
+                    case Ch('&'): r += detail::widen<Str>("&amp;"); break;
+                    case Ch('"'): r += detail::widen<Str>("&quot;"); break;
+                    case Ch('\''): r += detail::widen<Str>("&apos;"); break;
+                    default: r += *it; break;
+                }
+            }
+        }
+        return r;
+    }
+
+    template<class Str>
+    Str decode_char_entities(const Str &s)
+    {
+        typedef typename Str::value_type Ch;
+        Str r;
+        typename Str::const_iterator end = s.end();
+        for (typename Str::const_iterator it = s.begin(); it != end; ++it)
+        {
+            if (*it == Ch('&'))
+            {
+                typename Str::const_iterator semicolon = std::find(it + 1, end, Ch(';'));
+                if (semicolon == end)
+                    BOOST_PROPERTY_TREE_THROW(xml_parser_error("invalid character entity", "", 0));
+                Str ent(it + 1, semicolon);
+                if (ent == detail::widen<Str>("lt")) r += Ch('<');
+                else if (ent == detail::widen<Str>("gt")) r += Ch('>');
+                else if (ent == detail::widen<Str>("amp")) r += Ch('&');
+                else if (ent == detail::widen<Str>("quot")) r += Ch('"');
+                else if (ent == detail::widen<Str>("apos")) r += Ch('\'');
+                else
+                    BOOST_PROPERTY_TREE_THROW(xml_parser_error("invalid character entity", "", 0));
+                it = semicolon;
+            }
+            else
+                r += *it;
+        }
+        return r;
+    }
+
+    template<class Str>
+    const Str &xmldecl()
+    {
+        static Str s = detail::widen<Str>("<?xml>");
+        return s;
+    }
+
+    template<class Str>
+    const Str &xmlattr()
+    {
+        static Str s = detail::widen<Str>("<xmlattr>");
+        return s;
+    }
+
+    template<class Str>
+    const Str &xmlcomment()
+    {
+        static Str s = detail::widen<Str>("<xmlcomment>");
+        return s;
+    }
+
+    template<class Str>
+    const Str &xmltext()
+    {
+        static Str s = detail::widen<Str>("<xmltext>");
+        return s;
+    }
+
+} } }
+
+#endif
diff --git a/include/boost/property_tree/detail/xml_parser_write.hpp b/include/boost/property_tree/detail/xml_parser_write.hpp
new file mode 100644
index 0000000..0af2265
--- /dev/null
+++ b/include/boost/property_tree/detail/xml_parser_write.hpp
@@ -0,0 +1,195 @@
+// ----------------------------------------------------------------------------
+// Copyright (C) 2002-2006 Marcin Kalicinski
+// Copyright (C) 2013 Sebastian Redl
+//
+// 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_XML_PARSER_WRITE_HPP_INCLUDED
+#define BOOST_PROPERTY_TREE_DETAIL_XML_PARSER_WRITE_HPP_INCLUDED
+
+#include <boost/property_tree/ptree.hpp>
+#include <boost/property_tree/detail/xml_parser_utils.hpp>
+#include <string>
+#include <ostream>
+#include <iomanip>
+
+namespace boost { namespace property_tree { namespace xml_parser
+{
+    template<class Str>
+    void write_xml_indent(std::basic_ostream<typename Str::value_type> &stream,
+          int indent,
+          const xml_writer_settings<Str> & settings
+          )
+    {
+        stream << std::basic_string<typename Str::value_type>(indent * settings.indent_count, settings.indent_char);
+    }
+
+    template<class Str>
+    void write_xml_comment(std::basic_ostream<typename Str::value_type> &stream,
+                           const Str &s,
+                           int indent,
+                           bool separate_line,
+                           const xml_writer_settings<Str> & settings
+                           )
+    {
+        typedef typename Str::value_type Ch;
+        if (separate_line)
+            write_xml_indent(stream,indent,settings);
+        stream << Ch('<') << Ch('!') << Ch('-') << Ch('-');
+        stream << s;
+        stream << Ch('-') << Ch('-') << Ch('>');
+        if (separate_line)
+            stream << Ch('\n');
+    }
+
+    template<class Str>
+    void write_xml_text(std::basic_ostream<typename Str::value_type> &stream,
+                        const Str &s,
+                        int indent, 
+                        bool separate_line,
+                        const xml_writer_settings<Str> & settings
+                        )
+    {
+        typedef typename Str::value_type Ch;
+        if (separate_line)
+            write_xml_indent(stream,indent,settings);
+        stream << encode_char_entities(s);
+        if (separate_line)
+            stream << Ch('\n');
+    }
+
+    template<class Ptree>
+    void write_xml_element(std::basic_ostream<typename Ptree::key_type::value_type> &stream,
+                           const typename Ptree::key_type &key,
+                           const Ptree &pt,
+                           int indent,
+                           const xml_writer_settings<typename Ptree::key_type> & settings)
+    {
+        typedef typename Ptree::key_type::value_type Ch;
+        typedef typename Ptree::key_type Str;
+        typedef typename Ptree::const_iterator It;
+
+        bool want_pretty = settings.indent_count > 0;
+        // Find if elements present
+        bool has_elements = false;
+        bool has_attrs_only = pt.data().empty();
+        for (It it = pt.begin(), end = pt.end(); it != end; ++it)
+        {
+            if (it->first != xmlattr<Str>() )
+            {
+                has_attrs_only = false;
+                if (it->first != xmltext<Str>())
+                {
+                    has_elements = true;
+                    break;
+                }
+            }
+        }
+
+        // Write element
+        if (pt.data().empty() && pt.empty())    // Empty key
+        {
+            if (indent >= 0)
+            {
+                write_xml_indent(stream,indent,settings);
+                stream << Ch('<') << key << 
+                          Ch('/') << Ch('>');
+                if (want_pretty)
+                    stream << Ch('\n');
+            }
+        }
+        else    // Nonempty key
+        {
+            // Write opening tag, attributes and data
+            if (indent >= 0)
+            {
+                // Write opening brace and key
+                write_xml_indent(stream,indent,settings);
+                stream << Ch('<') << key;
+
+                // Write attributes
+                if (optional<const Ptree &> attribs = pt.get_child_optional(xmlattr<Str>()))
+                    for (It it = attribs.get().begin(); it != attribs.get().end(); ++it)
+                        stream << Ch(' ') << it->first << Ch('=')
+                               << Ch('"')
+                               << encode_char_entities(
+                                    it->second.template get_value<Str>())
+                               << Ch('"');
+
+                if ( has_attrs_only )
+                {
+                    // Write closing brace
+                    stream << Ch('/') << Ch('>');
+                    if (want_pretty)
+                        stream << Ch('\n');
+                }
+                else
+                {
+                    // Write closing brace
+                    stream << Ch('>');
+
+                    // Break line if needed and if we want pretty-printing
+                    if (has_elements && want_pretty)
+                        stream << Ch('\n');
+                }
+            }
+
+            // Write data text, if present
+            if (!pt.data().empty())
+                write_xml_text(stream,
+                    pt.template get_value<Str>(),
+                    indent + 1, has_elements && want_pretty, settings);
+
+            // Write elements, comments and texts
+            for (It it = pt.begin(); it != pt.end(); ++it)
+            {
+                if (it->first == xmlattr<Str>())
+                    continue;
+                else if (it->first == xmlcomment<Str>())
+                    write_xml_comment(stream,
+                        it->second.template get_value<Str>(),
+                        indent + 1, want_pretty, settings);
+                else if (it->first == xmltext<Str>())
+                    write_xml_text(stream,
+                        it->second.template get_value<Str>(),
+                        indent + 1, has_elements && want_pretty, settings);
+                else
+                    write_xml_element(stream, it->first, it->second,
+                        indent + 1, settings);
+            }
+
+            // Write closing tag
+            if (indent >= 0 && !has_attrs_only)
+            {
+                if (has_elements)
+                    write_xml_indent(stream,indent,settings);
+                stream << Ch('<') << Ch('/') << key << Ch('>');
+                if (want_pretty)
+                    stream << Ch('\n');
+            }
+
+        }
+    }
+
+    template<class Ptree>
+    void write_xml_internal(std::basic_ostream<typename Ptree::key_type::value_type> &stream, 
+                            const Ptree &pt,
+                            const std::string &filename,
+                            const xml_writer_settings<typename Ptree::key_type> & settings)
+    {
+        typedef typename Ptree::key_type Str;
+        stream  << detail::widen<Str>("<?xml version=\"1.0\" encoding=\"")
+                << settings.encoding
+                << detail::widen<Str>("\"?>\n");
+        write_xml_element(stream, Str(), pt, -1, settings);
+        if (!stream)
+            BOOST_PROPERTY_TREE_THROW(xml_parser_error("write error", filename, 0));
+    }
+
+} } }
+
+#endif
diff --git a/include/boost/property_tree/detail/xml_parser_writer_settings.hpp b/include/boost/property_tree/detail/xml_parser_writer_settings.hpp
new file mode 100644
index 0000000..5fb79f3
--- /dev/null
+++ b/include/boost/property_tree/detail/xml_parser_writer_settings.hpp
@@ -0,0 +1,64 @@
+// ----------------------------------------------------------------------------
+// Copyright (C) 2002-2007 Marcin Kalicinski
+// Copyright (C) 2007 Alexey Baskakov
+//
+// 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_XML_PARSER_WRITER_SETTINGS_HPP_INCLUDED
+#define BOOST_PROPERTY_TREE_DETAIL_XML_PARSER_WRITER_SETTINGS_HPP_INCLUDED
+
+#include <string>
+#include <boost/property_tree/detail/ptree_utils.hpp>
+
+namespace boost { namespace property_tree { namespace xml_parser
+{
+
+    // Naively convert narrow string to another character type
+    template<class Str>
+    Str widen(const char *text)
+    {
+        typedef typename Str::value_type Ch;
+        Str result;
+        while (*text)
+        {
+            result += Ch(*text);
+            ++text;
+        }
+        return result;
+    }
+
+    //! Xml writer settings. The default settings lead to no pretty printing.
+    template<class Str>
+    class xml_writer_settings
+    {
+        typedef typename Str::value_type Ch;
+    public:
+        xml_writer_settings(Ch inchar = Ch(' '),
+                typename Str::size_type incount = 0,
+                const Str &enc = widen<Str>("utf-8"))
+            : indent_char(inchar)
+            , indent_count(incount)
+            , encoding(enc)
+        {
+        }
+
+        Ch indent_char;
+        typename Str::size_type indent_count;
+        Str encoding;
+    };
+
+    template <class Str>
+    xml_writer_settings<Str> xml_writer_make_settings(typename Str::value_type indent_char = (typename Str::value_type)(' '),
+        typename Str::size_type indent_count = 0,
+        const Str &encoding = widen<Str>("utf-8"))
+    {
+        return xml_writer_settings<Str>(indent_char, indent_count, encoding);
+    }
+
+} } }
+
+#endif