diff options
author | Remko Tronçon <git@el-tramo.be> | 2011-03-11 20:22:35 (GMT) |
---|---|---|
committer | Remko Tronçon <git@el-tramo.be> | 2011-03-11 22:22:04 (GMT) |
commit | 59aa5d7e29ca142ae324ad97e6a5f0353d1a6b89 (patch) | |
tree | e450b95ff4c0ba7f770723402a2634773f1a0451 /3rdParty/Boost/src/boost/property_tree/detail | |
parent | 3ff52013d810f94b6095e93f550f58133e2df239 (diff) | |
download | swift-contrib-59aa5d7e29ca142ae324ad97e6a5f0353d1a6b89.zip swift-contrib-59aa5d7e29ca142ae324ad97e6a5f0353d1a6b89.tar.bz2 |
Store JID->Avatar mappings.
Resolves: #653
Diffstat (limited to '3rdParty/Boost/src/boost/property_tree/detail')
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 (' & " < > &#...;) + // - 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]) + { + + // & ' + 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; + + // " + 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; + + // > + case Ch('g'): + if (src[2] == Ch('t') && src[3] == Ch(';')) + { + *dest = Ch('>'); + ++dest; + src += 4; + continue; + } + break; + + // < + 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>(" "); + 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>("<"); break; + case Ch('>'): r += detail::widen<Ch>(">"); break; + case Ch('&'): r += detail::widen<Ch>("&"); break; + case Ch('"'): r += detail::widen<Ch>("""); break; + case Ch('\''): r += detail::widen<Ch>("'"); 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 |