summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRemko Tronçon <git@el-tramo.be>2011-03-11 20:22:35 (GMT)
committerRemko Tronçon <git@el-tramo.be>2011-03-11 22:22:04 (GMT)
commit59aa5d7e29ca142ae324ad97e6a5f0353d1a6b89 (patch)
treee450b95ff4c0ba7f770723402a2634773f1a0451 /3rdParty/Boost/src/boost/property_tree/detail
parent3ff52013d810f94b6095e93f550f58133e2df239 (diff)
downloadswift-contrib-59aa5d7e29ca142ae324ad97e6a5f0353d1a6b89.zip
swift-contrib-59aa5d7e29ca142ae324ad97e6a5f0353d1a6b89.tar.bz2
Store JID->Avatar mappings.
Resolves: #653
Diffstat (limited to '3rdParty/Boost/src/boost/property_tree/detail')
-rw-r--r--3rdParty/Boost/src/boost/property_tree/detail/exception_implementation.hpp83
-rw-r--r--3rdParty/Boost/src/boost/property_tree/detail/file_parser_error.hpp88
-rw-r--r--3rdParty/Boost/src/boost/property_tree/detail/ptree_implementation.hpp905
-rw-r--r--3rdParty/Boost/src/boost/property_tree/detail/ptree_utils.hpp106
-rw-r--r--3rdParty/Boost/src/boost/property_tree/detail/rapidxml.hpp2582
-rw-r--r--3rdParty/Boost/src/boost/property_tree/detail/xml_parser_error.hpp33
-rw-r--r--3rdParty/Boost/src/boost/property_tree/detail/xml_parser_flags.hpp31
-rw-r--r--3rdParty/Boost/src/boost/property_tree/detail/xml_parser_read_rapidxml.hpp144
-rw-r--r--3rdParty/Boost/src/boost/property_tree/detail/xml_parser_utils.hpp136
-rw-r--r--3rdParty/Boost/src/boost/property_tree/detail/xml_parser_write.hpp194
-rw-r--r--3rdParty/Boost/src/boost/property_tree/detail/xml_parser_writer_settings.hpp62
11 files changed, 4364 insertions, 0 deletions
diff --git a/3rdParty/Boost/src/boost/property_tree/detail/exception_implementation.hpp b/3rdParty/Boost/src/boost/property_tree/detail/exception_implementation.hpp
new file mode 100644
index 0000000..551e10c
--- /dev/null
+++ b/3rdParty/Boost/src/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()
+ {
+ 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()
+ {
+ return boost::any_cast<P>(m_path);
+ }
+
+}}
+
+#endif
diff --git a/3rdParty/Boost/src/boost/property_tree/detail/file_parser_error.hpp b/3rdParty/Boost/src/boost/property_tree/detail/file_parser_error.hpp
new file mode 100644
index 0000000..ff90583
--- /dev/null
+++ b/3rdParty/Boost/src/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/3rdParty/Boost/src/boost/property_tree/detail/ptree_implementation.hpp b/3rdParty/Boost/src/boost/property_tree/detail/ptree_implementation.hpp
new file mode 100644
index 0000000..4220002
--- /dev/null
+++ b/3rdParty/Boost/src/boost/property_tree/detail/ptree_implementation.hpp
@@ -0,0 +1,905 @@
+// ----------------------------------------------------------------------------
+// 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 <memory>
+#include <cassert>
+
+#if defined(BOOST_MSVC) && \
+ (_MSC_FULL_VER >= 160000000 && _MSC_FULL_VER < 170000000)
+#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));
+ typedef multi_index_container<value_type,
+ multi_index::indexed_by<
+ multi_index::sequenced<>,
+ multi_index::ordered_non_unique<multi_index::tag<by_name>,
+ multi_index::member_offset<value_type, const key_type,
+ first_offset>,
+ key_compare
+ >
+ >
+ > base_container;
+#else
+ typedef multi_index_container<value_type,
+ multi_index::indexed_by<
+ multi_index::sequenced<>,
+ multi_index::ordered_non_unique<multi_index::tag<by_name>,
+ multi_index::member<value_type, const key_type,
+ &value_type::first>,
+ key_compare
+ >
+ >
+ > base_container;
+#endif
+ // 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)
+ {
+ m_data.swap(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();
+ }
+
+ template<class K, class D, class C> inline
+ void basic_ptree<K, D, C>::sort()
+ {
+ subs::ch(this).sort();
+ }
+
+ 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() &&
+ 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)
+ {
+ 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/3rdParty/Boost/src/boost/property_tree/detail/ptree_utils.hpp b/3rdParty/Boost/src/boost/property_tree/detail/ptree_utils.hpp
new file mode 100644
index 0000000..7e56c8f
--- /dev/null
+++ b/3rdParty/Boost/src/boost/property_tree/detail/ptree_utils.hpp
@@ -0,0 +1,106 @@
+// ----------------------------------------------------------------------------
+// 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<class Ch>
+ std::basic_string<Ch> widen(const char *text)
+ {
+ std::basic_string<Ch> result;
+ while (*text)
+ {
+ result += Ch(*text);
+ ++text;
+ }
+ return result;
+ }
+
+ // Naively convert string to narrow character type
+ template<class Ch>
+ std::string narrow(const Ch *text)
+ {
+ std::string result;
+ while (*text)
+ {
+ if (*text < 0 || *text > (std::numeric_limits<char>::max)())
+ result += '*';
+ else
+ result += char(*text);
+ ++text;
+ }
+ return result;
+ }
+
+ // Remove trailing and leading spaces
+ template<class Ch>
+ std::basic_string<Ch> trim(const std::basic_string<Ch> &s,
+ const std::locale &loc = std::locale())
+ {
+ typename std::basic_string<Ch>::const_iterator first = s.begin();
+ typename std::basic_string<Ch>::const_iterator end = s.end();
+ while (first != end && std::isspace(*first, loc))
+ ++first;
+ if (first == end)
+ return std::basic_string<Ch>();
+ typename std::basic_string<Ch>::const_iterator last = end;
+ do --last; while (std::isspace(*last, loc));
+ if (first != s.begin() || last + 1 != end)
+ return std::basic_string<Ch>(first, last + 1);
+ else
+ return s;
+ }
+
+} } }
+
+#endif
diff --git a/3rdParty/Boost/src/boost/property_tree/detail/rapidxml.hpp b/3rdParty/Boost/src/boost/property_tree/detail/rapidxml.hpp
new file mode 100644
index 0000000..712bf3f
--- /dev/null
+++ b/3rdParty/Boost/src/boost/property_tree/detail/rapidxml.hpp
@@ -0,0 +1,2582 @@
+// ----------------------------------------------------------------------------
+// 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 <cstdlib> // For std::size_t
+#include <cassert> // For assert
+#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 occured.
+ 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 sematic is same as plain 'z'
+ if (c > 255)
+ {
+ 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
+ typedef void *(alloc_func)(std::size_t); // Type of user-defined function used to allocate memory
+ typedef void (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)
+ {
+ 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(alloc_func *af, free_func *ff)
+ {
+ 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);
+ 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
+ alloc_func *m_alloc_func; // Allocator function, or 0 if default is to be used
+ 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
+ {
+ 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
+ {
+ 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
+ {
+ 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)
+ {
+ 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)
+ {
+ 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)
+ {
+ assert(!where || where->parent() == this);
+ 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()
+ {
+ 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()
+ {
+ 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)
+ {
+ assert(where && where->parent() == this);
+ 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)
+ {
+ 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)
+ {
+ 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)
+ {
+ assert(!where || where->parent() == this);
+ 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()
+ {
+ 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()
+ {
+ 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)
+ {
+ 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)
+ {
+ 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 BOM, if any
+ template<int Flags>
+ void parse_bom(Ch *&text)
+ {
+ // UTF-8?
+ if (static_cast<unsigned char>(text[0]) == 0xEF &&
+ static_cast<unsigned char>(text[1]) == 0xBB &&
+ static_cast<unsigned char>(text[2]) == 0xBF)
+ {
+ text += 3; // Skip utf-8 bom
+ }
+ }
+
+ // 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/3rdParty/Boost/src/boost/property_tree/detail/xml_parser_error.hpp b/3rdParty/Boost/src/boost/property_tree/detail/xml_parser_error.hpp
new file mode 100644
index 0000000..c79835c
--- /dev/null
+++ b/3rdParty/Boost/src/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/3rdParty/Boost/src/boost/property_tree/detail/xml_parser_flags.hpp b/3rdParty/Boost/src/boost/property_tree/detail/xml_parser_flags.hpp
new file mode 100644
index 0000000..9340fe2
--- /dev/null
+++ b/3rdParty/Boost/src/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/3rdParty/Boost/src/boost/property_tree/detail/xml_parser_read_rapidxml.hpp b/3rdParty/Boost/src/boost/property_tree/detail/xml_parser_read_rapidxml.hpp
new file mode 100644
index 0000000..acec34d9
--- /dev/null
+++ b/3rdParty/Boost/src/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<Ch>(), 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() = attr->value();
+ }
+ }
+
+ // 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<Ch>(),
+ Ptree(node->value())));
+ else
+ pt.data() += node->value();
+ }
+ break;
+
+ // Comment nodes
+ case node_comment:
+ {
+ if (!(flags & no_comments))
+ pt.push_back(std::make_pair(xmlcomment<Ch>(),
+ Ptree(node->value())));
+ }
+ 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/3rdParty/Boost/src/boost/property_tree/detail/xml_parser_utils.hpp b/3rdParty/Boost/src/boost/property_tree/detail/xml_parser_utils.hpp
new file mode 100644
index 0000000..7c8a6e1
--- /dev/null
+++ b/3rdParty/Boost/src/boost/property_tree/detail/xml_parser_utils.hpp
@@ -0,0 +1,136 @@
+// ----------------------------------------------------------------------------
+// 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 Ch>
+ std::basic_string<Ch> condense(const std::basic_string<Ch> &s)
+ {
+ std::basic_string<Ch> r;
+ std::locale loc;
+ bool space = false;
+ typename std::basic_string<Ch>::const_iterator end = s.end();
+ for (typename std::basic_string<Ch>::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 Ch>
+ std::basic_string<Ch> encode_char_entities(const std::basic_string<Ch> &s)
+ {
+ // Don't do anything for empty strings.
+ if(s.empty()) return s;
+
+ typedef typename std::basic_string<Ch> Str;
+ 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<Ch>("&#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<Ch>("&lt;"); break;
+ case Ch('>'): r += detail::widen<Ch>("&gt;"); break;
+ case Ch('&'): r += detail::widen<Ch>("&amp;"); break;
+ case Ch('"'): r += detail::widen<Ch>("&quot;"); break;
+ case Ch('\''): r += detail::widen<Ch>("&apos;"); break;
+ default: r += *it; break;
+ }
+ }
+ }
+ return r;
+ }
+
+ template<class Ch>
+ std::basic_string<Ch> decode_char_entities(const std::basic_string<Ch> &s)
+ {
+ typedef typename std::basic_string<Ch> Str;
+ 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<Ch>("lt")) r += Ch('<');
+ else if (ent == detail::widen<Ch>("gt")) r += Ch('>');
+ else if (ent == detail::widen<Ch>("amp")) r += Ch('&');
+ else if (ent == detail::widen<Ch>("quot")) r += Ch('"');
+ else if (ent == detail::widen<Ch>("apos")) r += Ch('\'');
+ else
+ BOOST_PROPERTY_TREE_THROW(xml_parser_error("invalid character entity", "", 0));
+ it = semicolon;
+ }
+ else
+ r += *it;
+ }
+ return r;
+ }
+
+ template<class Ch>
+ const std::basic_string<Ch> &xmldecl()
+ {
+ static std::basic_string<Ch> s = detail::widen<Ch>("<?xml>");
+ return s;
+ }
+
+ template<class Ch>
+ const std::basic_string<Ch> &xmlattr()
+ {
+ static std::basic_string<Ch> s = detail::widen<Ch>("<xmlattr>");
+ return s;
+ }
+
+ template<class Ch>
+ const std::basic_string<Ch> &xmlcomment()
+ {
+ static std::basic_string<Ch> s = detail::widen<Ch>("<xmlcomment>");
+ return s;
+ }
+
+ template<class Ch>
+ const std::basic_string<Ch> &xmltext()
+ {
+ static std::basic_string<Ch> s = detail::widen<Ch>("<xmltext>");
+ return s;
+ }
+
+} } }
+
+#endif
diff --git a/3rdParty/Boost/src/boost/property_tree/detail/xml_parser_write.hpp b/3rdParty/Boost/src/boost/property_tree/detail/xml_parser_write.hpp
new file mode 100644
index 0000000..614854e
--- /dev/null
+++ b/3rdParty/Boost/src/boost/property_tree/detail/xml_parser_write.hpp
@@ -0,0 +1,194 @@
+// ----------------------------------------------------------------------------
+// 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_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 Ch>
+ void write_xml_indent(std::basic_ostream<Ch> &stream,
+ int indent,
+ const xml_writer_settings<Ch> & settings
+ )
+ {
+ stream << std::basic_string<Ch>(indent * settings.indent_count, settings.indent_char);
+ }
+
+ template<class Ch>
+ void write_xml_comment(std::basic_ostream<Ch> &stream,
+ const std::basic_string<Ch> &s,
+ int indent,
+ bool separate_line,
+ const xml_writer_settings<Ch> & settings
+ )
+ {
+ typedef typename std::basic_string<Ch> Str;
+ 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 Ch>
+ void write_xml_text(std::basic_ostream<Ch> &stream,
+ const std::basic_string<Ch> &s,
+ int indent,
+ bool separate_line,
+ const xml_writer_settings<Ch> & settings
+ )
+ {
+ 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 std::basic_string<typename Ptree::key_type::value_type> &key,
+ const Ptree &pt,
+ int indent,
+ const xml_writer_settings<typename Ptree::key_type::value_type> & settings)
+ {
+
+ typedef typename Ptree::key_type::value_type Ch;
+ typedef typename std::basic_string<Ch> 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<Ch>() )
+ {
+ has_attrs_only = false;
+ if (it->first != xmltext<Ch>())
+ {
+ 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<Ch>()))
+ for (It it = attribs.get().begin(); it != attribs.get().end(); ++it)
+ stream << Ch(' ') << it->first << Ch('=') <<
+ Ch('"') << it->second.template get_value<std::basic_string<Ch> >() << 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<std::basic_string<Ch> >(),
+ 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<Ch>())
+ continue;
+ else if (it->first == xmlcomment<Ch>())
+ write_xml_comment(stream,
+ it->second.template get_value<std::basic_string<Ch> >(),
+ indent + 1, want_pretty, settings);
+ else if (it->first == xmltext<Ch>())
+ write_xml_text(stream,
+ it->second.template get_value<std::basic_string<Ch> >(),
+ 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::value_type> & settings)
+ {
+ typedef typename Ptree::key_type::value_type Ch;
+ typedef typename std::basic_string<Ch> Str;
+ stream << detail::widen<Ch>("<?xml version=\"1.0\" encoding=\"")
+ << settings.encoding
+ << detail::widen<Ch>("\"?>\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/3rdParty/Boost/src/boost/property_tree/detail/xml_parser_writer_settings.hpp b/3rdParty/Boost/src/boost/property_tree/detail/xml_parser_writer_settings.hpp
new file mode 100644
index 0000000..f22d85e
--- /dev/null
+++ b/3rdParty/Boost/src/boost/property_tree/detail/xml_parser_writer_settings.hpp
@@ -0,0 +1,62 @@
+// ----------------------------------------------------------------------------
+// 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 Ch>
+ std::basic_string<Ch> widen(const char *text)
+ {
+ std::basic_string<Ch> result;
+ while (*text)
+ {
+ result += Ch(*text);
+ ++text;
+ }
+ return result;
+ }
+
+ //! Xml writer settings. The default settings lead to no pretty printing.
+ template<class Ch>
+ class xml_writer_settings
+ {
+ public:
+ xml_writer_settings(Ch inchar = Ch(' '),
+ typename std::basic_string<Ch>::size_type incount = 0,
+ const std::basic_string<Ch> &enc = widen<Ch>("utf-8"))
+ : indent_char(inchar)
+ , indent_count(incount)
+ , encoding(enc)
+ {
+ }
+
+ Ch indent_char;
+ typename std::basic_string<Ch>::size_type indent_count;
+ std::basic_string<Ch> encoding;
+ };
+
+ template <class Ch>
+ xml_writer_settings<Ch> xml_writer_make_settings(Ch indent_char = Ch(' '),
+ typename std::basic_string<Ch>::size_type indent_count = 0,
+ const std::basic_string<Ch> &encoding = widen<Ch>("utf-8"))
+ {
+ return xml_writer_settings<Ch>(indent_char, indent_count, encoding);
+ }
+
+} } }
+
+#endif