Boost logo

Boost-Commit :

Subject: [Boost-commit] svn:boost r55881 - in branches/sredl_2009_05_proptree_update: boost/property_tree boost/property_tree/detail libs/property_tree/test
From: sebastian.redl_at_[hidden]
Date: 2009-08-30 16:13:40


Author: cornedbee
Date: 2009-08-30 16:13:38 EDT (Sun, 30 Aug 2009)
New Revision: 55881
URL: http://svn.boost.org/trac/boost/changeset/55881

Log:
Remove all XML parsers except the RapidXML one. Update RapidXML to version 1.13 and fix resulting regressions. Fix a ODR violation.
Removed:
   branches/sredl_2009_05_proptree_update/boost/property_tree/detail/path_implementation.hpp
   branches/sredl_2009_05_proptree_update/boost/property_tree/detail/pugxml.hpp
   branches/sredl_2009_05_proptree_update/boost/property_tree/detail/xml_parser_read_pugixml.hpp
   branches/sredl_2009_05_proptree_update/boost/property_tree/detail/xml_parser_read_pugxml.hpp
   branches/sredl_2009_05_proptree_update/boost/property_tree/detail/xml_parser_read_spirit.hpp
   branches/sredl_2009_05_proptree_update/boost/property_tree/detail/xml_parser_read_tinyxml.hpp
   branches/sredl_2009_05_proptree_update/libs/property_tree/test/test_xml_parser_pugxml.cpp
   branches/sredl_2009_05_proptree_update/libs/property_tree/test/test_xml_parser_spirit.cpp
   branches/sredl_2009_05_proptree_update/libs/property_tree/test/test_xml_parser_tinyxml.cpp
Text files modified:
   branches/sredl_2009_05_proptree_update/boost/property_tree/detail/rapidxml.hpp | 1057 +++++++++++++++++++++------------------
   branches/sredl_2009_05_proptree_update/boost/property_tree/detail/xml_parser_read_rapidxml.hpp | 34
   branches/sredl_2009_05_proptree_update/boost/property_tree/ptree_fwd.hpp | 2
   branches/sredl_2009_05_proptree_update/boost/property_tree/string_path.hpp | 6
   branches/sredl_2009_05_proptree_update/boost/property_tree/xml_parser.hpp | 13
   branches/sredl_2009_05_proptree_update/libs/property_tree/test/Jamfile.v2 | 8
   6 files changed, 588 insertions(+), 532 deletions(-)

Deleted: branches/sredl_2009_05_proptree_update/boost/property_tree/detail/path_implementation.hpp
==============================================================================
--- branches/sredl_2009_05_proptree_update/boost/property_tree/detail/path_implementation.hpp 2009-08-30 16:13:38 EDT (Sun, 30 Aug 2009)
+++ (empty file)
@@ -1,181 +0,0 @@
-// ----------------------------------------------------------------------------
-// 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_PATH_IMPLEMENTATION_HPP_INCLUDED
-#define BOOST_PROPERTY_TREE_DETAIL_PATH_IMPLEMENTATION_HPP_INCLUDED
-
-namespace boost { namespace property_tree
-{
-
- namespace detail
- {
-
- // Path-to-string converter for basic_path
- template<class Key>
- std::string path_to_string(const basic_path<Key> &path)
- {
- return path.to_string();
- }
-
- }
-
- ///////////////////////////////////////////////////////////////////////
- // Free functions
-
- inline path operator /(const path &p1, const path &p2)
- {
- return path(p1) /= p2;
- }
-
- inline wpath operator /(const wpath &p1, const wpath &p2)
- {
- return wpath(p1) /= p2;
- }
-
- ///////////////////////////////////////////////////////////////////////
- // Construction & destruction
-
- template<class Key>
- basic_path<Key>::basic_path()
- {
- }
-
- template<class Key>
- basic_path<Key>::basic_path(const Key &path, char_type separator)
- {
- parse(path.begin(), path.end(), separator);
- }
-
- template<class Key>
- basic_path<Key>::basic_path(const char_type *path, char_type separator)
- {
- parse(path, path + std::char_traits<char_type>::length(path), separator);
- }
-
- ///////////////////////////////////////////////////////////////////////
- // Path manipulation
-
- template<class Key>
- basic_path<Key> &basic_path<Key>::operator /=(const basic_path<Key> &rhs)
- {
- for (typename std::vector<Key>::const_iterator it = rhs.m_path.begin(); it != rhs.m_path.end(); ++it)
- m_path.push_back(*it);
- return *this;
- }
-
- template<class Key>
- std::string basic_path<Key>::to_string() const
- {
- std::string s;
- for (typename std::vector<Key>::const_iterator it = m_path.begin(); it != m_path.end(); ++it)
- {
- if (it == m_path.begin())
- s += detail::narrow(it->c_str());
- else
- s += '.', s += detail::narrow(it->c_str());
- }
- return s;
- }
-
- ///////////////////////////////////////////////////////////////////////
- // Operations
-
- template<class Key>
- template<class D, class C, class A, class X>
- basic_ptree<Key, D, C, A, basic_path<Key>, X> *
- basic_path<Key>::get_child(basic_ptree<Key, D, C, A, basic_path<Key>, X> &root) const
- {
- typedef basic_ptree<Key, D, C, A, basic_path<Key>, X> ptree_type;
- ptree_type *pt = &root;
- for (typename std::vector<Key>::const_iterator it = m_path.begin(); it != m_path.end(); ++it)
- {
- typename ptree_type::iterator it_child = pt->find(*it);
- if (it_child == pt->end())
- return 0;
- else
- pt = &(it_child->second);
- }
- return pt;
- }
-
- template<class Key>
- template<class D, class C, class A, class X>
- const basic_ptree<Key, D, C, A, basic_path<Key>, X> *
- basic_path<Key>::get_child(const basic_ptree<Key, D, C, A, basic_path<Key>, X> &root) const
- {
- typedef basic_ptree<Key, D, C, A, basic_path<Key>, X> ptree_type;
- basic_path<Key> *nc_this = const_cast<basic_path<Key> *>(this);
- ptree_type &nc_root = const_cast<ptree_type &>(root);
- return nc_this->get_child(nc_root);
- }
-
- template<class Key>
- template<class D, class C, class A, class X>
- basic_ptree<Key, D, C, A, basic_path<Key>, X> *
- basic_path<Key>::put_child(basic_ptree<Key, D, C, A, basic_path<Key>, X> &root,
- const basic_ptree<Key, D, C, A, basic_path<Key>, X> &child,
- bool do_not_replace) const
- {
- if (m_path.empty())
- {
- return 0;
- }
- else
- {
-
- typedef basic_ptree<Key, D, C, A, basic_path<Key>, X> ptree_type;
- typedef typename std::vector<Key>::const_iterator path_iterator;
-
- ptree_type *pt = &root;
- for (path_iterator it = m_path.begin(), end = m_path.end() - 1; it != end; ++it)
- {
- typename ptree_type::iterator it_child = pt->find(*it);
- if (it_child == pt->end())
- pt = &pt->push_back(typename ptree_type::value_type(*it, empty_ptree<ptree_type>()))->second;
- else
- pt = &it_child->second;
- }
-
- if (do_not_replace)
- return &pt->push_back(typename ptree_type::value_type(m_path.back(), child))->second;
- else
- {
- typename ptree_type::iterator it = pt->find(m_path.back());
- if (it == pt->end())
- return &pt->push_back(typename ptree_type::value_type(m_path.back(), child))->second;
- else
- {
- it->second = child;
- return &it->second;
- }
- }
- }
- }
-
- ///////////////////////////////////////////////////////////////////////
- // Internal
-
- template<class Key>
- template<class RanIt>
- void basic_path<Key>::parse(RanIt begin, RanIt end, char_type separator)
- {
- m_path.reserve(8);
- while (1)
- {
- RanIt it = std::find(begin, end, separator);
- m_path.push_back(Key(begin, it));
- if (it == end)
- break;
- begin = it + 1;
- }
- }
-
-} }
-
-#endif

Deleted: branches/sredl_2009_05_proptree_update/boost/property_tree/detail/pugxml.hpp
==============================================================================
--- branches/sredl_2009_05_proptree_update/boost/property_tree/detail/pugxml.hpp 2009-08-30 16:13:38 EDT (Sun, 30 Aug 2009)
+++ (empty file)
@@ -1,3930 +0,0 @@
-///////////////////////////////////////////////////////////////////////////////
-//
-// Pug XML Parser - Version 1.0002
-// --------------------------------------------------------
-// Copyright (C) 2003, by Kristen Wegner (kristen_at_[hidden])
-// Released into the Public Domain. Use at your own risk.
-// See pugxml.xml for further information, history, etc.
-// Contributions by Neville Franks (readonly_at_[hidden]).
-//
-// Modified to suit boost::property_tree library by Marcin Kalicinski
-
-#ifndef BOOST_PROPERTY_TREE_DETAIL_PUGXML_HPP_INCLUDED
-#define BOOST_PROPERTY_TREE_DETAIL_PUGXML_HPP_INCLUDED
-
-#ifndef TCHAR
- #define UNDEF_TCHAR_AND_REST
- #define TCHAR char
- #define _tcslen strlen
- #define _istalnum isalnum
- #define _tcsncpy strncpy
- #define _tcscpy strcpy
- #define _tcscmp strcmp
- #define _tcstol strtol
- #define _tcstod strtod
- #define _tcstok strtok
- #define _stprintf sprintf
- #define _T(s) s
-#endif
-
-//#define PUGOPT_MEMFIL //Uncomment to enable memory-mapped file parsing support.
-//#define PUGOPT_NONSEG //Uncomment to enable non-destructive (non-segmenting) parsing support.
-
-#ifdef PUGOPT_MEMFIL
-# ifndef PUGOPT_NONSEG
-# define PUGOPT_NONSEG //PUGOPT_MEMFIL implies PUGOPT_NONSEG.
-# endif
-#endif
-
-#include <iostream>
-#include <ostream>
-#include <string>
-#include <cstring>
-#if defined(PUGOPT_MEMFIL) | defined(PUGOPT_NONSEG)
-# include <assert.h>
-#endif
-
-#ifndef HIWORD
-# define UNDEF_LOHIWORD
-# define HIWORD(X) ((unsigned short)((unsigned long)(X)>>16))
-# define LOWORD(X) ((unsigned short)((unsigned long)(X)&0xFFFF))
-#endif
-
-//<summary>
-// Library variant ID. The ID 0x58475550 is owned by Kristen Wegner. You *MUST*
-// provide your own unique ID if you modify or fork the code in this library to
-// your own purposes. If you change this then *you* are now the maintainer, not me.
-// Change also in the package section of pugxml.xml, and append yourself to the
-// authors section.
-//</summary>
-#define PUGAPI_INTERNAL_VARIANT 0xdeadbeef
-//<summary>Major version. Increment for each major release. Only change if you own the variant.</summary>
-#define PUGAPI_INTERNAL_VERSION_MAJOR 1
-//<summary>Minor version. Increment for each minor release. Only change if you own the variant ID.</summary>
-#define PUGAPI_INTERNAL_VERSION_MINOR 2
-
-#define PUGAPI_INTERNAL_VERSION ((PUGAPI_INTERNAL_VERSION_MINOR&0xFFFF)|PUGAPI_INTERNAL_VERSION_MAJOR<<16)
-
-#define PUGDEF_ATTR_NAME_SIZE 128
-#define PUGDEF_ATTR_VALU_SIZE 256
-#define PUGDEF_ELEM_NAME_SIZE 256
-
-//<summary>The PugXML Parser namespace.</summary>
-namespace boost { namespace property_tree { namespace xml_parser { namespace pug
-{
-
-//<summary>The Library Variant ID. See PUGAPI_INTERNAL_VARIANT for an explanation.</summary>
-//<returns>The current Library Variant ID.</returns>
-inline static unsigned long lib_variant(){ return PUGAPI_INTERNAL_VARIANT; }
-//<summary>The library version. High word is major version. Low word is minor version.</summary>
-//<returns>The current Library Version.</returns>
-inline static unsigned long lib_version(){ return PUGAPI_INTERNAL_VERSION; }
-
-
-//<summary>A 'name=value' XML attribute structure.</summary>
-typedef struct t_xml_attribute_struct
-{
- TCHAR* name; //Pointer to attribute name.
- bool name_insitu; //True if 'name' is a segment of the original parse string.
-#ifdef PUGOPT_NONSEG
- unsigned int name_size; //Length of element name.
-#endif
- TCHAR* value; //Pointer to attribute value.
- bool value_insitu; //True if 'value' is a segment of the original parse string.
-#ifdef PUGOPT_NONSEG
- unsigned int value_size; //Length of element name.
-#endif
-}
- xml_attribute_struct;
-
-
-//<summary>Tree node classification.</summary>
-//<remarks>See 'xml_node_struct::type'.</remarks>
-typedef enum t_xml_node_type
-{
- node_null, //An undifferentiated entity.
- node_document, //A document tree's absolute root.
- node_element, //E.g. '&lt;...&gt;'
- node_pcdata, //E.g. '&gt;...&lt;'
- node_cdata, //E.g. '&lt;![CDATA[...]]&gt;'
- node_comment, //E.g. '&lt;!--...--&gt;'
- node_pi, //E.g. '&lt;?...?&gt;'
- node_include, //E.g. '&lt;![INCLUDE[...]]&gt;'
- node_doctype, //E.g. '&lt;!DOCTYPE ...&gt;'.
- node_dtd_entity, //E.g. '&lt;!ENTITY ...&gt;'.
- node_dtd_attlist, //E.g. '&lt;!ATTLIST ...&gt;'.
- node_dtd_element, //E.g. '&lt;!ELEMENT ...&gt;'.
- node_dtd_notation //E.g. '&lt;!NOTATION ...&gt;'.
-}
- xml_node_type;
-
-
-static const unsigned long parse_grow = 4; //Default child element & attribute space growth increment.
-
-
-//Parser Options
-static const unsigned long parse_minimal = 0x00000000; //Unset the following flags.
-static const unsigned long parse_pi = 0x00000002; //Parse '&lt;?...?&gt;'
-static const unsigned long parse_doctype = 0x00000004; //Parse '&lt;!DOCTYPE ...&gt;' section, setting '[...]' as data member.
-static const unsigned long parse_comments = 0x00000008; //Parse &lt;!--...--&gt;'
-static const unsigned long parse_cdata = 0x00000010; //Parse '&lt;![CDATA[...]]&gt;', and/or '&lt;![INCLUDE[...]]&gt;'
-static const unsigned long parse_escapes = 0x00000020; //Not implemented.
-static const unsigned long parse_trim_pcdata = 0x00000040; //Trim '&gt;...&lt;'
-static const unsigned long parse_trim_attribute = 0x00000080; //Trim 'foo="..."'.
-static const unsigned long parse_trim_cdata = 0x00000100; //Trim '&lt;![CDATA[...]]&gt;', and/or '&lt;![INCLUDE[...]]&gt;'
-static const unsigned long parse_trim_entity = 0x00000200; //Trim '&lt;!ENTITY name ...&gt;', etc.
-static const unsigned long parse_trim_doctype = 0x00000400; //Trim '&lt;!DOCTYPE [...]&gt;'
-static const unsigned long parse_trim_comment = 0x00000800; //Trim &lt;!--...--&gt;'
-static const unsigned long parse_wnorm = 0x00001000; //Normalize all entities that are flagged to be trimmed.
-static const unsigned long parse_dtd = 0x00002000; //If parse_doctype set, then parse whatever is in data member ('[...]').
-static const unsigned long parse_dtd_only = 0x00004000; //If parse_doctype|parse_dtd set, then parse only '&lt;!DOCTYPE [*]&gt;'
-static const unsigned long parse_default = 0x0000FFFF;
-static const unsigned long parse_noset = 0x80000000;
-
-
-//<summary>An XML document tree node.</summary>
-typedef struct t_xml_node_struct
-{
- t_xml_node_struct* parent; //Pointer to parent
- TCHAR* name; //Pointer to element name.
-#ifdef PUGOPT_NONSEG
- unsigned int name_size; //Length of element name. Since 19 Jan 2003 NF.
-#endif
- bool name_insitu; //True if 'name' is a segment of the original parse string.
- xml_node_type type; //Node type; see xml_node_type.
- unsigned int attributes; //Count attributes.
- unsigned int attribute_space; //Available pointer space in 'attribute'.
- xml_attribute_struct** attribute; //Array of pointers to attributes; see xml_attribute_struct.
- unsigned int children; //Count children in member 'child'.
- unsigned int child_space; //Available pointer space in 'child'.
- t_xml_node_struct** child; //Array of pointers to children.
- TCHAR* value; //Pointer to any associated string data.
-#ifdef PUGOPT_NONSEG
- unsigned int value_size; //Length of element data. Since 19 Jan 2003 NF.
-#endif
- bool value_insitu; //True if 'data' is a segment of the original parse string.
-}
-xml_node_struct;
-
-
-//<summary>Concatenate 'rhs' to 'lhs', growing 'rhs' if neccessary.</summary>
-//<param name="lhs">Pointer to pointer to receiving string. Note: If '*lhs' is not null, it must have been dynamically allocated using 'malloc'.</param>
-//<param name="rhs">Source.</param>
-//<returns>Success if 'realloc' was successful.</returns>
-//<remarks>'rhs' is resized and 'rhs' is concatenated to it.</remarks>
-inline static bool strcatgrow(TCHAR** lhs,const TCHAR* rhs)
-{
- if(!*lhs) //Null, so first allocate.
- {
- *lhs = (TCHAR*) malloc(1UL*sizeof(TCHAR));
- **lhs = 0; //Zero-terminate.
- }
- size_t ulhs = _tcslen(*lhs);
- size_t urhs = _tcslen(rhs);
- TCHAR* temp = (TCHAR*) realloc(*lhs,(ulhs+urhs+1UL)*sizeof(TCHAR));
- if(!temp) return false; //Realloc failed.
- memcpy(temp+ulhs,rhs,urhs*sizeof(TCHAR)); //Concatenate.
- temp[ulhs+urhs] = 0; //Terminate it.
- *lhs = temp;
- return true;
-}
-
-
-inline static bool chartype_symbol(TCHAR c) //Character is alphanumeric, -or- '_', -or- ':', -or- '-', -or- '.'.
-{ return (_istalnum(c)||c==_T('_')||c==_T(':')||c==_T('-')||c==_T('.')); }
-inline static bool chartype_space(TCHAR c) //Character is greater than 0 or character is less than exclamation.
-{ return (c>0 && c<_T('!')); }
-inline static bool chartype_enter(TCHAR c) //Character is '&lt;'.
-{ return (c==_T('<')); }
-inline static bool chartype_leave(TCHAR c) //Character is '&gt;'.
-{ return (c==_T('>')); }
-inline static bool chartype_close(TCHAR c) //Character is '/'.
-{ return (c==_T('/')); }
-inline static bool chartype_equals(TCHAR c) //Character is '='.
-{ return (c==_T('=')); }
-inline static bool chartype_special(TCHAR c) //Character is '!'.
-{ return (c==_T('!')); }
-inline static bool chartype_pi(TCHAR c) //Character is '?'.
-{ return (c==_T('?')); }
-inline static bool chartype_dash(TCHAR c) //Character is '-'.
-{ return (c==_T('-')); }
-inline static bool chartype_quote(TCHAR c) //Character is &quot;&lsquo;&quot; -or- &lsquo;&quot;&lsquo;.
-{ return (c==_T('"')||c==_T('\'')); }
-inline static bool chartype_lbracket(TCHAR c) //Character is '['.
-{ return (c==_T('[')); }
-inline static bool chartype_rbracket(TCHAR c) //Character is ']'.
-{ return (c==_T(']')); }
-
-
-#ifdef PUGOPT_NONSEG
-
-
-//<summary>Concatenate 'rhs' to 'lhs', growing 'lhs' if neccessary.</summary>
-//<param name="lhs">Pointer to pointer to receiving string. Note: If '*lhs' is not null, it must have been dynamically allocated using 'malloc'.</param>
-//<param name="rhs">Source.</param>
-//<param name="lsize">Specifies the length of *lhs in bytes and returns its new length.</param>
-//<param name="rsize">Specifies the length of *rhs in bytes.</param>
-//<returns>Success if 'realloc' was successful.</returns>
-//<remarks>'lhs' is resized and 'rhs' is concatenated to it.</remarks>
-inline static bool strcatgrown_impl(TCHAR** lhs,const TCHAR* rhs,unsigned int& lsize,unsigned int rsize)
-{
- if(!*lhs) //Null, allocate and copy.
- {
- *lhs = (TCHAR*) malloc(rsize+sizeof(TCHAR));
- if(!*lhs)
- {
- lsize = 0;
- return false; //Allocate failed.
- }
- memcpy(*lhs,rhs,rsize); //Concatenate.
- *(*lhs + rsize) = 0; //Terminate it.
- lsize = rsize;
- }
- else //Reallocate. NF I don't think this is right for MBCS, nor is code in 'StrCatGrow()'.
- {
- TCHAR* temp = (TCHAR*) realloc(*lhs,lsize + rsize + sizeof(TCHAR));
- if(!temp) return false; //Realloc failed.
- memcpy(temp+lsize,rhs,rsize); //Concatenate.
- lsize += rsize; //Set new length.
- temp[lsize] = 0; //Terminate it.
- *lhs = temp;
- }
- return true;
-}
-
-//<summary>Concatenate 'rhs' to 'lhs', growing 'lhs' if neccessary.</summary>
-//<param name="lhs">Pointer to pointer to receiving string. Note: If '*lhs' is not null, it must have been dynamically allocated using 'malloc'.</param>
-//<param name="rhs">Source.</param>
-//<param name="lsize">Specifies the length of *lhs in bytes and returns its new length.</param>
-//<returns>Success if 'realloc' was successful.</returns>
-//<remarks>'lhs' is resized and 'rhs' is concatenated to it.</remarks>
-inline static bool strcatgrown(TCHAR** lhs,const TCHAR* rhs,unsigned int& lsize)
-{
- const unsigned int rsize = _tcslen(rhs) * sizeof(TCHAR);
- return pug::strcatgrown_impl(lhs,rhs,lsize,rsize);
-}
-
-//<summary>Trim leading and trailing whitespace.</summary>
-//<param name="s">Pointer to pointer to string.</param>
-//<param name="len">Specifies the length of *s in bytes and returns its new length.</param>
-//<returns>Success.</returns>
-//<remarks>*s is modified to point to the first non-white character in the string.</remarks>
-inline static bool strwtrim(TCHAR** s,unsigned int& len)
-{
- if(!s || !*s) return false;
- TCHAR* pse = *s + len;
- while(*s < pse && pug::chartype_space(**s)) //Find first non-white character.
- ++*s; //As long as we hit whitespace, increment the string pointer.
- for(; *s < --pse;) //As long as we hit whitespace, decrement.
- {
- if(!pug::chartype_space(*pse))
- {
- len = pse + 1 - *s;
- break;
- }
- }
- return true;
-}
-
-
-#else
-
-
-//<summary>Trim leading and trailing whitespace.</summary>
-//<param name="s">Pointer to pointer to string.</param>
-//<returns>Success.</returns>
-inline static bool strwtrim(TCHAR** s)
-{
- if(!s || !*s) return false;
- while(**s > 0 && **s < _T('!')) ++*s; //As long as we hit whitespace, increment the string pointer.
- const TCHAR* temp = *s;
- while(0 != *temp++); //Find the terminating null.
- long i, n = (long)(temp-*s-1);
- --n; //Start from the last string TCHAR.
- for(i=n; (i > -1) && (*s)[i] > 0 && (*s)[i] < _T('!'); --i); //As long as we hit whitespace, decrement.
- if(i<n) (*s)[i+1] = 0; //Zero-terminate.
- return true;
-}
-
-
-//<summary>
-// In situ trim leading and trailing whitespace, then convert all consecutive
-// whitespace to a single space TCHAR.
-//</summary>
-//<param name="s">Pointer to pointer to string.</param>
-//<returns>Success.</returns>
-inline static bool strwnorm(TCHAR** s)
-{
- if(!s || !*s) return false; //No string to normalize.
- while(**s > 0 && **s < _T('!')) ++(*s); //As long as we hit whitespace, increment the string pointer.
- const TCHAR* temp = *s;
- while(0 != *temp++); //Find the terminating null.
- long n = (long)(temp-*s-1);
- TCHAR* norm = (TCHAR*)malloc(sizeof(TCHAR)*(n+1)); //Allocate a temporary normalization buffer.
- if(!norm) return false; //Allocation failed.
- memset(norm,0,sizeof(TCHAR)*(n+1)); //Zero it.
- long j = 1;
- norm[0] = (*s)[0];
- long i;
- for(i=1; i<n; ++i) //For each character, starting at offset 1.
- {
- if((*s)[i] < _T('!')) //Whitespace-like.
- {
- if((*s)[i-1] >= _T('!')) //Previous was not whitespace-like.
- {
- norm[j] = _T(' '); //Convert to a space TCHAR.
- ++j; //Normalization buffer grew by one TCHAR.
- }
- }
- else { norm[j] = (*s)[i]; ++j; } //Not whitespace, so just copy over.
- }
- if(j < n) //Normalization buffer is actually different that input.
- {
- _tcsncpy(*s,norm,j); //So, copy it back to input.
- (*s)[j] = 0; //Zero-terminate.
- }
- free(norm); //Don't need this anymore.
- --n; //Start from the last string TCHAR.
- for(i=n; (i > -1) && (*s)[i] > 0 && (*s)[i] < _T('!'); --i); //Find the first non-whitespace from the end.
- if(i<n) (*s)[i+1] = 0; //Truncate it.
- return true;
-
-}
-
-#endif
-
-
-//<summary>Set structure string member to given value.</summary>
-//<param name="dest">Pointer to pointer to destination.</param>
-//<param name="src">Source.</param>
-//<param name="insitu">Pointer to boolean in-situ string flag.</param>
-//<returns>True if member was set to the new value.</returns>
-//<remarks>
-// If 'src' is larger than 'dest' then 'dest' is resized, in which case
-// it is probably no longer in-situ,and 'in_situ' is set to false. If
-// 'dest' is already no longer in-situ, and 'src' is too small then the
-// existing memory pointed to is freed. If 'dest' is larger than or equal
-// to 'dest' then it is merely copied with no resize.
-//</remarks>
-inline static bool strcpyinsitu
- (
- TCHAR** dest,
- const TCHAR* src,
- bool* insitu
-#ifdef PUGOPT_NONSEG
- ,
- unsigned int& destlen
-#endif
- )
-{
- if(!dest || !src || !insitu) return false; //Bad argument(s), so fail.
-#ifndef PUGOPT_NONSEG //Always use heap for our r/o string.
- size_t l = (*dest) ? _tcslen(*dest) : 0; //How long is destination?
- if(l >= _tcslen(src)) //Destination is large enough, so just copy.
- {
- _tcscpy(*dest,src); //Copy.
- return true; //Success.
- }
- else //Destination is too small.
-#endif
- {
- if(*dest && !*insitu) free(*dest); //If destination is not in-situ, then free it.
- *dest = NULL; //Mark destination as NULL, forcing 'StrCatGrow' to 'malloc.
-#ifdef PUGOPT_NONSEG
- if(strcatgrown(dest,src,destlen)) //Allocate & copy source to destination
-#else
- if(strcatgrow(dest,src)) //Allocate & copy source to destination
-#endif
- {
- *insitu = false; //Mark as no longer being in-situ, so we can free it later.
- return true; //Success.
- }
- }
- return false; //Failure.
-}
-
-
-//<summary>Character set pattern match.</summary>
-//<param name="lhs">String or expression for left-hand side of comparison.</param>
-//<param name="rhs">String for right-hand side of comparison.</param>
-//<remarks>Used by 'strcmpwild'.</remarks>
-inline int strcmpwild_cset(const TCHAR** src,const TCHAR** dst)
-{
- int find = 0;
- int excl = 0;
- int star = 1;
- if(**src == _T('!'))
- {
- excl = 1;
- ++(*src);
- }
- while(**src != _T(']') || star == 1)
- {
- if(find == 0)
- {
- if(**src == _T('-') && *(*src-1) < *(*src+1) && *(*src+1) != _T(']') && star == 0)
- {
- if(**dst >= *(*src-1) && **dst <= *(*src+1))
- {
- find = 1;
- ++(*src);
- }
- }
- else if(**src == **dst) find = 1;
- }
- ++(*src);
- star = 0;
- }
- if(excl == 1) find = (1 - find);
- if(find == 1) ++(*dst);
- return find;
-}
-
-
-inline int strcmpwild_impl(const TCHAR* src,const TCHAR* dst); //Forward declaration.
-
-
-//<summary>Wildcard pattern match.</summary>
-//<param name="lhs">String or expression for left-hand side of comparison.</param>
-//<param name="rhs">String for right-hand side of comparison.</param>
-//<remarks>Used by 'strcmpwild'.</remarks>
-inline int strcmpwild_astr(const TCHAR** src,const TCHAR** dst)
-{
- int find = 1;
- ++(*src);
- while((**dst != 0 && **src == _T('?')) || **src == _T('*'))
- {
- if(**src == _T('?')) ++(*dst);
- ++(*src);
- }
- while(**src == _T('*')) ++(*src);
- if(**dst == 0 && **src != 0) return 0;
- if(**dst == 0 && **src == 0) return 1;
- else
- {
- if(strcmpwild_impl(*src,*dst) == 0)
- {
- do
- {
- ++(*dst);
- while(**src != **dst && **src != _T('[') && **dst != 0)
- ++(*dst);
- }
- while((**dst != 0) ? strcmpwild_impl(*src,*dst) == 0 : 0 != (find=0));
- }
- if(**dst == 0 && **src == 0) find = 1;
- return find;
- }
-}
-
-
-//<summary>Compare two strings, with globbing, and character sets.</summary>
-//<param name="lhs">String or expression for left-hand side of comparison.</param>
-//<param name="rhs">String for right-hand side of comparison.</param>
-//<remarks>Used by 'strcmpwild'.</remarks>
-inline int strcmpwild_impl(const TCHAR* src,const TCHAR* dst)
-{
- int find = 1;
- for(; *src != 0 && find == 1 && *dst != 0; ++src)
- {
- switch(*src)
- {
- case _T('?'): ++dst; break;
- case _T('['): ++src; find = strcmpwild_cset(&src,&dst); break;
- case _T('*'): find = strcmpwild_astr(&src,&dst); --src; break;
- default : find = (int) (*src == *dst); ++dst;
- }
- }
- while(*src == _T('*') && find == 1) ++src;
- return (int) (find == 1 && *dst == 0 && *src == 0);
-}
-
-//<summary>Compare two strings, with globbing, and character sets.</summary>
-//<param name="lhs">String or expression for left-hand side of comparison.</param>
-//<param name="rhs">String for right-hand side of comparison.</param>
-//<returns>
-// Returns 1 if src does not match dst, or -1 if either src or dst are null,
-// or 0 if src matches dst.
-//</returns>
-//<remarks>
-// Simple regular expressions are permitted in 'src': The character '*' matches
-// zero or more characters up to the next pattern, or the end of the string. The
-// '?' character matches any single character. Character sets and negation are
-// also permitted, for example, '[abcd]', '[a-zA-Z]', etc.
-//</remarks>
-inline int strcmpwild(const TCHAR* src,const TCHAR* dst)
-{
- if(!src || !dst) return -1;
- return (strcmpwild_impl(src,dst)==1)?0:1;
-}
-
-
-//<summary>Allocate & init an xml_attribute_struct structure.</summary>
-//<returns>Pointer to new xml_attribute_struct structure.</returns>
-inline static xml_attribute_struct* new_attribute(void)
-{
- xml_attribute_struct* p = (xml_attribute_struct*)malloc(sizeof(xml_attribute_struct)); //Allocate one attribute.
- if(p) //If allocation succeeded.
- {
- p->name = p->value = 0; //No name or value.
-#ifdef PUGOPT_NONSEG
- p->name_size = p->value_size = 0; //Lengths of zero.
-#endif
- p->name_insitu = p->value_insitu = true; //Default to being in-situ of the parse string.
- }
- return p;
-}
-
-
-//<summary>Allocate & init an xml_node_struct structure.</summary>
-//<param name="type">Desired node type.</param>
-//<returns>Pointer to new xml_node_struct structure.</returns>
-inline static xml_node_struct* new_node(xml_node_type type = node_element)
-{
- xml_node_struct* p = (xml_node_struct*)malloc(sizeof(xml_node_struct)); //Allocate one node.
- if(p) //If allocation succeeded.
- {
- p->name = p->value = 0; //No name or data.
-#ifdef PUGOPT_NONSEG
- p->name_size = p->value_size = 0;
-#endif
- p->type = type; //Set the desired type.
- p->attributes = p->children = 0; //No attributes or children.
- p->name_insitu = p->value_insitu = true; //Default to being in-situ of the parse string.
- if
- (
- type != node_document && //None of these will have attributes.
- type != node_pcdata &&
- type != node_cdata &&
- type != node_include &&
- type != node_comment
- )
- p->attribute = (xml_attribute_struct**)malloc(sizeof(xml_attribute_struct*)); //Allocate one attribute.
- else p->attribute = NULL;
- p->attribute_space = (p->attribute) ? 1 : 0;
- if
- (
- type == node_element || //Only these will have children.
- type == node_doctype ||
- type == node_document
- )
- p->child = (xml_node_struct**)malloc(sizeof(xml_node_struct*)); //Allocate one child.
- else p->child = NULL;
- p->child_space = (p->child) ? 1 : 0;
- }
- return p;
-}
-
-
-//<summary>Allocate & append a new xml_node_struct onto the given parent.</summary>
-//<param name="parent">Pointer to parent node.</param>
-//<param name="grow">Pointer space growth increment.</param>
-//<param name="type">Desired node type.</param>
-//<returns>Pointer to new node.</returns>
-//<remarks>Child pointer space of 'node' may be reallocated.</remarks>
-inline static xml_node_struct* append_node(xml_node_struct* parent,long grow,xml_node_type type = node_element)
-{
- if(!parent) return NULL; //Must have a parent.
- if(parent->children == parent->child_space) //Out of pointer space.
- {
- xml_node_struct** t = (xml_node_struct**)realloc(parent->child,sizeof(xml_node_struct*)*(parent->child_space+grow)); //Grow pointer space.
- if(t) //Reallocation succeeded.
- {
- parent->child = t;
- parent->child_space += grow; //Update the available space.
- }
- }
- xml_node_struct* child = new_node(type); //Allocate a new child.
- child->parent = parent; //Set it's parent pointer.
- parent->child[parent->children] = child; //Set the parent's child pointer.
- parent->children++; //One more child.
- return child;
-}
-
-
-//<summary>Allocate & append a new attribute to the given xml_node_struct.</summary>
-//<param name="node">Pointer to parent node.</param>
-//<param name="grow">Pointer space growth increment.</param>
-//<returns>Pointer to appended xml_attribute_struct.</returns>
-//<remarks>Attribute pointer space of 'node' may be reallocated.</remarks>
-inline static xml_attribute_struct* append_attribute(xml_node_struct* node,long grow)
-{
- if(!node) return NULL;
- xml_attribute_struct* a = new_attribute();
- if(!a) return NULL;
- if(node->attributes == node->attribute_space) //Out of space, so grow.
- {
- xml_attribute_struct** t = (xml_attribute_struct**)realloc(node->attribute,sizeof(xml_node_struct*)*(node->attribute_space+grow));
- if(t)
- {
- node->attribute = t;
- node->attribute_space += grow;
- }
- }
- node->attribute[node->attributes] = a;
- node->attributes++;
- return a;
-}
-
-
-//<summary>Non-recursively free a tree.</summary>
-//<param name="root">
-// Pointer to the root of the tree. Note: 'root' must have been dynamically
-// allocated using 'malloc' or 'realloc', as 'free_node' tries to also free
-// the structure pointed to by 'root'.
-//</param>
-//<remarks>'root' no longer points to a valid structure.</remarks>
-inline static void free_node(xml_node_struct* node)
-{
- if(!node) return;
-
- register xml_node_struct* cursor = node;
-
- //Free all children of children.
- do
- {
-LOC_STEP_INTO:
- for(; cursor->children>0; --cursor->children) //Free each child in turn; 'children' keeps count while we jump around.
- {
- register xml_node_struct* t = cursor->child[cursor->children-1]; //Take a pointer to the child.
- if(t && t->children) //If the child has children.
- {
- cursor = t; //Step in.
- goto LOC_STEP_INTO; //Step into this node.
- }
- else if(t)
- {
- if(t->attributes) //Child has attributes.
- {
- register unsigned int n = t->attributes; //Free each attribute.
- for(register unsigned int i=0; i<n; ++i)
- {
- if(t->attribute[i]->name && !t->attribute[i]->name_insitu)
- free(t->attribute[i]->name);
- if(t->attribute[i]->value && !t->attribute[i]->value_insitu)
- free(t->attribute[i]->value);
- free(t->attribute[i]);
- }
- }
- if(t->attribute) free(t->attribute); //Free attribute pointer space.
- if(t->child) free(t->child); //Free child pointer space.
- if(t->name && !t->name_insitu) free(t->name);
- if(t->value && !t->value_insitu) free(t->value);
- free(t); //Free the child node.
- }
- }
- cursor = cursor->parent; //Step out.
- }
- while(cursor->children); //While there are children.
- //Finally, free the root's children & the root itself.
- if(cursor->attributes)
- {
- register unsigned int n = cursor->attributes;
- for(register unsigned int i=0; i<n; ++i)
- {
- if(cursor->attribute[i]->name && !cursor->attribute[i]->name_insitu)
- free(cursor->attribute[i]->name);
- if(cursor->attribute[i]->value && !cursor->attribute[i]->value_insitu)
- free(cursor->attribute[i]->value);
- free(cursor->attribute[i]);
- }
- }
- if(cursor->attribute) free(cursor->attribute); //Free attribute pointer space.
- if(cursor->child) free(cursor->child); //Free child pointer space.
- if(cursor->name && !cursor->name_insitu) free(cursor->name); //Free name & data.
- if(cursor->value && !cursor->value_insitu) free(cursor->value);
- free(cursor); //Free the root itself.
-}
-
-//<summary>Recursively free a tree.</summary>
-//<param name="root">Pointer to the root of the tree.</param>
-//<remarks>Not used.</remarks>
-inline static void free_node_recursive(xml_node_struct* root)
-{
- if(root)
- {
- unsigned int n = root->attributes;
- register unsigned int i;
- for(i=0; i<n; i++)
- {
- if(root->attribute[i]->name && !root->attribute[i]->name_insitu)
- free(root->attribute[i]->name);
- if(root->attribute[i]->value && !root->attribute[i]->value_insitu)
- free(root->attribute[i]->value);
- free(root->attribute[i]);
- }
- free(root->attribute);
- n = root->children;
- for(i=0; i<n; i++)
- free_node_recursive(root->child[i]);
- free(root->child);
- if(root->name && !root->name_insitu) free(root->name);
- if(root->value && !root->value_insitu) free(root->value);
- free(root);
- }
-}
-
-
-//<summary>Parser utilities.</summary>
-#define SKIPWS() { while(chartype_space(*s)) ++s; if(*s==0) return s; }
-#define OPTSET(OPT) ( optmsk & OPT )
-#define PUSHNODE(TYPE) { cursor = append_node(cursor,growby,TYPE); }
-#define POPNODE() { cursor = cursor->parent; }
-#define SCANFOR(X) { while(*s!=0 && !(X)) ++s; if(*s==0) return s; }
-#define SCANWHILE(X) { while((X)) ++s; if(*s==0) return s; }
-#ifndef PUGOPT_NONSEG
-# define ENDSEG() { ch = *s; *s = 0; ++s; if(*s==0) return s; }
-#else
-# define ENDSEG() { ch = *s; ++s; if(*s==0) return s; }
-# define SETLEN() ( cursor->value_size = s - cursor->value )
-# define ENDSEGDAT() { ch = *s; SETLEN(); ++s; if(*s==0) return s; }
-# define ENDSEGNAM(S) { ch = *s; S->name_size = s - S->name; ++s; if(*s==0) return s; }
-# define ENDSEGATT(S) { ch = *s; S->value_size = s - S->value; ++s; if(*s==0) return s; }
-#endif
-
-
-//<summary>Static single-pass in-situ parse the given xml string.</summary>
-//<param name="s">Pointer to XML-formatted string.</param>
-//<param name="root">Pointer to root.</param>
-//<param name="grow">Pointer space growth increment.</param>
-//<param name="optmsk">Parse options mask.</param>
-//<returns>Last string position or null.</returns>
-//<remarks>
-// Input string is zero-segmented if 'PUGOPT_NONSEG' is not defined. Memory
-// may have been allocated to 'root' (free with 'free_node').
-//</remarks>
-static TCHAR* parse(register TCHAR* s,xml_node_struct* xmldoc,long growby,unsigned long optmsk = parse_default)
-{
- if(!s || !xmldoc) return s;
- TCHAR ch = 0; //Current char, in cases where we must null-terminate before we test.
- xml_node_struct* cursor = xmldoc; //Tree node cursor.
- TCHAR* mark = s; //Marked string position for temporary look-ahead.
- while(*s!=0)
- {
-LOC_SEARCH: //Obliviously search for next element.
- SCANFOR(chartype_enter(*s)); //Find the next '<'.
- if(chartype_enter(*s))
- {
- ++s;
-LOC_CLASSIFY: //What kind of element?
- if(chartype_pi(*s)) //'<?...'
- {
- ++s;
- if(chartype_symbol(*s) && OPTSET(parse_pi))
- {
- mark = s;
- SCANFOR(chartype_pi(*s)); //Look for terminating '?'.
-#ifndef PUGOPT_NONSEG
- if(chartype_pi(*s)) *s = _T('/'); //Same semantics as for '<.../>', so fudge it.
-#endif
- s = mark;
- PUSHNODE(node_pi); //Append a new node on the tree.
- goto LOC_ELEMENT; //Go read the element name.
- }
- else //Bad PI or parse_pi not set.
- {
- SCANFOR(chartype_leave(*s)); //Look for '>'.
- ++s;
- mark = 0;
- continue;
- }
- }
- else if(chartype_special(*s)) //'<!...'
- {
- ++s;
- if(chartype_dash(*s)) //'<!-...'
- {
- ++s;
- if(OPTSET(parse_comments) && chartype_dash(*s)) //'<!--...'
- {
- ++s;
- PUSHNODE(node_comment); //Append a new node on the tree.
- cursor->value = s; //Save the offset.
- while(*s!=0 && *(s+1) && *(s+2) && !((chartype_dash(*s) && chartype_dash(*(s+1))) && chartype_leave(*(s+2)))) ++s; //Scan for terminating '-->'.
- if(*s==0) return s;
-#ifdef PUGOPT_NONSEG
- SETLEN(); //NF 19 Jan 2003.
-#else
- *s = 0; //Zero-terminate this segment at the first terminating '-'.
-#endif
- if(OPTSET(parse_trim_comment)) //Trim whitespace.
- {
-#ifdef PUGOPT_NONSEG
- strwtrim(&cursor->value,cursor->value_size);
-#else
- if(OPTSET(parse_wnorm)) strwnorm(&cursor->value);
- else strwtrim(&cursor->value);
-#endif
- }
- s += 2; //Step over the '\0-'.
- POPNODE(); //Pop since this is a standalone.
- goto LOC_LEAVE; //Look for any following PCDATA.
- }
- else
- {
- while(*s!=0 && *(s+1)!=0 && *(s+2)!=0 && !((chartype_dash(*s) && chartype_dash(*(s+1))) && chartype_leave(*(s+2)))) ++s; //Scan for terminating '-->'.
- if(*s==0) return s;
- s += 2;
- goto LOC_LEAVE; //Look for any following PCDATA.
- }
- }
- else if(chartype_lbracket(*s)) //'<![...'
- {
- ++s;
- if(*s==_T('I')) //'<![I...'
- {
- ++s;
- if(*s==_T('N')) //'<![IN...'
- {
- ++s;
- if(*s==_T('C')) //'<![INC...'
- {
- ++s;
- if(*s==_T('L')) //'<![INCL...'
- {
- ++s;
- if(*s==_T('U')) //'<![INCLU...'
- {
- ++s;
- if(*s==_T('D')) //'<![INCLUD...'
- {
- ++s;
- if(*s==_T('E')) //'<![INCLUDE...'
- {
- ++s;
- if(chartype_lbracket(*s)) //'<![INCLUDE[...'
- {
- ++s;
- if(OPTSET(node_cdata))
- {
- PUSHNODE(node_include); //Append a new node on the tree.
- cursor->value = s; //Save the offset.
- while(!(chartype_rbracket(*s) && chartype_rbracket(*(s+1)) && chartype_leave(*(s+2)))) ++s; //Scan for terminating ']]>'.
- if(chartype_rbracket(*s))
- {
-#ifdef PUGOPT_NONSEG
- SETLEN(); //NF 19 Jan 2003.
-#else
- *s = 0; //Zero-terminate this segment.
-#endif
- ++s;
- if(OPTSET(parse_trim_cdata)) //Trim whitespace.
- {
-#ifdef PUGOPT_NONSEG
- strwtrim(&cursor->value, cursor->value_size);
-#else
- if(OPTSET(parse_wnorm)) strwnorm(&cursor->value);
- else strwtrim(&cursor->value);
-#endif
- }
- }
- POPNODE(); //Pop since this is a standalone.
- }
- else //Flagged for discard, but we still have to scan for the terminator.
- {
- while(*s!=0 && *(s+1)!=0 && *(s+2)!=0 && !(chartype_rbracket(*s) && chartype_rbracket(*(s+1)) && chartype_leave(*(s+2)))) ++s; //Scan for terminating ']]>'.
- ++s;
- }
- ++s; //Step over the last ']'.
- goto LOC_LEAVE; //Look for any following PCDATA.
- }
- }
- }
- }
- }
- }
- }
- }
- else if(*s==_T('C')) //'<![C...'
- {
- ++s;
- if(*s==_T('D')) //'<![CD...'
- {
- ++s;
- if(*s==_T('A')) //'<![CDA...'
- {
- ++s;
- if(*s==_T('T')) //'<![CDAT...'
- {
- ++s;
- if(*s==_T('A')) //'<![CDATA...'
- {
- ++s;
- if(chartype_lbracket(*s)) //'<![CDATA[...'
- {
- ++s;
- if(OPTSET(parse_cdata))
- {
- PUSHNODE(node_cdata); //Append a new node on the tree.
- cursor->value = s; //Save the offset.
- while(*s!=0 && *(s+1)!=0 && *(s+2)!=0 && !(chartype_rbracket(*s) && chartype_rbracket(*(s+1)) && chartype_leave(*(s+2)))) ++s; //Scan for terminating ']]>'.
- if(*(s+2)==0) return s; //Very badly formed.
- if(chartype_rbracket(*s))
- {
-#ifdef PUGOPT_NONSEG
- SETLEN(); //NF 19 Jan 2003.
-#else
- *s = 0; //Zero-terminate this segment.
-#endif
- ++s;
- if(OPTSET(parse_trim_cdata)) //Trim whitespace.
- {
-#ifdef PUGOPT_NONSEG
- strwtrim(&cursor->value,cursor->value_size);
-#else
- if(OPTSET(parse_wnorm)) strwnorm(&cursor->value);
- else strwtrim(&cursor->value);
-#endif
- }
- }
- POPNODE(); //Pop since this is a standalone.
- }
- else //Flagged for discard, but we still have to scan for the terminator.
- {
- while(*s!=0 && *(s+1)!=0 && *(s+2)!=0 && !(chartype_rbracket(*s) && chartype_rbracket(*(s+1)) && chartype_leave(*(s+2)))) ++s; //Scan for terminating ']]>'.
- ++s;
- }
- ++s; //Step over the last ']'.
- goto LOC_LEAVE; //Look for any following PCDATA.
- }
- }
- }
- }
- }
- }
- continue; //Probably a corrupted CDATA section, so just eat it.
- }
- else if(*s==_T('D')) //'<!D...'
- {
- ++s;
- if(*s==_T('O')) //'<!DO...'
- {
- ++s;
- if(*s==_T('C')) //'<!DOC...'
- {
- ++s;
- if(*s==_T('T')) //'<!DOCT...'
- {
- ++s;
- if(*s==_T('Y')) //'<!DOCTY...'
- {
- ++s;
- if(*s==_T('P')) //'<!DOCTYP...'
- {
- ++s;
- if(*s==_T('E')) //'<!DOCTYPE...'
- {
- ++s;
- SKIPWS(); //Eat any whitespace.
- xml_attribute_struct* a = 0;
- if(OPTSET(parse_doctype))
- {
- PUSHNODE(node_doctype); //Append a new node on the tree.
- a = append_attribute(cursor,3); //Store the DOCTYPE name.
- a->value = a->name = s; //Save the offset.
- }
- SCANWHILE(chartype_symbol(*s)); //'<!DOCTYPE symbol...'
-#ifdef PUGOPT_NONSEG
- if(OPTSET(parse_doctype))
- a->name_size = a->value_size = s - a->value; //Save the length. rem: Before ENDSEG()
-#endif
- ENDSEG(); //Save char in 'ch', terminate & step over.
- if(chartype_space(ch)) SKIPWS(); //Eat any whitespace.
-LOC_DOCTYPE_SYMBOL:
- if(chartype_symbol(*s))
- {
- mark = s;
- SCANWHILE(chartype_symbol(*s)); //'...symbol SYSTEM...'
- if(OPTSET(parse_doctype))
- {
- a = append_attribute(cursor,1);
- a->value = a->name = mark;
-#ifdef PUGOPT_NONSEG
- a->value_size = a->name_size = s - mark; //NF 19 Jan 2003.
-#else
- *s = 0;
-#endif
- }
- ++s;
- SKIPWS();
- }
- if(chartype_quote(*s)) //'...SYSTEM "..."'
- {
-LOC_DOCTYPE_QUOTE:
- ch = *s;
- ++s;
- mark = s;
- while(*s!=0 && *s != ch) ++s;
- if(*s!=0)
- {
- if(OPTSET(parse_doctype))
- {
- a = append_attribute(cursor,1);
- a->value = mark;
-#ifdef PUGOPT_NONSEG
- a->value_size = s - mark; //NF 19 Jan 2003.
-#else
- *s = 0;
-#endif
- }
- ++s;
- SKIPWS(); //Eat whitespace.
- if(chartype_quote(*s)) goto LOC_DOCTYPE_QUOTE; //Another quoted section to store.
- else if(chartype_symbol(*s)) goto LOC_DOCTYPE_SYMBOL; //Not wellformed, but just parse it.
- }
- }
- if(chartype_lbracket(*s)) //'...[...'
- {
- ++s; //Step over the bracket.
- if(OPTSET(parse_doctype)) cursor->value = s; //Store the offset.
- unsigned int bd = 1; //Bracket depth counter.
- while(*s!=0) //Loop till we're out of all brackets.
- {
- if(chartype_rbracket(*s)) --bd;
- else if(chartype_lbracket(*s)) ++bd;
- if(bd == 0) break;
- ++s;
- }
- //Note: 's' now points to end of DTD, i.e.: ']'.
- if(OPTSET(parse_doctype))
- {
- //Note: If we aren't parsing the DTD ('!parse_dtd', etc.) then it is stored in the DOM as one whole chunk.
-#ifdef PUGOPT_NONSEG
- SETLEN(); //NF 19 Jan 2003
-#else
- *s = 0; //Zero-terminate.
-#endif
- if(OPTSET(parse_dtd)||OPTSET(parse_dtd_only))
- {
- if(OPTSET(parse_dtd))
- {
-#ifdef PUGOPT_NONSEG
- TCHAR svch = *s;
- try
- {
- *s = 0; //Zero-terminate.
- parse(cursor->value,cursor,growby,optmsk); //Parse it.
- }
- catch(...){ assert(false); }
- *s = svch;
-#else
- parse(cursor->value,cursor,growby,optmsk); //Parse it.
-#endif
- }
- if(OPTSET(parse_dtd_only)) return (s+1); //Flagged to parse DTD only, so leave here.
- }
- else if(OPTSET(parse_trim_doctype)) //Trim whitespace.
- {
-#ifdef PUGOPT_NONSEG
- strwtrim(&cursor->value, cursor->value_size);
-#else
- if(OPTSET(parse_wnorm)) strwnorm(&cursor->value);
- else strwtrim(&cursor->value);
-#endif
- }
- ++s; //Step over the zero.
- POPNODE(); //Pop since this is a standalone.
- }
- SCANFOR(chartype_leave(*s));
- continue;
- }
- //Fall-through; make sure we pop.
- POPNODE(); //Pop since this is a standalone.
- continue;
- }
- }
- }
- }
- }
- }
- }
- else if(chartype_symbol(*s)) //An inline DTD tag.
- {
- mark = s;
- SCANWHILE(chartype_symbol(*s));
- ENDSEG(); //Save char in 'ch', terminate & step over.
- xml_node_type e = node_dtd_entity;
-#ifdef PUGOPT_NONSEG
- const unsigned int dtdilen = (s - 1) - mark;
- if(_tcsncmp(mark,_T("ATTLIST"),max((7*sizeof(TCHAR)),dtdilen))==0) e = node_dtd_attlist;
- else if(_tcsncmp(mark,_T("ELEMENT"),max((7*sizeof(TCHAR)),dtdilen))==0) e = node_dtd_element;
- else if(_tcsncmp(mark,_T("NOTATION"),max((8*sizeof(TCHAR)),dtdilen))==0) e = node_dtd_notation;
-#else
- if(_tcscmp(mark,_T("ATTLIST"))==0) e = node_dtd_attlist;
- else if(_tcscmp(mark,_T("ELEMENT"))==0) e = node_dtd_element;
- else if(_tcscmp(mark,_T("NOTATION"))==0) e = node_dtd_notation;
-#endif
- PUSHNODE(e); //Append a new node on the tree.
- if(*s!=0 && chartype_space(ch))
- {
- SKIPWS(); //Eat whitespace.
- if(chartype_symbol(*s) || *s==_T('%'))
- {
- mark = s;
- if(*s==_T('%')) //Could be '<!ENTITY % name' -or- '<!ENTITY %name'
- {
-#ifdef PUGOPT_NONSEG
- //Note: For memory-mapped file support we need to treat 's' as read-only so we can't do '*(s-1) = _T('%');' below.
- cursor->name = mark; //Sort out extraneous whitespace when we retrieve it. TODO: Whitespace cleanup.
-#endif
- ++s;
- if(chartype_space(*s))
- {
- SKIPWS(); //Eat whitespace.
-#ifndef PUGOPT_NONSEG
- *(s-1) = _T('%');
- cursor->name = (s-1);
-#endif
- }
-#ifndef PUGOPT_NONSEG
- else cursor->name = mark;
-#endif
- }
- else cursor->name = s;
- SCANWHILE(chartype_symbol(*s));
-#ifdef PUGOPT_NONSEG
- cursor->name_size = s - cursor->name;
-#endif
- ENDSEG(); //Save char in 'ch', terminate & step over.
- if(chartype_space(ch))
- {
- SKIPWS(); //Eat whitespace.
- if(e == node_dtd_entity) //Special case; may have multiple quoted sections w/anything inside.
- {
- cursor->value = s; //Just store everything here.
- bool qq = false; //Quote in/out flag.
- while(*s != 0) //Loop till we find the right sequence.
- {
- if(!qq && chartype_quote(*s)){ ch = *s; qq = true; }
- else if(qq && *s == ch) qq = false;
- else if(!qq && chartype_leave(*s)) //Not in quoted reqion and '>' hit.
- {
-#ifdef PUGOPT_NONSEG
- SETLEN(); //NF 19 Jan 2003.
-#else
- *s = 0;
-#endif
- ++s;
- if(OPTSET(parse_trim_entity))
- {
-#ifdef PUGOPT_NONSEG
- strwtrim(&cursor->value,cursor->value_size);
-#else
- if(OPTSET(parse_wnorm)) strwnorm(&cursor->value);
- else strwtrim(&cursor->value);
-#endif
- }
- POPNODE();
- goto LOC_SEARCH;
- }
- ++s;
- }
- if(OPTSET(parse_trim_entity))
- {
-#ifdef PUGOPT_NONSEG
- strwtrim(&cursor->value, cursor->value_size);
-#else
- if(OPTSET(parse_wnorm)) strwnorm(&cursor->value);
- else strwtrim(&cursor->value);
-#endif
- }
- }
- else
- {
- cursor->value = s;
- SCANFOR(chartype_leave(*s)); //Just look for '>'.
-#ifdef PUGOPT_NONSEG
- SETLEN(); //NF 19 Jan 2003.
-#else
- *s = 0;
-#endif
- ++s;
- if(OPTSET(parse_trim_entity))
- {
-#ifdef PUGOPT_NONSEG
- strwtrim(&cursor->value, cursor->value_size);
-#else
- if(OPTSET(parse_wnorm)) strwnorm(&cursor->value);
- else strwtrim(&cursor->value);
-#endif
- }
- POPNODE();
- goto LOC_SEARCH;
- }
- }
- }
- }
- POPNODE();
- }
- }
- else if(chartype_symbol(*s)) //'<#...'
- {
- cursor = append_node(cursor,growby); //Append a new node to the tree.
-LOC_ELEMENT: //Scan for & store element name.
- cursor->name = s;
- SCANWHILE(chartype_symbol(*s)); //Scan for a terminator.
-#ifdef PUGOPT_NONSEG
- cursor->name_size = s - cursor->name; //Note: Before ENDSEG().
-#endif
- ENDSEG(); //Save char in 'ch', terminate & step over.
- if
- (
- *s!=0 &&
- (
- chartype_close(ch) //'</...'
-#ifdef PUGOPT_NONSEG
- //||
- //chartype_pi(ch) //Treat '?>' as '/>' NF 19 Jan 2003
-#endif
- )
- )
- {
- SCANFOR(chartype_leave(*s)); //Scan for '>', stepping over the tag name.
- POPNODE(); //Pop.
- continue;
- }
- else if(*s!=0 && !chartype_space(ch)) goto LOC_PCDATA; //No attributes, so scan for PCDATA.
- else if(*s!=0 && chartype_space(ch))
- {
- SKIPWS(); //Eat any whitespace.
-LOC_ATTRIBUTE:
- if(chartype_symbol(*s)) //<... #...
- {
- xml_attribute_struct* a = append_attribute(cursor,growby); //Make space for this attribute.
- a->name = s; //Save the offset.
- SCANWHILE(chartype_symbol(*s)); //Scan for a terminator.
-#ifdef PUGOPT_NONSEG
- ENDSEGNAM(a);
-#else
- ENDSEG(); //Save char in 'ch', terminate & step over.
-#endif
- if(*s!=0 && chartype_space(ch)) SKIPWS(); //Eat any whitespace.
- if(*s!=0 && (chartype_equals(ch) || chartype_equals(*s))) //'<... #=...'
- {
- if(chartype_equals(*s)) ++s;
- SKIPWS(); //Eat any whitespace.
- if(chartype_quote(*s)) //'<... #="...'
- {
- ch = *s; //Save quote char to avoid breaking on "''" -or- '""'.
- ++s; //Step over the quote.
- a->value = s; //Save the offset.
- SCANFOR(*s == ch); //Scan for the terminating quote, or '>'.
-#ifdef PUGOPT_NONSEG
- ENDSEGATT(a);
-#else
- ENDSEG(); //Save char in 'ch', terminate & step over.
-#endif
- if(OPTSET(parse_trim_attribute)) //Trim whitespace.
- {
-#ifdef PUGOPT_NONSEG
- strwtrim(&a->value,a->value_size);
-#else
- if(OPTSET(parse_wnorm)) strwnorm(&a->value);
- else strwtrim(&a->value);
-#endif
- }
- if(chartype_leave(*s)){ ++s; goto LOC_PCDATA; }
- else if(chartype_close(*s))
- {
- ++s;
- POPNODE();
- SKIPWS(); //Eat any whitespace.
- if(chartype_leave(*s)) ++s;
- goto LOC_PCDATA;
- }
- if(chartype_space(*s)) //This may indicate a following attribute.
- {
- SKIPWS(); //Eat any whitespace.
- goto LOC_ATTRIBUTE; //Go scan for additional attributes.
- }
- }
- }
- if(chartype_symbol(*s)) goto LOC_ATTRIBUTE;
- else if(*s!=0 && cursor->type == node_pi)
- {
-#ifdef PUGOPT_NONSEG
- SCANFOR(chartype_pi(*s)); //compliments change where we don't fudge to '/>' when we find the PI. NF 20 Jan 2003
- SKIPWS(); //Eat any whitespace.
- if(chartype_pi(*s)) ++s;
-#else
- SCANFOR(chartype_close(*s));
- SKIPWS(); //Eat any whitespace.
- if(chartype_close(*s)) ++s;
-#endif
- SKIPWS(); //Eat any whitespace.
- if(chartype_leave(*s)) ++s;
- POPNODE();
- goto LOC_PCDATA;
- }
- }
- }
-LOC_LEAVE:
- if(chartype_leave(*s)) //'...>'
- {
- ++s; //Step over the '>'.
-LOC_PCDATA: //'>...<'
- mark = s; //Save this offset while searching for a terminator.
- SKIPWS(); //Eat whitespace if no genuine PCDATA here.
- if(chartype_enter(*s)) //We hit a '<...', with only whitespace, so don't bother storing anything.
- {
- if(chartype_close(*(s+1))) //'</...'
- {
- SCANFOR(chartype_leave(*s)); //Scan for '>', stepping over any end-tag name.
- POPNODE(); //Pop.
- continue; //Continue scanning.
- }
- else goto LOC_SEARCH; //Expect a new element enter, so go scan for it.
- }
- s = mark; //We hit something other than whitespace; restore the original offset.
- PUSHNODE(node_pcdata); //Append a new node on the tree.
- cursor->value = s; //Save the offset.
- SCANFOR(chartype_enter(*s)); //'...<'
-#ifdef PUGOPT_NONSEG
- ENDSEGDAT();
-#else
- ENDSEG(); //Save char in 'ch', terminate & step over.
-#endif
- if(OPTSET(parse_trim_pcdata)) //Trim whitespace.
- {
-#ifdef PUGOPT_NONSEG
- strwtrim(&cursor->value,cursor->value_size);
-#else
- if(OPTSET(parse_wnorm)) strwnorm(&cursor->value);
- else strwtrim(&cursor->value);
-#endif
- }
- POPNODE(); //Pop since this is a standalone.
- if(chartype_enter(ch)) //Did we hit a '<...'?
- {
- if(chartype_close(*s)) //'</...'
- {
- SCANFOR(chartype_leave(*s)); //'...>'
- POPNODE(); //Pop.
- goto LOC_LEAVE;
- }
- else if(chartype_special(*s)) goto LOC_CLASSIFY; //We hit a '<!...'. We must test this here if we want comments intermixed w/PCDATA.
- else if(*s) goto LOC_CLASSIFY;
- else return s;
- }
- }
- //Fall-through A.
- else if(chartype_close(*s)) //'.../'
- {
- ++s;
- if(chartype_leave(*s)) //'.../>'
- {
- POPNODE(); //Pop.
- ++s;
- continue;
- }
- }
- }
- //Fall-through B.
- else if(chartype_close(*s)) //'.../'
- {
- SCANFOR(chartype_leave(*s)); //'.../>'
- POPNODE(); //Pop.
- continue;
- }
- }
- }
- return s;
-}
-
-
-/*
-//<summary>Read data from the file at 'path' into the buffer. Free with 'free'.</summary>
-//<param name="path">File path.</param>
-//<param name="buffer">Pointer to pointer to string to recieve buffer.</param>
-//<param name="size">Pointer to count bytes read and stored in 'buffer'.</param>
-//<param name="tempsize">Temporary read buffer size.</param>
-//<returns>Success if file at 'path' was opened and bytes were read into memory.</returns>
-//<remarks>Memory is allocated at '*buffer'. Free with 'free'.</remarks>
-inline static bool load_file(const TCHAR* path,TCHAR** buffer,unsigned long* size,unsigned long tempsize = 4096)
-{
- if(!path || !buffer || !size) return false;
- *size = 0;
- *buffer = 0;
- HANDLE file_handle = CreateFile(path,GENERIC_READ,FILE_SHARE_READ,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL);
- if(file_handle == INVALID_HANDLE_VALUE) return false;
- TCHAR* temp = (TCHAR*) malloc(sizeof(TCHAR)*tempsize);
- if(!temp) return false;
- unsigned long read_bytes = 0;
- ZeroMemory(temp,sizeof(TCHAR)*tempsize);
- while(ReadFile(file_handle,(void*)temp,tempsize-1,&read_bytes,0) && read_bytes && strcatgrow(buffer,temp))
- {
- *size += read_bytes;
- ZeroMemory(temp,sizeof(TCHAR)*tempsize);
- }
- CloseHandle(file_handle);
- free(temp);
- return (*size) ? true : false;
-}
-*/
-
-
-//<summary>A void pointer array. Used by various xml_node::find* functions.</summary>
-class pointer_array
-{
-//Internal Data Members
-protected:
- unsigned int _size; //Count items.
- unsigned int _room; //Available space.
- void** _data; //The list.
- unsigned int _grow; //Grow by increment.
-public:
- //<summary>Default constructor.</summary>
- //<param name="grow">Array growth increment.</param>
- pointer_array(unsigned int grow = 4):
- _size(0),
- _room(0),
- _data(NULL),
- _grow(grow)
- {
- _data = (void**)malloc(sizeof(void*)*_grow);
- _room = (_data) ? _grow : 0;
- }
- ~pointer_array(){ if(_data) free(_data); }
-public:
- bool empty(){ return (_size == 0); } //True if there is no data in the array.
- void remove_all(){ _size = 0; } //Remove all data elements from the array.
- void clear() //Free any allocated memory.
- {
- if(_data)
- {
- _data = (void**)realloc(_data,sizeof(void*)*_grow); //Reallocate to first growth increment.
- _room = _grow; //Mark it as such.
- _size = 0; //Mark array as empty.
- }
- }
- virtual void*& operator[](unsigned int i) //Access element at subscript, or dummy value if overflow.
- {
- static void* dummy = 0;
- if(i < _size) return _data[i]; else return dummy;
- }
- unsigned int size(){ return _size; } //Count data elements in the array.
- virtual void* at(unsigned int i){ if(i < _size) return _data[i]; else return NULL; } //Access element at subscript, or NULL if overflow.
- long push_back(void* element) //Append a new element to the array.
- {
- if(_data) //Fail if no array.
- {
- if(_size < _room) //There is enough allocated space.
- {
- _data[_size] = element; //Set it.
- _size++; //Increment our count of elements.
- return _size-1; //Return the element's subscript.
- }
- else //Not enough room.
- {
- void** temp = (void**)realloc(_data,sizeof(void*)*(_size+_grow)); //Grow the array.
- if(temp) //Reallocation succeeded.
- {
- _room += _grow; //Increment available space.
- _data = temp; //Assign reallocated value to array pointer.
- _data[_size] = element; //Set the element to be added.
- _size++; //Increment our count of elements.
- return _size-1; //Return the element's subscript.
- }
- }
- }
- return -1; //Something failed, so return a bad subscript.
- }
-};
-
-
-//<summary>A simple indentation stack.</summary>
-//<remarks>Used by xml_node::outer_xml function.</remarks>
-class indent_stack
-{
-//Internal Data Members
-protected:
- TCHAR _inch; //The indent character.
- TCHAR* _stac; //The aggregate indent string (stack).
- int _size; //Current depth (avoids using '_tcslen' on push/pop).
-//Construction/Destruction
-public:
- //<summary>Default constructor.</summary>
- //<param name="c">Indent character.</param>
- indent_stack(TCHAR c = _T('\t')):
- _inch(c),
- _stac(0) ,
- _size(0)
- {
- _stac = (TCHAR*)malloc(sizeof(TCHAR)); //Allocate.
- *_stac = 0; //Zero-terminate.
- }
- //Destructor.
- virtual ~indent_stack(){ if(_stac) free(_stac); }
-//Stack Operators
-public:
- //<summary>Grow indent string by one indent character.</summary>
- //<remarks>Reallocates the indent string.</remarks>
- void push()
- {
- if(_inch && _stac)
- {
- _size++;
- _stac = (TCHAR*)realloc(_stac,sizeof(TCHAR)*(_size+1));
- _stac[_size-1] = _inch;
- _stac[_size] = 0;
- }
- }
- //<summary>Shrink the indent string by one indent character.</summary>
- void pop()
- {
- if(_inch && _stac && _size > 0)
- {
- _size--;
- _stac = (TCHAR*)realloc(_stac,sizeof(TCHAR)*(_size+1));
- _stac[_size] = 0;
- }
- }
- //<summary>Accesses the indent depth.</summary>
- //<returns>The current indent string, or "" if empty.</returns>
- const TCHAR* depth(){ return (_inch && _stac) ? _stac : _T(""); }
-};
-
-
-//<summary>
-// Stream output. Recursively writes the given xml_node_struct structure to
-// the given stream. NOTE: Use this recursive implementation for debug purposes
-// only, since a large tree may cause a stack overflow.
-//</summary>
-//<param name="os">Reference to output stream.</param>
-//<param name="indent">Reference to indentation stack.</param>
-//<param name="node">Pointer to the node.</param>
-//<param name="breaks">Use linebreaks?</param>
-//<returns>
-// String data is written to stream. Indent stack may be altered.
-// If you want to make this prettier, and to avoid propagating whitespace,
-// you will have to trim excess whitespace from the PCDATA sections.
-//</returns>
-inline static void outer_xml(std::basic_ostream<TCHAR,std::char_traits<TCHAR> > & os,indent_stack& indent,xml_node_struct* node,bool breaks = true)
-{
- if(node && os.good()) //There is a node and ostream is OK.
- {
- register unsigned int n, i;
- os << indent.depth();
- switch(node->type)
- {
- case node_dtd_attlist:
- if(node->name)
- {
-#ifdef PUGOPT_NONSEG
- os << _T("<!ATTLIST ");
- os.write( node->name, node->name_size );
-#else
- os << _T("<!ATTLIST ") << node->name;
-#endif
- if(node->value)
-#ifdef PUGOPT_NONSEG
- {
- os << _T(" ");
- os.write( node->value, node->value_size );
- }
-#else
- os << _T(" ") << node->value;
-#endif
-
- os << _T(">");
- }
- break;
- case node_dtd_element:
- if(node->name)
- {
-#ifdef PUGOPT_NONSEG
- os << _T("<!ELEMENT ");
- os.write( node->name, node->name_size );
- if(node->value)
- {
- os << _T(" ");
- os.write( node->value, node->value_size );
- }
-#else
- os << _T("<!ELEMENT ") << node->name;
- if(node->value) os << _T(" ") << node->value;
-#endif
- os << _T(">");
- }
- break;
- case node_dtd_entity:
- if(node->name)
- {
-#ifdef PUGOPT_NONSEG
- os << _T("<!ENTITY ");
- os.write( node->name, node->name_size );
- if(node->value)
- {
- os << _T(" ");
- os.write( node->value, node->value_size );
- }
-#else
- os << _T("<!ENTITY ") << node->name;
- if(node->value) os << _T(" ") << node->value;
-#endif
- os << _T(">");
- }
- break;
- case node_dtd_notation:
- if(node->name)
- {
-#ifdef PUGOPT_NONSEG
- os << _T("<!NOTATION ");
- os.write( node->name, node->name_size );
- if(node->value)
- {
- os << _T(" ");
- os.write( node->value, node->value_size );
- }
-#else
- os << _T("<!NOTATION ") << node->name;
- if(node->value) os << _T(" ") << node->value;
-#endif
- os << _T(">");
- }
- break;
- case node_doctype:
- os << _T("<!DOCTYPE");
- n = node->attributes;
- for(i=0; i<n; ++i)
- {
- os << _T(" ");
- if(node->attribute[i]->name)
-#ifdef PUGOPT_NONSEG
- os.write( node->attribute[i]->name, node->attribute[i]->name_size );
-#else
- os << node->attribute[i]->name;
-#endif
- else if(node->attribute[i]->value)
-#ifdef PUGOPT_NONSEG
- {
- os << _T("\"");
- os.write( node->attribute[i]->value, node->attribute[i]->value_size );
- os << _T("\"");
- }
-#else
- os << _T("\"") << node->attribute[i]->value << _T("\"");
-#endif
- }
- if(node->children)
- {
- if(breaks) os << std::endl;
- else os << _T(" ");
- os << _T("[");
- if(breaks) os << std::endl;
- else os << _T(" ");
- n = node->children;
- indent.push(); //Push the indent stack.
- for(i=0; i<n; ++i)
- {
- if
- (
- node->child[i] && //There is a child at i.
- (
- node->child[i]->type == node_dtd_attlist || //Skip all other types.
- node->child[i]->type == node_dtd_element ||
- node->child[i]->type == node_dtd_entity ||
- node->child[i]->type == node_dtd_notation
- )
- )
- outer_xml(os,indent,node->child[i],breaks);
- }
- indent.pop(); //Pop the indent stack.
- os << _T("]");
- }
- else if(node->value)
-#ifdef PUGOPT_NONSEG
- {
- os << _T(" [");
- os.write(node->value,node->value_size);
- os << _T("]");
- }
-#else
- os << _T(" [") << node->value << _T("]");
-#endif
- os << _T(">");
- break;
- case node_pcdata:
-#ifdef PUGOPT_NONSEG
- if(node->value) os.write(node->value,node->value_size);
-#else
- if(node->value) os << node->value;
-#endif
- break;
- case node_cdata:
-#ifdef PUGOPT_NONSEG
- if(node->value)
- {
- os << _T("<![CDATA[");
- os.write(node->value,node->value_size);
- os << _T("]]>");
- }
-#else
- if(node->value) os << _T("<![CDATA[") << node->value << _T("]]>");
-#endif
- break;
- case node_include:
-#ifdef PUGOPT_NONSEG
- if(node->value)
- {
- os << _T("<![INCLUDE[");
- os.write(node->value, node->value_size);
- os << _T("]]>");
- }
-#else
- if(node->value) os << _T("<![INCLUDE[") << node->value << _T("]]>");
-#endif
- break;
- case node_comment:
-#ifdef PUGOPT_NONSEG
- if(node->value)
- {
- os << _T("<!--");
- os.write(node->value, node->value_size);
- os << _T("-->");
- }
-#else
- if(node->value) os << _T("<!--") << node->value << _T("-->");
-#endif
- break;
- case node_element:
- case node_pi:
- os << _T("<");
- if(node->type==node_pi) os << _T("?");
- if(node->name)
-#ifdef PUGOPT_NONSEG
- os.write(node->name,node->name_size);
-#else
- os << node->name;
-#endif
- else os << _T("anonymous");
- n = node->attributes;
- for(i=0; i<n; ++i)
- {
- if(node->attribute[i] && node->attribute[i]->name)
- {
-#ifdef PUGOPT_NONSEG
- os << _T(" ");
- os.write(node->attribute[i]->name,node->attribute[i]->name_size);
- if(node->attribute[i]->value)
- {
- os << _T("=\"");
- os.write(node->attribute[i]->value,node->attribute[i]->value_size);
- os << _T("\"");
- }
-#else
- os << _T(" ") << node->attribute[i]->name;
- if(node->attribute[i]->value) os << _T("=\"") << node->attribute[i]->value << _T("\"");
-#endif
- }
- }
- n = node->children;
- if(n && node->type == node_element)
- {
- os << _T(">");
- if(n == 1 && node->child[0]->type == node_pcdata)
- {
- if(node->child[0] && node->child[0]->value)
-#ifdef PUGOPT_NONSEG
- os.write(node->child[0]->value,node->child[0]->value_size);
-#else
- os << node->child[0]->value;
-#endif
- }
- else
- {
- if(breaks) os << std::endl;
- indent.push();
- for(i=0; i<n; ++i) pug::outer_xml(os,indent,node->child[i],breaks);
- indent.pop();
- os << indent.depth();
- }
- os << _T("</");
-#ifdef PUGOPT_NONSEG
- if(node->name)
- os.write(node->name, node->name_size);
-#else
- if(node->name) os << node->name;
-#endif
- os << _T(">");
- }
- else
- {
- if(node->type==node_pi) os << _T("?>");
- else os << _T("/>");
- }
- break;
- default: break;
- }
- if(breaks) os << std::endl;
- os.flush();
- }
-}
-
-
-//<summary>Abstract iterator class for interating over a node's members.</summary>
-//<remarks>Used as base class for 'xml_node_iterator' and 'xml_attribute_iterator'.</remarks>
-template <class _Ty,class _Diff,class _Pointer,class _Reference>
-class xml_iterator : public std::_Ranit<_Ty,_Diff,_Pointer,_Reference>
-{
-protected:
- xml_node_struct* _vref; //A pointer to the node over which to iterate.
- long _sscr; //Current subscript of element.
-public:
- xml_iterator() : _vref(0), _sscr(-1) {} //Default constructor.
- xml_iterator(xml_node_struct* vref,long sscr = 0) : _vref(vref), _sscr(sscr){ } //Initializing constructor.
- xml_iterator(const xml_iterator& r) : _vref(r._vref), _sscr(r._sscr){ } //Copy constructor.
- virtual ~xml_iterator(){} //Destructor.
-public:
- virtual bool good() = 0; //Internal validity of '_vref'.
- virtual bool oob() = 0; //Out of bounds check for '_sscr' with respect to '_vref'. Returns true if '_sscr' is O.O.B.
-public:
- virtual long subscript(){ return _sscr; } //Get subscript value;
- virtual void subscript(long new_subscript){ _sscr = new_subscript; } //Set subscript value;
-public:
- virtual xml_iterator& operator=(const xml_iterator& rhs){ _vref = rhs._vref; _sscr = rhs._sscr; return *this; } //Assignment.
- virtual bool operator==(const xml_iterator& rhs){ return (_sscr == rhs._sscr); } //True if this is equal to RHS.
- virtual bool operator!=(const xml_iterator& rhs){ return (_sscr != rhs._sscr); } //True if this is not equal to RHS.
- virtual bool operator<(const xml_iterator& rhs){ return (_sscr < rhs._sscr); } //True if this subscript is less than RHS.
- virtual bool operator>(const xml_iterator& rhs){ return (_sscr > rhs._sscr); } //True if this subscript is greater than RHS.
- virtual bool operator<=(const xml_iterator& rhs){ return (_sscr <= rhs._sscr); } //True if this subscript is less than or equal to RHS.
- virtual bool operator>=(const xml_iterator& rhs){ return (_sscr >= rhs._sscr); } //True if this subscript is greater than or equal to RHS.
- virtual xml_iterator& operator++(){ _sscr++; return *this; } //Increment the iterator (subscript).
- virtual xml_iterator& operator--(){ _sscr--; return *this; } //Decrement the iterator (subscript).
- virtual _Ty& operator*() = 0; //Dereference operator.
- virtual _Ty* operator->() = 0;
-};
-
-class xml_node; //Forward decl.
-
-
-//<summary>Abstract tree walker class for xml_node::traverse().</summary>
-class xml_tree_walker
-{
-protected:
- long _deep; //Current node depth.
-public:
- xml_tree_walker() : _deep(0) {} //Default constructor.
- virtual ~xml_tree_walker(){} //Destructor.
-public:
- virtual void push(){ ++_deep; } //Increment node depth.
- virtual void pop(){ --_deep; } //Decrement node depth.
- virtual long depth(){ return (_deep > 0) ? _deep : 0; } //Access node depth.
-public:
- //<summary>Callback when traverse on a given root node begins.</summary>
- //<returns>Returning false will abort the traversal.</returns>
- //<remarks>Override this to implement your own custom behavior.</remarks>
- virtual bool begin(xml_node&){ return true; }
- //<summary>Callback for each node that is hit on traverse.</summary>
- //<returns>Returning false will abort the traversal.</returns>
- virtual bool for_each(xml_node&) = 0;
- //<summary>Callback when traverse on a given root node ends.</summary>
- //<returns>Returning false will abort the traversal.</returns>
- //<remarks>Override this to implement your own custom behavior.</remarks>
- virtual bool end(xml_node&){ return true; }
-};
-
-
-//<summary>Provides a light-weight wrapper for manipulating xml_attribute_struct structures.</summary>
-//<remarks>
-// Note: xml_attribute does not create any memory for the attribute it wraps;
-// it only wraps a pointer to an existing xml_attribute_struct.
-//</remarks>
-class xml_attribute
-{
-//Internal Data Members
-protected:
- xml_attribute_struct* _attr; //The internal attribute pointer.
-//Construction/Destruction
-public:
- xml_attribute() : _attr(NULL) {} //Default constructor.
- xml_attribute(xml_attribute_struct* attr) : _attr(attr) {} //Initializing constructor.
- xml_attribute(const xml_attribute& r) : _attr(r._attr) {} //Copy constructor.
- virtual ~xml_attribute(){} //Destructor.
-//Operators
-public:
- void attach(xml_attribute_struct* v){ _attr = v; }
- xml_attribute& operator=(const xml_attribute& r){ _attr = r._attr; return *this; } //Assign internal pointer.
- bool operator==(const xml_attribute& r){ return (_attr == r._attr); } //Compare internal pointer.
- bool operator!=(const xml_attribute& r){ return (_attr != r._attr); }
- operator xml_attribute_struct*(){ return _attr; }
- //<summary>Cast attribute value as std::string. If not found, return empty.</summary>
- //<returns>The std::string attribute value, or empty.</returns>
- //<remarks>Note: Modifying this will not change the value, e.g. read only.</remarks>
- operator std::string()
- {
- std::string temp;
- if(!empty() && has_value())
- {
-#ifdef PUGOPT_NONSEG
- temp.append(_attr->value,_attr->value_size);
-#else
- temp = _attr->value;
-#endif
- }
- return temp;
- }
- //<summary>Cast attribute value as integral character string. If not found, return NULL.</summary>
- //<returns>Integral character string attribute value, or NULL.</returns>
- //<remarks>Warning: Modifying this may corrupt portions of the document tree.</remarks>
- operator const TCHAR*()
- {
- if(empty() || !has_value()) return NULL;
- return _attr->value;
- }
- //<summary>Cast attribute value as long. If not found, return 0.</summary>
- //<returns>Attribute value as long, or 0.</returns>
- //<remarks>Note: Modifying this will not change the value, e.g. read only.</remarks>
- operator long()
- {
- if(empty() || !has_value()) return 0;
-#ifdef PUGOPT_NONSEG
- TCHAR temp[PUGDEF_ATTR_VALU_SIZE];
- unsigned int valulen = sizeof(temp)-1;
- const unsigned int maxlen = valulen ? min(valulen,_attr->value_size) : _attr->value_size;
- _tcsncpy(temp,_attr->value,maxlen);
- temp[maxlen] = 0;
- return _tcstol(temp,NULL,10);
-#else
- return _tcstol(_attr->value,NULL,10);
-#endif
- }
- //<summary>Cast attribute value as double. If not found, return 0.0.</summary>
- //<returns>Attribute value as double, or 0.0.</returns>
- //<remarks>Note: Modifying this will not change the value, e.g. read only.</remarks>
- operator double()
- {
- if(empty() || !has_value()) return 0.0;
-#ifdef PUGOPT_NONSEG
- TCHAR temp[PUGDEF_ATTR_VALU_SIZE];
- unsigned int valulen = sizeof(temp)-1;
- const unsigned int maxlen = valulen ? min(valulen,_attr->value_size) : _attr->value_size;
- _tcsncpy(temp,_attr->value,maxlen);
- temp[maxlen] = 0;
- return _tcstod(temp,0);
-#else
- return _tcstod(_attr->value,0);
-#endif
- }
- //<summary>Cast attribute value as bool. If not found, return false.</summary>
- //<returns>Attribute value as bool, or false.</returns>
- //<remarks>Note: Modifying this will not change the value, e.g. read only.</remarks>
- operator bool()
- {
- if(empty() || !has_value()) return false;
- if(*(_attr->value))
- {
- return //Only look at first char:
- (
- *(_attr->value) == _T('1') || //1*
- *(_attr->value) == _T('t') || //t* (true)
- *(_attr->value) == _T('T') || //T* (True|true)
- *(_attr->value) == _T('y') || //y* (yes)
- *(_attr->value) == _T('Y') //Y* (Yes|YES)
- )
- ? true : false; //Return true if matches above, else false.
- }
- }
- //<summary>Set attribute to std::string.</summary>
- //<param name="rhs">Value std::string to set.</param>
- //<returns>Reference to xml_attribute.</returns>
- xml_attribute& operator=(const std::string& rhs){ value(rhs.c_str()); return *this; }
- //<summary>Set attribute to string.</summary>
- //<param name="rhs">Value string to set.</param>
- //<returns>Reference to xml_attribute.</returns>
- xml_attribute& operator=(const TCHAR* rhs){ if(rhs) value(rhs); return *this; }
- //<summary>Set attribute to long.</summary>
- //<param name="rhs">Value long to set.</param>
- //<returns>Reference to xml_attribute.</returns>
- xml_attribute& operator=(long rhs)
- {
- TCHAR temp[32] = {0};
- _stprintf(temp,_T("%ld"),rhs);
- value(temp);
- return *this;
- }
- //<summary>Set attribute to double.</summary>
- //<param name="rhs">Value double to set.</param>
- //<returns>Reference to xml_attribute.</returns>
- xml_attribute& operator=(double rhs)
- {
- TCHAR temp[32] = {0};
- _stprintf(temp,_T("%lf"),rhs);
- value(temp);
- return *this;
- }
- //<summary>Set attribute to bool.</summary>
- //<param name="rhs">Value bool to set.</param>
- //<returns>Reference to xml_attribute.</returns>
- xml_attribute& operator=(bool rhs)
- {
- value(rhs?_T("true"):_T("false"));
- return *this;
- }
- //<summary>Right-shift attribute value to std::string.</summary>
- //<param name="rhs">Reference to std::string to set.</param>
- //<returns>Reference to xml_attribute.</returns>
- xml_attribute& operator>>(std::string& rhs)
- {
-#ifdef PUGOPT_NONSEG
- rhs.clear();
- rhs.append(_attr->value,_attr->value_size);
-#else
- rhs = value();
-#endif
- return *this;
- }
- //<summary>Right-shift attribute value to long.</summary>
- //<param name="rhs">Reference to long to set.</param>
- //<returns>Reference to xml_attribute.</returns>
- xml_attribute& operator>>(long& rhs){ rhs = (long)*this; return *this; }
- //<summary>Right-shift attribute value to double.</summary>
- //<param name="rhs">Reference to double to set.</param>
- //<returns>Reference to xml_attribute.</returns>
- xml_attribute& operator>>(double& rhs){ rhs = (double)*this; return *this; }
- //<summary>Right-shift attribute value to bool.</summary>
- //<param name="rhs">Reference to bool to set.</param>
- //<returns>Reference to xml_attribute.</returns>
- xml_attribute& operator>>(bool& rhs){ rhs = (bool)*this; return *this; }
- //<summary>Left-shift attribute value to long.</summary>
- //<param name="lhs">Reference to long to set.</param>
- //<param name="rhs">Reference to xml_attribute to read.</param>
- //<returns>Reference to long.</returns>
- friend long& operator<<(long& lhs,xml_attribute& rhs){ lhs = (long)rhs; return lhs; }
- //<summary>Left-shift attribute value to double.</summary>
- //<param name="lhs">Reference to double to set.</param>
- //<param name="rhs">Reference to xml_attribute to read.</param>
- //<returns>Reference to double.</returns>
- friend double& operator<<(double& lhs,xml_attribute& rhs){ lhs = (double)rhs; return lhs; }
- //<summary>Left-shift attribute value to bool.</summary>
- //<param name="lhs">Reference to bool to set.</param>
- //<param name="rhs">Reference to xml_attribute to read.</param>
- //<returns>Reference to bool.</returns>
- friend bool& operator<<(bool& lhs,xml_attribute& rhs){ lhs = (bool)rhs; return lhs; }
- //<summary>Left-shift long to attribute value.</summary>
- //<param name="lhs">Reference to xml_attribute to set.</param>
- //<param name="rhs">Reference to long to read.</param>
- //<returns>Reference to xml_attribute.</returns>
- friend xml_attribute& operator<<(xml_attribute& lhs,const long rhs){ lhs = rhs; return lhs; }
- //<summary>Left-shift double to attribute value.</summary>
- //<param name="lhs">Reference to xml_attribute to set.</param>
- //<param name="rhs">Reference to double to read.</param>
- //<returns>Reference to xml_attribute.</returns>
- friend xml_attribute& operator<<(xml_attribute& lhs,const double& rhs){ lhs = rhs; return lhs; }
- //<summary>Left-shift bool to attribute value.</summary>
- //<param name="lhs">Reference to xml_attribute to set.</param>
- //<param name="rhs">Reference to bool to read.</param>
- //<returns>Reference to xml_attribute.</returns>
- friend xml_attribute& operator<<(xml_attribute& lhs,const bool& rhs){ lhs = rhs; return lhs; }
-public:
- bool empty(){ return (_attr == NULL); } //True if the internal xml_attribute_struct pointer is NULL.
- bool has_name(){ return (!empty() && _attr->name); } //True if the attribute has a name.
- bool has_value(){ return (!empty() && _attr->value); } //True if the attribute has a value.
-#ifdef PUGOPT_NONSEG
- bool has_name(const TCHAR* name) { return (name && !empty() && has_name() && _tcsncmp(_attr->name,name,_attr->name_size)==0); } //Is named 'name'.
- bool has_value(const TCHAR* value) { return (value && !empty() && has_value() && _tcsncmp(_attr->value,value,_attr->value_size)==0); } //Has value 'value'.
-#else
- bool has_name(const TCHAR* name) { return (name && !empty() && has_name() && _tcscmp(_attr->name,name)==0); } //Is named 'name'.
- bool has_value(const TCHAR* value) { return (value && !empty() && has_value() && _tcscmp(_attr->value,value)==0); } //Has value 'value'.
-#endif
-public:
- const TCHAR* name(){ return (!empty() && _attr->name) ? _attr->name : _T(""); } //Access the attribute name.
-#ifdef PUGOPT_NONSEG
- const unsigned int name_size(){ return (!empty()) ? _attr->name_size : 0; } //Access the attribute name length (for PUGOPT_NONSEG).
-#endif
- bool name(TCHAR* new_name) //Set the attribute name.
- {
- if(!empty() && new_name)
-#ifdef PUGOPT_NONSEG
- return strcpyinsitu(&_attr->name,new_name,&_attr->name_insitu,_attr->name_size);
-#else
- return strcpyinsitu(&_attr->name,new_name,&_attr->name_insitu);
-#endif
- return false;
- }
- const TCHAR* value(){ return (!empty()) ? _attr->value : _T(""); } //Access the attribute value.
-#ifdef PUGOPT_NONSEG
- const unsigned int value_size(){ return (!empty()) ? _attr->value_size : 0; } //Access the attribute name length (for PUGOPT_NONSEG).
-#endif
- bool value(const TCHAR* new_value) //Set the attribute value.
- {
- if(!empty() && new_value)
-#ifdef PUGOPT_NONSEG
- return strcpyinsitu(&_attr->value,new_value,&_attr->value_insitu,_attr->value_size);
-#else
- return strcpyinsitu(&_attr->value,new_value,&_attr->value_insitu);
-#endif
- return false;
- }
-};
-
-
-class xml_node; //Forward declaration.
-
-
-//<summary>Forward wrapper for any as-yet undefined class.</summary>
-//<remarks>
-// Used by xml_node_iterator, and xml_attribute_iterator to assist with
-// operator->(), and operator*() mapping to xml_node and xml_attribute
-// types.
-//</remarks>
-template <typename TYPE> class forward_class
-{
-protected:
- TYPE* _obj; //The class, internal.
-public:
- forward_class() : _obj(NULL) { _obj = new TYPE(); } //Default constructor.
- forward_class(const TYPE& r) : _obj(NULL) { _obj = new TYPE(r); } //Copy constructor.
- virtual ~forward_class(){ if(_obj) delete _obj; } //Destructor.
-public:
- TYPE& operator* (){ return *_obj; } //Dereference to the class.
- TYPE* operator->(){ return _obj; } //Class member selection.
- operator TYPE (){ return *_obj; } //Cast as class type.
- operator TYPE&(){ return *_obj; } //Cast as class type reference.
- operator TYPE*(){ return _obj; } //Cast as class type pointer.
-};
-
-
-//<summary>Provides a light-weight wrapper for manipulating xml_node_struct structures.</summary>
-class xml_node
-{
-//Internal Data Members
-protected:
-
- xml_node_struct* _root; //Pointer to node root.
- xml_node_struct _dummy; //Utility.
-
-//Construction/Destruction
-public:
-
- //<summary>Default constructor.</summary>
- //<remarks>
- // Node root points to a dummy 'xml_node_struct' structure. Test for this
- // with 'empty'.
- //</remarks>
- xml_node(): _root(0)
- {
- memset(&_dummy,0,sizeof(xml_node_struct));
- _dummy.type = node_null;
- _dummy.parent = &_dummy;
- _root = &_dummy;
- }
-
- //<summary>Construct, wrapping the given 'xml_node_struct' pointer.</summary>
- //<param name="p">Pointer to node to wrap.</param>
- //<remarks>It is possible that 'p' is NULL, so test for this with 'empty'.</remarks>
- xml_node(xml_node_struct* p): _root(p) { memset(&_dummy,0,sizeof(xml_node_struct)); }
-
- //<summary>Copy constructor.</summary>
- //<param name="r">Reference to node.</param>
- //<remarks>
- // Only the root pointer is assigned, so both classes now in fact point
- // to the same structure.
- //</remarks>
- xml_node(const xml_node& r): _root(r._root) {}
-
- //<summary>Destructor.</summary>
- virtual ~xml_node(){}
-
- //<summary>Attach to the given structure.</summary>
- //<param name="p">Pointer to node structure to wrap.</param>
- //<returns>Pointer to previous node structure.</returns>
- xml_node_struct* attach(xml_node_struct* p)
- {
- xml_node_struct* prev = _root;
- _root = p;
- return prev;
- }
-
-//Iteration
-public:
-
- //<summary>Child node iterator.</summary>
- class xml_node_iterator : public xml_iterator<xml_node,long,xml_node*,xml_node&>
- {
- protected:
- forward_class<xml_node> _wrap; //Wrapper for xml_node.
- public:
- xml_node_iterator() : _wrap(), xml_iterator<xml_node,long,xml_node*,xml_node&>() {} //Default constructor.
- xml_node_iterator(xml_node_struct* vref,long sscr = 0) : _wrap(), xml_iterator<xml_node,long,xml_node*,xml_node&>(vref,sscr) { } //Initializing constructor.
- xml_node_iterator(const xml_node_iterator& r) : _wrap(), xml_iterator<xml_node,long,xml_node*,xml_node&>(r) { } //Copy constructor.
- virtual bool good() //Internal validity.
- {
- if
- (
- _vref != 0 && //Pointing to some node.
- _vref->child != 0 && //The node has an array of children.
- _vref->children > 0 //There are 1 or more children in the array.
- )
- return true;
- return false;
- }
- virtual bool oob() //Out of bounds check.
- {
- if
- (
- !good() || //There is no data over which to iterate.
- _sscr < 0 || //Subscript is out of range.
- _sscr >= (long)_vref->children
- )
- return true;
- return false;
- }
- //<summary>Pointer dereference for current xml_node.<summary>
- //<returns>
- // Reference to the internal xml_node object, which wraps the
- // xml_node_struct corresponding to the node at the
- // current subscript.
- //</returns>
- virtual xml_node& operator*()
- {
- if(!oob()) _wrap->attach(_vref->child[_sscr]);
- else _wrap->attach(NULL);
- return (xml_node&)_wrap;
- }
- virtual xml_node* operator->() //Member selection for current xml_node.
- {
- if(!oob()) _wrap->attach(_vref->child[_sscr]);
- else _wrap->attach(NULL);
- return (xml_node*)_wrap;
- }
- };
-
- //<summary>Attribute iterator.</summary>
- class xml_attribute_iterator : public xml_iterator<xml_attribute,long,xml_attribute*,xml_attribute&>
- {
- protected:
- forward_class<xml_attribute> _wrap;
- public:
- xml_attribute_iterator() : _wrap(), xml_iterator<xml_attribute,long,xml_attribute*,xml_attribute&>() {} //Default constructor.
- xml_attribute_iterator(xml_node_struct* vref,long sscr = 0) : _wrap(), xml_iterator<xml_attribute,long,xml_attribute*,xml_attribute&>(vref,sscr) { } //Initializing constructor.
- xml_attribute_iterator(const xml_attribute_iterator& r) : _wrap(), xml_iterator<xml_attribute,long,xml_attribute*,xml_attribute&>(r) { } //Copy constructor.
- virtual bool good() //Internal validity check.
- {
- if
- (
- _vref != 0 && //Pointing to some node.
- _vref->attribute != 0 && //The node has an array of children.
- _vref->attributes > 0 //There are 1 or more children in the array.
- )
- return true;
- return false;
- }
- virtual bool oob() //Out of bounds check.
- {
- if
- (
- !good() || //There is no data over which to iterate.
- _sscr < 0 || //Subscript is out of range.
- _sscr >= (long)_vref->attributes //For 'end'
- )
- return true;
- return false;
- }
- //<summary>Pointer dereference for current xml_attribute.</summary>
- //<returns>
- // Reference to the internal xml_attribute object, which wraps the
- // xml_attribute_struct corresponding to the attribute at the
- // current subscript.
- //</returns>
- virtual xml_attribute& operator*()
- {
- if(!oob()) _wrap->attach(_vref->attribute[_sscr]);
- else _wrap->attach(NULL);
- return (xml_attribute&)_wrap;
- }
- //<summary>Member selection for current xml_attribute.</summary>
- //<returns></returns>
- virtual xml_attribute* operator->()
- {
- if(!oob()) _wrap->attach(_vref->attribute[_sscr]);
- else _wrap->attach(NULL);
- return (xml_attribute*)_wrap;
- }
- };
-
- //<summary>Base iterator type (for child nodes). Same as 'child_iterator'.</summary>
- typedef xml_node_iterator iterator;
- //<summary>Base iterator type (for child nodes). Same as 'iterator'.</summary>
- typedef xml_node_iterator child_iterator;
- //<summary>Base iterator type (for sibling nodes). Same as 'iterator'.</summary>
- typedef xml_node_iterator sibling_iterator;
- //<summary>Attribute iterator type.</summary>
- typedef xml_attribute_iterator attribute_iterator;
-
- //<summary>Access the begin iterator for this node's collection of child nodes.</summary>
- //<returns>The begin iterator for this node's collection of child nodes.</returns>
- //<remarks>Same as 'children_begin'.</remarks>
- iterator begin(){ return iterator(_root,0); }
- //<summary>Access the end iterator for this node's collection of child nodes.</summary>
- //<returns>The end iterator for this node's collection of child nodes.</returns>
- //<remarks>Same as 'children_end'.</remarks>
- iterator end(){ return iterator(_root,_root->children); }
- //<summary>Erase the given node from node's collection of child nodes.</summary>
- //<returns>The begin iterator for this node's collection of child nodes.</returns>
- //<remarks>Same as 'children_erase'.</remarks>
- iterator erase(iterator where){ remove_child((unsigned int)where.subscript()); return iterator(_root,0); }
-
- //<summary>Access the begin iterator for this node's collection of child nodes.</summary>
- //<returns>The begin iterator for this node's collection of child nodes.</returns>
- //<remarks>Same as 'begin'.</remarks>
- child_iterator children_begin(){ return child_iterator(_root,0); }
- //<summary>Access the end iterator for this node's collection of child nodes.</summary>
- //<returns>The end iterator for this node's collection of child nodes.</returns>
- //<remarks>Same as 'end'.</remarks>
- child_iterator children_end(){ return child_iterator(_root,_root->children); }
- //<summary>Erase the given node from node's collection of child nodes.</summary>
- //<returns>The begin iterator for this node's collection of child nodes.</returns>
- //<remarks>Same as 'erase'.</remarks>
- child_iterator children_erase(child_iterator where){ remove_child((unsigned int)where.subscript()); return child_iterator(_root,0); }
-
- //<summary>Access the begin iterator for this node's collection of attributes.</summary>
- //<returns>The begin iterator for this node's collection of attributes.</returns>
- attribute_iterator attributes_begin(){ return attribute_iterator(_root,0); }
- //<summary>Access the end iterator for this node's collection of attributes.</summary>
- //<returns>The end iterator for this node's collection of attributes.</returns>
- attribute_iterator attributes_end(){ return attribute_iterator(_root,_root->attributes); }
- //<summary>Erase the given attribute from node's collection of attributes.</summary>
- //<returns>The begin iterator for this node's collection of attributes.</returns>
- attribute_iterator attributes_erase(attribute_iterator where){ remove_attribute((unsigned int)where.subscript()); return attribute_iterator(_root,0); }
-
- //<summary>Access the begin iterator for this node's collection of siblings.</summary>
- //<returns>The begin iterator for this node's collection of siblings.</returns>
- sibling_iterator siblings_begin(){ if(!empty()) return sibling_iterator(_root->parent,0); return sibling_iterator(); }
- //<summary>Access the end iterator for this node's collection of siblings.</summary>
- //<returns>The end iterator for this node's collection of siblings.</returns>
- sibling_iterator siblings_end(){ if(!empty()) return sibling_iterator(_root->parent,_root->parent->children); return sibling_iterator(); }
- //<summary>Erase the given sibling from node's collection of siblings.</summary>
- //<returns>The begin iterator for this node's collection of siblings.</returns>
- sibling_iterator siblings_erase(sibling_iterator where){ parent().remove_child((unsigned int)where.subscript()); return iterator(_root->parent,0); }
-
-//Overloaded Operators
-public:
-
- operator xml_node_struct*(){ return _root; } //Cast as xml_node_struct pointer.
- operator void*(){ return (void*)_root; } //Cast root as void*.
- xml_node& operator=(const xml_node& r){ _root = r._root; return *this; } //Assign to xml_node_struct pointer.
- bool operator==(const xml_node& r){ return (_root == r._root); } //True if this has the same internal xml_node_struct pointer value.
- xml_node operator[](unsigned int i){ return child(i); } //Access the child at subscript.
-
-//Node Classification
-public:
-
- bool empty() { return (_root == 0 || _root->type == node_null); } //Node pointer is null, or type is node_null. Same as type_null.
- bool type_null() { return empty(); } //Node pointer is null, or type is node_null. Same as empty.
- bool type_document() { return (_root && _root == _root->parent && _root->type == node_document); } //Node is tree root.
- bool type_element() { return (_root && _root->type == node_element); } //Node is an element.
- bool type_comment() { return (_root && _root->type == node_comment); } //Node is a comment.
- bool type_pcdata() { return (_root && _root->type == node_pcdata); } //Node is PCDATA.
- bool type_cdata() { return (_root && _root->type == node_cdata); } //Node is CDATA.
- bool type_include() { return (_root && _root->type == node_include); } //Node is INCLUDE.
- bool type_pi() { return (_root && _root->type == node_pi); } //Node is a processing instruction.
- bool type_doctype() { return (_root && _root->type == node_doctype); } //Node is DOCTYPE.
- bool type_dtd_item() { return (_root && _root->type > node_doctype); } //Node is NODE_DTD_*.
- bool type_dtd_attlist() { return (_root && _root->type == node_dtd_attlist); } //Node is node_dtd_attlist.
- bool type_dtd_element() { return (_root && _root->type == node_dtd_element); } //Node is node_dtd_element.
- bool type_dtd_entity() { return (_root && _root->type == node_dtd_entity); } //Node is node_dtd_entity.
- bool type_dtd_notation() { return (_root && _root->type == node_dtd_notation); } //Node is node_dtd_notation.
-
-//Member Inventory
-public:
-
- bool has_value() { return (!empty() && _root->value != 0); } //Node has data (comment, CDATA or PCDATA).
- bool has_child_nodes() { return (!empty() && children() > 0); } //Node has 1 or more children.
- bool has_attributes() { return (!empty() && attributes() > 0); } //Node has 1 or more attributes.
- bool has_siblings() { return (!empty() && siblings() > 0); } //Node has one or more siblings.
- bool has_name() { return (!empty() && _root->name != 0); } //Node has a name.
- bool has_name(const std::string& name) const { return has_name(name.c_str()); } //Node is named 'name'.
- bool has_attribute(const std::string& name) { return has_attribute(name.c_str()); } //Node has an attribute named 'name'.
-#ifdef PUGOPT_NONSEG
- bool has_name(const TCHAR* name) const { return (name && _root && _root->name && _tcsncmp(_root->name,name,_root->name_size)==0); } //Node is named 'name'.
-#else
- bool has_name(const TCHAR* name) const { return (name && _root && _root->name && strcmpwild(name,_root->name)==0); } //Node is named 'name'.
-#endif
- bool has_attribute(const TCHAR* name){ return (mapto_attribute_idx(name) > -1); } //Node has an attribute named name.
-
-//Member Accessors
-public:
-
-#ifdef PUGOPT_NONSEG
-
- //<summary>Access node name if any.</summary>
- //<returns>Name, or dummy value if the no name.</returns>
- //<remarks>Only returns up to 'PUGDEF_ELEM_NAME_SIZE' chars of name.</remarks>
- const TCHAR* name()
- {
- static TCHAR temp[PUGDEF_ELEM_NAME_SIZE] = {0};
- if(has_name())
- {
- _tcsncpy(temp,_root->name,_root->name_size);
- temp[_root->name_size<PUGDEF_ELEM_NAME_SIZE?_root->name_size:(PUGDEF_ELEM_NAME_SIZE-1)] = 0;
- return temp;
- }
- return _T("");
- }
- unsigned int name_size(){ return (has_name()) ? _root->name_size : 0; } //Get node name length if any, else 0.
- unsigned int value_size(){ return (has_value()) ? _root->value_size : 0; } //Get node value length if any, else 0.
- inline bool matches_attribute_name(const TCHAR* name,const unsigned int namelen,const int i) const { return (_tcsncmp(name,_root->attribute[i]->name,max(namelen,_root->attribute[i]->name_size))==0); } //There is an attribute at 'i' named 'name'.
- inline bool matches_child_name(const TCHAR* name,const unsigned int namelen,const int i) const { return (_tcsncmp(name,_root->child[i]->name,max(namelen,_root->child[i]->name_size))==0); } //There is a child at 'i' named 'name'.
- inline bool matches_name(const TCHAR* name,const unsigned int namelen,xml_node_struct* node) const { return (_tcsncmp(name,node->name,max(namelen,node->name_size))==0); } //This is named 'name'.
- inline bool matches_value(const TCHAR* data,const unsigned int datalen,xml_node_struct* node) const { return (_tcsncmp(data,node->value,max(datalen,node->value_size))==0); } //This is valued 'value'.
- inline bool matches_attribute_name(const TCHAR* name,const unsigned int namelen,xml_attribute_struct* attr) const { return (_tcsncmp(name,attr->name,max(namelen,attr->name_size))==0); } //The given attribute is named 'name'.
- inline bool matches_attribute_name_value(const TCHAR* value,const unsigned int valulen,xml_attribute_struct* attr) const { return (_tcsncmp(value,attr->value,max(valulen,attr->value_size))==0); } //The given attribute is valued 'value'.
-#else
- const TCHAR* name(){ return (has_name()) ? _root->name : _T(""); } //Access pointer to node name if any, else empty string.
- inline bool matches_attribute_name(const TCHAR* name,const unsigned int i) const { return (strcmpwild(name,_root->attribute[i]->name)==0); } //There is an attribute at 'i' named 'name'.
- inline bool matches_child_name(const TCHAR* name,const unsigned int i) const { return (strcmpwild(name,_root->child[i]->name)==0); } //There is a child at 'i' named 'name'.
- inline bool matches_name(const TCHAR* name,xml_node_struct* node) const { return (strcmpwild(name,node->name)==0); } //This is named 'name'.
- inline bool matches_value(const TCHAR* data,xml_node_struct* node) const { return (strcmpwild(data,node->value)==0); } //This is valued 'value'.
- inline bool matches_attribute_name(const TCHAR* attribute,xml_attribute_struct* attr) const { return (strcmpwild(attribute,attr->name)==0); } //The given attribute is named 'name'.
- inline bool matches_attribute_name_value(const TCHAR* value,xml_attribute_struct* attr) const { return (strcmpwild(value,attr->value)==0); } //The given attribute is valued 'value'.
-#endif
- xml_node_type type() const { return (_root) ? (xml_node_type)_root->type : node_null; } //Access node entity type.
- const TCHAR* value() { return (has_value()) ? _root->value : _T(""); } //Access pointer to data if any, else empty string.
- unsigned int children() const { return _root->children; } //Access node's child count.
- xml_node child(unsigned int i){ return (i < children()) ? xml_node(_root->child[i]) : xml_node(); } //Access child node at subscript as xml_node or xml_node(NULL) if bad subscript.
- unsigned int attributes() const { return _root->attributes; } //Access node's attribute count.
- xml_attribute attribute(unsigned int i){ return (i < attributes()) ? xml_attribute(_root->attribute[i]) : xml_attribute(); } //Access attribute at subscript if any, else empty attribute.
- //<summary>Access or create the attribute having 'name'.</summary>
- //<param name="name">Name of attribute to access/create.</param>
- //<returns>Reference to xml_attribute wrapper.</returns>
- xml_attribute attribute(const std::string& name){ return attribute(name.c_str()); }
- //<summary>Access or create the attribute having 'name'.</summary>
- //<param name="name">Name of attribute to access/create.</param>
- //<returns>Reference to xml_attribute wrapper.</returns>
- xml_attribute attribute(const TCHAR* name)
- {
- xml_attribute_struct* attr = mapto_attribute_ptr(name);
- if(!attr) attr = append_attribute(name,_T(""));
- return xml_attribute(attr);
- }
- const unsigned int siblings(){ return (!type_document()) ? _root->parent->children : 0; } //Access node's sibling count (parent's child count).
- xml_node sibling(unsigned int i){ return (!type_document() && i < siblings()) ? xml_node(_root->parent->child[i]) : xml_node(); } //Access sibling node at subscript as xml_node or xml_node(NULL) if bad subscript.
- xml_node parent(){ return (!type_document()) ? xml_node(_root->parent) : xml_node(); } //Access node's parent if any, else xml_node(NULL)
-
- //<summary>Return the first child that has data's data. If none, return NULL.</summary>
- //<param name="value">Returns a copy of the data.</param>
- //<param name="valuelen">Specifies the maximum number of characters to copy into value.</param>
- //<returns>Pointer to value if exists, else NULL.</returns>
- //<remarks>
- // Used to get the PCDATA for the current element. This handles elements
- // like: &lt;LINE&gt;&lt;STAGEDIR&gt;Aside&lt;/STAGEDIR&gt;Thy father,
- // Pompey, would ne'er have&lt;/LINE&gt;, where 'this' points to &lt;LINE&gt;.
- //</remarks>
- TCHAR* child_value(TCHAR* value,const unsigned int valuelen)const
- {
- if(_root->children)
- {
- for(register unsigned int i=0; i < _root->children; ++i)
- {
- xml_node_struct* node = _root->child[i];
- if(node->value)
- {
- const unsigned int n =
-#ifdef PUGOPT_NONSEG
- (std::min)(valuelen,node->value_size);
-#else
- (std::min)(valuelen,unsigned(_tcslen(node->value)));
-#endif
- _tcsncpy(value,node->value,n);
- value[n] = 0;
- break;
- }
- }
- return value;
- }
- return NULL;
- }
-
-//Name-To-Object Mapping
-public:
-
- //<summary>Map an attribute name to a pointer to that attribute, if found.</summary>
- //<param name="name">Reference to name of attribute to find.</param>
- //<returns>Pointer to attribute, or NULL if not found.</returns>
- //<remarks>Implement your own hash table if you have a great many attributes.</remarks>
- xml_attribute_struct* mapto_attribute_ptr(const std::string& name){ return mapto_attribute_ptr(name.c_str()); }
-
- //<summary>Map an attribute name to a pointer to that attribute, if found.</summary>
- //<param name="name">Pointer to name of attribute to find.</param>
- //<returns>Pointer to attribute, or NULL if not found.</returns>
- //<remarks>Implement your own hash table if you have a great many attributes.</remarks>
- xml_attribute_struct* mapto_attribute_ptr(const TCHAR* name)
- {
- if(!_root || !name) return NULL;
- register unsigned int n = _root->attributes;
-#ifdef PUGOPT_NONSEG
- const int namelen = _tcslen(name);
-#endif
- for(register unsigned int i=0; i<n; ++i)
-#ifdef PUGOPT_NONSEG
- if(matches_attribute_name(name,namelen,i))
-#else
- if(matches_attribute_name(name,i))
-#endif
- return _root->attribute[i];
- return NULL;
- }
-
- //<summary>Map an attribute name to the index of that attribute, if found.</summary>
- //<param name="name">Pointer to name of attribute to find.</param>
- //<returns>Index of attribute, or -1 if not found.</returns>
- //<remarks>Implement your own hash table if you have a great many attributes.</remarks>
- int mapto_attribute_idx(const TCHAR* name)
- {
- if(!_root || !name) return -1;
- register unsigned int n = _root->attributes;
-#ifdef PUGOPT_NONSEG
- const int namelen = _tcslen(name);
-#endif
- for(register unsigned int i=0; i<n; ++i)
-#ifdef PUGOPT_NONSEG
- if(matches_attribute_name(name,namelen,i))
-#else
- if(matches_attribute_name(name,i))
-#endif
- return i;
- return -1;
- }
-
- //<summary>Map a child name to a pointer to the first instance, if found.</summary>
- //<param name="name">Reference to name of child to find.</param>
- //<returns>Index of child, or -1 if not found.</returns>
- //<remarks>Implement your own hash table if you have a great many children.</remarks>
- xml_node_struct* mapto_child_ptr(const std::string& name){ return mapto_child_ptr(name.c_str()); }
-
- //<summary>Map a child name to a pointer to the first instance, if found.</summary>
- //<param name="name">Pointer to name of child to find.</param>
- //<returns>Index of child, or -1 if not found.</returns>
- //<remarks>Implement your own hash table if you have a great many children.</remarks>
- xml_node_struct* mapto_child_ptr(const TCHAR* name)
- {
- if(!_root || !name) return NULL;
- register unsigned int n = _root->children;
-#ifdef PUGOPT_NONSEG
- const int namelen = _tcslen(name);
-#endif
- for(register unsigned int i=0; i<n; ++i)
- {
- if
- (
- _root->child[i]->name &&
-#ifdef PUGOPT_NONSEG
- matches_child_name(name,namelen,i)
-#else
- matches_child_name(name,i)
-#endif
- )
- return _root->child[i];
- }
- return NULL;
- }
-
- //<summary>Map a child name to the index of the first instance, if found.</summary>
- //<param name="name">Reference to name of child to find.</param>
- //<returns>Index of child, or -1 if not found.</returns>
- //<remarks>Implement your own hash table if you have a great many children.</remarks>
- int mapto_child_idx(const std::string& name){ return mapto_child_idx(name.c_str()); }
-
- //<summary>Map a child name to the index of the first instance, if found.</summary>
- //<param name="name">Pointer to name of child to find.</param>
- //<returns>Index of child, or -1 if not found.</returns>
- //<remarks>Implement your own hash table if you have a great many children.</remarks>
- int mapto_child_idx(const TCHAR* name)
- {
- if(!_root || !name) return -1;
- register unsigned int n = _root->children;
-#ifdef PUGOPT_NONSEG
- const int namelen = _tcslen(name);
-#endif
- for(register unsigned int i=0; i<n; ++i)
- {
- if
- (
- _root->child[i]->name &&
-#ifdef PUGOPT_NONSEG
- matches_child_name(name,namelen,i)
-#else
- matches_child_name(name,i)
-#endif
- )
- return i;
- }
- return -1;
- }
-
-//Traversal Helpers
-public:
-
- //<summary>Find all elements having the given name.</summary>
- //<param name="name">Reference to name of child to find.</param>
- //<param name="found">Reference to xml_node_list or pointer_array to receive the matching elements.
- void all_elements_by_name(const std::string& name,pointer_array& found){ all_elements_by_name(name.c_str(),found); }
-
- //<summary>Find all elements having the given name.</summary>
- //<param name="name">Pointer to name of child to find.</param>
- //<param name="found">Reference to xml_node_list or pointer_array to receive the matching elements.</param>
- void all_elements_by_name(const TCHAR* name,pointer_array& found)
- {
- if(empty() || !name) return; //Invalid node, so fail.
- if(_root->children > 0) //Has children.
- {
-#ifdef PUGOPT_NONSEG
- const unsigned int namelen = _tcslen(name);
-#endif
- register unsigned int n = _root->children; //For each child.
- for(register unsigned int i=0; i<n; ++i)
- {
- if
- (
- _root->child[i] && //There is a child at i.
- _root->child[i]->name && //The child has a name.
-#ifdef PUGOPT_NONSEG
- matches_child_name(name,namelen,i)
-#else
- matches_child_name(name,i)
-#endif
- )
- found.push_back(_root->child[i]); //push_back it to the array.
- if(_root->child[i]->children) //If there are children.
- {
- xml_node subsearch(_root->child[i]); //Wrap it up for ease.
- subsearch.all_elements_by_name(name,found); //Find any matching children.
- }
- }
- }
- }
-
- //<summary>
- // Recursively-implemented depth-first find the first matching element.
- // Use for shallow drill-downs.
- //</summary>
- //<param name="name">Const reference to name of element to find.</param>
- //<returns>Valid xml_node if such element named 'name' is found.</returns>
- //<remarks>xml_node may be invalid if not found; test with 'empty'.</remarks>
- xml_node first_element_by_name(const std::string& name){ return first_element_by_name(name.c_str()); }
-
- //<summary>
- // Recursively-implemented depth-first find the first matching element.
- // Use for shallow drill-downs.
- //</summary>
- //<param name="name">Pointer to name of element to find.</param>
- //<returns>Valid xml_node if such element named 'name' is found.</returns>
- //<remarks>xml_node may be invalid if not found; test with 'empty'.</remarks>
- xml_node first_element_by_name(const TCHAR* name)
- {
- if(empty() || !name) return xml_node(); //Invalid node, so fail.
- if(_root->children > 0) //Has children.
- {
- register unsigned int n = _root->children; //For each child.
-#ifdef PUGOPT_NONSEG
- const int namelen = _tcslen(name);
-#endif
- for(register unsigned int i=0; i<n; ++i)
- {
- if
- (
- _root->child[i]->name &&
-#ifdef PUGOPT_NONSEG
- matches_child_name(name,namelen,i)
-#else
- matches_child_name(name,i)
-#endif
- )
- return xml_node(_root->child[i]);
- else if(_root->child[i]->children)
- {
- xml_node subsearch(_root->child[i]); //Wrap it up for ease.
- xml_node found = subsearch.first_element_by_name(name);
- if(!found.empty()) return found; //Found.
- }
- }
- }
- return xml_node(); //Not found.
- }
-
- //<summary>
- // Recursively-implemented depth-first find the first matching element
- // also having matching PCDATA.
- //</summary>
- //<param name="name">Reference to name of element to find.</param>
- //<param name="value">Reference to PCDATA to find.</param>
- //<returns>Valid xml_node if such element named 'name' is found with PCDATA 'value'.</returns>
- //<remarks>xml_node may be invalid if not found; test with 'empty'.</remarks>
- xml_node first_element_by_value(const std::string& name,const std::string& value){ return first_element_by_value(name.c_str(),value.c_str()); }
-
- //<summary>
- // Recursively-implemented depth-first find the first matching element
- // also having matching PCDATA.
- //</summary>
- //<param name="name">Pointer to name of element to find.</param>
- //<param name="value">Pointer to PCDATA to find.</param>
- //<returns>Valid xml_node if such element named 'name' is found with PCDATA 'value'.</returns>
- //<remarks>xml_node may be invalid if not found; test with 'empty'.</remarks>
- xml_node first_element_by_value(const TCHAR* name,const TCHAR* value)
- {
- if(empty() || !name || !value) return xml_node(); //Invalid node, so fail.
- if(_root->children > 0) //Has children.
- {
- register unsigned int n = _root->children; //For each child.
-#ifdef PUGOPT_NONSEG
- const unsigned int namelen = _tcslen(name);
- const unsigned int valulen = _tcslen(value);
-#endif
- for(register unsigned int i=0; i<n; ++i)
- {
- if
- (
- _root->child[i] && //There is a child at i.
- _root->child[i]->name && //The child has a name.
-#ifdef PUGOPT_NONSEG
- matches_child_name(name,namelen,i)
-#else
- matches_child_name(name,i)
-#endif
- )
- {
- register unsigned int m = _root->child[i]->children; //For each child of child.
- for(register unsigned int j=0; j<m; ++j)
- {
- if
- (
- _root->child[i]->child[j] && //There is a child at j.
- _root->child[i]->child[j]->type == node_pcdata && //It is of the PCDATA type.
- _root->child[i]->child[j]->value && //It has data.
-#ifdef PUGOPT_NONSEG
- matches_value(value,valulen,_root->child[i]->child[j])
-#else
- matches_value(value,_root->child[i]->child[j])
-#endif
- )
- return xml_node(_root->child[i]); //Wrap it up and return.
- }
- }
- else if(_root->child[i] && _root->child[i]->children) //The child has children.
- {
- xml_node subsearch(_root->child[i]); //Wrap it up for ease.
- xml_node found = subsearch.first_element_by_value(name,value); //Search any children.
- if(!found.empty()) return found; //Found.
- }
- }
- }
- return xml_node(); //Not found.
- }
-
- //<summary>
- // Recursively-implemented depth-first find the first matching element
- // also having matching attribute.
- //</summary>
- //<param name="name">Reference to name of element to find.</param>
- //<param name="attr_name">Reference to name of attribute to find.</param>
- //<param name="attr_value">Reference to attribute value to find.</param>
- //<returns>Valid xml_node if such element named 'name' is found.</returns>
- //<remarks>xml_node may be invalid if not found; test with 'empty'.</remarks>
- xml_node first_element_by_attribute(const std::string& name,const std::string& attr_name,const std::string& attr_value){ return first_element_by_attribute(name.c_str(),attr_name.c_str(),attr_value.c_str()); }
-
- //<summary>
- // Recursively-implemented depth-first find the first matching element
- // also having matching attribute.
- //</summary>
- //<param name="name">Pointer to name of element to find.</param>
- //<param name="attr_name">Pointer to name of attribute to find.</param>
- //<param name="attr_value">Pointer to attribute value to find.</param>
- //<returns>Valid xml_node if such element named 'name' is found.</returns>
- //<remarks>xml_node may be invalid if not found; test with 'empty'.</remarks>
- xml_node first_element_by_attribute(const TCHAR* name,const TCHAR* attr_name,const TCHAR* attr_value)
- {
- if(empty() || !name || !attr_name || !attr_value) return xml_node(); //Invalid data, so fail.
- if(_root->children > 0) //Has children.
- {
-#ifdef PUGOPT_NONSEG
- const unsigned int namelen = _tcslen(name);
- const unsigned int attrlen = _tcslen(attr_name);
- const unsigned int valulen = _tcslen(attr_value);
-#endif
- register unsigned int n = _root->children; //For each child.
- for(register unsigned int i=0; i<n; ++i)
- {
- if
- (
- _root->child[i] && //There is a child at i.
- _root->child[i]->name && //The child has a name.
-#ifdef PUGOPT_NONSEG
- matches_name(name,namelen,_root->child[i])
-#else
- matches_name(name,_root->child[i])
-#endif
- )
- {
- register unsigned int m = _root->child[i]->attributes; //For each attribute of child.
- for(register unsigned int j=0; j<m; ++j)
- {
- if
- (
- _root->child[i]->attribute[j] && //There is an attribute at j.
- _root->child[i]->attribute[j]->name && //The attribute has a name.
-#ifdef PUGOPT_NONSEG
- matches_attribute_name(attr_name,attrlen,_root->child[i]->attribute[j]) &&
-#else
- matches_attribute_name(attr_name,_root->child[i]->attribute[j]) &&
-#endif
- _root->child[i]->attribute[j]->value && //The attribute has a value.
-#ifdef PUGOPT_NONSEG
- matches_attribute_name_value(attr_value,valulen,_root->child[i]->attribute[j])
-#else
- matches_attribute_name_value(attr_value,_root->child[i]->attribute[j])
-#endif
- )
- return xml_node(_root->child[i]); //Wrap it up and return.
- }
- }
- else if(_root->child[i] && _root->child[i]->children)
- {
- xml_node subsearch(_root->child[i]); //Wrap it up for ease.
- xml_node found = subsearch.first_element_by_attribute(name,attr_name,attr_value); //Search any children.
- if(!found.empty()) return found; //Found.
- }
- }
- }
- return xml_node(); //Not found.
- }
-
- //<summary>
- // Recursively-implemented depth-first find the first matching entity.
- // Use for shallow drill-downs.
- //</summary>
- //<param name="name">Pointer to name of element to find.</param>
- //<returns>Valid xml_node if such element named 'name' is found.</returns>
- //<remarks>xml_node may be invalid if not found; test with 'empty'.</remarks>
- xml_node first_node(xml_node_type type)
- {
- if(!_root) return xml_node();
- if(_root->children > 0) //Has children.
- {
- register unsigned int n = _root->children; //For each child.
- for(register unsigned int i=0; i<n; ++i)
- {
- if(_root->child[i]->type==type)
- return xml_node(_root->child[i]);
- else if(_root->child[i]->children)
- {
- xml_node subsearch(_root->child[i]);
- xml_node found = subsearch.first_node(type);
- if(!found.empty()) return found; //Found.
- }
- }
- }
- return xml_node(); //Not found.
- }
-
- //<summary>Move to the absolute root of the document tree.</summary>
- //<returns>True if the current node is valid.</returns>
- //<remarks>Member '_root' may now point to absolute root of the document.</remarks>
- bool moveto_root()
- {
- if(empty()) return false; //Nowhere to go.
- while(!type_document()) _root = _root->parent; //Keep stepping out until we hit the root.
- return true; //Success.
- }
-
- //<summary>Move to the current node's parent.</summary>
- //<returns>true if there is a parent and cursor is not parent, and cursor points thereto.</returns>
- //<remarks>'_root' may now point to parent.</remarks>
- bool moveto_parent()
- {
- if(empty() || type_document()) return false; //Invalid, or at the root (has no parent).
- _root = _root->parent; //Move to parent.
- return true; //Success.
- }
-
- //<summary>
- // Move to the current node's sibling at subscript. Equivalent to
- // 'moveto_child' following 'moveto_parent'.
- //</summary>
- //<param name="i">Subscript of sibling to move cursor to.</param>
- //<returns>True if valid subscript, and cursor points thereto.</returns>
- //<remarks>If matching co-node was found, '_root' points thereto.</remarks>
- bool moveto_sibling(unsigned int i)
- {
- if(empty()) return false; //Nowhere to go.
- xml_node_struct* restore = _root; //Save position in case invalid subscript & we want to restore.
- if(moveto_parent()) //Try to move to parent.
- {
- if(i < children()) //Subscript is in range. (Assume parent *does* have children.)
- {
- _root = _root->child[i]; //Move to child at subscript ('sibling').
- return true; //Success.
- }
- }
- _root = restore; //Bad subscript, or parent move; restore.
- return false;
- }
-
- //<summary>Move to the current node's first sibling matching given name.</summary>
- //<param name="name">Element name of sibling to move to.</param>
- //<returns>True if sibling was found, and cursor points thereto.</returns>
- //<remarks>If matching co-node was found, '_root' points thereto.</remarks>
- bool moveto_first_sibling(const std::string& name){ return moveto_first_sibling(name.c_str()); }
-
- //<summary>Move to the current node's first sibling matching given name.</summary>
- //<param name="name">Element name of sibling to move to.</param>
- //<returns>True if sibling was found, and cursor points thereto.</returns>
- //<remarks>If matching co-node was found, '_root' points thereto.</remarks>
- bool moveto_first_sibling(const TCHAR* name)
- {
- if(empty() || !name) return false; //Nowhere to go, or nothing to find.
- xml_node_struct* restore = _root; //Save position in case invalid subscript & we want to restore.
- if(moveto_parent()) //Try to move to parent.
- {
-#ifdef PUGOPT_NONSEG
- const unsigned int namelen = _tcslen(name);
-#endif
- register unsigned int n = children(); //Search for matching name
- for(register unsigned int i=0; i<n; ++i)
- {
- //NF 24 Jan 2003 Changed to get child(i) just once per iteration.
- xml_node node = child(i); //Access child node at subscript as xml_node or xml_node(NULL) if bad subscript.
- if(node.type_element()||node.type_pi()) //Other types won't have names.
- {
-#ifdef PUGOPT_NONSEG
- if(_tcsncmp(name,node.name(),max(namelen,node.name_size()))==0) //Do names match?
-#else
- if(strcmpwild(name,node.name())==0) //Do names match?
-#endif
- {
- _root = node; //Move there.
- return true; //Success.
- }
- }
- }
- }
- _root = restore; //Failed to locate any such sibling; restore position.
- return false;
- }
-
- //<summary>Move to the current node's child at subscript.</summary>
- //<param name="i">Subscript of child to move cursor to.</param>
- //<returns>true if valid subscript, and cursor points thereto.</returns>
- //<remarks>If matching sub-node was found, '_root' points thereto.</remarks>
- bool moveto_child(unsigned int i)
- {
- if(empty()) return false; //Null, so no children.
- if(has_child_nodes() && i < children()) //Has children and subscript is in bounds.
- {
- _root = child(i); //Move to the child at i.
- return true; //Success.
- }
- return false; //Failure.
- }
-
- //<summary>Move to the current node's child matching given name.</summary>
- //<param name="name">Element name of child to move to if found.</param>
- //<returns>True if child was found, and cursor points thereto.</returns>
- //<remarks>If matching sub-node was found, '_root' points thereto.</remarks>
- bool moveto_child(const std::string& name){ return moveto_child(name.c_str()); }
-
- //<summary>Move to the current node's child matching given name.</summary>
- //<param name="name">Element name of child to move to if found.</param>
- //<returns>True if child was found, and cursor points thereto.</returns>
- //<remarks>If matching sub-node was found, '_root' points thereto.</remarks>
- bool moveto_child(const TCHAR* name)
- {
- if(empty() || !name || !has_child_nodes()) return false; //The node is null, a name was not specified, or node has no children.
-#ifdef PUGOPT_NONSEG
- const unsigned int namelen = _tcslen(name);
-#endif
- register unsigned int n = children(); //For each child.
- for(register unsigned int i=0; i<n; ++i)
- {
- //NF 24 Jan 2003: Changed to get child(i) just once per iteration.
- xml_node node = child(i); //Access child node at subscript as xml_node or xml_node(NULL) if bad subscript.
-#ifdef PUGOPT_NONSEG
- if(_tcsncmp(name,node.name(),max(namelen,node.name_size()))==0) //Do names match?
-#else
- if(strcmpwild(name,node.name())==0) //If the name is identical with 'name'.
-#endif
- {
- _root = node; //Move to it.
- return true; //Success.
- }
- }
- return false; //Failure.
- }
-
- //<summary>Move to the current node's next sibling by position and name.</summary>
- //<param name="name">Name of sibling to move to if found.</param>
- //<returns>True if there is a next sibling, and cursor points thereto.</returns>
- bool moveto_next_sibling(const std::string& name){ return moveto_next_sibling(name.c_str()); }
-
- //<summary>Move to the current node's next sibling by position and name.</summary>
- //<param name="name">Name of sibling to move to if found.</param>
- //<returns>True if there is a next sibling, and cursor points thereto.</returns>
- bool moveto_next_sibling(const TCHAR* name)
- {
- if(empty() || type_document() || !_root->parent || !name) return false; //Null, or at root, or no name, so there are no valid matches.
-#ifdef PUGOPT_NONSEG
- const unsigned int namelen = _tcslen(name);
-#endif
- register unsigned int n = _root->parent->children; //For each child of parent.
- for(register unsigned int i=0; i<(n-1); ++i)
- {
- if
- (
- _root->parent->child[i] && //There is a child at i.
- _root->parent->child[i] == _root && //The child is identical with this node.
- i < (n-1) //This is not the last child.
- )
- {
- for(++i; i<n; ++i) //For each following child.
- {
- if
- (
- _root->parent->child[i] && //There is a child at i.
- _root->parent->child[i]->name && //The child's name is not null.
-#ifdef PUGOPT_NONSEG
- matches_name(name,namelen,_root->parent->child[i])
-#else
- matches_name(name,_root->parent->child[i])
-#endif
- )
- {
- moveto_sibling(i); //Move to it.
- return true; //Success.
- }
- }
- }
- }
- return false; //Failure.
- }
-
- //<summary>Move to the current node's next sibling by position.</summary>
- //<returns>True if there is a next sibling, and cursor points thereto.</returns>
- bool moveto_next_sibling()
- {
- if(empty() || type_document() || !_root->parent) return false; //Null or at root, so there are no valid siblings.
- register unsigned int n = _root->parent->children; //For each child of parent (each sibling).
- for(register unsigned int i=0; i<(n-1); ++i)
- {
- if
- (
- _root->parent->child[i] && //There is a child at i.
- _root->parent->child[i] == _root && //The child is identical with this node.
- i < (n-1) //This is not the last child.
- )
- {
- for(++i; i<n; ++i) //For each following child.
- {
- if(_root->parent->child[i]) //There is a child at i.
- {
- moveto_sibling(i); //Move to it.
- return true; //Success.
- }
- }
- }
- }
- return false; //Failure.
- }
-
- //<summary>Compile the absolute node path from root as a text string.</summary>
- //<param name="delimiter">Delimiter string to insert between element names.</param>
- //<returns>Path string (e.g. with '/' as delimiter, '/document/.../this'.</returns>
- std::string path(const TCHAR* delimiter = _T("/"))
- {
- TCHAR* path = NULL; //Current path.
- TCHAR* temp; //Temporary pointer.
- xml_node cursor = *this; //Make a copy.
-#ifdef PUGOPT_NONSEG
- unsigned int destlen = 0;
- strcatgrown_impl(&path,cursor.name(),destlen,cursor.name_size()); //Get this name.
-#else
- strcatgrow(&path,cursor.name()); //Get this name.
-#endif
- while(cursor.moveto_parent() && !cursor.type_document()) //Loop to parent (stopping on actual root because it has no name).
- {
- temp = NULL; //Mark as null so 'strcatgrow' will allocate memory.
-#ifdef PUGOPT_NONSEG
- destlen = 0;
- strcatgrown_impl(&temp,cursor.name(),destlen,cursor.name_size()); //Append next element name.
-#else
- strcatgrow(&temp,cursor.name()); //Append next element name.
-#endif
- strcatgrow(&temp,delimiter); //Append delimiter.
- strcatgrow(&temp,path); //Append current path.
- free(path); //Free the old path.
- path = temp; //Set path as new string.
- }
- temp = NULL;
- strcatgrow(&temp,delimiter); //Prepend final delimiter.
- strcatgrow(&temp,path); //Append current path.
- free(path); //Free the old path.
- std::string returns = temp; //Set path as new string.
- free(temp);
- return returns; //Return the path;
- }
-
- //<summary>Search for a node by path.</summary>
- //<param name="path">
- // Path string; e.g. './foo/bar' (relative to node), '/foo/bar' (relative
- // to root), '../foo/bar' (pop relative position).
- //</param>
- //<param name="delimiter">Delimiter string to use in tokenizing path.</param>
- //<returns>Matching node, or xml_node(NULL) if not found.</returns>
- xml_node first_element_by_path(const std::string& path,const std::string& delimiter = _T("/")){ return first_element_by_path(path.c_str(),delimiter.c_str()); }
-
- //<summary>Search for a node by path.</summary>
- //<param name="path">
- // Path string; e.g. './foo/bar' (relative to node), '/foo/bar' (relative
- // to root), '../foo/bar' (pop relative to position).
- //</param>
- //<param name="delimiter">Delimiter string to use in tokenizing path.</param>
- //<returns>Matching node, or xml_node(NULL) if not found.</returns>
- //<remarks>To-do: Support XPath-style queries.</remarks>
- xml_node first_element_by_path(const TCHAR* path,const TCHAR* delimiter = _T("/"))
- {
- if(!path) return xml_node();
- TCHAR* temp = NULL;
- pointer_array path_segments; //Array of path segments.
- xml_node found = *this; //Current search context.
- strcatgrow(&temp,path);
- TCHAR* name = _tcstok(temp,delimiter);
- while(name) //Tokenize the whole path.
- {
- path_segments.push_back((void*)name); //push_back it to array.
- name = _tcstok(NULL,delimiter); //Get the next token,
- }
- register unsigned int n = path_segments.size();
- if(n == 0) return xml_node(); //Return null node if no path segments.
- if(path[0]==delimiter[0]) found.moveto_root(); //Absolute path; e.g. '/foo/bar'
- for(register unsigned int i = 0; i<n; ++i) //For each path segment.
- {
- name = (TCHAR*)path_segments.at(i);
- if(name)
- {
- if(*name==_T('.')) //Is '.' or '..'
- {
- if(_tcscmp(name,_T(".."))==0) found.moveto_parent(); //Pop.
- else continue; //Ignore '.' since it is redundant if path is './path'.
- }
- else
- {
- register unsigned int j, m = found.children(); //For each child.
- for(j=0; j<m; ++j)
- {
- if(found.child(j).has_name(name)) //Name matches?
- {
- found = found.child(j); //Move to this child.
- goto NEXT_ELEM; //Search next path segment.
- }
- }
- if(found.moveto_next_sibling(found.name())) //Find next sibling having same name.
- {
- if(i > 0) --i; //Try the previous path segment.
- goto NEXT_ELEM;
- }
- else //Move to parent to search further.
- {
- if(!found.type_document() && found.moveto_parent() && !found.type_document()) //Not root and stepped to parent and parent is not root.
- {
- if(i > 0) --i; //Try the previous path segment.
- if(found.moveto_next_sibling(found.name())) //Try to find next sibling having same name.
- {
- if(i > 0) --i; //Try the previous path segment.
- goto NEXT_ELEM;
- }
- }
- }
- }
- }
-NEXT_ELEM:;
- if(found.type_document()) //Can't move up any higher, so fail.
- {
- free(temp); //Got to free this.
- return xml_node(); //Return null node.
- }
- }
- free(temp); //Got to free this.
- return found; //Return the matching node.
- }
-
- //<summary>Recursively traverse the tree.</summary>
- //<param name="walker">Reference to tree walker derived from xml_tree_walker.</param>
- //<returns>True if traversal was not halted by xml_tree_walker::for_each() callback.</returns>
- bool traverse(xml_tree_walker& walker)
- {
- if(walker.depth() == 0 && !walker.begin(*this)) return false; //Send the callback for begin traverse if depth is zero.
- if(!empty()) //Don't traveres if this is a null node.
- {
- walker.push(); //Increment the walker depth counter.
- register unsigned int n = _root->children; //For each child.
- for(register unsigned int i=0; i<n; ++i)
- {
- if(_root->child[i]) //There is a child at i.
- {
- xml_node subsearch(_root->child[i]); //Wrap it.
- if(!(walker.for_each(subsearch) && subsearch.traverse(walker)))
- return false; //Traversal was aborted.
- }
- }
- walker.pop(); //Decrement the walker depth counter.
- }
- if(walker.depth() == 0 && !walker.end(*this)) return false; //Send the callback for end traverse if depth is zero.
- return true;
- }
-
-//Editorial Helpers
-public:
-
- //<summary>Set element name.</summary>
- //<param name="new_name">New element name.</param>
- //<returns>Success.</returns>
- bool name(const std::string& new_name){ return name(new_name.c_str()); }
-
- //<summary>Set element name.</summary>
- //<param name="new_name">New element name.</param>
- //<returns>Success.</returns>
- bool name(const TCHAR* new_name)
- {
- if((type_element() || type_pi()) && new_name)
-#ifdef PUGOPT_NONSEG
- return strcpyinsitu(&_root->name,new_name,&_root->name_insitu,_root->name_size );
-#else
- return strcpyinsitu(&_root->name,new_name,&_root->name_insitu);
-#endif
- return false;
- }
-
- //<summary>Set node data.</summary>
- //<param name="value">New data (PCDATA, CDATA, or comment) value.</param>
- //<returns>Success.</returns>
- bool value(const std::string& new_value){ return value(new_value.c_str()); }
-
- //<summary>Set node data.</summary>
- //<param name="value">New data (PCDATA, CDATA, or comment) value.</param>
- //<returns>Success.</returns>
- bool value(const TCHAR* new_value)
- {
- if((type_pcdata() || type_cdata() || type_comment()) && new_value)
-#ifdef PUGOPT_NONSEG
- return strcpyinsitu(&_root->value,new_value,&_root->value_insitu,_root->value_size);
-#else
- return strcpyinsitu(&_root->value,new_value,&_root->value_insitu);
-#endif
- return false;
- }
-
- //<summary>Remove attribute at the given subscript.</summary>
- //<param name="i">Subscript.</param>
- //<returns>Success.</returns>
- bool remove_attribute(unsigned int i)
- {
- unsigned int n = _root->attributes;
- if(i < n)
- {
- xml_attribute_struct* temp = _root->attribute[i];
- --n;
- for(unsigned int j=i; j<n; ++j)
- _root->attribute[j] = _root->attribute[j+1];
- _root->attribute[n] = NULL;
- if(!temp->name_insitu) free(temp->name);
- if(!temp->value_insitu) free(temp->value);
- free(temp);
- --_root->attributes;
- return true;
- }
- return false;
- }
-
- //<summary>Remove attribute having the given name.</summary>
- //<param name="name">Name of attribute to delete.</param>
- //<returns>Success.</returns>
- bool remove_attribute(const std::string& name){ return remove_attribute(name.c_str()); }
-
- //<summary>Remove attribute having the given name.</summary>
- //<param name="name">Name of attribute to delete.</param>
- //<returns>Success.</returns>
- bool remove_attribute(const TCHAR* name)
- {
- int i = mapto_attribute_idx(name);
- if(i > -1) return remove_attribute((unsigned int)i);
- return false;
- }
-
- //<summary>Append a new attribute to the node list of attributes.</summary>
- //<param name="name">Name.</param>
- //<param name="value">Value thereof.</param>
- //<returns>Attribute structure wrapper.</returns>
- //<remarks>Pointer space may be grown, memory for name/value members allocated.</remarks>
- xml_attribute append_attribute(const std::string& name,const std::string& value){ return append_attribute(name.c_str(),value.c_str()); }
-
- //<summary>Append a new attribute to the node list of attributes.</summary>
- //<param name="name">Name.</param>
- //<param name="value">Value thereof.</param>
- //<returns>Attribute structure wrapper.</returns>
- //<remarks>Pointer space may be grown, memory for name/value members allocated.</remarks>
- xml_attribute append_attribute(const TCHAR* name,const TCHAR* value)
- {
- if(!name || !value) return xml_attribute(); //We must have both to proceed.
- xml_attribute_struct* p = pug::append_attribute(_root,1); //Append/allocate a new attribute structure.
- if(p) //If append/allocate succeeded.
- {
-#ifdef PUGOPT_NONSEG
- strcatgrown(&p->name,name,p->name_size); //Append the name.
- strcatgrown(&p->value,value,p->value_size); //Append the name.
-#else
- strcatgrow(&p->name,name); //Append the name.
- strcatgrow(&p->value,value); //Append the name.
-#endif
- p->name_insitu = p->value_insitu = false; //Mark as not part of original parse string.
- return xml_attribute(p); //Success.
- }
- return xml_attribute(); //Failure; return an empty.
- }
-
- //<summary>Append a new attribute of type long to the node list of attributes.</summary>
- //<param name="name">Name.</param>
- //<param name="value">Value thereof.</param>
- //<returns>Attribute structure wrapper.</returns>
- //<remarks>Pointer space may be grown, memory for name/value members allocated.</remarks>
- xml_attribute append_attribute(const TCHAR* name,long value)
- {
- if(!name) return false;
- TCHAR temp[32] = {0};
- _stprintf(temp,_T("%ld"),value);
- return append_attribute(name,temp);
- }
-
- //<summary>Append a new attribute of type double to the node list of attributes.</summary>
- //<param name="name">Name.</param>
- //<param name="value">Value thereof.</param>
- //<returns>Attribute structure wrapper.</returns>
- //<remarks>Pointer space may be grown, memory for name/value members allocated.</remarks>
- xml_attribute append_attribute(const TCHAR* name,double value)
- {
- if(!name) return false;
- TCHAR temp[32] = {0};
- _stprintf(temp,_T("%lf"),value);
- return append_attribute(name,temp);
- }
-
- //<summary>Append a new attribute of type bool to the node list of attributes.</summary>
- //<param name="name">Name.</param>
- //<param name="value">Value thereof.</param>
- //<returns>Attribute structure wrapper.</returns>
- //<remarks>Pointer space may be grown, memory for name/value members allocated.</remarks>
- xml_attribute append_attribute(const TCHAR* name,bool value)
- {
- if(!name) return false;
- return append_attribute(name,((value)?_T("true"):_T("false")));
- }
-
- //<summary>Set the current node entity type.</summary>
- //<param name="new_type">New type to set.</param>
- //<returns>Previous type.</returns>
- //<remarks>If has children and now is not node_element, children are obscured.</remarks>
- xml_node_type type(xml_node_type new_type)
- {
- xml_node_type prev = _root->type; //Save old type.
- _root->type = new_type; //Set new type.
- return prev; //Return old type.
- }
-
- //<summary>
- // Allocate & append a child node of the given type at the end of the
- // current node array of children.
- //</summary>
- //<param name="type">New child node type.</param>
- //<returns>xml_node wrapping the new child.</returns>
- //<remarks>Pointer space may be grown. An xml_node_struct structure is allocated.</remarks>
- xml_node append_child(xml_node_type type)
- {
- if(type_document()||type_element()) //Don't do anything if not an node_element or root.
- {
- xml_node_struct* p = pug::append_node(_root,1,type); //Append the node.
- if(p)
- {
- p->name_insitu = p->value_insitu = false;
- return xml_node(p); //If we have it, return wrapped.
- }
- }
- return xml_node(); //Return dummy.
- }
-
- //<summary>Allocate & insert a child node of the given type at subscript.</summary>
- //<param name="i">Subscript at which to insert.</param>
- //<param name="type">New child node type.</param>
- //<returns>xml_node wrapping the new child.</returns>
- //<remarks>
- // Pointer space may be grown. An xml_node_struct structure is allocated,
- // and existing children are shifted in their array position.
- //</remarks>
- xml_node insert_child(unsigned int i,xml_node_type type)
- {
- if(!type_element()) return xml_node(); //Don't do anything if not an node_element.
- unsigned int n = _root->children; //Get count of existing children.
- if(type_element() && i >= n) return append_child(type); //If subscript at end of array then just append.
- else if(type_element() && i < n)
- {
- xml_node_struct* p = pug::append_node(_root,1,type); //Append the new node (by default at last array position).
- if(p) //Ensure we have it.
- {
- register int m = (i-1); //Stop at i.
- for(register int j=(n-1); j>m; --j) //Starting at one less than end of array, reverse loop to i.
- _root->child[j+1] = _root->child[j]; //Shift node to right.
- _root->child[i] = p; //Set node at subscript to new node.
- return xml_node(p); //Return new node.
- }
- }
- return xml_node(); //Return dummy.
- }
-
- //<summary>Delete the child node at the given subscript.</summary>
- //<param name="i">Subscript.</param>
- //<returns>Success.</returns>
- //<remarks>Shifts child array element positions. Frees entire tree under child to be deleted.</remarks>
- bool remove_child(unsigned int i)
- {
- unsigned int n = _root->children;
- if(i < n) //Ensure subscript is in bounds.
- {
- xml_node_struct* p = _root->child[i]; //Keep a pointer to this node so we can free it.
- --n;
- unsigned int j;
- for(j=i; j<n; ++j) //Shift everything left from this point on.
- _root->child[j] = _root->child[j+1];
- _root->child[j] = NULL; //Mark the last element null.
- --_root->children; //One less children.
- p->parent = p; //This ensures we only free this node when calling 'free_node'.
- pug::free_node(p); //Free the node tree.
- return true; //Success.
- }
- return false; //Failure.
- }
-
- //Stream/Output Helpers
-public:
-
- //<summary>
- // Stream output. Recursively writes the internal xml_node_struct structure
- // to the given stream.
- //</summary>
- //<param name="os">Reference to output stream.</param>
- //<param name="indent_char">Char to use for indent.</param>
- //<param name="breaks">Use linebreaks?</param>
- //<remarks>String data is written to stream.</remarks>
- void outer_xml(std::basic_ostream<TCHAR,std::char_traits<TCHAR> >& os,TCHAR indent_char = _T('\t'),bool breaks = true)
- {
- if(empty()) return; //Make sure there is something to output.
- indent_stack indent(indent_char); //Prepare the indent.
- if(type_document()) //If this is the root, we don't want to output the root itself.
- {
- register unsigned int n = _root->children; //Output each child of the root.
- for(register unsigned int i=0; i<n; ++i)
- pug::outer_xml(os,indent,_root->child[i],breaks);
- }
- else pug::outer_xml(os,indent,_root,breaks); //Output the node.
- }
-
- //<summary>
- // Stream output operator. Wraps 'outer_xml'. Recursively writes
- // the given node to the given stream.
- //</summary>
- //<param name="os">Reference to output stream.</param>
- //<param name="xml_node">Reference to tree node.</param>
- //<returns>Reference to output stream.</returns>
- //<remarks>String data is written to stream.</remarks>
- friend std::basic_ostream<TCHAR,std::char_traits<TCHAR> >& operator<<(std::basic_ostream<TCHAR,std::char_traits<TCHAR> >& os,xml_node node)
- {
- if(!os.good()) return os;
- if((os.flags()|std::ostream::skipws) == std::ostream::skipws)
- node.outer_xml(os,0,false); //Skipping whitespace; suppress indents & linebreaks.
- else node.outer_xml(os); //Default options.
- return os;
- }
-};
-
-
-//<summary>Provides a high-level interface to the XML parser.</summary>
-class xml_parser
-{
-//Internal Data Members
-protected:
-
- xml_node_struct* _xmldoc; //Pointer to current XML document tree root.
- long _growby; //Attribute & child pointer space growth increment.
- bool _autdel; //Delete the tree on destruct?
- TCHAR* _buffer; //Pointer to in-memory buffer (for 'parse_file').
- TCHAR* _strpos; //Where parsing left off (for 'parse_file').
- unsigned long _optmsk; //Parser options.
-#ifdef PUGOPT_MEMFIL
- HANDLE _mmfile; //File handle.
- HANDLE _mmfmap; //Handle which maps the file.
- void* _mmaddr; //Base address of map.
- size_t _mfsize; //Size of memory-mapped file.
- bool _addeos; //True if we had to add a 0 to then end of the file.
-#endif
-
-//Construction/Destruction
-public:
-
- //<summary>Constructor.</summary>
- //<param name="optmsk">Options mask.</param>
- //<param name="autdel">Delete tree on destruct?</param>
- //<param name="growby">Parser pointer space growth increment.</param>
- //<remarks>Root node structure is allocated.</remarks>
- xml_parser(unsigned long optmsk = parse_default,bool autdel = true,long growby = parse_grow):
- _xmldoc(0),
- _growby(growby),
- _autdel(autdel),
- _optmsk(optmsk),
- _buffer(0),
- _strpos(0)
-#ifdef PUGOPT_MEMFIL
- ,
- _mmfile(0),
- _mmfmap(0),
- _mmaddr(0),
- _mfsize(0),
- _addeos(false)
-#endif
- {
- }
-
- //<summary>Direct parse constructor.</summary>
- //<param name="xmlstr">
- // XML-formatted string to parse. Note: String must persist for the
- // life of the tree. String is zero-segmented, but not freed.
- //</param>
- //<param name="optmsk">Parser options.</param>
- //<param name="autdel">Delete tree on destruct?</param>
- //<param name="growby">Parser pointer space growth increment.</param>
- //<remarks>Root node structure is allocated, string is parsed & tree may be grown.</remarks>
- xml_parser(TCHAR* xmlstr,unsigned long optmsk = parse_default,bool autdel = true,long growby = parse_grow) :
- _xmldoc(0),
- _growby(growby),
- _autdel(autdel),
- _optmsk(optmsk),
- _buffer(0),
- _strpos(0)
-#ifdef PUGOPT_MEMFIL
- ,
- _mmfile(0),
- _mmfmap(0),
- _mmaddr(0),
- _mfsize(0),
- _addeos(false)
-#endif
- {
- parse(xmlstr,_optmsk); //Parse it.
- }
-
- //<summary>Destructor.</summary>
- //<remarks>Tree memory and string memory may be freed.</remarks>
- virtual ~xml_parser()
- {
- if(_autdel && _xmldoc) free_node(_xmldoc);
- if(_buffer) free(_buffer);
-#ifdef PUGOPT_MEMFIL
- close_memfile();
-#endif
- }
-
-//Accessors/Operators
-public:
-
- operator xml_node_struct*() { return _xmldoc; } //Cast as xml_node_struct pointer to root.
- operator xml_node() { return xml_node(_xmldoc); } //Cast as xml_node (same as document).
- xml_node document(){ return xml_node(_xmldoc); } //Returns the root wrapped by an xml_node.
-
-//Miscellaneous
-public:
-
- //<summary>Allocate a new, empty root.</summary>
- //<remarks>Tree memory and string memory may be freed.</remarks>
- void create()
- {
- clear(); //Free any allocated memory.
- _xmldoc = new_node(node_document); //Allocate a new root.
- _xmldoc->parent = _xmldoc; //Point to self.
- }
-
- //<summary>Clear any existing tree or string.</summary>
- //<remarks>Tree memory and string memory may be freed.</remarks>
- void clear()
- {
- if(_xmldoc){ free_node(_xmldoc); _xmldoc = 0; }
- if(_buffer){ free(_buffer); _buffer = 0; }
-#ifdef PUGOPT_MEMFIL
- close_memfile();
-#endif
- }
-
-#ifdef PUGOPT_MEMFIL
-
-//Memory-Mapped File Support
-protected:
-
- //<summary>Closes any existing memory-mapped file.</summary>
- void close_memfile()
- {
- if(_mmaddr != 0)
- {
- UnmapViewOfFile(_mmaddr);
- _mmaddr = 0;
- }
- if(_mmfmap != 0)
- {
- CloseHandle(_mmfmap);
- _mmfmap = 0;
- }
- if(_mmfile != 0)
- {
- if(_addeos) //Remove the 0 we added to the end of the file.
- {
- SetFilePointer(_mmfile,_mfsize,NULL,FILE_BEGIN);
- SetEndOfFile(_mmfile);
- _addeos = false;
- }
- CloseHandle(_mmfile);
- _mmfile = 0;
- }
- _mfsize = 0;
- }
-
-public:
-
-#endif
-
- //<summary>Attach an externally-generated root to the parser.</summary>
- //<param name="root">Pointer to node structure.</param>
- //<returns>Pointer to old root if any.</returns>
- //<remarks>New root may be deleted on dtor if autodelete set.</remarks>
- xml_node_struct* attach(xml_node_struct* root)
- {
- xml_node_struct* t = _xmldoc; //Save this root.
- _xmldoc = root; //Assign.
- _xmldoc->parent = _xmldoc; //Ensure we are the root.
- return t; //Return the old root if any.
- }
-
- //<summary>Detach the current root from the parser.</summary>
- //<returns>Pointer to old root, if any.</returns>
- xml_node_struct* detach()
- {
- xml_node_struct* t = _xmldoc; //Save this root.
- _xmldoc = 0; //So we don't delete later on if autodelete set.
- return t; //Return the old root if any.
- }
-
- //<summary>Get parser optsions mask.</summary>
- //<returns>Options mask.</returns>
- unsigned long options(){ return _optmsk; }
-
- //<summary>Set parser options mask.</summary>
- //<param name="optmsk">Options mask to set.</param>
- //<returns>Old options mask.</returns>
- unsigned long options(unsigned long optmsk)
- {
- unsigned long prev = _optmsk;
- _optmsk = optmsk;
- return prev;
- }
-
- //<summary>Get pointer space growth size increment.</summary>
- //<returns>Grow size.</returns>
- unsigned long growby(){ return _growby; }
-
- //<summary>Set pointer space growth size increment.</summary>
- //<param name="grow">Grow size to set.</param>
- //<returns>Old size.</returns>
- unsigned long growby(long grow)
- {
- long prev = _growby;
- _growby = grow;
- return prev;
- }
-
- //<summary>Get parse file buffer last string position.</summary>
- //<returns>Last string position.</returns>
- //<remarks>
- // Use after parse_file, with parse_dtd_only set in order to recommence
- // parse of document body.
- //</remarks>
- TCHAR* strpos()
- {
- return _strpos;
- }
-
-//Parsing Helpers
-public:
-
- //<summary>Parse the given XML string in-situ.</summary>
- //<param name="s">Pointer to XML-formatted string.</param>
- //<param name="optmsk">Parser options mask.</param>
- //<returns>Last string position or null.</returns>
- //<remarks>Input string is zero-segmented.</remarks>
- TCHAR* parse(TCHAR* s,unsigned long optmsk = parse_noset)
- {
- if(!s) return s;
- clear(); //Free any allocated memory.
- _xmldoc = new_node(node_document); //Allocate a new root.
- _xmldoc->parent = _xmldoc; //Point to self.
- if(optmsk != parse_noset) _optmsk = optmsk;
- return pug::parse(s,_xmldoc,_growby,_optmsk); //Parse the input string.
- }
-
- /*
- //<summary>Load into memory and parse the contents of the file at the given path.</summary>
- //<param name="path">File path.</param>
- //<param name="optmsk">Parser options.</param>
- //<returns>Success if the file was loaded.</returns>
- //<remarks>
- // The file contents is loaded and stored in the member '_buffer' until
- // freed by calling 'Parse', 'parse_file', 'clear' or '~xml_parser'.
- //</remarks>
- bool parse_file(const TCHAR* path,unsigned long optmsk = parse_noset)
- {
- if(!path) return false;
- clear(); //clear any existing data.
- unsigned long bytes;
- if(optmsk != parse_noset) _optmsk = optmsk;
- if(load_file(path,&_buffer,&bytes) && bytes > 0)
- {
- _xmldoc = pug::new_node(node_document);
- _xmldoc->parent = _xmldoc; //Point to self.
- TCHAR* s = pug::parse(_buffer,_xmldoc,_growby,_optmsk);
- _strpos = s;
- return true;
- }
- return false;
- }
- */
-
-#ifdef PUGOPT_MEMFIL
-
- //<summary>Parse the contents of the file at the given path, using a memory-mapped file.</summary>
- //<param name="path">File path.</param>
- //<param name="optmsk">Parser options.</param>
- //<returns>
- // True (1) if the file was parsed successfully, false (0) if open failed,
- // and -1 if an exception occured.
- //</returns>
- //<remarks>
- // The file contents are available until closed by calling 'parse',
- // 'parse_file', 'clear' or '~xml_parser'.
- //</remarks>
- int parse_mmfile(const TCHAR* path,unsigned long optmsk = parse_noset)
- {
- int status = 0;
- if(path)
- {
- clear(); //Clear any existing data.
- if(optmsk != parse_noset) _optmsk = optmsk;
- assert((optmsk & parse_wnorm) == 0); //Normalization isn't implemented for memory-mapped files, as of 23 Jan 2003.
- const bool readonly = (optmsk & (parse_dtd|parse_dtd_only)) == 0;
- if(open_mmfile(path,readonly,false))
- {
- //If the file has a 0 at the end we are ok to proceed, otherwise add one.
- if
- (
- (
- *(((TCHAR*)_mmaddr) + _mfsize) == 0
- ||
- (
- _mfsize > 0 &&
- *(((TCHAR*)_mmaddr) + _mfsize - 1) == 0
- )
- )
- ||
- open_mmfile(path,false,true) //Re-open and add 0 at EOF.
- )
- {
- try
- {
- _xmldoc = new_node(node_document);
- _xmldoc->parent = _xmldoc; //Point to self.
- TCHAR* s = pug::parse((TCHAR*)_mmaddr,_xmldoc,_growby,_optmsk);
- _strpos = s;
- status = 1;
- }
- catch(...)
- {
- status = -1;
- assert(false);
- }
- }
- }
- }
- return status;
- }
-
-protected:
-
- //<summary>Opens the specified memory-mapped file.</summary>
- //<param name="path">File path.</param>
- //<param name="readonly">True to open the file for read-only access.</param>
- //<param name="addeos">True to add a 0 to the end of the file.</param>
- //<returns>Success if the file was opened.</returns>
- bool open_mmfile(const TCHAR* path,const bool readonly,const bool addeos)
- {
- clear(); //Close any existing MMF and clear any existing data.
- assert(_mmfile == NULL && _mmfile == NULL && _mmaddr == NULL);
- _addeos = false;
- _mmfile = CreateFile(path,readonly?GENERIC_READ:GENERIC_READ|GENERIC_WRITE,0,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL); //Open read-only, no share, no security attrs, ..., no template.
- if(_mmfile != INVALID_HANDLE_VALUE)
- {
- _mfsize = ::GetFileSize(_mmfile,NULL);
- _mmfmap = CreateFileMapping(_mmfile,NULL,readonly?PAGE_READONLY:PAGE_READWRITE,0,_mfsize+(addeos?sizeof(TCHAR):0),NULL); //Create map: handle, no security attr, read|read/write, larger if addeos, anonymous.
- if(_mmfmap != NULL)
- {
- assert(_mmaddr == NULL);
- _mmaddr = MapViewOfFile(_mmfmap,readonly?FILE_MAP_READ:FILE_MAP_WRITE,0,0,0); //Map the view: handle, read|read/write, start at beginning, map entire file.
- if(_mmaddr != NULL)
- {
- if(addeos) //Add a terminating 0 to the end of the file for 'parse()'.
- {
- assert(!readonly);
- *(((TCHAR*)_mmaddr) + _mfsize) = 0;
- _addeos = true;
- }
- }
- else
- {
- CloseHandle(_mmfmap);
- CloseHandle(_mmfile);
- _mmfile = _mmfmap = 0;
- }
- }
- else
- {
- CloseHandle(_mmfile);
- _mmfile = 0;
- }
- }
- return (_mmaddr != NULL);
- }
-
-#endif
-
-};
-
-
-//<summary>An array of nodes, used by xml_node queries.</summary>
-class xml_node_list: public pointer_array
-{
-public:
- xml_node_list(unsigned int grow = 4) : pointer_array(grow) { }
- virtual ~xml_node_list(){ }
-public:
- xml_node at(long i){ return xml_node((xml_node_struct*)pointer_array::at((unsigned int)i)); } //Access xml_node at subscript.
- xml_node operator[](long i){ return xml_node((xml_node_struct*)pointer_array::at((unsigned int)i)); } //Access xml_node at subscript.
- friend std::ostream& operator<<(std::ostream& os,xml_node_list& list) //Output helper.
- {
- if(!os.good()) return os;
- unsigned int n = list.size();
- for(unsigned int i=0; i<n; ++i) os << list[i];
- return os;
- }
-};
-
-
-} } } }
-
-// Undefine these horrible macros
-#undef PUGOPT_MEMFIL
-#undef PUGOPT_NONSEG
-#undef PUGAPI_INTERNAL_VARIANT
-#undef PUGAPI_INTERNAL_VERSION_MAJOR
-#undef PUGAPI_INTERNAL_VERSION_MINOR
-#undef PUGAPI_INTERNAL_VERSION
-#undef PUGDEF_ATTR_NAME_SIZE
-#undef PUGDEF_ATTR_VALU_SIZE
-#undef PUGDEF_ELEM_NAME_SIZE
-#undef SKIPWS
-#undef OPTSET
-#undef PUSHNODE
-#undef POPNODE
-#undef SCANFOR
-#undef SCANWHILE
-
-#ifdef UNDEF_LOHIWORD
- #undef HIWORD
- #undef LOWORD
- #undef UNDEF_LOHIWORD
-#endif
-
-#ifdef UNDEF_TCHAR_AND_REST
- #undef TCHAR
- #undef _tcslen
- #undef _istalnum
- #undef _tcsncpy
- #undef _tcscpy
- #undef _tcscmp
- #undef _tcstol
- #undef _tcstod
- #undef _tcstok
- #undef _stprintf
- #undef _T
- #undef UNDEF_TCHAR_AND_REST
-#endif
-
-#endif

Modified: branches/sredl_2009_05_proptree_update/boost/property_tree/detail/rapidxml.hpp
==============================================================================
--- branches/sredl_2009_05_proptree_update/boost/property_tree/detail/rapidxml.hpp (original)
+++ branches/sredl_2009_05_proptree_update/boost/property_tree/detail/rapidxml.hpp 2009-08-30 16:13:38 EDT (Sun, 30 Aug 2009)
@@ -1,22 +1,17 @@
-// ----------------------------------------------------------------------------
-// Copyright (C) 2006-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
-// This file is derived from RapidXml project, see http://rapidxml.sourceforge.net
-// ----------------------------------------------------------------------------
 #ifndef RAPIDXML_HPP_INCLUDED
 #define RAPIDXML_HPP_INCLUDED
 
-// Revision $DateTime: 2007/03/22 21:25:05 $
+// Copyright (C) 2006, 2009 Marcin Kalicinski
+// Version 1.13
+// Revision $DateTime: 2009/05/13 01:46:17 $
 //! \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
+// If standard library is disabled, user must provide implementations of required functions and typedefs
+#if !defined(RAPIDXML_NO_STDLIB)
+ #include <cstdlib> // For std::size_t
+ #include <cassert> // For assert
+ #include <new> // For placement new
+#endif
 
 // On MSVC, disable "conditional expression is constant" warning (level 4).
 // This warning is almost impossible to avoid with certain types of templated code
@@ -111,12 +106,37 @@
 
 #endif
 
+///////////////////////////////////////////////////////////////////////////
+// Pool sizes
+
+#ifndef RAPIDXML_STATIC_POOL_SIZE
+ // Size of static memory block of memory_pool.
+ // Define 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 RAPIDXML_STATIC_POOL_SIZE (64 * 1024)
+#endif
+
+#ifndef RAPIDXML_DYNAMIC_POOL_SIZE
+ // Size of dynamic memory block of memory_pool.
+ // Define 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 RAPIDXML_DYNAMIC_POOL_SIZE (64 * 1024)
+#endif
+
+#ifndef RAPIDXML_ALIGNMENT
+ // Memory allocation alignment.
+ // Define 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 RAPIDXML_ALIGNMENT sizeof(void *)
+#endif
+
 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.
@@ -136,63 +156,95 @@
     // 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 parse_no_element_values flag is also specified.
+ //! 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 leading and trailing whitespace of text,
- //! and condense all interior whitespace runs to a single space character.
+ //! 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.
- const int parse_normalize_whitespace = 0x400;
+ //! <br><br>
+ //! See xml_document::parse() function.
+ const int parse_normalize_whitespace = 0x800;
 
     // Compound flags
     
@@ -200,8 +252,10 @@
     //! 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 reads <code>parse_no_utf8</code>, it means that utf-8 is <i>enabled</i> by default,
+ //! 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.
@@ -211,14 +265,19 @@
     //! <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.
+ //! 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.
- const int parse_full = parse_declaration_node | parse_comment_nodes | parse_doctype_node | parse_pi_nodes | parse_validate_closing_tags | parse_normalize_whitespace;
+ //! <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
@@ -243,6 +302,7 @@
             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
@@ -257,16 +317,24 @@
 
         // Compare strings for equality
         template<class Ch>
- inline bool compare(const Ch *p1, std::size_t size1, const Ch *p2, std::size_t size2)
+ 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;
- for (const Ch *end = p1 + size1; p1 < end; ++p1, ++p2)
- if (*p1 != *p2)
- 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;
         }
-
     }
     //! \endcond
 
@@ -290,15 +358,24 @@
     //! 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>StaticBlockSize</code> bytes of statically allocated memory.
- //! Until this memory is exhausted, no dynamic memory allocations are performed.
- //! When static memory is exhausted, pool allocates additional chunks of memory,
- //! by using <code>new</code> and <code>delete</code> operators.
- //! This behaviour can be changed by suppyling custom allocation routines.
+ //! Pool maintains <code>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>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>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>RAPIDXML_STATIC_POOL_SIZE</code>, <code>RAPIDXML_DYNAMIC_POOL_SIZE</code> and <code>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.
- //! \param StaticBlockSize Size of static memory block owned by the pool, in bytes. Pool is guaranteed not to make dynamic memory allocations until this block is exhausted. Using too large static block will cause stack overflow if xml_document or memory_pool is allocated on the stack.
- template<class Ch, int StaticBlockSize>
+ template<class Ch = char>
     class memory_pool
     {
         
@@ -311,11 +388,10 @@
         
         //! Constructs empty pool with default allocator functions.
         memory_pool()
- : m_block(&m_static_block)
- , m_static_block(0)
- , m_alloc_func(0)
+ : m_alloc_func(0)
             , m_free_func(0)
         {
+ init();
         }
 
         //! Destroys pool and frees all the memory.
@@ -326,94 +402,53 @@
             clear();
         }
 
- //! Allocates a new node from the pool.
+ //! 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 parse_error_handler() function.
- //! \param type Type of node to allocate.
+ //! 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)
+ 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_memory(sizeof(xml_node<Ch>));
+ void *memory = allocate_aligned(sizeof(xml_node<Ch>));
             xml_node<Ch> *node = new(memory) xml_node<Ch>(type);
- return node;
- }
-
- //! Allocates a new element node from the pool and 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 parse_error_handler() function.
- //! \param name Name to assign to the element, or 0 to assign no name.
- //! \param value Value to assign to the element, or 0 to assign no value.
- //! \param name_size Size of name to assign, or 0 to automatically calculate from name string.
- //! \param value_size Size of value to assign, or 0 to automatically calculate from value string.
- //! \return Pointer to allocated element. This pointer will never be NULL.
- xml_node<Ch> *allocate_element(Ch *name, Ch *value = 0,
- std::size_t name_size = 0, std::size_t value_size = 0)
- {
- xml_node<Ch> *element = allocate_node(node_element);
             if (name)
             {
                 if (name_size > 0)
- element->name(name, name_size);
+ node->name(name, name_size);
                 else
- element->name(name);
+ node->name(name);
             }
             if (value)
             {
                 if (value_size > 0)
- element->value(value, value_size);
+ node->value(value, value_size);
                 else
- element->value(value);
+ node->value(value);
             }
- return element;
- }
-
- //! Allocates a new data node from the pool and assigns a 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 parse_error_handler() function.
- //! \param value Value to assign to the element, or 0 to assign no value.
- //! \param value_size Size of value to assign, or 0 to automatically calculate from value string.
- //! \return Pointer to allocated element. This pointer will never be NULL.
- xml_node<Ch> *allocate_data(Ch *value = 0, std::size_t value_size = 0)
- {
- xml_node<Ch> *data = allocate_node(node_data);
- if (value)
- {
- if (value_size > 0)
- data->value(value, value_size);
- else
- data->value(value);
- }
- return data;
- }
-
- //! Allocates a new attribute from the pool and 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 parse_error_handler() function.
- //! \return Pointer to allocated attribute. This pointer will never be NULL.
- xml_attribute<Ch> *allocate_attribute()
- {
- void *memory = allocate_memory(sizeof(xml_attribute<Ch>));
- xml_attribute<Ch> *attribute = new(memory) xml_attribute<Ch>;
- return attribute;
+ return node;
         }
 
- //! Allocates a new attribute from the pool and assigns name and value to it.
+ //! 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 parse_error_handler() 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 from name string.
- //! \param value_size Size of value to assign, or 0 to automatically calculate from value string.
+ //! \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(Ch *name, Ch *value = 0,
+ 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)
         {
- xml_attribute<Ch> *attribute = allocate_attribute();
+ void *memory = allocate_aligned(sizeof(xml_attribute<Ch>));
+ xml_attribute<Ch> *attribute = new(memory) xml_attribute<Ch>;
             if (name)
             {
                 if (name_size > 0)
@@ -431,53 +466,74 @@
             return attribute;
         }
 
- //! Allocates a char array of given size from the pool.
+ //! 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 parse_error_handler() function.
- //! \param size Number of characters to allocate.
+ //! 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(std::size_t size)
+ Ch *allocate_string(const Ch *source = 0, std::size_t size = 0)
         {
- assert(size > 0);
- void *memory = allocate_memory(size);
- return static_cast<Ch *>(memory);
- }
-
- //! Allocates a char array of appropriate size from the pool,
- //! and copies 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 parse_error_handler() function.
- //! \param source String to initialize the allocated memory with.
- //! \param size Number of characters to allocate, or zero to calculate it automatically from string length.
- //! \return Pointer to allocated char array. This pointer will never be NULL.
- Ch *allocate_string(const Ch *source, std::size_t size = 0)
- {
- assert(source);
+ assert(source || size); // Either source or size (or both) must be specified
             if (size == 0)
                 size = internal::measure(source) + 1;
- Ch *result = allocate_string(size);
- for (std::size_t i = 0; i < size; ++i)
- result[i] = source[i];
+ 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 will be freed.
- //! Nodes allocated from the pool will no longer be valid.
+ //! 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_block != &m_static_block)
+ while (m_begin != m_static_memory)
             {
- block *tmp = m_block->previous_block;
+ char *previous_begin = reinterpret_cast<header *>(align(m_begin))->previous_begin;
                 if (m_free_func)
- m_free_func(m_block);
+ m_free_func(m_begin);
                 else
- delete m_block;
- m_block = tmp;
+ delete[] m_begin;
+ m_begin = previous_begin;
             }
- m_block->pointer = m_block->data; // Restore static block pointer
+ init();
         }
 
         //! Sets or resets the user-defined memory allocation functions for the pool.
@@ -495,61 +551,91 @@
         //! \param ff Free function, or 0 to restore default function
         void set_allocator(alloc_func *af, free_func *ff)
         {
- assert(m_block == &m_static_block && m_block->pointer == m_block->data); // Verify that no memory is allocated
+ 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:
 
- // Memory block
- struct block
+ struct header
         {
- block(block *previous_block)
- : previous_block(previous_block)
- , pointer(data)
- {
- }
- block *previous_block; // Pointer to previous block in list (used during deallocation)
- char *pointer; // Pointer to first free byte in block
- char data[StaticBlockSize]; // Memory
+ char *previous_begin;
         };
 
- // Allocates memory from block
- void *allocate_memory(std::size_t size)
+ 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 = ((RAPIDXML_ALIGNMENT - (std::size_t(ptr) & (RAPIDXML_ALIGNMENT - 1))) & (RAPIDXML_ALIGNMENT - 1));
+ return ptr + alignment;
+ }
+
+ char *allocate_raw(std::size_t size)
         {
- if (size > StaticBlockSize)
- RAPIDXML_PARSE_ERROR("out of memory", 0);
- if (m_block->pointer - m_block->data + size > StaticBlockSize) // If current block exhausted, allocate a new block
+ // Allocate
+ void *memory;
+ if (m_alloc_func) // Allocate memory using either user-specified allocation function or global operator new[]
             {
- if (m_alloc_func)
- {
- void *memory = m_alloc_func(sizeof(block));
- assert(memory); // Allocator is not allowed to return 0, on failure it must either throw, stop the program or use longjmp
- m_block = new(memory) block(m_block);
- }
- else
- {
- m_block = new block(m_block);
+ 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];
 #ifdef RAPIDXML_NO_EXCEPTIONS
- // If exceptions are disabled, verify memory allocation, because new will not be able to throw bad_alloc
- if (!m_block)
- {
- RAPIDXML_PARSE_ERROR("out of memory", 0);
- }
+ if (!memory) // If exceptions are disabled, verify memory allocation, because new will not be able to throw bad_alloc
+ RAPIDXML_PARSE_ERROR("out of memory", 0);
 #endif
- }
             }
- char *result = m_block->pointer;
- m_block->pointer += size; // Advance pointer to after current allocation
- return result;
+ 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 RAPIDXML_DYNAMIC_POOL_SIZE)
+ std::size_t pool_size = RAPIDXML_DYNAMIC_POOL_SIZE;
+ if (pool_size < size)
+ pool_size = size;
+
+ // Allocate
+ std::size_t alloc_size = sizeof(header) + (2 * 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);
+ }
 
- block *m_block; // Current block
- block m_static_block; // Static block
- 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
+ // 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[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
     };
 
     ///////////////////////////////////////////////////////////////////////////
@@ -558,7 +644,7 @@
     //! 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>
+ template<class Ch = char>
     class xml_base
     {
 
@@ -580,7 +666,7 @@
     
         //! Gets name of the node.
         //! Interpretation of name depends on type of node.
- //! Note that name will not be zero-terminated if parse_no_string_terminators option was selected during parse.
+ //! 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.
@@ -599,7 +685,7 @@
 
         //! Gets value of node.
         //! Interpretation of value depends on type of node.
- //! Note that value will not be zero-terminated if parse_no_string_terminators option was selected during parse.
+ //! 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.
@@ -620,7 +706,7 @@
         // Node modification
     
         //! Sets name of node to a non zero-terminated string.
- //! See lifetimes of names and values.
+ //! 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.
@@ -628,7 +714,7 @@
         //! 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 it does not have to be zero terminated.
+ //! 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 name 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.
@@ -639,7 +725,7 @@
         }
 
         //! Sets name of node to a zero-terminated string.
- //! See lifetimes of names and values.
+ //! See also \ref ownership_of_strings and xml_node::name(const Ch *, std::size_t).
         //! \param name Name of node to set. Must be zero terminated.
         void name(const Ch *name)
         {
@@ -647,7 +733,7 @@
         }
 
         //! Sets value of node to a non zero-terminated string.
- //! See lifetimes of values and values.
+ //! 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.
@@ -657,6 +743,9 @@
         //! <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 value 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 *value, std::size_t size)
@@ -666,7 +755,7 @@
         }
 
         //! Sets value of node to a zero-terminated string.
- //! See lifetimes of names and values.
+ //! See also \ref ownership_of_strings and xml_node::value(const Ch *, std::size_t).
         //! \param value Vame of node to set. Must be zero terminated.
         void value(const Ch *value)
         {
@@ -677,7 +766,7 @@
         // Related nodes access
     
         //! Gets node parent.
- //! \return Pointer to parent node, or 0 if node has no parent.
+ //! \return Pointer to parent node, or 0 if there is no parent.
         xml_node<Ch> *parent() const
         {
             return m_parent;
@@ -705,7 +794,7 @@
     //! 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>
+ template<class Ch = char>
     class xml_attribute: public xml_base<Ch>
     {
 
@@ -725,62 +814,58 @@
         ///////////////////////////////////////////////////////////////////////////
         // Related nodes access
     
- //! Gets previous attribute.
- //! \return Pointer to previous sibling of attribute, or 0 if attribute has no previous sibling.
- xml_attribute<Ch> *previous_attribute() const
- {
- return this->m_parent && m_prev_attribute ? m_prev_attribute : 0;
- }
-
- //! Finds previous attribute with given name.
- //! \param name Name of attribute to find, must be zero-terminated
- //! \return Pointer to found attribute, or 0 if not found.
- xml_attribute<Ch> *previous_attribute(const Ch *name) const
- {
- assert(name);
- return previous_attribute(name, internal::measure(name));
- }
-
- //! Finds previous attribute with given name.
- //! \param name Name of attribute to find, doesn't have to be zero-terminated
- //! \param name_size Size of name, in characters
- //! \return Pointer to found attribute, or 0 if not found.
- xml_attribute<Ch> *previous_attribute(const Ch *name, std::size_t name_size) const
- {
- assert(name);
- for (xml_attribute<Ch> *attribute = previous_attribute(); attribute; attribute = attribute->previous_attribute())
- if (internal::compare(attribute->name(), attribute->name_size(), name, name_size))
- return attribute;
- return 0;
- }
-
- //! Gets next attribute.
- //! \return Pointer to next sibling of attribute, or 0 if attribute has no next sibling.
- xml_attribute<Ch> *next_attribute() const
- {
- return this->m_parent ? m_next_attribute : 0;
+ //! 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;
         }
 
- //! Finds next attribute with given name.
- //! \param name Name of attribute to find, must be zero-terminated
+ //! Gets previous attribute, optionally matching attribute name.
+ //! \param name 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 name_size is non-zero
+ //! \param name_size 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 *name) const
+ xml_attribute<Ch> *previous_attribute(const Ch *name = 0, std::size_t name_size = 0, bool case_sensitive = true) const
         {
- assert(name);
- return next_attribute(name, internal::measure(name));
+ if (name)
+ {
+ if (name_size == 0)
+ name_size = internal::measure(name);
+ for (xml_attribute<Ch> *attribute = m_prev_attribute; attribute; attribute = attribute->m_prev_attribute)
+ if (internal::compare(attribute->name(), attribute->name_size(), name, name_size, case_sensitive))
+ return attribute;
+ return 0;
+ }
+ else
+ return this->m_parent ? m_prev_attribute : 0;
         }
 
- //! Finds next attribute with given name.
- //! \param name Name of attribute to find, doesn't have to be zero-terminated
- //! \param name_size Size of name, in characters
+ //! Gets next attribute, optionally matching attribute name.
+ //! \param name 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 name_size is non-zero
+ //! \param name_size 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 *name, std::size_t name_size) const
+ xml_attribute<Ch> *next_attribute(const Ch *name = 0, std::size_t name_size = 0, bool case_sensitive = true) const
         {
- assert(name);
- for (xml_attribute<Ch> *attribute = next_attribute(); attribute; attribute = attribute->next_attribute())
- if (internal::compare(attribute->name(), attribute->name_size(), name, name_size))
- return attribute;
- return 0;
+ if (name)
+ {
+ if (name_size == 0)
+ name_size = internal::measure(name);
+ for (xml_attribute<Ch> *attribute = m_next_attribute; attribute; attribute = attribute->m_next_attribute)
+ if (internal::compare(attribute->name(), attribute->name_size(), name, name_size, case_sensitive))
+ return attribute;
+ return 0;
+ }
+ else
+ return this->m_parent ? m_next_attribute : 0;
         }
 
     private:
@@ -801,7 +886,7 @@
     //! 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>
+ template<class Ch = char>
     class xml_node: public xml_base<Ch>
     {
 
@@ -815,7 +900,7 @@
         //! \param type Type of node to construct.
         xml_node(node_type type)
             : m_type(type)
- , m_first_child(0)
+ , m_first_node(0)
             , m_first_attribute(0)
         {
         }
@@ -833,190 +918,143 @@
         ///////////////////////////////////////////////////////////////////////////
         // Related nodes access
     
- //! Gets first child of node
- //! \return Pointer to first child of node, or 0 if node has no children.
- xml_node<Ch> *first_child() const
+ //! 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 name 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 name_size is non-zero
+ //! \param name_size 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 *name = 0, std::size_t name_size = 0, bool case_sensitive = true) const
         {
- return m_first_child;
- }
-
- //! Finds first child of node with given name
- //! \param name Name of child to find, must be zero-terminated.
- //! \return Pointer to found child of node, or 0 if not found.
- xml_node<Ch> *first_child(const Ch *name) const
- {
- assert(name);
- return first_child(name, internal::measure(name));
- }
-
- //! Finds first child of node with given name
- //! \param name Name of child to find, doesn't have to be zero-terminated.
- //! \param name_size Size of name, in characters.
- //! \return Pointer to found child of node, or 0 if not found.
- xml_node<Ch> *first_child(const Ch *name, std::size_t name_size) const
- {
- assert(name);
- for (xml_node<Ch> *child = first_child(); child; child = child->next_sibling())
- if (internal::compare(child->name(), child->name_size(), name, name_size))
- return child;
- return 0;
- }
-
- //! Gets last child of node. Behaviour is undefined if node has no children.
- //! Use first_child() to test if node has children.
- //! \return Pointer to last child of node.
- xml_node<Ch> *last_child() const
- {
- assert(m_first_child); // Cannot query for last child if node has no children
- return m_last_child;
- }
-
- //! Finds last child of node with given name. Behaviour is undefined if node has no children.
- //! Use first_child() to test if node has children.
- //! \param name Name of child to find, must be zero-terminated
- //! \return Pointer to found child of node, or 0 if not found.
- xml_node<Ch> *last_child(const Ch *name) const
- {
- assert(name);
- return first_child(name, internal::measure(name));
+ if (name)
+ {
+ if (name_size == 0)
+ name_size = internal::measure(name);
+ for (xml_node<Ch> *child = m_first_node; child; child = child->next_sibling())
+ if (internal::compare(child->name(), child->name_size(), name, name_size, case_sensitive))
+ return child;
+ return 0;
+ }
+ else
+ return m_first_node;
         }
 
- //! Finds last child of node with given name. Behaviour is undefined if node has no children.
- //! Use first_child() to test if node has children.
- //! \param name Name of child to find, doesn't have to be zero-terminated
- //! \param name_size Size of name, in characters
- //! \return Pointer to found child of node, or 0 if not found.
- xml_node<Ch> *last_child(const Ch *name, std::size_t name_size) const
+ //! 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 name 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 name_size is non-zero
+ //! \param name_size 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 *name = 0, std::size_t name_size = 0, bool case_sensitive = true) const
         {
- assert(name);
- for (xml_node<Ch> *child = last_child(); child; child = child->prev_sibling())
- if (internal::compare(child->name(), child->name_size(), name, name_size))
- return child;
- return 0;
+ assert(m_first_node); // Cannot query for last child if node has no children
+ if (name)
+ {
+ if (name_size == 0)
+ name_size = internal::measure(name);
+ for (xml_node<Ch> *child = m_last_node; child; child = child->previous_sibling())
+ if (internal::compare(child->name(), child->name_size(), name, name_size, case_sensitive))
+ return child;
+ return 0;
+ }
+ else
+ return m_last_node;
         }
 
- //! Gets previous sibling of node. Behaviour is undefined if node has no parent.
+ //! 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.
- //! \return Pointer to previous sibling of node, or 0 if node has no previous sibling.
- xml_node<Ch> *previous_sibling() const
+ //! \param name 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 name_size is non-zero
+ //! \param name_size 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 *name = 0, std::size_t name_size = 0, bool case_sensitive = true) const
         {
             assert(this->m_parent); // Cannot query for siblings if node has no parent
- return m_prev_sibling;
- }
-
- //! Finds previous sibling of node with given name. Behaviour is undefined if node has no parent.
- //! Use parent() to test if node has a parent.
- //! \param name Name of sibling to find, must be zero-terminated
- //! \return Pointer to found sibling of node, or 0 if not found.
- xml_node<Ch> *previous_sibling(const Ch *name) const
- {
- assert(name);
- return previous_sibling(name, internal::measure(name));
- }
-
- //! Finds previous sibling of node with given name. Behaviour is undefined if node has no parent.
- //! Use parent() to test if node has a parent.
- //! \param name Name of sibling to find, doesn't have to be zero-terminated
- //! \param name_size Size of name, in characters
- //! \return Pointer to found sibling of node, or 0 if not found.
- xml_node<Ch> *previous_sibling(const Ch *name, std::size_t name_size) const
- {
- assert(name);
- for (xml_node<Ch> *sibling = previous_sibling(); sibling; sibling = sibling->previous_sibling())
- if (internal::compare(sibling->name(), sibling->name_size(), name, name_size))
- return sibling;
- return 0;
+ if (name)
+ {
+ if (name_size == 0)
+ name_size = internal::measure(name);
+ for (xml_node<Ch> *sibling = m_prev_sibling; sibling; sibling = sibling->m_prev_sibling)
+ if (internal::compare(sibling->name(), sibling->name_size(), name, name_size, case_sensitive))
+ return sibling;
+ return 0;
+ }
+ else
+ return m_prev_sibling;
         }
 
- //! Gets next sibling of node. Behaviour is undefined if node has no parent.
+ //! 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.
- //! \return Pointer to next sibling of node, or 0 if node has no next sibling.
- xml_node<Ch> *next_sibling() const
+ //! \param name 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 name_size is non-zero
+ //! \param name_size 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 *name = 0, std::size_t name_size = 0, bool case_sensitive = true) const
         {
             assert(this->m_parent); // Cannot query for siblings if node has no parent
- return m_next_sibling;
- }
-
- //! Finds next sibling of node with given name. Behaviour is undefined if node has no parent.
- //! Use parent() to test if node has a parent.
- //! \param name Name of sibling to find, must be zero-terminated.
- //! \return Pointer to found sibling of node, or 0 if not found.
- xml_node<Ch> *next_sibling(const Ch *name) const
- {
- assert(name);
- return next_sibling(name, internal::measure(name));
- }
-
- //! Finds next sibling of node with given name. Behaviour is undefined if node has no parent.
- //! Use parent() to test if node has a parent.
- //! \param name Name of sibling to find, doesn't have to be zero-terminated.
- //! \param name_size Size of name, in characters.
- //! \return Pointer to found sibling of node, or 0 if not found.
- xml_node<Ch> *next_sibling(const Ch *name, std::size_t name_size) const
- {
- assert(name);
- for (xml_node<Ch> *sibling = next_sibling(); sibling; sibling = sibling->next_sibling())
- if (internal::compare(sibling->name(), sibling->name_size(), name, name_size))
- return sibling;
- return 0;
- }
-
- //! Gets first attribute of node.
- //! \return Pointer to first attribute of node, or 0 if node has no attributes.
- xml_attribute<Ch> *first_attribute() const
- {
- return m_first_attribute;
- }
-
- //! Finds first attribute of node with given name.
- //! \param name Name of attribute to find, must be zero-terminated.
- //! \return Pointer to found attribute, or 0 if not found.
- xml_attribute<Ch> *first_attribute(const Ch *name) const
- {
- assert(name);
- return first_attribute(name, internal::measure(name));
- }
-
- //! Finds first attribute of node with given name
- //! \param name Name of attribute to find, doesn't have to be zero-terminated.
- //! \param name_size Size of name, in characters.
- //! \return Pointer to found attribute, or 0 if not found.
- xml_attribute<Ch> *first_attribute(const Ch *name, std::size_t name_size) const
- {
- assert(name);
- for (xml_attribute<Ch> *attribute = first_attribute(); attribute; attribute = attribute->next_attribute())
- if (internal::compare(attribute->name(), attribute->name_size(), name, name_size))
- return attribute;
- return 0;
- }
-
- //! Gets last attribute of node.
- //! \return Pointer to last attribute of node, or 0 if node has no attributes.
- xml_attribute<Ch> *last_attribute() const
- {
- return m_first_attribute ? m_last_attribute : 0;
+ if (name)
+ {
+ if (name_size == 0)
+ name_size = internal::measure(name);
+ for (xml_node<Ch> *sibling = m_next_sibling; sibling; sibling = sibling->m_next_sibling)
+ if (internal::compare(sibling->name(), sibling->name_size(), name, name_size, case_sensitive))
+ return sibling;
+ return 0;
+ }
+ else
+ return m_next_sibling;
         }
 
- //! Finds last attribute of node with given name.
- //! \param name Name of attribute to find, must be zero-terminated.
+ //! Gets first attribute of node, optionally matching attribute name.
+ //! \param name 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 name_size is non-zero
+ //! \param name_size 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 *name) const
+ xml_attribute<Ch> *first_attribute(const Ch *name = 0, std::size_t name_size = 0, bool case_sensitive = true) const
         {
- assert(name);
- return last_attribute(name, internal::measure(name));
+ if (name)
+ {
+ if (name_size == 0)
+ name_size = internal::measure(name);
+ for (xml_attribute<Ch> *attribute = m_first_attribute; attribute; attribute = attribute->m_next_attribute)
+ if (internal::compare(attribute->name(), attribute->name_size(), name, name_size, case_sensitive))
+ return attribute;
+ return 0;
+ }
+ else
+ return m_first_attribute;
         }
 
- //! Finds last attribute of node with given name.
- //! \param name Name of attribute to find, doesn't have to be zero-terminated.
- //! \param name_size Size of name, in characters.
+ //! Gets last attribute of node, optionally matching attribute name.
+ //! \param name 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 name_size is non-zero
+ //! \param name_size 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 *name, std::size_t name_size) const
+ xml_attribute<Ch> *last_attribute(const Ch *name = 0, std::size_t name_size = 0, bool case_sensitive = true) const
         {
- assert(name);
- for (xml_attribute<Ch> *attribute = last_attribute(); attribute; attribute = attribute->previous_attribute())
- if (internal::compare(attribute->name(), attribute->name_size(), name, name_size))
- return attribute;
- return 0;
+ if (name)
+ {
+ if (name_size == 0)
+ name_size = internal::measure(name);
+ for (xml_attribute<Ch> *attribute = m_last_attribute; attribute; attribute = attribute->m_prev_attribute)
+ if (internal::compare(attribute->name(), attribute->name_size(), name, name_size, case_sensitive))
+ return attribute;
+ return 0;
+ }
+ else
+ return m_first_attribute ? m_last_attribute : 0;
         }
 
         ///////////////////////////////////////////////////////////////////////////
@@ -1032,60 +1070,60 @@
         ///////////////////////////////////////////////////////////////////////////
         // Node manipulation
 
- //! Prepends a new child to the node.
+ //! 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_child(xml_node<Ch> *child)
+ void prepend_node(xml_node<Ch> *child)
         {
             assert(child && !child->parent() && child->type() != node_document);
- if (first_child())
+ if (first_node())
             {
- child->m_next_sibling = m_first_child;
- m_first_child->m_prev_sibling = child;
+ child->m_next_sibling = m_first_node;
+ m_first_node->m_prev_sibling = child;
             }
             else
             {
                 child->m_next_sibling = 0;
- m_last_child = child;
+ m_last_node = child;
             }
- m_first_child = child;
+ m_first_node = child;
             child->m_parent = this;
             child->m_prev_sibling = 0;
         }
 
- //! Appends a new child to the node.
+ //! Appends a new child node.
         //! The appended child becomes the last child.
         //! \param child Node to append.
- void append_child(xml_node<Ch> *child)
+ void append_node(xml_node<Ch> *child)
         {
             assert(child && !child->parent() && child->type() != node_document);
- if (first_child())
+ if (first_node())
             {
- child->m_prev_sibling = m_last_child;
- m_last_child->m_next_sibling = child;
+ child->m_prev_sibling = m_last_node;
+ m_last_node->m_next_sibling = child;
             }
             else
             {
                 child->m_prev_sibling = 0;
- m_first_child = child;
+ m_first_node = child;
             }
- m_last_child = child;
+ m_last_node = child;
             child->m_parent = this;
             child->m_next_sibling = 0;
         }
 
- //! Inserts a new child at specified place inside the node.
+ //! 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_child(xml_node<Ch> *where, xml_node<Ch> *child)
+ 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_child)
- prepend_child(child);
+ if (where == m_first_node)
+ prepend_node(child);
             else if (where == 0)
- append_child(child);
+ append_node(child);
             else
             {
                 child->m_prev_sibling = where->m_prev_sibling;
@@ -1096,48 +1134,48 @@
             }
         }
 
- //! Removes first child from the node.
+ //! Removes first child node.
         //! If node has no children, behaviour is undefined.
- //! Use first_child() to test if node has children.
- void remove_first_child()
+ //! Use first_node() to test if node has children.
+ void remove_first_node()
         {
- assert(first_child());
- xml_node<Ch> *child = m_first_child;
- m_first_child = child->m_next_sibling;
+ 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_child = 0;
+ m_last_node = 0;
             child->m_parent = 0;
         }
 
         //! Removes last child of the node.
         //! If node has no children, behaviour is undefined.
- //! Use first_child() to test if node has children.
- void remove_last_child()
+ //! Use first_node() to test if node has children.
+ void remove_last_node()
         {
- assert(first_child());
- xml_node<Ch> *child = m_last_child;
+ assert(first_node());
+ xml_node<Ch> *child = m_last_node;
             if (child->m_prev_sibling)
             {
- m_last_child = child->m_prev_sibling;
+ m_last_node = child->m_prev_sibling;
                 child->m_prev_sibling->m_next_sibling = 0;
             }
             else
- m_first_child = 0;
+ m_first_node = 0;
             child->m_parent = 0;
         }
 
         //! Removes specified child from the node
         // \param where Pointer to child to be removed.
- void remove_child(xml_node<Ch> *where)
+ void remove_node(xml_node<Ch> *where)
         {
             assert(where && where->parent() == this);
- assert(first_child());
- if (where == m_first_child)
- remove_first_child();
- else if (where == m_last_child)
- remove_last_child();
+ 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;
@@ -1146,12 +1184,12 @@
             }
         }
 
- //! Removes all children of node (but not attributes).
- void remove_all_children()
+ //! Removes all child nodes (but not attributes).
+ void remove_all_nodes()
         {
- for (xml_node<Ch> *node = first_child(); node; node = node->m_next_sibling)
+ for (xml_node<Ch> *node = first_node(); node; node = node->m_next_sibling)
                 node->m_parent = 0;
- m_first_child = 0;
+ m_first_node = 0;
         }
 
         //! Prepends a new attribute to the node.
@@ -1292,13 +1330,13 @@
         // unneded/redundant values.
         //
         // The rules are as follows:
- // 1. prev_sibling and next_sibling are valid only if node has a parent, otherwise they contain garbage
- // 2. last_child and last_attribute are valid only if node has one or more children/attributes respectively, otherwise they contain garbage
- // 3. Remaining pointers are always valid
+ // 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_child; // Pointer to first child of node, or 0 if none; always valid
- xml_node<Ch> *m_last_child; // Pointer to last child of node, or 0 if none; this value is only valid if m_first_child is non-zero
+ 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
@@ -1309,16 +1347,15 @@
     ///////////////////////////////////////////////////////////////////////////
     // XML document
     
- //! This class represents a root of the DOM hierarchy.
+ //! 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.
- //! \param StaticBlockSize Size of static block to use for allocating nodes; no dynamic memory allocations occur until this block is exhausted.
- template<class Ch, int StaticBlockSize = 128 * 1024>
- class xml_document: public xml_node<Ch>, public memory_pool<Ch, StaticBlockSize>
+ template<class Ch = char>
+ class xml_document: public xml_node<Ch>, public memory_pool<Ch>
     {
     
     public:
@@ -1330,20 +1367,24 @@
         }
 
         //! Parses zero-terminated XML string according to given flags.
- //! Passed string will be modified by the parser, unless parse_non_destructive flag is used.
+ //! 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, parse_error exception will be thrown.
+ //! 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);
             
- // Clear document
- clear();
+ // Remove current contents
+ this->remove_all_nodes();
+ this->remove_all_attributes();
             
             // Parse BOM, if any
             parse_bom<Flags>(text);
@@ -1361,7 +1402,7 @@
                 {
                     ++text; // Skip '<'
                     if (xml_node<Ch> *node = parse_node<Flags>(text))
- this->append_child(node);
+ this->append_node(node);
                 }
                 else
                     RAPIDXML_PARSE_ERROR("expected <", text);
@@ -1373,9 +1414,9 @@
         //! All nodes owned by document pool are destroyed.
         void clear()
         {
- this->remove_all_children();
+ this->remove_all_nodes();
             this->remove_all_attributes();
- memory_pool<Ch, StaticBlockSize>::clear();
+ memory_pool<Ch>::clear();
         }
         
     private:
@@ -1447,6 +1488,7 @@
                     return internal::lookup_tables<0>::lookup_attribute_data_1[static_cast<unsigned char>(ch)];
                 if (Quote == Ch('\"'))
                     return internal::lookup_tables<0>::lookup_attribute_data_2[static_cast<unsigned char>(ch)];
+ return 0; // Should never be executed, to avoid warnings on Comeau
             }
         };
 
@@ -1460,6 +1502,7 @@
                     return internal::lookup_tables<0>::lookup_attribute_data_1_pure[static_cast<unsigned char>(ch)];
                 if (Quote == Ch('\"'))
                     return internal::lookup_tables<0>::lookup_attribute_data_2_pure[static_cast<unsigned char>(ch)];
+ return 0; // Should never be executed, to avoid warnings on Comeau
             }
         };
 
@@ -1526,9 +1569,10 @@
         template<class StopPred, class StopPredPure, int Flags>
         static Ch *skip_and_expand_character_refs(Ch *&text)
         {
- // If entity translation and whitespace condense is disabled, use plain skip
+ // 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_normalize_whitespace) &&
+ !(Flags & parse_trim_whitespace))
             {
                 skip<StopPred, Flags>(text);
                 return text;
@@ -1895,50 +1939,54 @@
         template<int Flags>
         Ch parse_and_append_data(xml_node<Ch> *node, Ch *&text, Ch *contents_start)
         {
- Ch *value, *end;
+ // Backup to contents start if whitespace trimming is disabled
+ if (!(Flags & parse_trim_whitespace))
+ text = contents_start;
+
+ // Skip until end of data
+ Ch *value = text, *end;
             if (Flags & parse_normalize_whitespace)
- {
- value = text;
- end = skip_and_expand_character_refs<text_pred, text_pure_with_ws_pred, Flags>(text); // Skip until end of data
- }
+ end = skip_and_expand_character_refs<text_pred, text_pure_with_ws_pred, Flags>(text);
             else
- {
- value = contents_start; // Back up to to start of whitespace
- end = skip_and_expand_character_refs<text_pred, text_pure_no_ws_pred, Flags>(text); // Skip until end of data
- }
+ end = skip_and_expand_character_refs<text_pred, text_pure_no_ws_pred, Flags>(text);
 
- // If data present at all
- if (end > value)
+ // Trim trailing whitespace if flag is set; leading was already trimmed by whitespace skip after >
+ if (Flags & parse_trim_whitespace)
             {
- // Trim trailing whitespace, leading was already trimmed by whitespace skip after >
- // It is already condensed to single space characters by skipping function, so just trim 1 char off the end
- if ((Flags & parse_normalize_whitespace) && *(end - 1) == Ch(' '))
- --end;
-
- // If characters are still left between end and value (this test is only necessary if normalization is enabled)
- if (!(Flags & parse_normalize_whitespace) || end > value)
+ if (Flags & parse_normalize_whitespace)
                 {
- // Create new data node
- if (!(Flags & parse_no_data_nodes))
- {
- xml_node<Ch> *data = this->allocate_node(node_data);
- data->value(value, end - value);
- node->append_child(data);
- }
+ // 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(value, end - value);
+ 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(value, end - value);
+ // Add data to parent node if no data exists yet
+ if (!(Flags & parse_no_element_values))
+ if (*node->value() == Ch('\0'))
+ node->value(value, end - value);
 
- // Place zero terminator after value
- if (!(Flags & parse_no_string_terminators))
- {
- Ch ch = *text;
- *end = Ch('\0');
- return ch; // Return character that ends data
- }
- }
+ // 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
@@ -2122,7 +2170,7 @@
             while (1)
             {
                 // Skip whitespace between > and node contents
- Ch *contents_start = text;
+ Ch *contents_start = text; // Store start of node contents before whitespace is skipped
                 skip<whitespace_pred, Flags>(text);
                 Ch next_char = *text;
 
@@ -2147,7 +2195,7 @@
                             // 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))
+ if (!internal::compare(node->name(), node->name_size(), closing_name, text - closing_name, true))
                                 RAPIDXML_PARSE_ERROR("invalid closing tag name", text);
                         }
                         else
@@ -2167,14 +2215,13 @@
                         // Child node
                         ++text; // Skip '<'
                         if (xml_node<Ch> *child = parse_node<Flags>(text))
- node->append_child(child);
+ node->append_node(child);
                     }
                     break;
 
                 // End of data - error
                 case Ch('\0'):
                     RAPIDXML_PARSE_ERROR("unexpected end of data", text);
- break;
 
                 // Data node
                 default:
@@ -2511,6 +2558,28 @@
            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
 

Deleted: branches/sredl_2009_05_proptree_update/boost/property_tree/detail/xml_parser_read_pugixml.hpp
==============================================================================
--- branches/sredl_2009_05_proptree_update/boost/property_tree/detail/xml_parser_read_pugixml.hpp 2009-08-30 16:13:38 EDT (Sun, 30 Aug 2009)
+++ (empty file)
@@ -1,106 +0,0 @@
-// ----------------------------------------------------------------------------
-// Copyright (C) 2006-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
-// ----------------------------------------------------------------------------
-
-// PugiXML-based parser. To enable it define
-// BOOST_PROPERTY_TREE_XML_PARSER_PUGIXML before including xml_parser.hpp file.
-//
-// PugiXML library has to be obtained separately.
-// Check it out at http://code.google.com/p/pugixml/
-//
-// This module is derived from an example shipped as part of
-// the PugiXML documentation. This example contains the following notice:
-// Copyright (C) 2006, by Arseny Kapoulkine (arseny.kapoulkine_at_[hidden])
-
-#ifndef BOOST_PROPERTY_TREE_DETAIL_XML_PARSER_READ_PUGIXML_HPP_INCLUDED
-#define BOOST_PROPERTY_TREE_DETAIL_XML_PARSER_READ_PUGIXML_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 <pugixml.hpp>
-
-namespace boost { namespace property_tree { namespace xml_parser
-{
-
- template<class Ptree>
- void read_xml_node( pugi::xml_node node, Ptree &pt, int flags)
- {
- typedef typename Ptree::key_type::value_type Ch;
-
- switch ( node.type() )
- {
- case pugi::node_element:
- {
- Ptree &tmp = pt.push_back(std::make_pair( node.name(), Ptree()))->second;
- for ( pugi::xml_attribute attr = node.first_attribute(); attr; attr = attr.next_attribute() )
- tmp.put( xmlattr<Ch>() + "." + attr.name(), attr.value());
- for ( pugi::xml_node child = node.first_child(); child; child = child.next_sibling())
- read_xml_node(child, tmp, flags);
- }
- break;
- case pugi::node_pcdata:
- {
- if (flags & no_concat_text)
- pt.push_back(std::make_pair(xmltext<Ch>(), Ptree( node.value() )));
- else
- pt.data() += node.value();
- }
- break;
- case pugi::node_comment:
- {
- if (!(flags & no_comments))
- pt.push_back(std::make_pair(xmlcomment<Ch>(), Ptree( node.value() )));
- }
- break;
- default:
- // skip other 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;
-
- // Create and load document from stream
- stream.unsetf(std::ios::skipws);
-
- if (!stream.good())
- throw xml_parser_error("read error", filename, 0);
-
- std::vector<Ch> buf;
- std::copy(std::istream_iterator<Ch>(stream), std::istream_iterator<Ch>(), std::back_inserter(buf));
- buf.push_back(0); // zero-terminate
-
- unsigned int pugi_flags = pugi::parse_w3c;
- if ( flags & no_comments )
- pugi_flags = pugi_flags & ~pugi::parse_comments;
-
- pugi::xml_parser parser(&buf[0], pugi_flags);
- pugi::xml_node doc = parser.document();
-
- // Create ptree from nodes
- Ptree local;
- for ( pugi::xml_node child = doc.first_child(); child; child = child.next_sibling())
- read_xml_node( child, local, flags );
-
- // Swap local and result ptrees
- pt.swap(local);
- }
-
-} } }
-
-#endif

Deleted: branches/sredl_2009_05_proptree_update/boost/property_tree/detail/xml_parser_read_pugxml.hpp
==============================================================================
--- branches/sredl_2009_05_proptree_update/boost/property_tree/detail/xml_parser_read_pugxml.hpp 2009-08-30 16:13:38 EDT (Sun, 30 Aug 2009)
+++ (empty file)
@@ -1,82 +0,0 @@
-// ----------------------------------------------------------------------------
-// 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_READ_PUGXML_HPP_INCLUDED
-#define BOOST_PROPERTY_TREE_DETAIL_XML_PARSER_READ_PUGXML_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/pugxml.hpp>
-
-namespace boost { namespace property_tree { namespace xml_parser
-{
-
- template<class Ptree>
- void read_xml_node(pug::xml_node node, Ptree &pt, int flags)
- {
- typedef typename Ptree::key_type::value_type Ch;
- if (node.type() == pug::node_element ||
- node.type() == pug::node_document)
- {
- Ptree &tmp = pt.push_back(std::make_pair(node.name(), empty_ptree<Ptree>()))->second;
- for (pug::xml_node::attribute_iterator it = node.attributes_begin(); it != node.attributes_end(); ++it)
- tmp.put(xmlattr<Ch>() + Ch('.') + it->name(), it->value());
- for (pug::xml_node::child_iterator it = node.children_begin(); it != node.children_end(); ++it)
- read_xml_node(*it, tmp, flags);
- }
- else if (node.type() == pug::node_pcdata)
- {
- if (flags & no_concat_text)
- pt.push_back(std::make_pair(xmltext<Ch>(), Ptree(node.value())));
- else
- pt.data() += node.value();
- }
- else if (node.type() == pug::node_comment)
- {
- if (!(flags & no_comments))
- pt.push_back(std::make_pair(xmlcomment<Ch>(), Ptree(node.value())));
- }
- }
-
- 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;
-
- // Load data into vector
- std::vector<Ch> data(std::istreambuf_iterator<Ch>(stream.rdbuf()),
- std::istreambuf_iterator<Ch>());
- if (!stream.good())
- BOOST_PROPERTY_TREE_THROW(xml_parser_error("read error", filename, 0));
- data.push_back(Ch('\0'));
-
- // Parse
- pug::xml_parser parser;
- if (parser.parse(&data.front()))
- {
- Ptree local;
- pug::xml_node doc = parser.document();
- for (pug::xml_node::child_iterator it = doc.children_begin(); it != doc.children_end(); ++it)
- read_xml_node(*it, local, flags);
- local.swap(pt);
- }
- else
- BOOST_PROPERTY_TREE_THROW(xml_parser_error("parse error", filename, 0));
-
- }
-
-} } }
-
-#endif

Modified: branches/sredl_2009_05_proptree_update/boost/property_tree/detail/xml_parser_read_rapidxml.hpp
==============================================================================
--- branches/sredl_2009_05_proptree_update/boost/property_tree/detail/xml_parser_read_rapidxml.hpp (original)
+++ branches/sredl_2009_05_proptree_update/boost/property_tree/detail/xml_parser_read_rapidxml.hpp 2009-08-30 16:13:38 EDT (Sun, 30 Aug 2009)
@@ -41,9 +41,9 @@
                         pt_attr.data() = attr->value();
                     }
                 }
-
+
                 // Copy children
- for (rapidxml::xml_node<Ch> *child = node->first_child(); child; child = child->next_sibling())
+ for (rapidxml::xml_node<Ch> *child = node->first_node(); child; child = child->next_sibling())
                     read_xml_node(child, pt_node, flags);
             }
             break;
@@ -73,7 +73,8 @@
     }
 
     template<class Ptree>
- void read_xml_internal(std::basic_istream<typename Ptree::key_type::value_type> &stream,
+ void read_xml_internal(std::basic_istream<
+ typename Ptree::key_type::value_type> &stream,
                            Ptree &pt,
                            int flags,
                            const std::string &filename)
@@ -85,31 +86,34 @@
         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
+ BOOST_PROPERTY_TREE_THROW(
+ xml_parser_error("read error", filename, 0));
+ v.push_back(0); // zero-terminate
 
- try
- {
+ try {
             // Parse using appropriate flags
             using namespace rapidxml;
+ const int ncflags = parse_normalize_whitespace
+ | parse_trim_whitespace;
+ const int cflags = ncflags | parse_comment_nodes;
             xml_document<Ch> doc;
             if (flags & no_comments)
- doc.BOOST_NESTED_TEMPLATE parse<parse_normalize_whitespace>(&v.front());
+ doc.BOOST_NESTED_TEMPLATE parse<ncflags>(&v.front());
             else
- doc.BOOST_NESTED_TEMPLATE parse<parse_normalize_whitespace | parse_comment_nodes>(&v.front());
+ doc.BOOST_NESTED_TEMPLATE parse<cflags>(&v.front());
 
             // Create ptree from nodes
             Ptree local;
- for (rapidxml::xml_node<Ch> *child = doc.first_child(); child; child = child->next_sibling())
+ for (rapidxml::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 (rapidxml::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));
+ } catch (rapidxml::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));
         }
     }
 

Deleted: branches/sredl_2009_05_proptree_update/boost/property_tree/detail/xml_parser_read_spirit.hpp
==============================================================================
--- branches/sredl_2009_05_proptree_update/boost/property_tree/detail/xml_parser_read_spirit.hpp 2009-08-30 16:13:38 EDT (Sun, 30 Aug 2009)
+++ (empty file)
@@ -1,735 +0,0 @@
-// ----------------------------------------------------------------------------
-// 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)
-//
-// Based on XML grammar by Daniel C. Nuffer
-// http://spirit.sourceforge.net/repository/applications/xml.zip
-//
-// For more information, see www.boost.org
-// ----------------------------------------------------------------------------
-#ifndef BOOST_PROPERTY_TREE_DETAIL_XML_PARSER_READ_SPIRIT_HPP_INCLUDED
-#define BOOST_PROPERTY_TREE_DETAIL_XML_PARSER_READ_SPIRIT_HPP_INCLUDED
-
-//#define BOOST_SPIRIT_DEBUG
-
-#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/spirit/include/classic_spirit.hpp>
-#include <boost/spirit/include/classic_position_iterator.hpp>
-#include <string>
-#include <locale>
-#include <istream>
-#include <vector>
-
-namespace boost { namespace property_tree { namespace xml_parser
-{
-
- // XML parser context
- template<class Ptree>
- struct context
- {
-
- typedef typename Ptree::key_type::value_type Ch;
- typedef std::basic_string<Ch> Str;
- typedef typename Ptree::path_type Path;
- typedef boost::spirit::classic::position_iterator<typename std::vector<Ch>::const_iterator> It;
-
- int flags;
- std::vector<Ptree *> stack;
-
- ///////////////////////////////////////////////////////////////////////
- // Actions
-
- struct a_key_s
- {
- context &c;
- a_key_s(context &c): c(c) { }
- void operator()(It b, It e) const
- {
- if (c.stack.empty())
- BOOST_PROPERTY_TREE_THROW(xml_parser_error("xml parse error",
- detail::narrow(b.get_position().file.c_str()),
- b.get_position().line));
- Str name(b, e);
- Ptree *child = &c.stack.back()->push_back(std::make_pair(name, Ptree()))->second;
- c.stack.push_back(child);
- }
- };
-
- struct a_key_e
- {
- context &c;
- a_key_e(context &c): c(c) { }
- void operator()(It b, It e) const
- {
- if (c.stack.size() <= 1)
- BOOST_PROPERTY_TREE_THROW(xml_parser_error("xml parse error",
- detail::narrow(b.get_position().file.c_str()),
- b.get_position().line));
- c.stack.pop_back();
- }
- };
-
- struct a_content
- {
- context &c;
- a_content(context &c): c(c) { }
- void operator()(It b, It e) const
- {
- Str s = decode_char_entities(detail::trim(condense(Str(b, e))));
- if (!s.empty())
- {
- if (c.flags & no_concat_text)
- c.stack.back()->push_back(std::make_pair(xmltext<Ch>(), Ptree(s)));
- else
- c.stack.back()->put_value(c.stack.back()->template get_value<std::basic_string<Ch> >() + s);
- }
- }
- };
-
- struct a_attr_key
- {
- context &c;
- a_attr_key(context &c): c(c) { }
- void operator()(It b, It e) const
- {
- Path p(xmlattr<Ch>());
- p /= Str(b, e);
- c.stack.back()->put_child(p, empty_ptree<Ptree>());
- }
- };
-
- struct a_attr_data
- {
- context &c;
- a_attr_data(context &c): c(c) { }
- void operator()(It b, It e) const
- {
- Ptree &attr = c.stack.back()->get_child(xmlattr<Ch>());
- attr.back().second.put_value(Str(b.base() + 1, e.base() - 1));
- }
- };
-
- struct a_comment
- {
- context &c;
- a_comment(context &c): c(c) { }
- void operator()(It b, It e) const
- {
- c.stack.back()->push_back(std::make_pair(xmlcomment<Ch>(), Ptree(Str(b, e))));
- }
- };
-
- };
-
- ///////////////////////////////////////////////////////////////////////
- // Grammar
-
- template<class Ptree>
- struct xml_grammar :
- public boost::spirit::classic::grammar<xml_grammar<Ptree> >
- {
-
- typedef context<Ptree> context_t;
-
- mutable context_t c;
-
- template<class ScannerT>
- struct definition
- {
-
- typedef typename ScannerT::value_t char_t;
- typedef boost::spirit::classic::chset<char_t> chset_t;
-
- boost::spirit::classic::rule<ScannerT>
- prolog, element, Misc, PEReference, Reference, PITarget, CData,
- doctypedecl, XMLDecl, SDDecl, VersionInfo, EncodingDecl, VersionNum,
- Eq, DeclSep, ExternalID, markupdecl, NotationDecl, EntityDecl,
- AttlistDecl, elementdecl, TextDecl, extSubsetDecl, conditionalSect,
- EmptyElemTag, STag, content, ETag, Attribute, contentspec, Mixed,
- children, choice, seq, cp, AttDef, AttType, DefaultDecl, StringType,
- TokenizedType, EnumeratedType, NotationType, Enumeration, EntityValue,
- AttValue, SystemLiteral, PubidLiteral, CharDataChar, CharData, Comment,
- PI, CDSect, extSubset, includeSect, ignoreSect, ignoreSectContents,
- Ignore, CharRef, EntityRef, GEDecl, PEDecl, EntityDef, PEDef,
- NDataDecl, extParsedEnt, EncName, PublicID, document, S, Name, Names,
- Nmtoken, Nmtokens, STagB, STagE1, STagE2;
-
- definition(const xml_grammar &self)
- {
-
- using namespace boost::spirit::classic;
-
- // XML Char sets
- chset_t Char("\x9\xA\xD\x20-\x7F");
- chset_t Sch("\x20\x9\xD\xA");
- chset_t Letter("\x41-\x5A\x61-\x7A");
- chset_t Digit("0-9");
- chset_t XDigit("0-9A-Fa-f");
- chset_t Extender("\xB7");
- chset_t NameChar =
- Letter
- | Digit
- | (char_t)'.'
- | (char_t)'-'
- | (char_t)'_'
- | (char_t)':'
- | Extender;
-
- document =
- prolog >> element >> *Misc
- ;
-
- S =
- +(Sch)
- ;
-
- Name =
- (Letter | '_' | ':')
- >> *(NameChar)
- ;
-
- Names =
- Name >> *(S >> Name)
- ;
-
- Nmtoken =
- +NameChar
- ;
-
- Nmtokens =
- Nmtoken >> *(S >> Nmtoken)
- ;
-
- EntityValue =
- '"' >> *( (anychar_p - (chset_t(detail::widen<char_t>("%&\"").c_str())))
- | PEReference
- | Reference)
- >> '"'
- | '\'' >> *( (anychar_p - (chset_t("%&'")))
- | PEReference
- | Reference)
- >> '\''
- ;
-
- AttValue =
- '"' >> *( (anychar_p - (chset_t("<&\"")))
- | Reference)
- >> '"'
- | '\'' >> *( (anychar_p - (chset_t("<&'")))
- | Reference)
- >> '\''
- ;
-
- SystemLiteral=
- ('"' >> *(anychar_p - '"') >> '"')
- | ('\'' >> *(anychar_p - '\'') >> '\'')
- ;
-
- chset_t PubidChar("\x20\xD\xA'a-zA-Z0-9()+,./:=?;!*#@$_%-");
-
- PubidLiteral =
- '"' >> *PubidChar >> '"'
- | '\'' >> *(PubidChar - '\'') >> '\''
- ;
-
- CharDataChar =
- //anychar_p - (chset_t("<&"))
- anychar_p - (chset_t("<"))
- ;
-
- CharData =
- *(CharDataChar - "]]>")
- ;
-
- Comment =
- "<!--" >>
- (
- *(
- (Char - '-')
- | ('-' >> (Char - '-'))
- )
- )[typename context_t::a_comment(self.c)]
- >> "-->"
- ;
-
- PI =
- "<?" >> PITarget >> !(S >> (*(Char - "?>"))) >> "?>"
- ;
-
- PITarget =
- Name - (as_lower_d["xml"])
- ;
-
- CDSect =
- "<![CDATA[" >> CData >> "]]>"
- ;
-
- CData =
- *(Char - "]]>")
- ;
-
- prolog =
- !XMLDecl >> *Misc >> !(doctypedecl >> *Misc)
- ;
-
- XMLDecl =
- "<?xml" >> VersionInfo >> !EncodingDecl >> !SDDecl
- >> !S >> "?>"
- ;
-
- VersionInfo =
- S >> "version" >> Eq >>
- (
- '\'' >> VersionNum >> '\''
- | '"' >> VersionNum >> '"'
- )
- ;
-
- Eq =
- !S >> '=' >> !S
- ;
-
- chset_t VersionNumCh("a-zA-Z0-9_.:-");
-
- VersionNum =
- +(VersionNumCh)
- ;
-
- Misc =
- Comment
- | PI
- | S
- ;
-
- doctypedecl =
- "<!DOCTYPE" >> S >> Name >> !(S >> ExternalID) >> !S >>
- !(
- '[' >> *(markupdecl | DeclSep) >> ']' >> !S
- )
- >> '>'
- ;
-
- DeclSep =
- PEReference
- | S
- ;
-
- markupdecl =
- elementdecl
- | AttlistDecl
- | EntityDecl
- | NotationDecl
- | PI
- | Comment
- ;
-
- extSubset =
- !TextDecl >> extSubsetDecl
- ;
-
- extSubsetDecl =
- *(
- markupdecl
- | conditionalSect
- | DeclSep
- )
- ;
-
- SDDecl =
- S >> "standalone" >> Eq >>
- (
- ('\'' >> (str_p("yes") | "no") >> '\'')
- | ('"' >> (str_p("yes") | "no") >> '"')
- )
- ;
-
- /*
- element =
- EmptyElemTag
- | STag >> content >> ETag
- ;
- */
- element =
- STagB >> (STagE2 | (STagE1 >> content >> ETag))[typename context_t::a_key_e(self.c)]
- ;
-
- STag =
- '<' >> Name >> *(S >> Attribute) >> !S >> '>'
- ;
-
- STagB =
- '<'
- >> Name[typename context_t::a_key_s(self.c)]
- >> *(S >> Attribute)
- >> !S
- ;
-
- STagE1 =
- ch_p(">")
- ;
-
- STagE2 =
- str_p("/>")
- ;
-
- Attribute =
- Name[typename context_t::a_attr_key(self.c)]
- >> Eq
- >> AttValue[typename context_t::a_attr_data(self.c)]
- ;
-
- ETag =
- "</" >> Name >> !S >> '>'
- ;
-
- content =
- !(CharData[typename context_t::a_content(self.c)]) >>
- *(
- (
- element
- // | Reference
- | CDSect
- | PI
- | Comment
- ) >>
- !(CharData[typename context_t::a_content(self.c)])
- )
- ;
-
- EmptyElemTag =
- '<' >> Name >> *(S >> Attribute) >> !S >> "/>"
- ;
-
- elementdecl =
- "<!ELEMENT" >> S >> Name >> S >> contentspec >> !S >> '>'
- ;
-
- contentspec =
- str_p("EMPTY")
- | "ANY"
- | Mixed
- | children
- ;
-
- children =
- (choice | seq) >> !(ch_p('?') | '*' | '+')
- ;
-
- cp =
- (Name | choice | seq) >> !(ch_p('?') | '*' | '+')
- ;
-
- choice =
- '(' >> !S >> cp
- >> +(!S >> '|' >> !S >> cp)
- >> !S >> ')'
- ;
-
- seq =
- '(' >> !S >> cp >>
- *(!S >> ',' >> !S >> cp)
- >> !S >> ')'
- ;
-
- Mixed =
- '(' >> !S >> "#PCDATA"
- >> *(!S >> '|' >> !S >> Name)
- >> !S >> ")*"
- | '(' >> !S >> "#PCDATA" >> !S >> ')'
- ;
-
- AttlistDecl =
- "<!ATTLIST" >> S >> Name >> *AttDef >> !S >> '>'
- ;
-
- AttDef =
- S >> Name >> S >> AttType >> S >> DefaultDecl
- ;
-
- AttType =
- StringType
- | TokenizedType
- | EnumeratedType
- ;
-
- StringType =
- str_p("CDATA")
- ;
-
- TokenizedType =
- longest_d[
- str_p("ID")
- | "IDREF"
- | "IDREFS"
- | "ENTITY"
- | "ENTITIES"
- | "NMTOKEN"
- | "NMTOKENS"
- ]
- ;
-
- EnumeratedType =
- NotationType
- | Enumeration
- ;
-
- NotationType =
- "NOTATION" >> S >> '(' >> !S >> Name
- >> *(!S >> '|' >> !S >> Name)
- >> !S >> ')'
- ;
-
- Enumeration =
- '(' >> !S >> Nmtoken
- >> *(!S >> '|' >> !S >> Nmtoken)
- >> !S >> ')'
- ;
-
- DefaultDecl =
- str_p("#REQUIRED")
- | "#IMPLIED"
- | !("#FIXED" >> S) >> AttValue
- ;
-
- conditionalSect =
- includeSect
- | ignoreSect
- ;
-
- includeSect =
- "<![" >> !S >> "INCLUDE" >> !S
- >> '[' >> extSubsetDecl >> "]]>"
- ;
-
- ignoreSect =
- "<![" >> !S >> "IGNORE" >> !S
- >> '[' >> *ignoreSectContents >> "]]>"
- ;
-
- ignoreSectContents =
- Ignore >> *("<![" >> ignoreSectContents >> "]]>" >> Ignore)
- ;
-
- Ignore =
- *(Char - (str_p("<![") | "]]>"))
- ;
-
- CharRef =
- "&#" >> +Digit >> ';'
- | "&#x" >> +XDigit >> ';'
- ;
-
- Reference =
- EntityRef
- | CharRef
- ;
-
- EntityRef =
- '&' >> Name >> ';'
- ;
-
- PEReference =
- '%' >> Name >> ';'
- ;
-
- EntityDecl =
- GEDecl
- | PEDecl
- ;
-
- GEDecl =
- "<!ENTITY" >> S >> Name >> S >> EntityDef >> !S >> '>'
- ;
-
- PEDecl =
- "<!ENTITY" >> S >> '%' >> S >> Name >> S >> PEDef
- >> !S >> '>'
- ;
-
- EntityDef =
- EntityValue
- | ExternalID >> !NDataDecl
- ;
-
- PEDef =
- EntityValue
- | ExternalID
- ;
-
- ExternalID =
- "SYSTEM" >> S >> SystemLiteral
- | "PUBLIC" >> S >> PubidLiteral >> S >> SystemLiteral
- ;
-
- NDataDecl =
- S >> "NDATA" >> S >> Name
- ;
-
- TextDecl =
- "<?xml" >> !VersionInfo >> EncodingDecl >> !S >> "?>"
- ;
-
- extParsedEnt =
- !TextDecl >> content
- ;
-
- EncodingDecl =
- S >> "encoding" >> Eq
- >> ( '"' >> EncName >> '"'
- | '\'' >> EncName >> '\''
- )
- ;
-
- EncName =
- Letter >> *(Letter | Digit | '.' | '_' | '-')
- ;
-
- NotationDecl =
- "<!NOTATION" >> S >> Name >> S
- >> (ExternalID | PublicID) >> !S >> '>'
- ;
-
- PublicID =
- "PUBLIC" >> S >> PubidLiteral
- ;
-
- BOOST_SPIRIT_DEBUG_RULE(document);
- BOOST_SPIRIT_DEBUG_RULE(prolog);
- BOOST_SPIRIT_DEBUG_RULE(element);
- BOOST_SPIRIT_DEBUG_RULE(Misc);
- BOOST_SPIRIT_DEBUG_RULE(PEReference);
- BOOST_SPIRIT_DEBUG_RULE(Reference);
- BOOST_SPIRIT_DEBUG_RULE(PITarget);
- BOOST_SPIRIT_DEBUG_RULE(CData);
- BOOST_SPIRIT_DEBUG_RULE(doctypedecl);
- BOOST_SPIRIT_DEBUG_RULE(XMLDecl);
- BOOST_SPIRIT_DEBUG_RULE(SDDecl);
- BOOST_SPIRIT_DEBUG_RULE(VersionInfo);
- BOOST_SPIRIT_DEBUG_RULE(EncodingDecl);
- BOOST_SPIRIT_DEBUG_RULE(VersionNum);
- BOOST_SPIRIT_DEBUG_RULE(Eq);
- BOOST_SPIRIT_DEBUG_RULE(DeclSep);
- BOOST_SPIRIT_DEBUG_RULE(ExternalID);
- BOOST_SPIRIT_DEBUG_RULE(markupdecl);
- BOOST_SPIRIT_DEBUG_RULE(NotationDecl);
- BOOST_SPIRIT_DEBUG_RULE(EntityDecl);
- BOOST_SPIRIT_DEBUG_RULE(AttlistDecl);
- BOOST_SPIRIT_DEBUG_RULE(elementdecl);
- BOOST_SPIRIT_DEBUG_RULE(TextDecl);
- BOOST_SPIRIT_DEBUG_RULE(extSubsetDecl);
- BOOST_SPIRIT_DEBUG_RULE(conditionalSect);
- BOOST_SPIRIT_DEBUG_RULE(EmptyElemTag);
- BOOST_SPIRIT_DEBUG_RULE(STag);
- BOOST_SPIRIT_DEBUG_RULE(content);
- BOOST_SPIRIT_DEBUG_RULE(ETag);
- BOOST_SPIRIT_DEBUG_RULE(Attribute);
- BOOST_SPIRIT_DEBUG_RULE(contentspec);
- BOOST_SPIRIT_DEBUG_RULE(Mixed);
- BOOST_SPIRIT_DEBUG_RULE(children);
- BOOST_SPIRIT_DEBUG_RULE(choice);
- BOOST_SPIRIT_DEBUG_RULE(seq);
- BOOST_SPIRIT_DEBUG_RULE(cp);
- BOOST_SPIRIT_DEBUG_RULE(AttDef);
- BOOST_SPIRIT_DEBUG_RULE(AttType);
- BOOST_SPIRIT_DEBUG_RULE(DefaultDecl);
- BOOST_SPIRIT_DEBUG_RULE(StringType);
- BOOST_SPIRIT_DEBUG_RULE(TokenizedType);
- BOOST_SPIRIT_DEBUG_RULE(EnumeratedType);
- BOOST_SPIRIT_DEBUG_RULE(NotationType);
- BOOST_SPIRIT_DEBUG_RULE(Enumeration);
- BOOST_SPIRIT_DEBUG_RULE(EntityValue);
- BOOST_SPIRIT_DEBUG_RULE(AttValue);
- BOOST_SPIRIT_DEBUG_RULE(SystemLiteral);
- BOOST_SPIRIT_DEBUG_RULE(PubidLiteral);
- BOOST_SPIRIT_DEBUG_RULE(CharDataChar);
- BOOST_SPIRIT_DEBUG_RULE(CharData);
- BOOST_SPIRIT_DEBUG_RULE(Comment);
- BOOST_SPIRIT_DEBUG_RULE(PI);
- BOOST_SPIRIT_DEBUG_RULE(CDSect);
- BOOST_SPIRIT_DEBUG_RULE(extSubset);
- BOOST_SPIRIT_DEBUG_RULE(includeSect);
- BOOST_SPIRIT_DEBUG_RULE(ignoreSect);
- BOOST_SPIRIT_DEBUG_RULE(ignoreSectContents);
- BOOST_SPIRIT_DEBUG_RULE(Ignore);
- BOOST_SPIRIT_DEBUG_RULE(CharRef);
- BOOST_SPIRIT_DEBUG_RULE(EntityRef);
- BOOST_SPIRIT_DEBUG_RULE(GEDecl);
- BOOST_SPIRIT_DEBUG_RULE(PEDecl);
- BOOST_SPIRIT_DEBUG_RULE(EntityDef);
- BOOST_SPIRIT_DEBUG_RULE(PEDef);
- BOOST_SPIRIT_DEBUG_RULE(NDataDecl);
- BOOST_SPIRIT_DEBUG_RULE(extParsedEnt);
- BOOST_SPIRIT_DEBUG_RULE(EncName);
- BOOST_SPIRIT_DEBUG_RULE(PublicID);
- BOOST_SPIRIT_DEBUG_RULE(document);
- BOOST_SPIRIT_DEBUG_RULE(S);
- BOOST_SPIRIT_DEBUG_RULE(Name);
- BOOST_SPIRIT_DEBUG_RULE(Names);
- BOOST_SPIRIT_DEBUG_RULE(Nmtoken);
- BOOST_SPIRIT_DEBUG_RULE(Nmtokens);
- BOOST_SPIRIT_DEBUG_RULE(STagB);
- BOOST_SPIRIT_DEBUG_RULE(STagE1);
- BOOST_SPIRIT_DEBUG_RULE(STagE2);
-
- }
-
- const boost::spirit::classic::rule<ScannerT> &start() const
- {
- return document;
- }
-
- };
-
- };
-
- 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;
- typedef boost::spirit::classic::position_iterator<typename std::vector<Ch>::const_iterator> It;
-
- BOOST_ASSERT(validate_flags(flags));
-
- // Load data into vector
- 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));
-
- // Initialize iterators
- It begin(v.begin(), v.end());
- It end(v.end(), v.end());;
-
- begin.set_position(detail::widen<Ch>(filename.c_str()));
-
- // Prepare grammar
- Ptree local;
- xml_grammar<Ptree> g;
- g.c.stack.push_back(&local); // Push root ptree on context stack
- g.c.flags = flags;
-
- // Parse into local
- boost::spirit::classic::parse_info<It> result =
- boost::spirit::classic::parse(begin, end, g);
- if (!result.full || g.c.stack.size() != 1)
- BOOST_PROPERTY_TREE_THROW(xml_parser_error("xml parse error",
- detail::narrow(result.stop.get_position().file.c_str()),
- result.stop.get_position().line));
-
- // Swap local and pt
- pt.swap(local);
- }
-
-} } }
-
-#endif

Deleted: branches/sredl_2009_05_proptree_update/boost/property_tree/detail/xml_parser_read_tinyxml.hpp
==============================================================================
--- branches/sredl_2009_05_proptree_update/boost/property_tree/detail/xml_parser_read_tinyxml.hpp 2009-08-30 16:13:38 EDT (Sun, 30 Aug 2009)
+++ (empty file)
@@ -1,143 +0,0 @@
-// ----------------------------------------------------------------------------
-// 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_READ_TINYXML_HPP_INCLUDED
-#define BOOST_PROPERTY_TREE_DETAIL_XML_PARSER_READ_TINYXML_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 <tinyxml.h>
-
-namespace boost { namespace property_tree { namespace xml_parser
-{
-
-#ifdef TIXML_USE_STL
-
- template<class Ptree>
- void read_xml_node(TiXmlNode *node, Ptree &pt, int flags)
- {
-
- typedef typename Ptree::key_type::value_type Ch;
-
- if (TiXmlElement *elem = node->ToElement())
- {
- Ptree &tmp = pt.push_back(std::make_pair(elem->Value(), Ptree()))->second;
- for (TiXmlAttribute *attr = elem->FirstAttribute(); attr; attr = attr->Next())
- tmp.put(xmlattr<Ch>() + Ch('.') + attr->Name(), attr->Value());
- for (TiXmlNode *child = node->FirstChild(); child; child = child->NextSibling())
- read_xml_node(child, tmp, flags);
- }
- else if (TiXmlText *text = node->ToText())
- {
- if (flags & no_concat_text)
- pt.push_back(std::make_pair(xmltext<Ch>(), Ptree(text->Value())));
- else
- pt.data() += text->Value();
- }
- else if (TiXmlComment *comment = node->ToComment())
- {
- if (!(flags & no_comments))
- pt.push_back(std::make_pair(xmlcomment<Ch>(), Ptree(comment->Value())));
- }
- }
-
- 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)
- {
-
- // Create and load document from stream
- TiXmlDocument doc;
- stream >> doc;
- if (!stream.good())
- BOOST_PROPERTY_TREE_THROW(xml_parser_error("read error", filename, 0));
- if (doc.Error())
- BOOST_PROPERTY_TREE_THROW(xml_parser_error(doc.ErrorDesc(), filename, doc.ErrorRow()));
-
- // Create ptree from nodes
- Ptree local;
- for (TiXmlNode *child = doc.FirstChild(); child; child = child->NextSibling())
- read_xml_node(child, local, flags);
-
- // Swap local and result ptrees
- pt.swap(local);
-
- }
-
-#else
-
- template<class Ptree>
- void read_xml_node(TiXmlNode *node, Ptree &pt, int flags)
- {
-
- typedef typename Ptree::key_type::value_type Ch;
-
- if (TiXmlElement *elem = node->ToElement())
- {
- Ptree &tmp = pt.push_back(std::make_pair(elem->Value(), Ptree()))->second;
- for (TiXmlAttribute *attr = elem->FirstAttribute(); attr; attr = attr->Next())
- tmp.put(xmlattr<Ch>() + Ch('.') + attr->Name(), attr->Value());
- for (TiXmlNode *child = node->FirstChild(); child; child = child->NextSibling())
- read_xml_node(child, tmp, flags);
- }
- else if (TiXmlText *text = node->ToText())
- {
- if (flags & no_concat_text)
- pt.push_back(std::make_pair(xmltext<Ch>(), Ptree(text->Value())));
- else
- pt.data() += text->Value();
- }
- else if (TiXmlComment *comment = node->ToComment())
- {
- if (!(flags & no_comments))
- pt.push_back(std::make_pair(xmlcomment<Ch>(), Ptree(comment->Value())));
- }
- }
-
- 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)
- {
-
- // Load data into vector
- typedef typename Ptree::key_type::value_type Ch;
- std::vector<Ch> data(std::istreambuf_iterator<Ch>(stream.rdbuf()),
- std::istreambuf_iterator<Ch>());
- if (!stream.good())
- BOOST_PROPERTY_TREE_THROW(xml_parser_error("read error", filename, 0));
- data.push_back(Ch('\0'));
-
- // Create and load document
- TiXmlDocument doc;
- doc.Parse(&data.front());
- if (doc.Error())
- BOOST_PROPERTY_TREE_THROW(xml_parser_error(doc.ErrorDesc(), filename, doc.ErrorRow()));
-
- // Create ptree from nodes
- Ptree local;
- for (TiXmlNode *child = doc.FirstChild(); child; child = child->NextSibling())
- read_xml_node(child, local, flags);
-
- // Swap local and result ptrees
- pt.swap(local);
-
- }
-
-#endif
-
-} } }
-
-#endif

Modified: branches/sredl_2009_05_proptree_update/boost/property_tree/ptree_fwd.hpp
==============================================================================
--- branches/sredl_2009_05_proptree_update/boost/property_tree/ptree_fwd.hpp (original)
+++ branches/sredl_2009_05_proptree_update/boost/property_tree/ptree_fwd.hpp 2009-08-30 16:13:38 EDT (Sun, 30 Aug 2009)
@@ -34,7 +34,7 @@
     template <typename String, typename Translator>
     class string_path;
 
- // We'll want to do this with concepts in C++0x.
+ // Texas-style concepts for documentation only.
 #if 0
     concept PropertyTreePath<class Path> {
         // The key type for which this path works.

Modified: branches/sredl_2009_05_proptree_update/boost/property_tree/string_path.hpp
==============================================================================
--- branches/sredl_2009_05_proptree_update/boost/property_tree/string_path.hpp (original)
+++ branches/sredl_2009_05_proptree_update/boost/property_tree/string_path.hpp 2009-08-30 16:13:38 EDT (Sun, 30 Aug 2009)
@@ -49,15 +49,15 @@
         }
 
         template <typename Sequence>
- std::string dump_sequence(const Sequence &)
+ inline std::string dump_sequence(const Sequence &)
         {
             return "<undumpable sequence>";
         }
- std::string dump_sequence(const std::string &s)
+ inline std::string dump_sequence(const std::string &s)
         {
             return s;
         }
- std::string dump_sequence(const std::wstring &s)
+ inline std::string dump_sequence(const std::wstring &s)
         {
             return narrow(s.c_str());
         }

Modified: branches/sredl_2009_05_proptree_update/boost/property_tree/xml_parser.hpp
==============================================================================
--- branches/sredl_2009_05_proptree_update/boost/property_tree/xml_parser.hpp (original)
+++ branches/sredl_2009_05_proptree_update/boost/property_tree/xml_parser.hpp 2009-08-30 16:13:38 EDT (Sun, 30 Aug 2009)
@@ -1,5 +1,6 @@
 // ----------------------------------------------------------------------------
 // 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
@@ -15,19 +16,7 @@
 #include <boost/property_tree/detail/xml_parser_error.hpp>
 #include <boost/property_tree/detail/xml_parser_writer_settings.hpp>
 #include <boost/property_tree/detail/xml_parser_flags.hpp>
-
-// Include proper parser
-#if defined(BOOST_PROPERTY_TREE_XML_PARSER_TINYXML)
-#include <boost/property_tree/detail/xml_parser_read_tinyxml.hpp>
-#elif defined(BOOST_PROPERTY_TREE_XML_PARSER_PUGXML)
-#include <boost/property_tree/detail/xml_parser_read_pugxml.hpp>
-#elif defined(BOOST_PROPERTY_TREE_XML_PARSER_PUGIXML)
-#include <boost/property_tree/detail/xml_parser_read_pugixml.hpp>
-#elif defined(BOOST_PROPERTY_TREE_XML_PARSER_SPIRIT)
-#include <boost/property_tree/detail/xml_parser_read_spirit.hpp>
-#else
 #include <boost/property_tree/detail/xml_parser_read_rapidxml.hpp>
-#endif
 
 #include <fstream>
 #include <string>

Modified: branches/sredl_2009_05_proptree_update/libs/property_tree/test/Jamfile.v2
==============================================================================
--- branches/sredl_2009_05_proptree_update/libs/property_tree/test/Jamfile.v2 (original)
+++ branches/sredl_2009_05_proptree_update/libs/property_tree/test/Jamfile.v2 2009-08-30 16:13:38 EDT (Sun, 30 Aug 2009)
@@ -11,15 +11,9 @@
      # danieljames: The following tests were previously missing.
      # I don't know why.
 
- [ run test_xml_parser_spirit.cpp ]
      [ run test_multi_module1.cpp test_multi_module2.cpp ]
- [ run test_registry_parser.cpp ]
+ #[ run test_registry_parser.cpp ]
 
- # I think these require external dependencies:
- #
- # [ run test_xml_parser_pugxml.cpp ]
- # [ run test_xml_parser_tinyxml.cpp ]
-
      # The implementation for this seems to be missing:
      #
      # [ run test_cmdline_parser.cpp ]

Deleted: branches/sredl_2009_05_proptree_update/libs/property_tree/test/test_xml_parser_pugxml.cpp
==============================================================================
--- branches/sredl_2009_05_proptree_update/libs/property_tree/test/test_xml_parser_pugxml.cpp 2009-08-30 16:13:38 EDT (Sun, 30 Aug 2009)
+++ (empty file)
@@ -1,25 +0,0 @@
-// ----------------------------------------------------------------------------
-// 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
-// ----------------------------------------------------------------------------
-
-#define _CRT_SECURE_NO_DEPRECATE
-#define BOOST_PROPERTY_TREE_XML_PARSER_PUGXML
-#include "test_xml_parser_common.hpp"
-
-int test_main(int argc, char *argv[])
-{
- using namespace boost::property_tree;
- test_xml_parser<ptree>();
- //test_xml_parser<iptree>();
-#ifndef BOOST_NO_CWCHAR
- //test_xml_parser<wptree>();
- //test_xml_parser<wiptree>();
-#endif
- return 0;
-}

Deleted: branches/sredl_2009_05_proptree_update/libs/property_tree/test/test_xml_parser_spirit.cpp
==============================================================================
--- branches/sredl_2009_05_proptree_update/libs/property_tree/test/test_xml_parser_spirit.cpp 2009-08-30 16:13:38 EDT (Sun, 30 Aug 2009)
+++ (empty file)
@@ -1,24 +0,0 @@
-// ----------------------------------------------------------------------------
-// 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
-// ----------------------------------------------------------------------------
-
-#define BOOST_PROPERTY_TREE_XML_PARSER_SPIRIT
-#include "test_xml_parser_common.hpp"
-
-int test_main(int argc, char *argv[])
-{
- using namespace boost::property_tree;
- test_xml_parser<ptree>();
- test_xml_parser<iptree>();
-#ifndef BOOST_NO_CWCHAR
- test_xml_parser<wptree>();
- test_xml_parser<wiptree>();
-#endif
- return 0;
-}

Deleted: branches/sredl_2009_05_proptree_update/libs/property_tree/test/test_xml_parser_tinyxml.cpp
==============================================================================
--- branches/sredl_2009_05_proptree_update/libs/property_tree/test/test_xml_parser_tinyxml.cpp 2009-08-30 16:13:38 EDT (Sun, 30 Aug 2009)
+++ (empty file)
@@ -1,26 +0,0 @@
-// ----------------------------------------------------------------------------
-// Copyright (C) 2002-2005 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
-// ----------------------------------------------------------------------------
-
-#ifdef _DEBUG
- #pragma comment( lib, "tinyxmld_STL.lib" )
-#else
- #pragma comment( lib, "tinyxml_STL.lib" )
-#endif
-
-#define BOOST_PROPERTY_TREE_XML_PARSER_TINYXML
-#include "test_xml_parser_common.hpp"
-
-int test_main(int argc, char *argv[])
-{
- using namespace boost::property_tree;
- test_xml_parser<ptree>();
- test_xml_parser<iptree>();
- return 0;
-}


Boost-Commit list run by bdawes at acm.org, david.abrahams at rcn.com, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk