|
Boost-Commit : |
Subject: [Boost-commit] svn:boost r55966 - in trunk: boost/property_tree boost/property_tree/detail libs/property_tree libs/property_tree/doc libs/property_tree/examples libs/property_tree/test
From: sebastian.redl_at_[hidden]
Date: 2009-09-01 17:27:50
Author: cornedbee
Date: 2009-09-01 17:27:45 EDT (Tue, 01 Sep 2009)
New Revision: 55966
URL: http://svn.boost.org/trac/boost/changeset/55966
Log:
Merge proptree rewrite branch to trunk.
Added:
trunk/boost/property_tree/detail/exception_implementation.hpp
- copied unchanged from r55965, /branches/sredl_2009_05_proptree_update/boost/property_tree/detail/exception_implementation.hpp
trunk/boost/property_tree/exceptions.hpp
- copied unchanged from r55965, /branches/sredl_2009_05_proptree_update/boost/property_tree/exceptions.hpp
trunk/boost/property_tree/id_translator.hpp
- copied unchanged from r55965, /branches/sredl_2009_05_proptree_update/boost/property_tree/id_translator.hpp
trunk/boost/property_tree/stream_translator.hpp
- copied unchanged from r55965, /branches/sredl_2009_05_proptree_update/boost/property_tree/stream_translator.hpp
trunk/boost/property_tree/string_path.hpp
- copied unchanged from r55965, /branches/sredl_2009_05_proptree_update/boost/property_tree/string_path.hpp
trunk/libs/property_tree/breaking_changes.txt
- copied unchanged from r55965, /branches/sredl_2009_05_proptree_update/libs/property_tree/breaking_changes.txt
Removed:
trunk/boost/property_tree/detail/exceptions_implementation.hpp
trunk/boost/property_tree/detail/path_implementation.hpp
trunk/boost/property_tree/detail/pugxml.hpp
trunk/boost/property_tree/detail/translator_implementation.hpp
trunk/boost/property_tree/detail/xml_parser_read_pugixml.hpp
trunk/boost/property_tree/detail/xml_parser_read_pugxml.hpp
trunk/boost/property_tree/detail/xml_parser_read_spirit.hpp
trunk/boost/property_tree/detail/xml_parser_read_tinyxml.hpp
trunk/libs/property_tree/test/test_cmdline_parser.cpp
trunk/libs/property_tree/test/test_xml_parser_pugxml.cpp
trunk/libs/property_tree/test/test_xml_parser_spirit.cpp
trunk/libs/property_tree/test/test_xml_parser_tinyxml.cpp
Text files modified:
trunk/boost/property_tree/detail/file_parser_error.hpp | 45
trunk/boost/property_tree/detail/info_parser_error.hpp | 8
trunk/boost/property_tree/detail/info_parser_read.hpp | 117 ++-
trunk/boost/property_tree/detail/json_parser_read.hpp | 22
trunk/boost/property_tree/detail/ptree_implementation.hpp | 1099 +++++++++++++++++++++--------------
trunk/boost/property_tree/detail/ptree_utils.hpp | 28
trunk/boost/property_tree/detail/rapidxml.hpp | 1057 ++++++++++++++++++----------------
trunk/boost/property_tree/detail/xml_parser_error.hpp | 2
trunk/boost/property_tree/detail/xml_parser_read_rapidxml.hpp | 36
trunk/boost/property_tree/info_parser.hpp | 113 +-
trunk/boost/property_tree/ini_parser.hpp | 212 ++++--
trunk/boost/property_tree/json_parser.hpp | 61 +
trunk/boost/property_tree/ptree.hpp | 1203 +++++++++++++--------------------------
trunk/boost/property_tree/ptree_fwd.hpp | 121 ++-
trunk/boost/property_tree/ptree_serialization.hpp | 76 +-
trunk/boost/property_tree/xml_parser.hpp | 83 +-
trunk/libs/property_tree/doc/info_parser.qbk | 29
trunk/libs/property_tree/doc/ini_parser.qbk | 30
trunk/libs/property_tree/doc/json_parser.qbk | 29
trunk/libs/property_tree/doc/parsers.qbk | 11
trunk/libs/property_tree/doc/xml_parser.qbk | 66 +
trunk/libs/property_tree/examples/speed_test.cpp | 6
trunk/libs/property_tree/test/Jamfile.v2 | 15
trunk/libs/property_tree/test/test_info_parser.cpp | 4
trunk/libs/property_tree/test/test_ini_parser.cpp | 47
trunk/libs/property_tree/test/test_property_tree.cpp | 38
trunk/libs/property_tree/test/test_property_tree.hpp | 366 ++++++-----
trunk/libs/property_tree/test/test_utils.hpp | 23
trunk/libs/property_tree/test/test_xml_parser_common.hpp | 13
trunk/libs/property_tree/test/test_xml_parser_rapidxml.cpp | 10
trunk/libs/property_tree/test/xml_parser_test_data.hpp | 40
31 files changed, 2558 insertions(+), 2452 deletions(-)
Deleted: trunk/boost/property_tree/detail/exceptions_implementation.hpp
==============================================================================
--- trunk/boost/property_tree/detail/exceptions_implementation.hpp 2009-09-01 17:27:45 EDT (Tue, 01 Sep 2009)
+++ (empty file)
@@ -1,106 +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_EXCEPTIONS_IMPLEMENTATION_HPP_INCLUDED
-#define BOOST_PROPERTY_TREE_DETAIL_EXCEPTIONS_IMPLEMENTATION_HPP_INCLUDED
-
-namespace boost { namespace property_tree
-{
-
- namespace detail
- {
-
- // Default path-to-string converter; this is overridden for default path
- template<class P>
- std::string path_to_string(const P &path)
- {
- return std::string("<cannot convert path to string>");
- }
-
- // Helper for preparing what string in ptree_bad_path exception
- template<class P>
- std::string prepare_bad_path_what(const std::string &what, const P &path)
- {
- using namespace detail; // To allow correct resolution of path_to_string()
- return what + " (" + path_to_string(path) + ")";
- }
-
- // Default data-to-string converter; this is overridden for default data (string)
- template<class D>
- std::string data_to_string(const D &data)
- {
- return std::string("<cannot convert data to string>");
- }
-
- // Helper for preparing what string in ptree_bad_data exception
- template<class D>
- std::string prepare_bad_data_what(const std::string &what, const D &data)
- {
- using namespace detail; // To allow correct resolution of data_to_string()
- return what + " (" + data_to_string(data) + ")";
- }
-
- }
-
- ///////////////////////////////////////////////////////////////////////////
- // ptree_error
-
- inline ptree_error::ptree_error(const std::string &what):
- std::runtime_error(what)
- {
- }
-
- inline ptree_error::~ptree_error() throw()
- {
- }
-
- ///////////////////////////////////////////////////////////////////////////
- // ptree_bad_data
-
- template<class D>
- ptree_bad_data::ptree_bad_data(const std::string &what, const D &data):
- ptree_error(detail::prepare_bad_data_what(what, data)),
- m_data(data)
- {
- }
-
- inline ptree_bad_data::~ptree_bad_data() throw()
- {
- }
-
- template<class D>
- D ptree_bad_data::data()
- {
- return boost::any_cast<D>(m_data);
- }
-
- ///////////////////////////////////////////////////////////////////////////
- // ptree_bad_path
-
- template<class P>
- ptree_bad_path::ptree_bad_path(const std::string &what, const P &path):
- ptree_error(detail::prepare_bad_path_what(what, path)),
- m_path(path)
- {
-
- }
-
- inline ptree_bad_path::~ptree_bad_path() throw()
- {
- }
-
- template<class P>
- P ptree_bad_path::path()
- {
- return boost::any_cast<P>(m_path);
- }
-
-} }
-
-#endif
Modified: trunk/boost/property_tree/detail/file_parser_error.hpp
==============================================================================
--- trunk/boost/property_tree/detail/file_parser_error.hpp (original)
+++ trunk/boost/property_tree/detail/file_parser_error.hpp 2009-09-01 17:27:45 EDT (Tue, 01 Sep 2009)
@@ -24,30 +24,32 @@
///////////////////////////////////////////////////////////////////////
// Construction & destruction
-
+
// Construct error
- file_parser_error(const std::string &message,
- const std::string &filename,
- unsigned long line):
- ptree_error(format_what(message, filename, line)),
+ file_parser_error(const std::string &message,
+ const std::string &filename,
+ unsigned long line) :
+ ptree_error(format_what(message, filename, line)),
m_message(message), m_filename(filename), m_line(line)
- {
+ {
}
- ~file_parser_error() throw()
- // gcc 3.4.2 complains about lack of throw specifier on compiler generated dtor
+ ~file_parser_error() throw()
+ // gcc 3.4.2 complains about lack of throw specifier on compiler
+ // generated dtor
{
}
///////////////////////////////////////////////////////////////////////
// Data access
-
- // Get error message (without line and file - use what() to get full message)
+
+ // Get error message (without line and file - use what() to get
+ // full message)
std::string message()
{
return m_message;
}
-
+
// Get error filename
std::string filename()
{
@@ -55,29 +57,32 @@
}
// Get error line number
- unsigned long line()
- {
- return m_line;
+ unsigned long line()
+ {
+ return m_line;
}
private:
-
+
std::string m_message;
std::string m_filename;
unsigned long m_line;
// Format error message to be returned by std::runtime_error::what()
std::string format_what(const std::string &message,
- const std::string &filename,
+ const std::string &filename,
unsigned long line)
{
std::stringstream stream;
if (line > 0)
- stream << (filename.empty() ? "<unspecified file>" : filename.c_str()) <<
- '(' << line << "): " << message;
+ stream << (filename.empty() ? "<unspecified file>"
+ : filename.c_str())
+ << '(' << line << "): "
+ << message;
else
- stream << (filename.empty() ? "<unspecified file>" : filename.c_str()) <<
- ": " << message;
+ stream << (filename.empty() ? "<unspecified file>"
+ : filename.c_str())
+ << ": " << message;
return stream.str();
}
Modified: trunk/boost/property_tree/detail/info_parser_error.hpp
==============================================================================
--- trunk/boost/property_tree/detail/info_parser_error.hpp (original)
+++ trunk/boost/property_tree/detail/info_parser_error.hpp 2009-09-01 17:27:45 EDT (Tue, 01 Sep 2009)
@@ -19,11 +19,11 @@
class info_parser_error: public file_parser_error
{
public:
- info_parser_error(const std::string &message,
- const std::string &filename,
- unsigned long line):
+ info_parser_error(const std::string &message,
+ const std::string &filename,
+ unsigned long line) :
file_parser_error(message, filename, line)
- {
+ {
}
};
Modified: trunk/boost/property_tree/detail/info_parser_read.hpp
==============================================================================
--- trunk/boost/property_tree/detail/info_parser_read.hpp (original)
+++ trunk/boost/property_tree/detail/info_parser_read.hpp 2009-09-01 17:27:45 EDT (Tue, 01 Sep 2009)
@@ -21,10 +21,10 @@
namespace boost { namespace property_tree { namespace info_parser
{
-
+
// Expand known escape sequences
template<class It>
- std::basic_string<typename std::iterator_traits<It>::value_type>
+ std::basic_string<typename std::iterator_traits<It>::value_type>
expand_escapes(It b, It e)
{
typedef typename std::iterator_traits<It>::value_type Ch;
@@ -36,7 +36,8 @@
++b;
if (b == e)
{
- BOOST_PROPERTY_TREE_THROW(info_parser_error("character expected after backslash", "", 0));
+ BOOST_PROPERTY_TREE_THROW(info_parser_error(
+ "character expected after backslash", "", 0));
}
else if (*b == Ch('0')) result += Ch('\0');
else if (*b == Ch('a')) result += Ch('\a');
@@ -50,7 +51,8 @@
else if (*b == Ch('\'')) result += Ch('\'');
else if (*b == Ch('\\')) result += Ch('\\');
else
- BOOST_PROPERTY_TREE_THROW(info_parser_error("unknown escape sequence", "", 0));
+ BOOST_PROPERTY_TREE_THROW(info_parser_error(
+ "unknown escape sequence", "", 0));
}
else
result += *b;
@@ -58,7 +60,7 @@
}
return result;
}
-
+
// Advance pointer past whitespace
template<class Ch>
void skip_whitespace(const Ch *&text)
@@ -67,7 +69,7 @@
while (isspace(*text))
++text;
}
-
+
// Extract word (whitespace delimited) and advance pointer accordingly
template<class Ch>
std::basic_string<Ch> read_word(const Ch *&text)
@@ -102,10 +104,10 @@
skip_whitespace(text);
if (*text == Ch('\"'))
{
-
+
// Skip "
++text;
-
+
// Find end of string, but skip escaped "
bool escaped = false;
const Ch *start = text;
@@ -114,7 +116,7 @@
escaped = (!escaped && *text == Ch('\\'));
++text;
}
-
+
// If end of string found
if (*text == Ch('\"'))
{
@@ -123,13 +125,15 @@
if (*text == Ch('\\'))
{
if (!need_more_lines)
- BOOST_PROPERTY_TREE_THROW(info_parser_error("unexpected \\", "", 0));
+ BOOST_PROPERTY_TREE_THROW(info_parser_error(
+ "unexpected \\", "", 0));
++text;
skip_whitespace(text);
if (*text == Ch('\0') || *text == Ch(';'))
*need_more_lines = true;
else
- BOOST_PROPERTY_TREE_THROW(info_parser_error("expected end of line after \\", "", 0));
+ BOOST_PROPERTY_TREE_THROW(info_parser_error(
+ "expected end of line after \\", "", 0));
}
else
if (need_more_lines)
@@ -137,13 +141,14 @@
return result;
}
else
- BOOST_PROPERTY_TREE_THROW(info_parser_error("unexpected end of line", "", 0));
+ BOOST_PROPERTY_TREE_THROW(info_parser_error(
+ "unexpected end of line", "", 0));
}
else
BOOST_PROPERTY_TREE_THROW(info_parser_error("expected \"", "", 0));
}
-
+
// Extract key
template<class Ch>
std::basic_string<Ch> read_key(const Ch *&text)
@@ -170,89 +175,90 @@
}
// Build ptree from info stream
- template<class Ptree>
- void read_info_internal(std::basic_istream<typename Ptree::key_type::value_type> &stream,
- Ptree &pt,
+ template<class Ptree, class Ch>
+ void read_info_internal(std::basic_istream<Ch> &stream,
+ Ptree &pt,
const std::string &filename,
int include_depth)
{
-
- // Character type
- typedef typename Ptree::key_type::value_type Ch;
-
+ typedef std::basic_string<Ch> str_t;
// Possible parser states
- enum state_t {
+ enum state_t {
s_key, // Parser expects key
s_data, // Parser expects data
s_data_cont // Parser expects data continuation
};
-
+
unsigned long line_no = 0;
state_t state = s_key; // Parser state
Ptree *last = NULL; // Pointer to last created ptree
- std::basic_string<Ch> line; // Define line here to minimize reallocations
-
+ // Define line here to minimize reallocations
+ str_t line;
+
// Initialize ptree stack (used to handle nesting)
std::stack<Ptree *> stack;
stack.push(&pt); // Push root ptree on stack initially
-
- try
- {
-
+
+ try {
// While there are characters in the stream
- while (stream.good())
- {
-
+ while (stream.good()) {
// Read one line from stream
++line_no;
std::getline(stream, line);
if (!stream.good() && !stream.eof())
- BOOST_PROPERTY_TREE_THROW(info_parser_error("read error", "", 0));
+ BOOST_PROPERTY_TREE_THROW(info_parser_error(
+ "read error", filename, line_no));
const Ch *text = line.c_str();
// If directive found
skip_whitespace(text);
- if (*text == Ch('#'))
- {
-
+ if (*text == Ch('#')) {
// Determine directive type
++text; // skip #
std::basic_string<Ch> directive = read_word(text);
- if (directive == convert_chtype<Ch, char>("include")) // #include
- {
- if (include_depth > 100)
- BOOST_PROPERTY_TREE_THROW(info_parser_error("include depth too large, probably recursive include", "", 0));
- std::basic_string<Ch> s = read_string(text, NULL);
- std::string inc_name = convert_chtype<char, Ch>(s.c_str());
+ if (directive == convert_chtype<Ch, char>("include")) {
+ // #include
+ if (include_depth > 100) {
+ BOOST_PROPERTY_TREE_THROW(info_parser_error(
+ "include depth too large, "
+ "probably recursive include",
+ filename, line_no));
+ }
+ str_t s = read_string(text, NULL);
+ std::string inc_name =
+ convert_chtype<char, Ch>(s.c_str());
std::basic_ifstream<Ch> inc_stream(inc_name.c_str());
if (!inc_stream.good())
- BOOST_PROPERTY_TREE_THROW(info_parser_error("cannot open include file " + inc_name, "", 0));
- read_info_internal(inc_stream, *stack.top(), inc_name, include_depth + 1);
+ BOOST_PROPERTY_TREE_THROW(info_parser_error(
+ "cannot open include file " + inc_name,
+ filename, line_no));
+ read_info_internal(inc_stream, *stack.top(),
+ inc_name, include_depth + 1);
+ } else { // Unknown directive
+ BOOST_PROPERTY_TREE_THROW(info_parser_error(
+ "unknown directive", filename, line_no));
}
- else // Unknown directive
- BOOST_PROPERTY_TREE_THROW(info_parser_error("unknown directive", "", 0));
// Directive must be followed by end of line
skip_whitespace(text);
- if (*text != Ch('\0'))
- BOOST_PROPERTY_TREE_THROW(info_parser_error("expected end of line", "", 0));
+ if (*text != Ch('\0')) {
+ BOOST_PROPERTY_TREE_THROW(info_parser_error(
+ "expected end of line", filename, line_no));
+ }
// Go to next line
continue;
-
}
// While there are characters left in line
- while (1)
- {
+ while (1) {
// Stop parsing on end of line or comment
skip_whitespace(text);
- if (*text == Ch('\0') || *text == Ch(';'))
- {
+ if (*text == Ch('\0') || *text == Ch(';')) {
if (state == s_data) // If there was no data set state to s_key
state = s_key;
- break;
+ break;
}
// Process according to current parser state
@@ -282,7 +288,8 @@
else // Key text found
{
std::basic_string<Ch> key = read_key(text);
- last = &stack.top()->push_back(std::make_pair(key, Ptree()))->second;
+ last = &stack.top()->push_back(
+ std::make_pair(key, Ptree()))->second;
state = s_data;
}
@@ -367,7 +374,7 @@
}
}
-
+
} } }
#endif
Modified: trunk/boost/property_tree/detail/json_parser_read.hpp
==============================================================================
--- trunk/boost/property_tree/detail/json_parser_read.hpp (original)
+++ trunk/boost/property_tree/detail/json_parser_read.hpp 2009-09-01 17:27:45 EDT (Tue, 01 Sep 2009)
@@ -15,7 +15,7 @@
#include <boost/property_tree/ptree.hpp>
#include <boost/property_tree/detail/ptree_utils.hpp>
#include <boost/property_tree/detail/json_parser_error.hpp>
-#include <boost/spirit.hpp>
+#include <boost/spirit/include/classic.hpp>
#include <boost/limits.hpp>
#include <string>
#include <locale>
@@ -154,9 +154,10 @@
///////////////////////////////////////////////////////////////////////
// Json grammar
-
+
template<class Ptree>
- struct json_grammar: public boost::spirit::grammar<json_grammar<Ptree> >
+ struct json_grammar :
+ public boost::spirit::classic::grammar<json_grammar<Ptree> >
{
typedef context<Ptree> Context;
@@ -168,13 +169,16 @@
struct definition
{
- boost::spirit::rule<Scanner> root, object, member, array, item, value, string, number;
- boost::spirit::rule<typename boost::spirit::lexeme_scanner<Scanner>::type> character, escape;
+ boost::spirit::classic::rule<Scanner>
+ root, object, member, array, item, value, string, number;
+ boost::spirit::classic::rule<
+ typename boost::spirit::classic::lexeme_scanner<Scanner>::type>
+ character, escape;
definition(const json_grammar &self)
{
-
- using namespace boost::spirit;
+
+ using namespace boost::spirit::classic;
// Assertions
assertion<std::string> expect_object("expected object");
@@ -260,7 +264,7 @@
}
- const boost::spirit::rule<Scanner> &start() const
+ const boost::spirit::classic::rule<Scanner> &start() const
{
return root;
}
@@ -281,7 +285,7 @@
const std::string &filename)
{
- using namespace boost::spirit;
+ using namespace boost::spirit::classic;
typedef typename Ptree::key_type::value_type Ch;
typedef typename std::vector<Ch>::iterator It;
Deleted: trunk/boost/property_tree/detail/path_implementation.hpp
==============================================================================
--- trunk/boost/property_tree/detail/path_implementation.hpp 2009-09-01 17:27:45 EDT (Tue, 01 Sep 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 C, class D, class X>
- basic_ptree<C, Key, basic_path<Key>, D, X> *
- basic_path<Key>::get_child(basic_ptree<C, Key, basic_path<Key>, D, X> &root) const
- {
- typedef basic_ptree<C, Key, basic_path<Key>, D, 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 C, class D, class X>
- const basic_ptree<C, Key, basic_path<Key>, D, X> *
- basic_path<Key>::get_child(const basic_ptree<C, Key, basic_path<Key>, D, X> &root) const
- {
- typedef basic_ptree<C, Key, basic_path<Key>, D, 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 C, class D, class X>
- basic_ptree<C, Key, basic_path<Key>, D, X> *
- basic_path<Key>::put_child(basic_ptree<C, Key, basic_path<Key>, D, X> &root,
- const basic_ptree<C, Key, basic_path<Key>, D, X> &child,
- bool do_not_replace) const
- {
- if (m_path.empty())
- {
- return 0;
- }
- else
- {
-
- typedef basic_ptree<C, Key, basic_path<Key>, D, 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
Modified: trunk/boost/property_tree/detail/ptree_implementation.hpp
==============================================================================
--- trunk/boost/property_tree/detail/ptree_implementation.hpp (original)
+++ trunk/boost/property_tree/detail/ptree_implementation.hpp 2009-09-01 17:27:45 EDT (Tue, 01 Sep 2009)
@@ -1,8 +1,9 @@
// ----------------------------------------------------------------------------
// 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
+// 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
@@ -10,649 +11,857 @@
#ifndef BOOST_PROPERTY_TREE_DETAIL_PTREE_IMPLEMENTATION_HPP_INCLUDED
#define BOOST_PROPERTY_TREE_DETAIL_PTREE_IMPLEMENTATION_HPP_INCLUDED
-//////////////////////////////////////////////////////////////////////////////
-// Debug macros
+#include <boost/iterator/iterator_adaptor.hpp>
+#include <boost/iterator/reverse_iterator.hpp>
+#include <memory>
-#ifdef BOOST_PROPERTY_TREE_DEBUG
-
- // Increment instances counter
- #define BOOST_PROPERTY_TREE_DEBUG_INCREMENT_INSTANCES_COUNT() \
- { \
- typedef boost::detail::lightweight_mutex::scoped_lock lock; \
- lock l(debug_mutex); \
- ++debug_instances_count; \
+namespace boost { namespace property_tree
+{
+ template <class K, class D, class C>
+ struct basic_ptree<K, D, C>::subs
+ {
+ struct by_name {};
+ // The actual child container.
+ typedef multi_index_container<value_type,
+ multi_index::indexed_by<
+ multi_index::sequenced<>,
+ multi_index::ordered_non_unique<multi_index::tag<by_name>,
+ multi_index::member<value_type, const key_type,
+ &value_type::first>,
+ key_compare
+ >
+ >
+ > base_container;
+ // The by-name lookup index.
+ typedef typename base_container::template index<by_name>::type
+ by_name_index;
+
+ // Access functions for getting to the children of a tree.
+ static base_container& ch(self_type *s) {
+ return *static_cast<base_container*>(s->m_children);
}
-
- // Decrement instances counter
- #define BOOST_PROPERTY_TREE_DEBUG_DECREMENT_INSTANCES_COUNT() \
- { \
- typedef boost::detail::lightweight_mutex::scoped_lock lock; \
- lock l(debug_mutex); \
- BOOST_ASSERT(debug_instances_count > 0); \
- --debug_instances_count; \
+ static const base_container& ch(const self_type *s) {
+ return *static_cast<const base_container*>(s->m_children);
+ }
+ static by_name_index& assoc(self_type *s) {
+ return ch(s).get<by_name>();
+ }
+ static const by_name_index& assoc(const self_type *s) {
+ return ch(s).get<by_name>();
+ }
+ };
+ template <class K, class D, class C>
+ class basic_ptree<K, D, C>::iterator : public boost::iterator_adaptor<
+ iterator, typename subs::base_container::iterator, value_type>
+ {
+ friend class boost::iterator_core_access;
+ public:
+ iterator() {}
+ explicit iterator(typename iterator::base_type b)
+ : iterator::iterator_adaptor_(b)
+ {}
+ typename iterator::reference dereference() const
+ {
+ // multi_index doesn't allow modification of its values, because
+ // indexes could sort by anything, and modification screws that up.
+ // However, we only sort by the key, and it's protected against
+ // modification in the value_type, so this const_cast is safe.
+ return const_cast<typename iterator::reference>(
+ *this->base_reference());
+ }
+ };
+ template <class K, class D, class C>
+ class basic_ptree<K, D, C>::const_iterator : public boost::iterator_adaptor<
+ const_iterator, typename subs::base_container::const_iterator>
+ {
+ public:
+ const_iterator() {}
+ explicit const_iterator(typename const_iterator::base_type b)
+ : const_iterator::iterator_adaptor_(b)
+ {}
+ const_iterator(iterator b)
+ : const_iterator::iterator_adaptor_(b.base())
+ {}
+ };
+ template <class K, class D, class C>
+ class basic_ptree<K, D, C>::reverse_iterator
+ : public boost::reverse_iterator<iterator>
+ {
+ public:
+ reverse_iterator() {}
+ explicit reverse_iterator(iterator b)
+ : boost::reverse_iterator<iterator>(b)
+ {}
+ };
+ template <class K, class D, class C>
+ class basic_ptree<K, D, C>::const_reverse_iterator
+ : public boost::reverse_iterator<const_iterator>
+ {
+ public:
+ const_reverse_iterator() {}
+ explicit const_reverse_iterator(const_iterator b)
+ : boost::reverse_iterator<const_iterator>(b)
+ {}
+ const_reverse_iterator(reverse_iterator b)
+ : boost::reverse_iterator<const_iterator>(b)
+ {}
+ };
+ template <class K, class D, class C>
+ class basic_ptree<K, D, C>::assoc_iterator
+ : public boost::iterator_adaptor<assoc_iterator,
+ typename subs::by_name_index::iterator,
+ value_type>
+ {
+ friend class boost::iterator_core_access;
+ public:
+ assoc_iterator() {}
+ explicit assoc_iterator(typename assoc_iterator::base_type b)
+ : assoc_iterator::iterator_adaptor_(b)
+ {}
+ typename assoc_iterator::reference dereference() const
+ {
+ return const_cast<typename assoc_iterator::reference>(
+ *this->base_reference());
}
+ };
+ template <class K, class D, class C>
+ class basic_ptree<K, D, C>::const_assoc_iterator
+ : public boost::iterator_adaptor<const_assoc_iterator,
+ typename subs::by_name_index::const_iterator>
+ {
+ public:
+ const_assoc_iterator() {}
+ explicit const_assoc_iterator(
+ typename const_assoc_iterator::base_type b)
+ : const_assoc_iterator::iterator_adaptor_(b)
+ {}
+ const_assoc_iterator(assoc_iterator b)
+ : const_assoc_iterator::iterator_adaptor_(b.base())
+ {}
+ };
-#else // BOOST_PROPERTY_TREE_DEBUG
- #define BOOST_PROPERTY_TREE_DEBUG_INCREMENT_INSTANCES_COUNT() static_cast<void>(0)
- #define BOOST_PROPERTY_TREE_DEBUG_DECREMENT_INSTANCES_COUNT() static_cast<void>(0)
+ // Big five
-#endif // BOOST_PROPERTY_TREE_DEBUG
+ // Perhaps the children collection could be created on-demand only, to
+ // reduce heap traffic. But that's a lot more work to implement.
-namespace boost { namespace property_tree
-{
+ template<class K, class D, class C> inline
+ basic_ptree<K, D, C>::basic_ptree()
+ : m_children(new typename subs::base_container)
+ {
+ }
- ///////////////////////////////////////////////////////////////////////////
- // Construction & destruction
+ template<class K, class D, class C> inline
+ basic_ptree<K, D, C>::basic_ptree(const data_type &data)
+ : m_data(data), m_children(new typename subs::base_container)
+ {
+ }
- template<class C, class K, class P, class D, class X>
- basic_ptree<C, K, P, D, X>::basic_ptree()
+ template<class K, class D, class C> inline
+ basic_ptree<K, D, C>::basic_ptree(const basic_ptree<K, D, C> &rhs)
+ : m_data(rhs.m_data),
+ m_children(new typename subs::base_container(subs::ch(&rhs)))
{
- BOOST_PROPERTY_TREE_DEBUG_INCREMENT_INSTANCES_COUNT();
}
- template<class C, class K, class P, class D, class X>
- basic_ptree<C, K, P, D, X>::basic_ptree(const data_type &rhs):
- m_data(rhs)
+ template<class K, class D, class C>
+ basic_ptree<K, D, C> &
+ basic_ptree<K, D, C>::operator =(const basic_ptree<K, D, C> &rhs)
{
- BOOST_PROPERTY_TREE_DEBUG_INCREMENT_INSTANCES_COUNT();
+ self_type(rhs).swap(*this);
+ return *this;
}
- template<class C, class K, class P, class D, class X>
- basic_ptree<C, K, P, D, X>::basic_ptree(const basic_ptree<C, K, P, D, X> &rhs)
+ template<class K, class D, class C>
+ basic_ptree<K, D, C>::~basic_ptree()
{
- m_data = rhs.m_data;
- insert(end(), rhs.begin(), rhs.end());
- BOOST_PROPERTY_TREE_DEBUG_INCREMENT_INSTANCES_COUNT();
+ delete &subs::ch(this);
}
- template<class C, class K, class P, class D, class X>
- basic_ptree<C, K, P, D, X>::~basic_ptree()
+ template<class K, class D, class C> inline
+ void basic_ptree<K, D, C>::swap(basic_ptree<K, D, C> &rhs)
{
- BOOST_PROPERTY_TREE_DEBUG_DECREMENT_INSTANCES_COUNT();
+ m_data.swap(rhs.m_data);
+ // Void pointers, no ADL necessary
+ std::swap(m_children, rhs.m_children);
}
- ///////////////////////////////////////////////////////////////////////////
- // Iterator access
+ // Container view
- template<class C, class K, class P, class D, class X>
- typename basic_ptree<C, K, P, D, X>::iterator
- basic_ptree<C, K, P, D, X>::begin()
+ template<class K, class D, class C> inline
+ typename basic_ptree<K, D, C>::size_type
+ basic_ptree<K, D, C>::size() const
{
- return m_container.begin();
+ return subs::ch(this).size();
}
- template<class C, class K, class P, class D, class X>
- typename basic_ptree<C, K, P, D, X>::const_iterator
- basic_ptree<C, K, P, D, X>::begin() const
+ template<class K, class D, class C> inline
+ typename basic_ptree<K, D, C>::size_type
+ basic_ptree<K, D, C>::max_size() const
{
- return m_container.begin();
+ return subs::ch(this).max_size();
}
- template<class C, class K, class P, class D, class X>
- typename basic_ptree<C, K, P, D, X>::iterator
- basic_ptree<C, K, P, D, X>::end()
+ template<class K, class D, class C> inline
+ bool basic_ptree<K, D, C>::empty() const
{
- return m_container.end();
+ return subs::ch(this).empty();
}
- template<class C, class K, class P, class D, class X>
- typename basic_ptree<C, K, P, D, X>::const_iterator
- basic_ptree<C, K, P, D, X>::end() const
+ template<class K, class D, class C> inline
+ typename basic_ptree<K, D, C>::iterator
+ basic_ptree<K, D, C>::begin()
{
- return m_container.end();
+ return iterator(subs::ch(this).begin());
}
- template<class C, class K, class P, class D, class X>
- typename basic_ptree<C, K, P, D, X>::reverse_iterator
- basic_ptree<C, K, P, D, X>::rbegin()
+ template<class K, class D, class C> inline
+ typename basic_ptree<K, D, C>::const_iterator
+ basic_ptree<K, D, C>::begin() const
{
- return m_container.rbegin();
+ return const_iterator(subs::ch(this).begin());
}
- template<class C, class K, class P, class D, class X>
- typename basic_ptree<C, K, P, D, X>::const_reverse_iterator
- basic_ptree<C, K, P, D, X>::rbegin() const
+ template<class K, class D, class C> inline
+ typename basic_ptree<K, D, C>::iterator
+ basic_ptree<K, D, C>::end()
{
- return m_container.rbegin();
+ return iterator(subs::ch(this).end());
}
- template<class C, class K, class P, class D, class X>
- typename basic_ptree<C, K, P, D, X>::reverse_iterator
- basic_ptree<C, K, P, D, X>::rend()
+ template<class K, class D, class C> inline
+ typename basic_ptree<K, D, C>::const_iterator
+ basic_ptree<K, D, C>::end() const
{
- return m_container.rend();
+ return const_iterator(subs::ch(this).end());
}
- template<class C, class K, class P, class D, class X>
- typename basic_ptree<C, K, P, D, X>::const_reverse_iterator
- basic_ptree<C, K, P, D, X>::rend() const
+ template<class K, class D, class C> inline
+ typename basic_ptree<K, D, C>::reverse_iterator
+ basic_ptree<K, D, C>::rbegin()
{
- return m_container.rend();
+ return reverse_iterator(this->end());
}
- ///////////////////////////////////////////////////////////////////////////
- // Data access
+ template<class K, class D, class C> inline
+ typename basic_ptree<K, D, C>::const_reverse_iterator
+ basic_ptree<K, D, C>::rbegin() const
+ {
+ return const_reverse_iterator(this->end());
+ }
- template<class C, class K, class P, class D, class X>
- typename basic_ptree<C, K, P, D, X>::size_type
- basic_ptree<C, K, P, D, X>::size() const
+ template<class K, class D, class C> inline
+ typename basic_ptree<K, D, C>::reverse_iterator
+ basic_ptree<K, D, C>::rend()
{
- return m_container.size();
+ return reverse_iterator(this->begin());
}
- template<class C, class K, class P, class D, class X>
- typename basic_ptree<C, K, P, D, X>::size_type
- basic_ptree<C, K, P, D, X>::max_size() const
+ template<class K, class D, class C> inline
+ typename basic_ptree<K, D, C>::const_reverse_iterator
+ basic_ptree<K, D, C>::rend() const
{
- return m_container.max_size();
+ return const_reverse_iterator(this->begin());
}
- template<class C, class K, class P, class D, class X>
- bool basic_ptree<C, K, P, D, X>::empty() const
+ template<class K, class D, class C> inline
+ typename basic_ptree<K, D, C>::value_type &
+ basic_ptree<K, D, C>::front()
{
- return m_container.empty();
+ return const_cast<value_type&>(subs::ch(this).front());
}
- template<class C, class K, class P, class D, class X>
- typename basic_ptree<C, K, P, D, X>::data_type &
- basic_ptree<C, K, P, D, X>::data()
+ template<class K, class D, class C> inline
+ const typename basic_ptree<K, D, C>::value_type &
+ basic_ptree<K, D, C>::front() const
{
- return m_data;
+ return subs::ch(this).front();
}
- template<class C, class K, class P, class D, class X>
- const typename basic_ptree<C, K, P, D, X>::data_type &
- basic_ptree<C, K, P, D, X>::data() const
+ template<class K, class D, class C> inline
+ typename basic_ptree<K, D, C>::value_type &
+ basic_ptree<K, D, C>::back()
{
- return m_data;
+ return const_cast<value_type&>(subs::ch(this).back());
}
- template<class C, class K, class P, class D, class X>
- typename basic_ptree<C, K, P, D, X>::value_type &
- basic_ptree<C, K, P, D, X>::front()
+ template<class K, class D, class C> inline
+ const typename basic_ptree<K, D, C>::value_type &
+ basic_ptree<K, D, C>::back() const
{
- return m_container.front();
+ return subs::ch(this).back();
}
-
- template<class C, class K, class P, class D, class X>
- const typename basic_ptree<C, K, P, D, X>::value_type &
- basic_ptree<C, K, P, D, X>::front() const
+
+ template<class K, class D, class C> inline
+ typename basic_ptree<K, D, C>::iterator
+ basic_ptree<K, D, C>::insert(iterator where, const value_type &value)
{
- return m_container.front();
+ return iterator(subs::ch(this).insert(where.base(), value).first);
}
- template<class C, class K, class P, class D, class X>
- typename basic_ptree<C, K, P, D, X>::value_type &
- basic_ptree<C, K, P, D, X>::back()
+ template<class K, class D, class C>
+ template<class It> inline
+ void basic_ptree<K, D, C>::insert(iterator where, It first, It last)
{
- return m_container.back();
+ subs::ch(this).insert(where.base(), first, last);
}
- template<class C, class K, class P, class D, class X>
- const typename basic_ptree<C, K, P, D, X>::value_type &
- basic_ptree<C, K, P, D, X>::back() const
+ template<class K, class D, class C> inline
+ typename basic_ptree<K, D, C>::iterator
+ basic_ptree<K, D, C>::erase(iterator where)
{
- return m_container.back();
+ return iterator(subs::ch(this).erase(where.base()));
}
- ///////////////////////////////////////////////////////////////////////////
- // Operators
+ template<class K, class D, class C> inline
+ typename basic_ptree<K, D, C>::iterator
+ basic_ptree<K, D, C>::erase(iterator first, iterator last)
+ {
+ return iterator(subs::ch(this).erase(first.base(), last.base()));
+ }
- template<class C, class K, class P, class D, class X>
- basic_ptree<C, K, P, D, X> &
- basic_ptree<C, K, P, D, X>::operator =(const basic_ptree<C, K, P, D, X> &rhs)
+ template<class K, class D, class C> inline
+ typename basic_ptree<K, D, C>::iterator
+ basic_ptree<K, D, C>::push_front(const value_type &value)
{
- if (&rhs != this)
- {
- clear();
- data() = rhs.data();
- insert(end(), rhs.begin(), rhs.end());
- }
- return *this;
+ return iterator(subs::ch(this).push_front(value).first);
+ }
+
+ template<class K, class D, class C> inline
+ typename basic_ptree<K, D, C>::iterator
+ basic_ptree<K, D, C>::push_back(const value_type &value)
+ {
+ return iterator(subs::ch(this).push_back(value).first);
}
- template<class C, class K, class P, class D, class X>
- bool basic_ptree<C, K, P, D, X>::operator ==(const basic_ptree<C, K, P, D, X> &rhs) const
+ template<class K, class D, class C> inline
+ void basic_ptree<K, D, C>::pop_front()
{
-
- // Data and sizes must be equal
- if (size() != rhs.size() || data() != rhs.data())
- return false;
+ subs::ch(this).pop_front();
+ }
- // Keys and children must be equal
- C comp;
- const_iterator it = begin();
- const_iterator it_rhs = rhs.begin();
- const_iterator it_end = end();
- for (; it != it_end; ++it, ++it_rhs)
- if (comp(it->first, it_rhs->first)
- || comp(it_rhs->first, it->first)
- || it->second != it_rhs->second)
- {
- return false;
- }
+ template<class K, class D, class C> inline
+ void basic_ptree<K, D, C>::pop_back()
+ {
+ subs::ch(this).pop_back();
+ }
- // Equal
- return true;
+ template<class K, class D, class C> inline
+ void basic_ptree<K, D, C>::reverse()
+ {
+ subs::ch(this).reverse();
+ }
+ template<class K, class D, class C> inline
+ void basic_ptree<K, D, C>::sort()
+ {
+ subs::ch(this).sort();
}
- template<class C, class K, class P, class D, class X>
- bool basic_ptree<C, K, P, D, X>::operator !=(const basic_ptree<C, K, P, D, X> &rhs) const
+ template<class K, class D, class C>
+ template<class Compare> inline
+ void basic_ptree<K, D, C>::sort(Compare comp)
{
- return !operator ==(rhs);
+ subs::ch(this).sort(comp);
}
- ///////////////////////////////////////////////////////////////////////////
- // Container operations
+ // Equality
- template<class C, class K, class P, class D, class X>
- typename basic_ptree<C, K, P, D, X>::iterator
- basic_ptree<C, K, P, D, X>::find(const key_type &key)
+ template<class K, class D, class C> inline
+ bool basic_ptree<K, D, C>::operator ==(
+ const basic_ptree<K, D, C> &rhs) const
{
- C comp;
- for (iterator it = begin(); it != end(); ++it)
- if (!comp(it->first, key) && !comp(key, it->first))
- return it;
- return end();
+ // The size test is cheap, so add it as an optimization
+ return size() == rhs.size() && data() == rhs.data() &&
+ subs::ch(this) == subs::ch(&rhs);
}
- template<class C, class K, class P, class D, class X>
- typename basic_ptree<C, K, P, D, X>::const_iterator
- basic_ptree<C, K, P, D, X>::find(const key_type &key) const
+ template<class K, class D, class C> inline
+ bool basic_ptree<K, D, C>::operator !=(
+ const basic_ptree<K, D, C> &rhs) const
{
- C comp;
- for (const_iterator it = begin(); it != end(); ++it)
- if (!comp(it->first, key) && !comp(key, it->first))
- return it;
- return end();
+ return !(*this == rhs);
}
- template<class C, class K, class P, class D, class X>
- typename basic_ptree<C, K, P, D, X>::size_type
- basic_ptree<C, K, P, D, X>::count(const key_type &key) const
+ // Associative view
+
+ template<class K, class D, class C> inline
+ typename basic_ptree<K, D, C>::assoc_iterator
+ basic_ptree<K, D, C>::ordered_begin()
{
- C comp;
- size_type count = 0;
- for (const_iterator it = begin(); it != end(); ++it)
- if (!comp(it->first, key) && !comp(key, it->first))
- ++count;
- return count;
+ return assoc_iterator(subs::assoc(this).begin());
}
- template<class C, class K, class P, class D, class X>
- void basic_ptree<C, K, P, D, X>::clear()
+ template<class K, class D, class C> inline
+ typename basic_ptree<K, D, C>::const_assoc_iterator
+ basic_ptree<K, D, C>::ordered_begin() const
{
- m_data = data_type();
- m_container.clear();
+ return const_assoc_iterator(subs::assoc(this).begin());
}
- template<class C, class K, class P, class D, class X>
- typename basic_ptree<C, K, P, D, X>::iterator
- basic_ptree<C, K, P, D, X>::insert(iterator where,
- const value_type &value)
+ template<class K, class D, class C> inline
+ typename basic_ptree<K, D, C>::assoc_iterator
+ basic_ptree<K, D, C>::not_found()
{
- return m_container.insert(where, value);
+ return assoc_iterator(subs::assoc(this).end());
}
- template<class C, class K, class P, class D, class X>
- template<class It>
- void basic_ptree<C, K, P, D, X>::insert(iterator where, It first, It last)
+ template<class K, class D, class C> inline
+ typename basic_ptree<K, D, C>::const_assoc_iterator
+ basic_ptree<K, D, C>::not_found() const
{
- for (; first != last; ++first, ++where)
- where = insert(where, value_type(first->first, first->second));
+ return const_assoc_iterator(subs::assoc(this).end());
}
- template<class C, class K, class P, class D, class X>
- typename basic_ptree<C, K, P, D, X>::iterator
- basic_ptree<C, K, P, D, X>::erase(iterator where)
+ template<class K, class D, class C> inline
+ typename basic_ptree<K, D, C>::assoc_iterator
+ basic_ptree<K, D, C>::find(const key_type &key)
{
- return m_container.erase(where);
+ return assoc_iterator(subs::assoc(this).find(key));
}
- template<class C, class K, class P, class D, class X>
- typename basic_ptree<C, K, P, D, X>::size_type
- basic_ptree<C, K, P, D, X>::erase(const key_type &key)
+ template<class K, class D, class C> inline
+ typename basic_ptree<K, D, C>::const_assoc_iterator
+ basic_ptree<K, D, C>::find(const key_type &key) const
{
- C comp;
- size_type count = 0;
- iterator it = m_container.begin();
- while (it != m_container.end())
- {
- if (!comp(it->first, key) && !comp(key, it->first))
- {
- it = erase(it);
- ++count;
- }
- else
- ++it;
- }
- return count;
+ return const_assoc_iterator(subs::assoc(this).find(key));
}
- template<class C, class K, class P, class D, class X>
- template<class It>
- typename basic_ptree<C, K, P, D, X>::iterator
- basic_ptree<C, K, P, D, X>::erase(It first, It last)
+ template<class K, class D, class C> inline
+ std::pair<
+ typename basic_ptree<K, D, C>::assoc_iterator,
+ typename basic_ptree<K, D, C>::assoc_iterator
+ > basic_ptree<K, D, C>::equal_range(const key_type &key)
{
- while (first != last)
- first = erase(first);
- return first;
+ std::pair<typename subs::by_name_index::iterator,
+ typename subs::by_name_index::iterator> r(
+ subs::assoc(this).equal_range(key));
+ return std::pair<assoc_iterator, assoc_iterator>(r.first.base(),
+ r.second.base());
}
- template<class C, class K, class P, class D, class X>
- typename basic_ptree<C, K, P, D, X>::iterator
- basic_ptree<C, K, P, D, X>::push_front(const value_type &value)
+ template<class K, class D, class C> inline
+ std::pair<
+ typename basic_ptree<K, D, C>::const_assoc_iterator,
+ typename basic_ptree<K, D, C>::const_assoc_iterator
+ > basic_ptree<K, D, C>::equal_range(const key_type &key) const
{
- return insert(begin(), value);
+ std::pair<typename subs::by_name_index::const_iterator,
+ typename subs::by_name_index::const_iterator> r(
+ subs::assoc(this).equal_range(key));
+ return std::pair<const_assoc_iterator, const_assoc_iterator>(
+ r.first.base(), r.second.base());
}
- template<class C, class K, class P, class D, class X>
- typename basic_ptree<C, K, P, D, X>::iterator
- basic_ptree<C, K, P, D, X>::push_back(const value_type &value)
+ template<class K, class D, class C> inline
+ typename basic_ptree<K, D, C>::size_type
+ basic_ptree<K, D, C>::count(const key_type &key) const
{
- return insert(end(), value);
+ return subs::assoc(this).count(key);
}
- template<class C, class K, class P, class D, class X>
- void basic_ptree<C, K, P, D, X>::pop_front()
+ template<class K, class D, class C> inline
+ typename basic_ptree<K, D, C>::size_type
+ basic_ptree<K, D, C>::erase(const key_type &key)
{
- erase(begin());
+ return subs::assoc(this).erase(key);
}
- template<class C, class K, class P, class D, class X>
- void basic_ptree<C, K, P, D, X>::pop_back()
+ template<class K, class D, class C> inline
+ typename basic_ptree<K, D, C>::iterator
+ basic_ptree<K, D, C>::to_iterator(assoc_iterator ai)
{
- iterator last = end();
- --last;
- erase(last);
+ return iterator(subs::ch(this).project<0>(ai.base()));
}
-
- template<class C, class K, class P, class D, class X>
- void basic_ptree<C, K, P, D, X>::swap(basic_ptree<C, K, P, D, X> &rhs)
+
+ template<class K, class D, class C> inline
+ typename basic_ptree<K, D, C>::const_iterator
+ basic_ptree<K, D, C>::to_iterator(const_assoc_iterator ai) const
{
- m_data.swap(rhs.m_data);
- m_container.swap(rhs.m_container);
+ return const_iterator(subs::ch(this).project<0>(ai.base()));
}
- template<class C, class K, class P, class D, class X>
- void basic_ptree<C, K, P, D, X>::reverse()
+ // Property tree view
+
+ template<class K, class D, class C> inline
+ typename basic_ptree<K, D, C>::data_type &
+ basic_ptree<K, D, C>::data()
{
- m_container.reverse();
+ return m_data;
}
-
- template<class C, class K, class P, class D, class X>
- template<class SortTr>
- void basic_ptree<C, K, P, D, X>::sort(SortTr tr)
+
+ template<class K, class D, class C> inline
+ const typename basic_ptree<K, D, C>::data_type &
+ basic_ptree<K, D, C>::data() const
{
- m_container.sort(tr);
+ return m_data;
}
- ///////////////////////////////////////////////////////////////////////////
- // ptree operations
+ template<class K, class D, class C> inline
+ void basic_ptree<K, D, C>::clear()
+ {
+ m_data = data_type();
+ subs::ch(this).clear();
+ }
- // Get child ptree
- template<class C, class K, class P, class D, class X>
- basic_ptree<C, K, P, D, X> &
- basic_ptree<C, K, P, D, X>::get_child(const path_type &path)
+ template<class K, class D, class C>
+ basic_ptree<K, D, C> &
+ basic_ptree<K, D, C>::get_child(const path_type &path)
{
- self_type *child = path.get_child(*this);
- if (child)
- return *child;
- else
- BOOST_PROPERTY_TREE_THROW(ptree_bad_path("path does not exist", path));
+ path_type p(path);
+ self_type *n = walk_path(p);
+ if (!n) {
+ BOOST_PROPERTY_TREE_THROW(ptree_bad_path("No such node", path));
+ }
+ return *n;
}
- // Get child ptree
- template<class C, class K, class P, class D, class X>
- const basic_ptree<C, K, P, D, X> &
- basic_ptree<C, K, P, D, X>::get_child(const path_type &path) const
+ template<class K, class D, class C> inline
+ const basic_ptree<K, D, C> &
+ basic_ptree<K, D, C>::get_child(const path_type &path) const
{
- self_type *nc_this = const_cast<self_type *>(this);
- return nc_this->get_child(path);
+ return const_cast<self_type*>(this)->get_child(path);
}
- // Get child ptree
- template<class C, class K, class P, class D, class X>
- basic_ptree<C, K, P, D, X> &
- basic_ptree<C, K, P, D, X>::get_child(const path_type &path,
- basic_ptree<C, K, P, D, X> &default_value)
+ template<class K, class D, class C> inline
+ basic_ptree<K, D, C> &
+ basic_ptree<K, D, C>::get_child(const path_type &path,
+ self_type &default_value)
{
- self_type *child = path.get_child(*this);
- if (child)
- return *child;
- else
- return default_value;
+ path_type p(path);
+ self_type *n = walk_path(p);
+ return n ? *n : default_value;
}
- // Get child ptree
- template<class C, class K, class P, class D, class X>
- const basic_ptree<C, K, P, D, X> &
- basic_ptree<C, K, P, D, X>::get_child(const path_type &path,
- const basic_ptree<C, K, P, D, X> &default_value) const
+ template<class K, class D, class C> inline
+ const basic_ptree<K, D, C> &
+ basic_ptree<K, D, C>::get_child(const path_type &path,
+ const self_type &default_value) const
{
- self_type *nc_this = const_cast<self_type *>(this);
- self_type &nc_default_value = const_cast<self_type &>(default_value);
- return nc_this->get_child(path, nc_default_value);
+ return const_cast<self_type*>(this)->get_child(path,
+ const_cast<self_type&>(default_value));
}
- // Get child ptree
- template<class C, class K, class P, class D, class X>
- optional<basic_ptree<C, K, P, D, X> &>
- basic_ptree<C, K, P, D, X>::get_child_optional(const path_type &path)
+ template<class K, class D, class C>
+ optional<basic_ptree<K, D, C> &>
+ basic_ptree<K, D, C>::get_child_optional(const path_type &path)
{
- self_type *child = path.get_child(*this);
- if (child)
- return optional<self_type &>(*child);
- else
- return optional<self_type &>();
+ path_type p(path);
+ self_type *n = walk_path(p);
+ if (!n) {
+ return optional<self_type&>();
+ }
+ return *n;
}
- // Get child ptree
- template<class C, class K, class P, class D, class X>
- optional<const basic_ptree<C, K, P, D, X> &>
- basic_ptree<C, K, P, D, X>::get_child_optional(const path_type &path) const
- {
- self_type *nc_this = const_cast<self_type *>(this);
- optional<self_type &> tmp = nc_this->get_child_optional(path);
- if (tmp)
- return optional<const self_type &>(tmp.get());
- else
- return optional<const self_type &>();
+ template<class K, class D, class C>
+ optional<const basic_ptree<K, D, C> &>
+ basic_ptree<K, D, C>::get_child_optional(const path_type &path) const
+ {
+ path_type p(path);
+ self_type *n = walk_path(p);
+ if (!n) {
+ return optional<const self_type&>();
+ }
+ return *n;
+ }
+
+ template<class K, class D, class C>
+ basic_ptree<K, D, C> &
+ basic_ptree<K, D, C>::put_child(const path_type &path,
+ const self_type &value)
+ {
+ path_type p(path);
+ self_type &parent = force_path(p);
+ // Got the parent. Now get the correct child.
+ key_type fragment = p.reduce();
+ assoc_iterator el = parent.find(fragment);
+ // If the new child exists, replace it.
+ if(el != parent.not_found()) {
+ return el->second = value;
+ } else {
+ return parent.push_back(value_type(fragment, value))->second;
+ }
}
- // Put child ptree
- template<class C, class K, class P, class D, class X>
- basic_ptree<C, K, P, D, X> &
- basic_ptree<C, K, P, D, X>::put_child(const path_type &path,
- const basic_ptree<C, K, P, D, X> &value,
- bool do_not_replace)
+ template<class K, class D, class C>
+ basic_ptree<K, D, C> &
+ basic_ptree<K, D, C>::add_child(const path_type &path,
+ const self_type &value)
+ {
+ path_type p(path);
+ self_type &parent = force_path(p);
+ // Got the parent.
+ key_type fragment = p.reduce();
+ return parent.push_back(value_type(fragment, value))->second;
+ }
+
+ template<class K, class D, class C>
+ template<class Type, class Translator>
+ typename boost::enable_if<detail::is_translator<Translator>, Type>::type
+ basic_ptree<K, D, C>::get_value(Translator tr) const
{
- self_type *child = path.put_child(*this, value, do_not_replace);
- if (child)
- return *child;
- else
- BOOST_PROPERTY_TREE_THROW(ptree_bad_path("path does not exist", path));
+ if(boost::optional<Type> o = get_value_optional<Type>(tr)) {
+ return *o;
+ }
+ BOOST_PROPERTY_TREE_THROW(ptree_bad_data(
+ std::string("conversion of data to type \"") +
+ typeid(Type).name() + "\" failed", data()));
}
- // Get value from data of ptree
- template<class C, class K, class P, class D, class X>
- template<class Type>
- Type basic_ptree<C, K, P, D, X>::get_value(const translator_type &x) const
+ template<class K, class D, class C>
+ template<class Type> inline
+ Type basic_ptree<K, D, C>::get_value() const
{
- BOOST_STATIC_ASSERT(boost::is_pointer<Type>::value == false); // Disallow pointer types, they are unsafe
- Type value;
- if (x.get_value(*this, value))
- return value;
- else
- BOOST_PROPERTY_TREE_THROW(ptree_bad_data(std::string("conversion of data into type \"") +
- typeid(Type).name() + "\" failed", data()));
+ return get_value<Type>(
+ typename translator_between<data_type, Type>::type());
}
- // Get value from data of ptree
- template<class C, class K, class P, class D, class X>
- template<class Type>
- Type basic_ptree<C, K, P, D, X>::get_value(const Type &default_value,
- const translator_type &x) const
+ template<class K, class D, class C>
+ template<class Type, class Translator> inline
+ Type basic_ptree<K, D, C>::get_value(const Type &default_value,
+ Translator tr) const
{
- BOOST_STATIC_ASSERT(boost::is_pointer<Type>::value == false); // Disallow pointer types, they are unsafe
- Type value;
- if (x.get_value(*this, value))
- return value;
- else
- return default_value;
+ return get_value_optional<Type>(tr).get_value_or(default_value);
}
- // Get value from data of ptree
- template<class C, class K, class P, class D, class X>
- template<class CharType>
- std::basic_string<CharType>
- basic_ptree<C, K, P, D, X>::get_value(const CharType *default_value,
- const translator_type &x) const
+ template<class K, class D, class C>
+ template <class Ch, class Translator>
+ typename boost::enable_if<
+ detail::is_character<Ch>,
+ std::basic_string<Ch>
+ >::type
+ basic_ptree<K, D, C>::get_value(const Ch *default_value, Translator tr)const
{
- return get_value(std::basic_string<CharType>(default_value), x);
+ return get_value<std::basic_string<Ch>, Translator>(default_value, tr);
}
- // Get value from data of ptree
- template<class C, class K, class P, class D, class X>
- template<class Type>
- optional<Type>
- basic_ptree<C, K, P, D, X>::get_value_optional(const translator_type &x) const
+ template<class K, class D, class C>
+ template<class Type> inline
+ typename boost::disable_if<detail::is_translator<Type>, Type>::type
+ basic_ptree<K, D, C>::get_value(const Type &default_value) const
{
- BOOST_STATIC_ASSERT(boost::is_pointer<Type>::value == false); // Disallow pointer types, they are unsafe
- Type value;
- if (x.get_value(*this, value))
- return optional<Type>(value);
- else
- return optional<Type>();
+ return get_value(default_value,
+ typename translator_between<data_type, Type>::type());
}
- // Get value from data of child ptree
- template<class C, class K, class P, class D, class X>
- template<class Type>
- Type basic_ptree<C, K, P, D, X>::get(const path_type &path,
- const translator_type &x) const
+ template<class K, class D, class C>
+ template <class Ch>
+ typename boost::enable_if<
+ detail::is_character<Ch>,
+ std::basic_string<Ch>
+ >::type
+ basic_ptree<K, D, C>::get_value(const Ch *default_value) const
{
- return get_child(path).get_value<Type>(x);
+ return get_value< std::basic_string<Ch> >(default_value);
}
- // Get value from data of child ptree
- template<class C, class K, class P, class D, class X>
- template<class Type>
- Type basic_ptree<C, K, P, D, X>::get(const path_type &path,
- const Type &default_value,
- const translator_type &x) const
+ template<class K, class D, class C>
+ template<class Type, class Translator> inline
+ optional<Type> basic_ptree<K, D, C>::get_value_optional(
+ Translator tr) const
{
- if (optional<Type> result = get_optional<Type>(path, x))
- return *result;
- else
- return default_value;
+ return tr.get_value(data());
+ }
+
+ template<class K, class D, class C>
+ template<class Type> inline
+ optional<Type> basic_ptree<K, D, C>::get_value_optional() const
+ {
+ return get_value_optional<Type>(
+ typename translator_between<data_type, Type>::type());
+ }
+
+ template<class K, class D, class C>
+ template<class Type, class Translator> inline
+ typename boost::enable_if<detail::is_translator<Translator>, Type>::type
+ basic_ptree<K, D, C>::get(const path_type &path,
+ Translator tr) const
+ {
+ return get_child(path).get_value<Type>(tr);
+ }
+
+ template<class K, class D, class C>
+ template<class Type> inline
+ Type basic_ptree<K, D, C>::get(const path_type &path) const
+ {
+ return get_child(path).get_value<Type>();
+ }
+
+ template<class K, class D, class C>
+ template<class Type, class Translator> inline
+ Type basic_ptree<K, D, C>::get(const path_type &path,
+ const Type &default_value,
+ Translator tr) const
+ {
+ return get_optional<Type>(path, tr).get_value_or(default_value);
+ }
+
+ template<class K, class D, class C>
+ template <class Ch, class Translator>
+ typename boost::enable_if<
+ detail::is_character<Ch>,
+ std::basic_string<Ch>
+ >::type
+ basic_ptree<K, D, C>::get(
+ const path_type &path, const Ch *default_value, Translator tr) const
+ {
+ return get<std::basic_string<Ch>, Translator>(path, default_value, tr);
+ }
+
+ template<class K, class D, class C>
+ template<class Type> inline
+ typename boost::disable_if<detail::is_translator<Type>, Type>::type
+ basic_ptree<K, D, C>::get(const path_type &path,
+ const Type &default_value) const
+ {
+ return get_optional<Type>(path).get_value_or(default_value);
}
- // Get value from data of child ptree
- template<class C, class K, class P, class D, class X>
- template<class CharType>
- std::basic_string<CharType>
- basic_ptree<C, K, P, D, X>::get(const path_type &path,
- const CharType *default_value,
- const translator_type &x) const
+ template<class K, class D, class C>
+ template <class Ch>
+ typename boost::enable_if<
+ detail::is_character<Ch>,
+ std::basic_string<Ch>
+ >::type
+ basic_ptree<K, D, C>::get(
+ const path_type &path, const Ch *default_value) const
{
- return get(path, std::basic_string<CharType>(default_value), x);
+ return get< std::basic_string<Ch> >(path, default_value);
}
- // Get value from data of child ptree
- template<class C, class K, class P, class D, class X>
+ template<class K, class D, class C>
+ template<class Type, class Translator>
+ optional<Type> basic_ptree<K, D, C>::get_optional(const path_type &path,
+ Translator tr) const
+ {
+ if (optional<const self_type&> child = get_child_optional(path))
+ return child.get().get_value_optional<Type>(tr);
+ else
+ return optional<Type>();
+ }
+
+ template<class K, class D, class C>
template<class Type>
- optional<Type>
- basic_ptree<C, K, P, D, X>::get_optional(const path_type &path,
- const translator_type &x) const
+ optional<Type> basic_ptree<K, D, C>::get_optional(
+ const path_type &path) const
{
- if (optional<const basic_ptree<C, K, P, D, X> &> child = get_child_optional(path))
- return child.get().get_value_optional<Type>(x);
+ if (optional<const self_type&> child = get_child_optional(path))
+ return child.get().get_value_optional<Type>();
else
return optional<Type>();
}
- // Put value in data of ptree
- template<class C, class K, class P, class D, class X>
- template<class Type>
- void basic_ptree<C, K, P, D, X>::put_value(const Type &value, const translator_type &x)
- {
- if (!x.put_value(*this, value))
- BOOST_PROPERTY_TREE_THROW(ptree_bad_data(std::string("conversion of type \"") + typeid(Type).name() +
- "\" into data failed", boost::any()));
- }
-
- // Put value in data of child ptree
- template<class C, class K, class P, class D, class X>
- template<class Type>
- basic_ptree<C, K, P, D, X> &
- basic_ptree<C, K, P, D, X>::put(const path_type &path,
- const Type &value,
- bool do_not_replace,
- const translator_type &x)
+ template<class K, class D, class C>
+ template<class Type, class Translator>
+ void basic_ptree<K, D, C>::put_value(const Type &value, Translator tr)
+ {
+ if(optional<data_type> o = tr.put_value(value)) {
+ data() = *o;
+ } else {
+ BOOST_PROPERTY_TREE_THROW(ptree_bad_data(
+ std::string("conversion of type \"") + typeid(Type).name() +
+ "\" to data failed", boost::any()));
+ }
+ }
+
+ template<class K, class D, class C>
+ template<class Type> inline
+ void basic_ptree<K, D, C>::put_value(const Type &value)
{
- optional<self_type &> child;
- if (!do_not_replace && (child = get_child_optional(path)))
- {
- child.get().put_value(value, x);
+ put_value(value, typename translator_between<data_type, Type>::type());
+ }
+
+ template<class K, class D, class C>
+ template<class Type, typename Translator>
+ basic_ptree<K, D, C> & basic_ptree<K, D, C>::put(
+ const path_type &path, const Type &value, Translator tr)
+ {
+ if(optional<self_type &> child = get_child_optional(path)) {
+ child.get().put_value(value, tr);
return *child;
- }
- else
- {
- self_type &child2 = put_child(path, empty_ptree<self_type>(), do_not_replace);
- child2.put_value(value, x);
+ } else {
+ self_type &child2 = put_child(path, self_type());
+ child2.put_value(value, tr);
return child2;
}
}
- ////////////////////////////////////////////////////////////////////////////
- // Debugging
+ template<class K, class D, class C>
+ template<class Type> inline
+ basic_ptree<K, D, C> & basic_ptree<K, D, C>::put(
+ const path_type &path, const Type &value)
+ {
+ return put(path, value,
+ typename translator_between<data_type, Type>::type());
+ }
-#ifdef BOOST_PROPERTY_TREE_DEBUG
+ template<class K, class D, class C>
+ template<class Type, typename Translator> inline
+ basic_ptree<K, D, C> & basic_ptree<K, D, C>::add(
+ const path_type &path, const Type &value, Translator tr)
+ {
+ self_type &child = add_child(path, self_type());
+ child.put_value(value, tr);
+ return child;
+ }
- template<class C, class K, class P, class D, class X>
- typename basic_ptree<C, K, P, D, X>::size_type
- basic_ptree<C, K, P, D, X>::debug_get_instances_count()
- {
- empty_ptree<basic_ptree<C, K, P, D, X> >(); // Make sure empty ptree exists
- return debug_instances_count - 1; // Do not count empty ptree
- }
-
- template<class C, class K, class P, class D, class X>
- typename basic_ptree<C, K, P, D, X>::size_type
- basic_ptree<C, K, P, D, X>::debug_instances_count;
-
- template<class C, class K, class P, class D, class X>
- boost::detail::lightweight_mutex
- basic_ptree<C, K, P, D, X>::debug_mutex;
+ template<class K, class D, class C>
+ template<class Type> inline
+ basic_ptree<K, D, C> & basic_ptree<K, D, C>::add(
+ const path_type &path, const Type &value)
+ {
+ return add(path, value,
+ typename translator_between<data_type, Type>::type());
+ }
-#endif
- ///////////////////////////////////////////////////////////////////////////
- // Free functions
+ template<class K, class D, class C>
+ basic_ptree<K, D, C> *
+ basic_ptree<K, D, C>::walk_path(path_type &p) const
+ {
+ if(p.empty()) {
+ // I'm the child we're looking for.
+ return const_cast<basic_ptree*>(this);
+ }
+ // Recurse down the tree to find the path.
+ key_type fragment = p.reduce();
+ const_assoc_iterator el = find(fragment);
+ if(el == not_found()) {
+ // No such child.
+ return 0;
+ }
+ // Not done yet, recurse.
+ return el->second.walk_path(p);
+ }
- template<class Ptree>
- inline const Ptree &empty_ptree()
+ template<class K, class D, class C>
+ basic_ptree<K, D, C> & basic_ptree<K, D, C>::force_path(path_type &p)
{
- static Ptree pt;
- return pt;
+ assert(!p.empty() && "Empty path not allowed for put_child.");
+ if(p.single()) {
+ // I'm the parent we're looking for.
+ return *this;
+ }
+ key_type fragment = p.reduce();
+ assoc_iterator el = find(fragment);
+ // If we've found an existing child, go down that path. Else
+ // create a new one.
+ self_type& child = el == not_found() ?
+ push_back(value_type(fragment, self_type()))->second : el->second;
+ return child.force_path(p);
}
- template<class C, class K, class P, class D, class X>
- inline void swap(basic_ptree<C, K, P, D, X> &pt1, basic_ptree<C, K, P, D, X> &pt2)
+ // Free functions
+
+ template<class K, class D, class C>
+ inline void swap(basic_ptree<K, D, C> &pt1, basic_ptree<K, D, C> &pt2)
{
pt1.swap(pt2);
}
} }
-// Undefine debug macros
-#ifdef BOOST_PROPERTY_TREE_DEBUG
-# undef BOOST_PROPERTY_TREE_DEBUG_INCREMENT_INSTANCES_COUNT
-# undef BOOST_PROPERTY_TREE_DEBUG_DECREMENT_INSTANCES_COUNT
-#endif
-
#endif
Modified: trunk/boost/property_tree/detail/ptree_utils.hpp
==============================================================================
--- trunk/boost/property_tree/detail/ptree_utils.hpp (original)
+++ trunk/boost/property_tree/detail/ptree_utils.hpp 2009-09-01 17:27:45 EDT (Tue, 01 Sep 2009)
@@ -11,6 +11,9 @@
#define BOOST_PROPERTY_TREE_DETAIL_PTREE_UTILS_HPP_INCLUDED
#include <boost/limits.hpp>
+#include <boost/type_traits/integral_constant.hpp>
+#include <boost/mpl/has_xxx.hpp>
+#include <boost/mpl/and.hpp>
#include <string>
#include <algorithm>
#include <locale>
@@ -29,10 +32,26 @@
}
inline bool operator()(const T &t1, const T &t2) const
{
- return std::lexicographical_compare(t1.begin(), t1.end(), t2.begin(), t2.end(), *this);
+ return std::lexicographical_compare(t1.begin(), t1.end(),
+ t2.begin(), t2.end(), *this);
}
};
+ template <typename Ch>
+ struct is_character : public boost::false_type {};
+ template <>
+ struct is_character<char> : public boost::true_type {};
+ template <>
+ struct is_character<wchar_t> : public boost::true_type {};
+
+
+ BOOST_MPL_HAS_XXX_TRAIT_DEF(internal_type)
+ BOOST_MPL_HAS_XXX_TRAIT_DEF(external_type)
+ template <typename T>
+ struct is_translator : public boost::mpl::and_<
+ has_internal_type<T>, has_external_type<T> > {};
+
+
// Naively convert narrow string to another character type
template<class Ch>
@@ -51,7 +70,6 @@
template<class Ch>
std::string narrow(const Ch *text)
{
- std::locale loc;
std::string result;
while (*text)
{
@@ -66,17 +84,17 @@
// Remove trailing and leading spaces
template<class Ch>
- std::basic_string<Ch> trim(const std::basic_string<Ch> &s,
+ std::basic_string<Ch> trim(const std::basic_string<Ch> &s,
const std::locale &loc = std::locale())
{
typename std::basic_string<Ch>::const_iterator first = s.begin();
typename std::basic_string<Ch>::const_iterator end = s.end();
- while (first != end && std::isspace(*first, loc))
+ while (first != end && std::isspace(*first, loc))
++first;
if (first == end)
return std::basic_string<Ch>();
typename std::basic_string<Ch>::const_iterator last = end;
- do --last; while (std::isspace(*last, loc));
+ do --last; while (std::isspace(*last, loc));
if (first != s.begin() || last + 1 != end)
return std::basic_string<Ch>(first, last + 1);
else
Deleted: trunk/boost/property_tree/detail/pugxml.hpp
==============================================================================
--- trunk/boost/property_tree/detail/pugxml.hpp 2009-09-01 17:27:45 EDT (Tue, 01 Sep 2009)
+++ (empty file)
@@ -1,3931 +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>
-#include <algorithm>
-#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. '<...>'
- node_pcdata, //E.g. '>...<'
- node_cdata, //E.g. '<![CDATA[...]]>'
- node_comment, //E.g. '<!--...-->'
- node_pi, //E.g. '<?...?>'
- node_include, //E.g. '<![INCLUDE[...]]>'
- node_doctype, //E.g. '<!DOCTYPE ...>'.
- node_dtd_entity, //E.g. '<!ENTITY ...>'.
- node_dtd_attlist, //E.g. '<!ATTLIST ...>'.
- node_dtd_element, //E.g. '<!ELEMENT ...>'.
- node_dtd_notation //E.g. '<!NOTATION ...>'.
-}
- 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 '<?...?>'
-static const unsigned long parse_doctype = 0x00000004; //Parse '<!DOCTYPE ...>' section, setting '[...]' as data member.
-static const unsigned long parse_comments = 0x00000008; //Parse <!--...-->'
-static const unsigned long parse_cdata = 0x00000010; //Parse '<![CDATA[...]]>', and/or '<![INCLUDE[...]]>'
-static const unsigned long parse_escapes = 0x00000020; //Not implemented.
-static const unsigned long parse_trim_pcdata = 0x00000040; //Trim '>...<'
-static const unsigned long parse_trim_attribute = 0x00000080; //Trim 'foo="..."'.
-static const unsigned long parse_trim_cdata = 0x00000100; //Trim '<![CDATA[...]]>', and/or '<![INCLUDE[...]]>'
-static const unsigned long parse_trim_entity = 0x00000200; //Trim '<!ENTITY name ...>', etc.
-static const unsigned long parse_trim_doctype = 0x00000400; //Trim '<!DOCTYPE [...]>'
-static const unsigned long parse_trim_comment = 0x00000800; //Trim <!--...-->'
-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 '<!DOCTYPE [*]>'
-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 '<'.
-{ return (c==_T('<')); }
-inline static bool chartype_leave(TCHAR c) //Character is '>'.
-{ 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 "‘" -or- ‘"‘.
-{ 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"),(std::max)((7*sizeof(TCHAR)),dtdilen))==0) e = node_dtd_attlist;
- else if(_tcsncmp(mark,_T("ELEMENT"),(std::max)((7*sizeof(TCHAR)),dtdilen))==0) e = node_dtd_element;
- else if(_tcsncmp(mark,_T("NOTATION"),(std::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 ? (std::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 ? (std::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,(std::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,(std::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,(std::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,(std::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,(std::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,(std::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: <LINE><STAGEDIR>Aside</STAGEDIR>Thy father,
- // Pompey, would ne'er have</LINE>, where 'this' points to <LINE>.
- //</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(),(std::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(),(std::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: trunk/boost/property_tree/detail/rapidxml.hpp
==============================================================================
--- trunk/boost/property_tree/detail/rapidxml.hpp (original)
+++ trunk/boost/property_tree/detail/rapidxml.hpp 2009-09-01 17:27:45 EDT (Tue, 01 Sep 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: trunk/boost/property_tree/detail/translator_implementation.hpp
==============================================================================
--- trunk/boost/property_tree/detail/translator_implementation.hpp 2009-09-01 17:27:45 EDT (Tue, 01 Sep 2009)
+++ (empty file)
@@ -1,279 +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_TRANSLATOR_IMPLEMENTATION_HPP_INCLUDED
-#define BOOST_PROPERTY_TREE_DETAIL_TRANSLATOR_IMPLEMENTATION_HPP_INCLUDED
-
-#include <boost/limits.hpp>
-
-namespace boost { namespace property_tree
-{
-
- namespace detail
- {
-
- ////////////////////////////////////////////////////////////////////////////
- // Helpers
-
- // Data-to-string converter for std::string
- inline std::string data_to_string(const std::string &data)
- {
- return data;
- }
-
- // Data-to-string converter for std::basic_string<Ch>
- template<class Ch>
- std::string data_to_string(const std::basic_string<Ch> &data)
- {
- return narrow(data.c_str());
- }
-
- template<class T>
- struct array_to_pointer_decay
- {
- typedef T type;
- };
-
- template<class T, std::size_t N>
- struct array_to_pointer_decay<T[N]>
- {
- typedef const T *type;
- };
-
- ////////////////////////////////////////////////////////////////////////////
- // Extractor
-
- // Various specializations of extractors and inserters are provided to:
- // 1. Optimize use of strings by copying them directly instead through stringstream
- // 2. Optimize use of native char (i.e the same char as used by data string) by copying
- // it directly instead of through stringstream
- // 3. Treat signed and unsigned chars as integers, not as characters, i.e.
- // pt.put_value(signed char(65)) produces data equal to "65", instead of "A".
- // Only plain char is treated as a character type, i.e pt.put_value(char(65)) will
- // produce "A"
- // 4. Allow recognizing various bool strings (0, 1, true, false)
-
- template<class Ch, class T>
- struct extractor
- {
- inline bool operator()(const std::basic_string<Ch> &data,
- T &extracted,
- const std::locale &loc) const
- {
- std::basic_istringstream<Ch> stream(data);
- stream.imbue(loc);
- stream >> extracted;
- if (!stream.eof())
- stream >> std::ws;
- return stream.eof() && !stream.fail() && !stream.bad();
- }
- };
-
- template<class Ch>
- struct extractor<Ch, std::basic_string<Ch> >
- {
- inline bool operator()(const std::basic_string<Ch> &data,
- std::basic_string<Ch> &extracted,
- const std::locale &loc) const
- {
- extracted = data;
- return true;
- }
- };
-
- template<class Ch>
- struct extractor<Ch, Ch>
- {
- inline bool operator()(const std::basic_string<Ch> &data,
- Ch &extracted,
- const std::locale &loc) const
- {
- if (data.size() == 1)
- {
- extracted = data[0];
- return true;
- }
- else
- return false;
- }
- };
-
- template<class Ch>
- struct extractor<Ch, signed char>
- {
- inline bool operator()(const std::basic_string<Ch> &data,
- signed char &extracted,
- const std::locale &loc) const
- {
- std::basic_istringstream<Ch> stream(data);
- stream.imbue(loc);
- int tmp;
- stream >> tmp;
- if (!stream.eof())
- stream >> std::ws;
- if (stream.eof() && !stream.fail() && !stream.bad())
- {
- extracted = static_cast<signed char>(tmp);
- return true;
- }
- else
- return false;
- }
- };
-
- template<class Ch>
- struct extractor<Ch, unsigned char>
- {
- inline bool operator()(const std::basic_string<Ch> &data,
- unsigned char &extracted,
- const std::locale &loc) const
- {
- std::basic_istringstream<Ch> stream(data);
- stream.imbue(loc);
- unsigned int tmp;
- stream >> tmp;
- if (!stream.eof())
- stream >> std::ws;
- if (stream.eof() && !stream.fail() && !stream.bad())
- {
- extracted = static_cast<unsigned char>(tmp);
- return true;
- }
- else
- return false;
- }
- };
-
- template<class Ch>
- struct extractor<Ch, bool>
- {
- inline bool operator()(const std::basic_string<Ch> &data,
- bool &extracted,
- const std::locale &loc) const
- {
- std::basic_istringstream<Ch> stream(data);
- stream.imbue(loc);
- bool tmp;
- stream >> std::boolalpha >> tmp;
- if (!stream.eof())
- stream >> std::ws;
- if (stream.eof() && !stream.fail() && !stream.bad())
- {
- extracted = tmp;
- return true;
- }
- else
- {
- std::basic_istringstream<Ch> stream2(data);
- stream2.imbue(loc);
- bool tmp;
- stream2 >> tmp;
- if (!stream2.eof())
- stream >> std::ws;
- if (stream2.eof() && !stream2.fail() && !stream2.bad())
- {
- extracted = tmp;
- return true;
- }
- }
- return false;
- }
- };
-
- ////////////////////////////////////////////////////////////////////////////
- // Inserter
-
- template<class Ch, class T>
- struct inserter
- {
- inline bool operator()(std::basic_string<Ch> &data,
- const T &to_insert,
- const std::locale &loc) const
- {
- typedef typename detail::array_to_pointer_decay<T>::type T2;
- std::basic_ostringstream<Ch> stream;
- stream.imbue(loc);
- if (std::numeric_limits<T2>::is_specialized
- && !std::numeric_limits<T2>::is_exact)
- stream.precision(std::numeric_limits<T2>::digits10 + 1);
- stream << std::boolalpha << to_insert;
- data = stream.str();
- return !stream.fail() && !stream.bad();
- }
- };
-
- template<class Ch>
- struct inserter<Ch, signed char>
- {
- inline bool operator()(std::basic_string<Ch> &data,
- const signed char &to_insert,
- const std::locale &loc) const
- {
- return detail::inserter<Ch, int>()(data, static_cast<int>(to_insert), loc);
- }
- };
-
- template<class Ch>
- struct inserter<Ch, unsigned char>
- {
- inline bool operator()(std::basic_string<Ch> &data,
- const unsigned char &to_insert,
- const std::locale &loc) const
- {
- return detail::inserter<Ch, unsigned int>()(data, static_cast<unsigned int>(to_insert), loc);
- }
- };
-
- template<class Ch>
- struct inserter<Ch, std::basic_string<Ch> >
- {
- inline bool operator()(std::basic_string<Ch> &data,
- const std::basic_string<Ch> &to_insert,
- const std::locale &loc) const
- {
- data = to_insert;
- return true;
- }
- };
-
- }
-
- inline translator::translator()
- {
- }
-
- inline translator::translator(const std::locale &loc):
- m_locale(loc)
- {
- }
-
- template<class Ptree, class T>
- bool translator::get_value(const Ptree &pt, T &value) const
- {
- typedef typename Ptree::data_type::value_type Ch;
- return detail::extractor<Ch, T>()(pt.data(), value, m_locale);
- }
-
- template<class Ptree, class T>
- bool translator::put_value(Ptree &pt, const T &value) const
- {
-
- typedef typename Ptree::data_type::value_type Ch;
-
- // Make sure that no pointer other than char_type * is allowed
- BOOST_STATIC_ASSERT((is_pointer<T>::value == false ||
- is_same<Ch, typename remove_const<typename remove_pointer<T>::type>::type>::value == true));
-
- return detail::inserter<Ch, T>()(pt.data(), value, m_locale);
-
- }
-
-} }
-
-#endif
Modified: trunk/boost/property_tree/detail/xml_parser_error.hpp
==============================================================================
--- trunk/boost/property_tree/detail/xml_parser_error.hpp (original)
+++ trunk/boost/property_tree/detail/xml_parser_error.hpp 2009-09-01 17:27:45 EDT (Tue, 01 Sep 2009)
@@ -24,7 +24,7 @@
const std::string &filename,
unsigned long line):
file_parser_error(message, filename, line)
- {
+ {
}
};
Deleted: trunk/boost/property_tree/detail/xml_parser_read_pugixml.hpp
==============================================================================
--- trunk/boost/property_tree/detail/xml_parser_read_pugixml.hpp 2009-09-01 17:27:45 EDT (Tue, 01 Sep 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: trunk/boost/property_tree/detail/xml_parser_read_pugxml.hpp
==============================================================================
--- trunk/boost/property_tree/detail/xml_parser_read_pugxml.hpp 2009-09-01 17:27:45 EDT (Tue, 01 Sep 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: trunk/boost/property_tree/detail/xml_parser_read_rapidxml.hpp
==============================================================================
--- trunk/boost/property_tree/detail/xml_parser_read_rapidxml.hpp (original)
+++ trunk/boost/property_tree/detail/xml_parser_read_rapidxml.hpp 2009-09-01 17:27:45 EDT (Tue, 01 Sep 2009)
@@ -15,6 +15,7 @@
#include <boost/property_tree/detail/xml_parser_flags.hpp>
#include <boost/property_tree/detail/xml_parser_utils.hpp>
#include <boost/property_tree/detail/rapidxml.hpp>
+#include <vector>
namespace boost { namespace property_tree { namespace xml_parser
{
@@ -40,15 +41,16 @@
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;
// Data nodes
case rapidxml::node_data:
+ case rapidxml::node_cdata:
{
if (flags & no_concat_text)
pt.push_back(std::make_pair(xmltext<Ch>(), Ptree(node->value())));
@@ -72,7 +74,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)
@@ -84,31 +87,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: trunk/boost/property_tree/detail/xml_parser_read_spirit.hpp
==============================================================================
--- trunk/boost/property_tree/detail/xml_parser_read_spirit.hpp 2009-09-01 17:27:45 EDT (Tue, 01 Sep 2009)
+++ (empty file)
@@ -1,733 +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.hpp>
-#include <boost/spirit/iterator/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::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::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::chset<char_t> chset_t;
-
- boost::spirit::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;
-
- // 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::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::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::parse_info<It> result = boost::spirit::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: trunk/boost/property_tree/detail/xml_parser_read_tinyxml.hpp
==============================================================================
--- trunk/boost/property_tree/detail/xml_parser_read_tinyxml.hpp 2009-09-01 17:27:45 EDT (Tue, 01 Sep 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: trunk/boost/property_tree/info_parser.hpp
==============================================================================
--- trunk/boost/property_tree/info_parser.hpp (original)
+++ trunk/boost/property_tree/info_parser.hpp 2009-09-01 17:27:45 EDT (Tue, 01 Sep 2009)
@@ -22,14 +22,12 @@
/**
* Read INFO from a the given stream and translate it to a property tree.
- * @note Clears existing contents of property tree. In case of error the property tree unmodified.
- * @throw info_parser_error On error translating the INFO stream to a property tree.
- * @param stream Stream from which to read in the property tree.
- * @param[out] pt The property tree to populate.
+ * @note Replaces the existing contents. Strong exception guarantee.
+ * @throw info_parser_error If the stream cannot be read, doesn't contain
+ * valid INFO, or a conversion fails.
*/
template<class Ptree, class Ch>
- void read_info(std::basic_istream<Ch> &stream,
- Ptree &pt)
+ void read_info(std::basic_istream<Ch> &stream, Ptree &pt)
{
Ptree local;
read_info_internal(stream, local, std::string(), 0);
@@ -38,42 +36,38 @@
/**
* Read INFO from a the given stream and translate it to a property tree.
- * @note Clears existing contents of property tree. In case of error the property tree unmodified.
- * @param stream Stream from which to read in the property tree.
- * @param[out] pt The property tree to populate.
- * @param default_ptree The property tree to which to set @c pt on error reading the INFO stream.
+ * @note Replaces the existing contents. Strong exception guarantee.
+ * @param default_ptree If parsing fails, pt is set to a copy of this tree.
*/
template<class Ptree, class Ch>
- void read_info(std::basic_istream<Ch> &stream,
- Ptree &pt,
+ void read_info(std::basic_istream<Ch> &stream, Ptree &pt,
const Ptree &default_ptree)
{
- try
- {
+ try {
read_info(stream, pt);
- }
- catch (file_parser_error &)
- {
+ } catch(file_parser_error &) {
pt = default_ptree;
}
}
/**
- * Read INFO from a the given file and translate it to a property tree.
- * @note Clears existing contents of property tree. In case of error the property tree unmodified.
- * @throw info_parser_error On error translating the INFO stream to a property tree.
- * @param filename Name of file from which to read in the property tree.
- * @param[out] pt The property tree to populate.
- * @param loc The locale to use when reading in the file contents.
+ * Read INFO from a the given file and translate it to a property tree. The
+ * tree's key type must be a string type, i.e. it must have a nested
+ * value_type typedef that is a valid parameter for basic_ifstream.
+ * @note Replaces the existing contents. Strong exception guarantee.
+ * @throw info_parser_error If the file cannot be read, doesn't contain
+ * valid INFO, or a conversion fails.
*/
template<class Ptree>
- void read_info(const std::string &filename,
- Ptree &pt,
+ void read_info(const std::string &filename, Ptree &pt,
const std::locale &loc = std::locale())
{
- std::basic_ifstream<typename Ptree::key_type::value_type> stream(filename.c_str());
- if (!stream)
- BOOST_PROPERTY_TREE_THROW(info_parser_error("cannot open file for reading", filename, 0));
+ std::basic_ifstream<typename Ptree::key_type::value_type>
+ stream(filename.c_str());
+ if (!stream) {
+ BOOST_PROPERTY_TREE_THROW(info_parser_error(
+ "cannot open file for reading", filename, 0));
+ }
stream.imbue(loc);
Ptree local;
read_info_internal(stream, local, filename, 0);
@@ -81,65 +75,64 @@
}
/**
- * Read INFO from a the given file and translate it to a property tree.
- * @note Clears existing contents of property tree. In case of error the property tree unmodified.
- * @param filename Name of file from which to read in the property tree.
- * @param[out] pt The property tree to populate.
- * @param loc The locale to use when reading in the file contents.
- * @param default_ptree The property tree to which to set @c pt on error reading the INFO stream.
+ * Read INFO from a the given file and translate it to a property tree. The
+ * tree's key type must be a string type, i.e. it must have a nested
+ * value_type typedef that is a valid parameter for basic_ifstream.
+ * @note Replaces the existing contents. Strong exception guarantee.
+ * @param default_ptree If parsing fails, pt is set to a copy of this tree.
*/
template<class Ptree>
- void read_info(const std::string &filename,
+ void read_info(const std::string &filename,
Ptree &pt,
const Ptree &default_ptree,
const std::locale &loc = std::locale())
{
- try
- {
+ try {
read_info(filename, pt, loc);
- }
- catch (file_parser_error &)
- {
+ } catch(file_parser_error &) {
pt = default_ptree;
}
}
/**
- * Translates the property tree to INFO and writes it the given output stream.
- * @throw info_parser_error In case of error translating the property tree to INFO
- * or writing to the output stream.
- * @param stream The stream to which to write the INFO representation of the
- * property tree.
- * @param pt The property tree to tranlsate to INFO and output.
+ * Writes a tree to the stream in INFO format.
+ * @throw info_parser_error If the stream cannot be written to, or a
+ * conversion fails.
* @param settings The settings to use when writing the INFO data.
*/
template<class Ptree, class Ch>
- void write_info(std::basic_ostream<Ch> &stream,
+ void write_info(std::basic_ostream<Ch> &stream,
const Ptree &pt,
- const info_writer_settings<Ch> &settings=info_writer_settings<Ch>())
+ const info_writer_settings<Ch> &settings =
+ info_writer_settings<Ch>())
{
write_info_internal(stream, pt, std::string(), settings);
}
/**
- * Translates the property tree to INFO and writes it the given file.
- * @throw info_parser_error In case of error translating the property tree to INFO
- * or writing to the file.
- * @param filename The name of the file to which to write the INFO representation
- * of the property tree.
- * @param pt The property tree to tranlsate to INFO and output.
+ * Writes a tree to the file in INFO format. The tree's key type must be a
+ * string type, i.e. it must have a nested value_type typedef that is a
+ * valid parameter for basic_ofstream.
+ * @throw info_parser_error If the file cannot be written to, or a
+ * conversion fails.
* @param settings The settings to use when writing the INFO data.
- * @param loc The locale to use when writing the file.
*/
template<class Ptree>
void write_info(const std::string &filename,
const Ptree &pt,
const std::locale &loc = std::locale(),
- const info_writer_settings<typename Ptree::key_type::value_type> &settings = info_writer_make_settings<typename Ptree::key_type::value_type>())
- {
- std::basic_ofstream<typename Ptree::key_type::value_type> stream(filename.c_str());
- if (!stream)
- BOOST_PROPERTY_TREE_THROW(info_parser_error("cannot open file for writing", filename, 0));
+ const info_writer_settings<
+ typename Ptree::key_type::value_type
+ > &settings =
+ info_writer_make_settings<
+ typename Ptree::key_type::value_type>())
+ {
+ std::basic_ofstream<typename Ptree::key_type::value_type>
+ stream(filename.c_str());
+ if (!stream) {
+ BOOST_PROPERTY_TREE_THROW(info_parser_error(
+ "cannot open file for writing", filename, 0));
+ }
stream.imbue(loc);
write_info_internal(stream, pt, filename, settings);
}
Modified: trunk/boost/property_tree/ini_parser.hpp
==============================================================================
--- trunk/boost/property_tree/ini_parser.hpp (original)
+++ trunk/boost/property_tree/ini_parser.hpp 2009-09-01 17:27:45 EDT (Tue, 01 Sep 2009)
@@ -22,9 +22,6 @@
namespace boost { namespace property_tree { namespace ini_parser
{
- /** Skip check if ptree is a valid ini */
- static const int skip_ini_validity_check = 1;
-
/**
* Determines whether the @c flags are valid for use with the ini_parser.
* @param flags value to check for validity as flags to ini_parser.
@@ -32,7 +29,7 @@
*/
inline bool validate_flags(int flags)
{
- return (flags & ~skip_ini_validity_check) == 0;
+ return flags == 0;
}
/** Indicates an error parsing INI formatted data. */
@@ -42,31 +39,37 @@
/**
* Construct an @c ini_parser_error
* @param message Message describing the parser error.
- * @param filename The name of the file being parsed containing the error.
- * @param line The line in the given file where an error was encountered.
+ * @param filename The name of the file being parsed containing the
+ * error.
+ * @param line The line in the given file where an error was
+ * encountered.
*/
- ini_parser_error(const std::string &message,
- const std::string &filename,
- unsigned long line):
- file_parser_error(message, filename, line)
- {
+ ini_parser_error(const std::string &message,
+ const std::string &filename,
+ unsigned long line)
+ : file_parser_error(message, filename, line)
+ {
}
};
/**
* Read INI from a the given stream and translate it to a property tree.
- * @note Clears existing contents of property tree. In case of error the property tree unmodified.
- * @throw ini_parser_error In case of error deserializing the property tree.
+ * @note Clears existing contents of property tree. In case of error
+ * the property tree is not modified.
+ * @throw ini_parser_error If a format violation is found.
* @param stream Stream from which to read in the property tree.
* @param[out] pt The property tree to populate.
*/
template<class Ptree>
- void read_ini(std::basic_istream<typename Ptree::key_type::value_type> &stream,
+ void read_ini(std::basic_istream<
+ typename Ptree::key_type::value_type> &stream,
Ptree &pt)
{
-
typedef typename Ptree::key_type::value_type Ch;
typedef std::basic_string<Ch> Str;
+ const Ch semicolon = stream.widen(';');
+ const Ch lbracket = stream.widen('[');
+ const Ch rbracket = stream.widen(']');
Ptree local;
unsigned long line_no = 0;
@@ -81,45 +84,59 @@
++line_no;
std::getline(stream, line);
if (!stream.good() && !stream.eof())
- BOOST_PROPERTY_TREE_THROW(ini_parser_error("read error", "", line_no));
+ BOOST_PROPERTY_TREE_THROW(ini_parser_error(
+ "read error", "", line_no));
// If line is non-empty
line = detail::trim(line, stream.getloc());
if (!line.empty())
{
-
// Comment, section or key?
- if (line[0] == Ch(';'))
+ if (line[0] == semicolon)
{
// Ignore comments
}
- else if (line[0] == Ch('['))
+ else if (line[0] == lbracket)
{
- typename Str::size_type end = line.find(Ch(']'));
+ // If the previous section was empty, drop it again.
+ if (section && section->empty())
+ local.pop_back();
+ typename Str::size_type end = line.find(rbracket);
if (end == Str::npos)
- BOOST_PROPERTY_TREE_THROW(ini_parser_error("unmatched '['", "", line_no));
- Str key = detail::trim(line.substr(1, end - 1), stream.getloc());
- if (local.find(key) != local.end())
- BOOST_PROPERTY_TREE_THROW(ini_parser_error("duplicate section name", "", line_no));
- section = &local.push_back(std::make_pair(key, Ptree()))->second;
+ BOOST_PROPERTY_TREE_THROW(ini_parser_error(
+ "unmatched '['", "", line_no));
+ Str key = detail::trim(line.substr(1, end - 1),
+ stream.getloc());
+ if (local.find(key) != local.not_found())
+ BOOST_PROPERTY_TREE_THROW(ini_parser_error(
+ "duplicate section name", "", line_no));
+ section = &local.push_back(
+ std::make_pair(key, Ptree()))->second;
}
else
{
- if (!section)
- BOOST_PROPERTY_TREE_THROW(ini_parser_error("section expected", "", line_no));
+ Ptree &container = section ? *section : local;
typename Str::size_type eqpos = line.find(Ch('='));
if (eqpos == Str::npos)
- BOOST_PROPERTY_TREE_THROW(ini_parser_error("'=' character not found in line", "", line_no));
+ BOOST_PROPERTY_TREE_THROW(ini_parser_error(
+ "'=' character not found in line", "", line_no));
if (eqpos == 0)
- BOOST_PROPERTY_TREE_THROW(ini_parser_error("key expected", "", line_no));
- Str key = detail::trim(line.substr(0, eqpos), stream.getloc());
- Str data = detail::trim(line.substr(eqpos + 1, Str::npos), stream.getloc());
- if (section->find(key) != section->end())
- BOOST_PROPERTY_TREE_THROW(ini_parser_error("duplicate key name", "", line_no));
- section->push_back(std::make_pair(key, Ptree(data)));
+ BOOST_PROPERTY_TREE_THROW(ini_parser_error(
+ "key expected", "", line_no));
+ Str key = detail::trim(line.substr(0, eqpos),
+ stream.getloc());
+ Str data = detail::trim(line.substr(eqpos + 1, Str::npos),
+ stream.getloc());
+ if (container.find(key) != container.not_found())
+ BOOST_PROPERTY_TREE_THROW(ini_parser_error(
+ "duplicate key name", "", line_no));
+ container.push_back(std::make_pair(key, Ptree(data)));
}
}
}
+ // If the last section was empty, drop it again.
+ if (section && section->empty())
+ local.pop_back();
// Swap local ptree with result ptree
pt.swap(local);
@@ -128,7 +145,8 @@
/**
* Read INI from a the given file and translate it to a property tree.
- * @note Clears existing contents of property tree. In case of error the property tree unmodified.
+ * @note Clears existing contents of property tree. In case of error the
+ * property tree unmodified.
* @throw ini_parser_error In case of error deserializing the property tree.
* @param filename Name of file from which to read in the property tree.
* @param[out] pt The property tree to populate.
@@ -139,85 +157,122 @@
Ptree &pt,
const std::locale &loc = std::locale())
{
- std::basic_ifstream<typename Ptree::key_type::value_type> stream(filename.c_str());
+ std::basic_ifstream<typename Ptree::key_type::value_type>
+ stream(filename.c_str());
if (!stream)
- BOOST_PROPERTY_TREE_THROW(ini_parser_error("cannot open file", filename, 0));
+ BOOST_PROPERTY_TREE_THROW(ini_parser_error(
+ "cannot open file", filename, 0));
stream.imbue(loc);
try {
read_ini(stream, pt);
}
catch (ini_parser_error &e) {
- BOOST_PROPERTY_TREE_THROW(ini_parser_error(e.message(), filename, e.line()));
+ BOOST_PROPERTY_TREE_THROW(ini_parser_error(
+ e.message(), filename, e.line()));
+ }
+ }
+
+ namespace detail
+ {
+ template<class Ptree>
+ void check_dupes(const Ptree &pt)
+ {
+ if(pt.size() <= 1)
+ return;
+ const typename Ptree::key_type *lastkey = 0;
+ typename Ptree::const_assoc_iterator it = pt.ordered_begin(),
+ end = pt.not_found();
+ lastkey = &it->first;
+ for(++it; it != end; ++it) {
+ if(*lastkey == it->first)
+ BOOST_PROPERTY_TREE_THROW(ini_parser_error(
+ "duplicate key", "", 0));
+ lastkey = &it->first;
+ }
}
}
/**
- * Translates the property tree to INI and writes it the given output stream.
- * @pre @e pt cannot have keys with data at its root level.
- * @pre @e pt cannot be deaper than two levels.
+ * Translates the property tree to INI and writes it the given output
+ * stream.
+ * @pre @e pt cannot have data in its root.
+ * @pre @e pt cannot have keys both data and children.
+ * @pre @e pt cannot be deeper than two levels.
* @pre There cannot be duplicate keys on any given level of @e pt.
- * @throw ini_parser_error In case of error translating the property tree to INI
- * or writing to the output stream.
+ * @throw ini_parser_error In case of error translating the property tree to
+ * INI or writing to the output stream.
* @param stream The stream to which to write the INI representation of the
* property tree.
* @param pt The property tree to tranlsate to INI and output.
* @param flags The flags to use when writing the INI file.
- * The following flags are supported:
- * @li @c skip_ini_validity_check -- Skip check if ptree is a valid ini. The
- * validity check covers the preconditions but takes <tt>O(n log n)</tt> time.
+ * No flags are currently supported.
*/
template<class Ptree>
- void write_ini(std::basic_ostream<typename Ptree::key_type::value_type> &stream,
+ void write_ini(std::basic_ostream<
+ typename Ptree::key_type::value_type
+ > &stream,
const Ptree &pt,
int flags = 0)
{
+ using detail::check_dupes;
typedef typename Ptree::key_type::value_type Ch;
typedef std::basic_string<Ch> Str;
BOOST_ASSERT(validate_flags(flags));
-
- // Verify if ptree is not too rich to be saved as ini
- if (!(flags & skip_ini_validity_check))
- for (typename Ptree::const_iterator it = pt.begin(), end = pt.end(); it != end; ++it)
- {
+ (void)flags;
+
+ if (!pt.data().empty())
+ BOOST_PROPERTY_TREE_THROW(ini_parser_error(
+ "ptree has data on root", "", 0));
+ check_dupes(pt);
+
+ for (typename Ptree::const_iterator it = pt.begin(), end = pt.end();
+ it != end; ++it)
+ {
+ check_dupes(it->second);
+ if (it->second.empty()) {
+ stream << it->first << Ch('=')
+ << it->second.template get_value<
+ std::basic_string<Ch> >()
+ << Ch('\n');
+ } else {
if (!it->second.data().empty())
- BOOST_PROPERTY_TREE_THROW(ini_parser_error("ptree has data on root level keys", "", 0));
- if (pt.count(it->first) > 1)
- BOOST_PROPERTY_TREE_THROW(ini_parser_error("duplicate section name", "", 0));
- for (typename Ptree::const_iterator it2 = it->second.begin(), end2 = it->second.end(); it2 != end2; ++it2)
+ BOOST_PROPERTY_TREE_THROW(ini_parser_error(
+ "mixed data and children", "", 0));
+ stream << Ch('[') << it->first << Ch(']') << Ch('\n');
+ for (typename Ptree::const_iterator it2 = it->second.begin(),
+ end2 = it->second.end(); it2 != end2; ++it2)
{
if (!it2->second.empty())
- BOOST_PROPERTY_TREE_THROW(ini_parser_error("ptree is too deep", "", 0));
- if (it->second.count(it2->first) > 1)
- BOOST_PROPERTY_TREE_THROW(ini_parser_error("duplicate key name", "", 0));
+ BOOST_PROPERTY_TREE_THROW(ini_parser_error(
+ "ptree is too deep", "", 0));
+ stream << it2->first << Ch('=')
+ << it2->second.template get_value<
+ std::basic_string<Ch> >()
+ << Ch('\n');
}
}
-
- // Write ini
- for (typename Ptree::const_iterator it = pt.begin(), end = pt.end(); it != end; ++it)
- {
- stream << Ch('[') << it->first << Ch(']') << Ch('\n');
- for (typename Ptree::const_iterator it2 = it->second.begin(), end2 = it->second.end(); it2 != end2; ++it2)
- stream << it2->first << Ch('=') << it2->second.template get_value<std::basic_string<Ch> >() << Ch('\n');
}
}
/**
* Translates the property tree to INI and writes it the given file.
- * @pre @e pt cannot have keys with data at its root level.
- * @pre @e pt cannot be deaper than two levels.
+ * @pre @e pt cannot have data in its root.
+ * @pre @e pt cannot have keys both data and children.
+ * @pre @e pt cannot be deeper than two levels.
* @pre There cannot be duplicate keys on any given level of @e pt.
- * @throw info_parser_error In case of error translating the property tree to INI
- * or writing to the file.
- * @param filename The name of the file to which to write the INI representation
- * of the property tree.
+ * @throw info_parser_error In case of error translating the property tree
+ * to INI or writing to the file.
+ * @param filename The name of the file to which to write the INI
+ * representation of the property tree.
* @param pt The property tree to tranlsate to INI and output.
* @param flags The flags to use when writing the INI file.
* The following flags are supported:
- * @li @c skip_ini_validity_check -- Skip check if ptree is a valid ini. The
- * validity check covers the preconditions but takes <tt>O(n log n)</tt> time.
+ * @li @c skip_ini_validity_check -- Skip check if ptree is a valid ini. The
+ * validity check covers the preconditions but takes <tt>O(n log n)</tt>
+ * time.
* @param loc The locale to use when writing the file.
*/
template<class Ptree>
@@ -226,15 +281,18 @@
int flags = 0,
const std::locale &loc = std::locale())
{
- std::basic_ofstream<typename Ptree::key_type::value_type> stream(filename.c_str());
+ std::basic_ofstream<typename Ptree::key_type::value_type>
+ stream(filename.c_str());
if (!stream)
- BOOST_PROPERTY_TREE_THROW(ini_parser_error("cannot open file", filename, 0));
+ BOOST_PROPERTY_TREE_THROW(ini_parser_error(
+ "cannot open file", filename, 0));
stream.imbue(loc);
try {
write_ini(stream, pt, flags);
}
catch (ini_parser_error &e) {
- BOOST_PROPERTY_TREE_THROW(ini_parser_error(e.message(), filename, e.line()));
+ BOOST_PROPERTY_TREE_THROW(ini_parser_error(
+ e.message(), filename, e.line()));
}
}
Modified: trunk/boost/property_tree/json_parser.hpp
==============================================================================
--- trunk/boost/property_tree/json_parser.hpp (original)
+++ trunk/boost/property_tree/json_parser.hpp 2009-09-01 17:27:45 EDT (Tue, 01 Sep 2009)
@@ -29,14 +29,17 @@
* @note Items of JSON arrays are translated into ptree keys with empty
* names. Members of objects are translated into named keys.
* @note JSON data can be a string, a numeric value, or one of literals
- * "null", "true" and "false". During parse, any of the above is copied
- * verbatim into ptree data string.
- * @throw json_parser_error In case of error deserializing the property tree.
+ * "null", "true" and "false". During parse, any of the above is
+ * copied verbatim into ptree data string.
+ * @throw json_parser_error In case of error deserializing the property
+ * tree.
* @param stream Stream from which to read in the property tree.
* @param[out] pt The property tree to populate.
*/
template<class Ptree>
- void read_json(std::basic_istream<typename Ptree::key_type::value_type> &stream,
+ void read_json(std::basic_istream<
+ typename Ptree::key_type::value_type
+ > &stream,
Ptree &pt)
{
read_json_internal(stream, pt, std::string());
@@ -49,9 +52,10 @@
* @note Items of JSON arrays are translated into ptree keys with empty
* names. Members of objects are translated into named keys.
* @note JSON data can be a string, a numeric value, or one of literals
- * "null", "true" and "false". During parse, any of the above is copied
- * verbatim into ptree data string.
- * @throw json_parser_error In case of error deserializing the property tree.
+ * "null", "true" and "false". During parse, any of the above is
+ * copied verbatim into ptree data string.
+ * @throw json_parser_error In case of error deserializing the property
+ * tree.
* @param filename Name of file from which to read in the property tree.
* @param[out] pt The property tree to populate.
* @param loc The locale to use when reading in the file contents.
@@ -61,26 +65,31 @@
Ptree &pt,
const std::locale &loc = std::locale())
{
- std::basic_ifstream<typename Ptree::key_type::value_type> stream(filename.c_str());
+ std::basic_ifstream<typename Ptree::key_type::value_type>
+ stream(filename.c_str());
if (!stream)
- BOOST_PROPERTY_TREE_THROW(json_parser_error("cannot open file", filename, 0));
+ BOOST_PROPERTY_TREE_THROW(json_parser_error(
+ "cannot open file", filename, 0));
stream.imbue(loc);
read_json_internal(stream, pt, filename);
}
/**
- * Translates the property tree to JSON and writes it the given output stream.
- * @note Any property tree key containing only unnamed subkeys will be rendered
- * as JSON arrays.
+ * Translates the property tree to JSON and writes it the given output
+ * stream.
+ * @note Any property tree key containing only unnamed subkeys will be
+ * rendered as JSON arrays.
* @pre @e pt cannot contain keys that have both subkeys and non-empty data.
- * @throw json_parser_error In case of error translating the property tree to JSON
- * or writing to the output stream.
- * @param stream The stream to which to write the JSON representation of the
+ * @throw json_parser_error In case of error translating the property tree
+ * to JSON or writing to the output stream.
+ * @param stream The stream to which to write the JSON representation of the
* property tree.
* @param pt The property tree to tranlsate to JSON and output.
*/
template<class Ptree>
- void write_json(std::basic_ostream<typename Ptree::key_type::value_type> &stream,
+ void write_json(std::basic_ostream<
+ typename Ptree::key_type::value_type
+ > &stream,
const Ptree &pt)
{
write_json_internal(stream, pt, std::string());
@@ -88,14 +97,14 @@
/**
* Translates the property tree to JSON and writes it the given file.
- * @note Any property tree key containing only unnamed subkeys will be rendered
- * as JSON arrays.
+ * @note Any property tree key containing only unnamed subkeys will be
+ * rendered as JSON arrays.
* @pre @e pt cannot contain keys that have both subkeys and non-empty data.
- * @throw json_parser_error In case of error translating the property tree to JSON
- * or writing to the file.
- * @param filename The name of the file to which to write the JSON representation
- * of the property tree.
- * @param pt The property tree to tranlsate to JSON and output.
+ * @throw json_parser_error In case of error translating the property tree
+ * to JSON or writing to the file.
+ * @param filename The name of the file to which to write the JSON
+ * representation of the property tree.
+ * @param pt The property tree to translate to JSON and output.
* @param loc The locale to use when writing out to the output file.
*/
template<class Ptree>
@@ -103,9 +112,11 @@
const Ptree &pt,
const std::locale &loc = std::locale())
{
- std::basic_ofstream<typename Ptree::key_type::value_type> stream(filename.c_str());
+ std::basic_ofstream<typename Ptree::key_type::value_type>
+ stream(filename.c_str());
if (!stream)
- BOOST_PROPERTY_TREE_THROW(json_parser_error("cannot open file", filename, 0));
+ BOOST_PROPERTY_TREE_THROW(json_parser_error(
+ "cannot open file", filename, 0));
stream.imbue(loc);
write_json_internal(stream, pt, filename);
}
Modified: trunk/boost/property_tree/ptree.hpp
==============================================================================
--- trunk/boost/property_tree/ptree.hpp (original)
+++ trunk/boost/property_tree/ptree.hpp 2009-09-01 17:27:45 EDT (Tue, 01 Sep 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
@@ -8,58 +9,42 @@
// For more information, see www.boost.org
// ----------------------------------------------------------------------------
-/// This header contains definition of basic_ptree class template and supporting definitions.
-
#ifndef BOOST_PROPERTY_TREE_PTREE_HPP_INCLUDED
#define BOOST_PROPERTY_TREE_PTREE_HPP_INCLUDED
-#include <boost/property_tree/ptree_fwd.hpp> // Must be the first include, because of config.hpp
-
-#include <boost/assert.hpp>
-#include <boost/optional.hpp>
-#include <boost/static_assert.hpp>
-#include <boost/type_traits/is_pointer.hpp>
-#include <boost/type_traits/is_same.hpp>
-#include <boost/type_traits/remove_const.hpp>
-#include <boost/type_traits/remove_pointer.hpp>
-#include <boost/any.hpp>
+#include <boost/property_tree/ptree_fwd.hpp>
+#include <boost/property_tree/string_path.hpp>
+#include <boost/property_tree/stream_translator.hpp>
+#include <boost/property_tree/exceptions.hpp>
+#include <boost/property_tree/detail/ptree_utils.hpp>
+
+#include <boost/multi_index_container.hpp>
+#include <boost/multi_index/indexed_by.hpp>
+#include <boost/multi_index/sequenced_index.hpp>
+#include <boost/multi_index/ordered_index.hpp>
+#include <boost/multi_index/member.hpp>
+#include <boost/utility/enable_if.hpp>
#include <boost/throw_exception.hpp>
-
-#ifdef BOOST_PROPERTY_TREE_DEBUG
-# include <boost/detail/lightweight_mutex.hpp> // For syncing debug instances counter
-#endif
-
-#include <functional> // for std::less
-#include <limits>
-#include <list>
-#include <sstream>
-#include <stdexcept>
+#include <boost/optional.hpp>
#include <utility> // for std::pair
-#include <vector>
-#include <cstdlib>
-
-#if !defined(BOOST_PROPERTY_TREE_DOXYGEN_INVOKED)
- // Throwing macro to avoid no return warnings portably
-# define BOOST_PROPERTY_TREE_THROW(e) { throw_exception(e); std::exit(1); }
-#endif
namespace boost { namespace property_tree
{
/**
- * Class template implementing property tree.
+ * Property tree main structure. A property tree is a hierarchical data
+ * structure which has one element of type @p Data in each node, as well
+ * as an ordered sequence of sub-nodes, which are additionally identified
+ * by a non-unique key of type @p Key.
*
- * A property tree can have data associated with it
- * along with a sequence of @c (key,basic_ptree) children.
- * Iterators provide bidirectional iterative access into children sequence.
+ * Key equivalency is defined by @p KeyCompare, a predicate defining a
+ * strict weak ordering.
*
- * @tparam C Key comparison type
- * @tparam K Key type
- * @tparam P Path type
- * @tparam D Data type
- * @tparam X Translator type to use for converting values to and from std::string
+ * Property tree defines a Container-like interface to the (key-node) pairs
+ * of its direct sub-nodes. The iterators are bidirectional. The sequence
+ * of nodes is held in insertion order, not key order.
*/
- template<class C, class K, class P, class D, class X>
+ template<class Key, class Data, class KeyCompare>
class basic_ptree
{
#if defined(BOOST_PROPERTY_TREE_DOXYGEN_INVOKED)
@@ -67,868 +52,466 @@
#endif
// Internal types
/**
- * Simpler way to refer to this basic_ptree<C,K,P,D,X> type.
- * Do not use in client code; exposed only for documentation purposes.
+ * Simpler way to refer to this basic_ptree\<C,K,P,A\> type.
+ * Note that this is private, and made public only for doxygen.
*/
- typedef basic_ptree<C, K, P, D, X> self_type;
+ typedef basic_ptree<Key, Data, KeyCompare> self_type;
public:
// Basic types
- typedef C key_compare;
- typedef K key_type;
- typedef P path_type;
- typedef D data_type;
- typedef X translator_type;
+ typedef Key key_type;
+ typedef Data data_type;
+ typedef KeyCompare key_compare;
- /**
- * Property tree stores a sequence of values of this type.
- *
- * The first element is the key and the second is the child property tree
- * stored at this key.
- */
- typedef std::pair<key_type, self_type> value_type;
+ // Container view types
+ typedef std::pair<const Key, self_type> value_type;
+ typedef std::size_t size_type;
- private:
- // Internal types
- typedef std::list<value_type> container_type;
+ // The problem with the iterators is that I can't make them complete
+ // until the container is complete. Sucks. Especially for the reverses.
+ class iterator;
+ class const_iterator;
+ class reverse_iterator;
+ class const_reverse_iterator;
- public:
- // Container-related types
- typedef typename container_type::size_type size_type;
- typedef typename container_type::iterator iterator;
- typedef typename container_type::const_iterator const_iterator;
- typedef typename container_type::reverse_iterator reverse_iterator;
- typedef typename container_type::const_reverse_iterator const_reverse_iterator;
+ // Associative view types
+ class assoc_iterator;
+ class const_assoc_iterator;
- public:
- ///////////////////////////////////////////////////////////////////////////
- // Construction & destruction
+ // Property tree view types
+ typedef typename path_of<Key>::type path_type;
- /** Creates an empty property tree. */
- basic_ptree();
- /**
- * Creates a property_tree with the given data.
- * @param data Data to be assigned to the tree's data field.
- */
+ // The big five
+
+ /** Creates a node with no children and default-constructed data. */
+ basic_ptree();
+ /** Creates a node with no children and a copy of the given data. */
explicit basic_ptree(const data_type &data);
+ basic_ptree(const self_type &rhs);
+ ~basic_ptree();
+ /** Basic guarantee only. */
+ self_type &operator =(const self_type &rhs);
- /**
- * Copy constructor from another property_tree.
- * @param rhs The property tree to be copied.
+ /** Swap with other tree. Only constant-time and nothrow if the
+ * data type's swap is.
*/
- basic_ptree(const self_type &rhs);
+ void swap(self_type &rhs);
- /** Destroys the property tree including recusively destoying all children. */
- ~basic_ptree();
+ // Container view functions
- ///////////////////////////////////////////////////////////////////////////
- // Iterator access
+ /** The number of direct children of this node. */
+ size_type size() const;
+ size_type max_size() const;
+ /** Whether there are any direct children. */
+ bool empty() const;
- /**
- * Access to the start of the direct children sequence.
- * @return iterator pointing to the first element of the direct children sequence.
- */
iterator begin();
-
- /**
- * Const access to the start of the direct children sequence.
- * @return const_iterator pointing to the first element of the direct children sequence.
- */
const_iterator begin() const;
-
- /**
- * Access to the end of the direct children sequence.
- * @return iterator pointing just past the end of the direct children sequence.
- */
iterator end();
-
- /**
- * Const access to the end of the direct children sequence.
- * @return const_iterator pointing just past the end of the direct children sequence.
- */
const_iterator end() const;
-
- /**
- * Access to the start of the reversed direct children sequence.
- * @return reverse_iterator pointing to first element of the reversed direct children sequence.
- */
reverse_iterator rbegin();
-
- /**
- * Const access to the start of the reversed direct children sequence.
- * @return const_reverse_iterator pointing to first element of the reversed direct children sequence.
- */
const_reverse_iterator rbegin() const;
-
- /**
- * Access to the end of the reverse direct children sequence.
- * @return reverse_iterator pointing just past the end of the reversed direct children sequence.
- */
reverse_iterator rend();
-
- /**
- * Const access to the end of the reverse direct children sequence.
- * @return const_reverse_iterator pointing just past the end of the reversed direct children sequence.
- */
const_reverse_iterator rend() const;
- ///////////////////////////////////////////////////////////////////////////
- // Data access
-
- /**
- * The size fo the direct children sequnce.
- * @return Number of direct children of the property tree.
- */
- size_type size() const;
-
- size_type max_size() const;
-
- /**
- * Determine whether the children sequence is empty.
- * @note empty() should be prefered over <tt>size() == 0</tt>
- * @retval true There are no direct children.
- * @retval false There is at least one direct child.
- */
- bool empty() const;
-
- /**
- * Retruns a reference to the data of a property tree.
- * @return Reference to the stored data which can be used to modify the data.
- */
- data_type &data();
-
- /**
- * Returns a const reference to the data of a property tree.
- * @return Const reference to the stored data.
- */
- const data_type &data() const;
-
- /**
- * Returns a reference to the first element in the direct children sequence.
- * @pre !(this->empty())
- * @return Reference to the first element in the direct children sequence.
- */
value_type &front();
-
- /**
- * Returns a const reference to the first element in the direct children sequence.
- * @pre !(this->empty())
- * @return Const reference to the first element in the direct children sequence.
- */
const value_type &front() const;
-
- /**
- * Returns a reference to the last element in the direct children sequence.
- * @pre !(this->empty())
- * @return Reference to the last element in the direct children sequence.
- */
value_type &back();
-
- /**
- * Returns a const reference to the last element in the direct children sequence.
- * @pre !(this->empty())
- * @return Const reference to the last element in the direct children sequence.
- */
const value_type &back() const;
- ///////////////////////////////////////////////////////////////////////////
- // Operators
-
- /**
- * Replaces current contents of this property tree with another's contents.
- * @param rhs The property tree to assign to this property tree.
- */
- self_type &operator =(const self_type &rhs);
-
- /**
- * Check for equality of property trees.
- * @retval true If both property trees contain the same data values and equivalent
- * children sequences, recusively.
- * @retval false Otherwise.
- */
- bool operator ==(const self_type &rhs) const;
-
- /**
- * Check for inequality of property trees.
- * @return !(*this == rhs)
- */
- bool operator !=(const self_type &rhs) const;
-
- ///////////////////////////////////////////////////////////////////////////
- // Container operations
-
- /**
- * Finds direct child stored at specified key.
- *
- * If there is more than one child with the same key, the first one is
- * returned. Time complexity is <tt>O(log n)</tt>. Keys equivalence is
- * tested with a predicate supplied as basic_ptree template parameter.
- * If childe is not found, returns end(). Both const and non-const
- * versions are provided. To find non-direct children use get_child
- * function.
- *
- * @param key The key to search in the direct children sequence.
- * @return iterator pointing to the found sequence element, or end()
- * if no such element exists.
- */
- iterator find(const key_type &key);
-
- /**
- * Finds direct child stored at specified key.
- *
- * If there is more than one child with the same key, the first one is
- * returned. Time complexity is <tt>O(log n)</tt>. Keys equivalence is
- * tested with a predicate supplied as basic_ptree template parameter.
- * If child is not found, returns end(). Both const and non-const
- * versions are provided. To find non-direct children use get_child
- * function.
- *
- * @param key The key to search in the direct children sequence.
- * @return const_iterator pointing to the found sequence element,
- * or end() if no such element exists.
- */
- const_iterator find(const key_type &key) const;
-
- /**
- * Count the number of direct children with the given key.
- *
- * Keys equivalence is tested with a predicate supplied as basic_ptree
- * template parameter.
- * @param key Key to count.
- * @return Number of direct children with given key.
- */
- size_type count(const key_type &key) const;
-
- /**
- * Recursively deletes all children of the property tree and clears the
- * data from the property tree.
- */
- void clear();
-
- /**
- * Inserts a new direct child into the property tree.
- *
- * @param where Iterator pointing at the position where new element will be
- * inserted. Passing begin() will insert at the front of the
- * list. Passing end() will insert at the back. Any other
- * valid iterator will insert in the appropriate place in the
- * middle.
- * @param value value to be inserted.
- * @return iterator pointing to newly inserted element of the sequence.
+ /** Insert a copy of the given tree with its key just before the given
+ * position in this node. This operation invalidates no iterators.
+ * @return An iterator to the newly created child.
*/
iterator insert(iterator where, const value_type &value);
- /**
- * Inserts a range of direct children into the property tree.
- *
- * Time complexity is <tt>O(m log n)</tt>, where @c m is number of inserted
- * children, @c n is number of existing children.
- *
- * @param where Iterator pointing at the position where new elements will be
- * inserted. Passing begin() will insert at the front of the
- * list. Passing end() will insert at the back. Any other
- * valid iterator will insert in the appropriate place in the
- * middle.
- * @param first Iterator designating the first element of range to be
- * inserted.
- * @param last Iterator referring to just past the end of the range to be
- * inserted.
+ /** Range insert. Equivalent to:
+ * @code
+ * for(; first != last; ++first) insert(where, *first);
+ * @endcode
*/
template<class It> void insert(iterator where, It first, It last);
- /**
- * Erases a direct child from the property tree.
- *
- * @param where Iterator pointing at the child to be erased from the property tree.
- * @return Iterator pointing to the element after the erased element of the sequence,
- * or end() if the element erased was the last in the sequence.
+ /** Erase the child pointed at by the iterator. This operation
+ * invalidates the given iterator, as well as its equivalent
+ * assoc_iterator.
+ * @return A valid iterator pointing to the element after the erased.
*/
iterator erase(iterator where);
- /**
- * Erases direct children from the property tree matching the given key.
- *
- * @param key Key designating child or children to erase.
- * @return Number of children that were erased.
- */
- size_type erase(const key_type &key);
-
- /**
- * Erases a range of direct children from the property tree.
- *
- * @param first Iterator designating the first element of range to be
- * erased.
- * @param last Iterator referring to just past the end of the range to be
- * erased.
+ /** Range erase. Equivalent to:
+ * @code
+ * while(first != last;) first = erase(first);
+ * @endcode
*/
- template<class It> iterator erase(It first, It last);
+ iterator erase(iterator first, iterator last);
- /**
- * Inserts a new direct child at the front of the sequence.
- *
- * Equivalent to insert(begin(), value).
- * @param value Value to be inserted.
- * @return Iterator pointing to newly inserted element of the sequence.
- */
+ /** Equivalent to insert(begin(), value). */
iterator push_front(const value_type &value);
- /**
- * Inserts a new direct child at the back of the sequence.
- *
- * Equivalent to insert(end(), value)
- * @param value Value to be inserted.
- * @return Iterator pointing to newly inserted element of the sequence.
- */
+ /** Equivalent to insert(end(), value). */
iterator push_back(const value_type &value);
- /**
- * Erases the first direct child in the sequence.
- *
- * Equivalent to erase(begin()).
- * @pre !(this->empty())
- */
+ /** Equivalent to erase(begin()). */
void pop_front();
- /**
- * Erases the last direct child in the sequence.
- *
- * Equivalent to erase(boost::prior(end())).
- * @pre !(this->empty())
- */
+ /** Equivalent to erase(boost::prior(end())). */
void pop_back();
- /**
- * Swaps contents of this property tree with the contents of another.
- *
- * Time complexity is <tt>O(1)</tt>.
- * @param rhs Property tree with which to swap.
- */
- void swap(self_type &rhs);
-
/** Reverses the order of direct children in the property tree. */
void reverse();
- /**
- * Sorts direct children of the property tree in ascending order.
- * @param tr The binary predicate used to sort child values of type @c #value_type.
- * @post For each adjacent child of the sequence, @c v1 followed by @c v2,
- * @c tr(v1,v2) evaluates to true.
- */
- template<class SortTr> void sort(SortTr tr);
-
- ///////////////////////////////////////////////////////////////////////////
- // ptree operations
-
- /**
- * Get a reference to the child property tree at the given path.
- *
- * Traverses the tree using the given path and retrieves a child property tree
- * stored there. This function will retrieve indirect children if the path contains
- * at least one separator.
- * @param path A sequence of keys with zero or more separator characters.
- * Can indicate indirect children if path contains at least one separator
- * character.
- * @throw ptree_bad_path if child property tree cannot be located.
- * @return A reference to the child property tree at the given path relative to this
- * property tree.
- */
- self_type &get_child(const path_type &path);
-
- /**
- * Get a const reference to the child property tree at the given path.
- *
- * Traverses the tree using the given path and retrieves a child property tree
- * stored there. This function will retrieve indirect children if the path contains
- * at least one separator.
- * @param path A sequence of keys with zero or more separator characters.
- * Can indicate indirect children if path contains at least one separator
- * character.
- * @throw ptree_bad_path if child property tree cannot be located.
- * @return A const reference to the child property tree at the given path relative to this
- * property tree.
- */
- const self_type &get_child(const path_type &path) const;
-
- /**
- * Get a reference to the child property tree at the given path or a default if none found.
- *
- * Traverses the tree using the given path and retrieves a child property tree
- * stored there. This function will retrieve indirect children if the path contains
- * at least one separator. If child isn't found then the @c default_value will be returned.
- * @param path A sequence of keys with zero or more separator characters.
- * Can indicate indirect children if path contains at least one separator
- * character.
- * @param default_value The value to be returned if no child is found at @c path.
- * @return A reference to the child property tree at the given path relative to this
- * property tree or the @c default_value if that child isn't found
- */
- self_type &get_child(const path_type &path, self_type &default_value);
-
- /**
- * Get a const reference to the child property tree at the given path or a default if none found.
- *
- * Traverses the tree using the given path and retrieves a child property tree
- * stored there. This function will retrieve indirect children if the path contains
- * at least one separator. If child isn't found then the @c default_value will be returned.
- * @note One use of default value is to return a reference to empty property tree if the
- * required one is not found. In many cases, the subsequent code using the return
- * value can be then made simpler. @see boost::property_tree::empty_ptree.
- * @param path A sequence of keys with zero or more separator characters.
- * Can indicate indirect children if path contains at least one separator
- * character.
- * @param default_value The value to be returned if no child is found at @c path.
- * @return A const reference to the child property tree at the given path relative to this
- * property tree or the @c default_value if that child isn't found
- */
- const self_type &get_child(const path_type &path, const self_type &default_value) const;
-
- /**
- * Get a reference to the child property tree at the given path if it exists.
- *
- * Traverses the tree using the given path and retrieves a child property tree
- * stored there. This function will retrieve indirect children if the path contains
- * at least one separator.
- * @param path A sequence of keys with zero or more separator characters.
- * Can indicate indirect children if path contains at least one separator
- * character.
- * @return If the child is found, the function returns boost::optional initialized with
- * a reference to it. Otherwise it returns uninitialized boost::optional.
- */
- optional<self_type &> get_child_optional(const path_type &path);
-
- /**
- * Get a const reference to the child property tree at the given path if it exists.
- *
- * Traverses the tree using the given path and retrieves a child property tree
- * stored there. This function will retrieve indirect children if the path contains
- * at least one separator.
- * @param path A sequence of keys with zero or more separator characters.
- * Can indicate indirect children if path contains at least one separator
- * character.
- * @return If the child is found, the function returns boost::optional initialized with
- * a const reference to it. Otherwise it returns uninitialized boost::optional.
+ /** Sorts the direct children of this node according to the predicate.
+ * The predicate is passed the whole pair of key and child.
*/
- optional<const self_type &> get_child_optional(const path_type &path) const;
+ template<class Compare> void sort(Compare comp);
- /**
- * Traverses the tree using given path, and inserts a new property tree or replaces
- * existing one. If any of the intermediate keys specified by path does not exist,
- * it is inserted, with empty data and no children, at the back of existing sequence.
- *
- * For example, if @c path is "key1.key2.key3", the function will find a child designated
- * by "key1.key2" path. This child will be checked for presence of "key3" subkey. If it
- * exists, it will be replaced with the one specified by value parameter. If it does not
- * exist, "key3" will be added at the back of existing sequence (if any). If either
- * "key1" or "key1.key2" do not exist, the function will insert them as well.
- *
- * This function is a complement to @c #get_child. If @c put_child(path,value) was called,
- * @c get_child(path) will return a reference to element inserted/replaced by put_child.
- *
- * @param path Location to place value. A sequence of keys with zero or more separator
- * characters.
- * @param value Property tree to be inserted as a child of this property tree.
- * @param do_not_replace If set to true, causes function to always insert a new key,
- * even if there already exists key with the same name.
- * @return Reference to the inserted property tree.
- */
- self_type &put_child(const path_type &path, const self_type &value, bool do_not_replace = false);
+ /** Sorts the direct children of this node according to key order. */
+ void sort();
- /**
- * Extracts value stored in property tree data and translates it to Type using
- * the given translator.
- * @throw ptree_bad_data If data cannot be translated to an instance of @c Type
- * using the given translator_type.
- * @param x Translator to use to extract and convert the contained #data_type to @c Type
- * using <tt>bool translator_type::get_value(self_type const&, Type&)</tt>.
- * @return The extracted value as an instance of @c Type.
- */
- template<class Type> Type get_value(const translator_type &x = translator_type()) const;
+ // Equality
- /**
- * Extracts value stored in property tree data and translates it to Type using the
- * given translator. If extraction does not succeed then return the given default value.
- * @param default_value The value to be returned if the the given translator cannot
- * extract the data as an instance of @c Type.
- * @param x Translator to use to extract and convert the contained #data_type to @c Type
- * using <tt>bool translator_type::get_value(self_type const&, Type&)</tt>.
- * @return The extracted value as an instance of @c Type if extraction succeeds.
- * Otherwise it returns the @c default_value.
+ /** Two property trees are the same if they have the same data, the keys
+ * and order of their children are the same, and the children compare
+ * equal, recursively.
*/
- template<class Type> Type get_value(const Type &default_value, const translator_type &x = translator_type()) const;
-
- /**
- * Extracts value stored in property tree data and translates it to @c std::basic_string<CharType>
- * using the given translator. If extraction does not succeed then return the given default string.
- * @param default_value The string to be returned if the the given translator cannot
- * extract the data as an instance of @c Type.
- * @param x Translator to use to extract and convert the contained #data_type to @c std::basic_string<CharType>
- * using <tt>bool translator_type::get_value(self_type const&, std::basic_string<CharType>&)</tt>.
- * @return The extracted value as an instance of @c std::basic_string<CharType> if extraction succeeds.
- * Otherwise it returns the @c default_value.
- */
- template<class CharType> std::basic_string<CharType> get_value(const CharType *default_value, const translator_type &x = translator_type()) const;
-
- /**
- * Extracts value stored in property tree data and translates it to Type using the
- * given translator.
- * @param default_value The value to be returned if the the given translator cannot
- * extract the data as an instance of @c Type.
- * @param x Translator to use to extract and convert the contained #data_type to @c Type
- * using <tt>bool translator_type::get_value(self_type const&, Type&)</tt>.
- * @return The extracted value as an instance of @c Type if extraction succeeds.
- * Otherwise it returns an uninitialized @c boost::optional<Type>.
- */
- template<class Type> optional<Type> get_value_optional(const translator_type &x = translator_type()) const;
+ bool operator ==(const self_type &rhs) const;
+ bool operator !=(const self_type &rhs) const;
- /**
- * Get the property tree value at the given path.
- *
- * Traverses the tree using the given path and retrieves the value stored there.
- * This function will retrieve values of indirect children if the path contains at least
- * one separator. The value will be converted to an instance of @c Type using the
- * given translator.
- * @param path A sequence of keys with zero or more separator characters.
- * Can indicate indirect children if path contains at least one separator
- * character.
- * @param x Translator to use to extract and convert the contained #data_type to @c Type
- * using <tt>bool translator_type::get_value(self_type const&, Type&)</tt>.
- * @throw ptree_bad_path if child property tree cannot be located using the given path.
- * @return The child property tree's value at the given path relative to this
- * property tree.
- */
- template<class Type> Type get(const path_type &path, const translator_type &x = translator_type()) const;
+ // Associative view
- /**
- * Get the property tree value at the given path or a default if none found.
- *
- * Traverses the tree using the given path and retrieves the value stored there
- * This function will retrieve values of indirect children if the path contains at least
- * one separator. The value will be converted to an instance of @c Type using the
- * given translator. If child isn't found then the @c default_value will be returned.
- * @param path A sequence of keys with zero or more separator characters.
- * Can indicate indirect children if path contains at least one separator
- * character.
- * @param default_value The value to be returned if no child is found at @c path
- * or translation fails.
- * @param x Translator to use to extract and convert the contained #data_type to @c Type
- * using <tt>bool translator_type::get_value(self_type const&, Type&)</tt>.
- * @return The child property tree's value at the given path relative to this
- * property tree or the @c default_value if that child is not found.
- */
- template<class Type> Type get(const path_type &path, const Type &default_value, const translator_type &x = translator_type()) const;
+ /** Returns an iterator to the first child, in order. */
+ assoc_iterator ordered_begin();
+ /** Returns an iterator to the first child, in order. */
+ const_assoc_iterator ordered_begin() const;
- /**
- * Get the property tree value as @c std::basic_string<CharType> at the given path
- * or a default if none found.
- *
- * Traverses the tree using the given path and retrieves the value stored there
- * This function will retrieve values of indirect children if the path contains at least
- * one separator. The value will be converted to an instance of
- * @c std::basic_string<CharType> using the given translator. If child isn't
- * found then the @c default_value will be returned.
- * @param path A sequence of keys with zero or more separator characters.
- * Can indicate indirect children if path contains at least one separator
- * character.
- * @param default_value The string to be returned if no child is found at @c path
- * or translation fails.
- * @param x Translator to use to extract and convert the contained #data_type to @c std::basic_string<CharType>
- * using <tt>bool translator_type::get_value(self_type const&, std::basic_string<CharType>&)</tt>.
- * @return The child property tree's value as @c std::basic_string<CharType> at
- * the given path relative to this property tree or the @c default_value
- * if that child is not found or translation fails.
+ /** Returns the not-found iterator. Equivalent to end() in a real
+ * associative container.
*/
- template<class CharType> std::basic_string<CharType> get(const path_type &path, const CharType *default_value, const translator_type &x = translator_type()) const;
-
- /**
- * Get the property tree value at the given path or an uninitialized
- * @c boost::optional<Type> if none found.
- *
- * Traverses the tree using the given path and retrieves the value stored there
- * This function will retrieve values of indirect children if the path contains at least
- * one separator. The value will be converted to an instance of @c Type using the
- * given translator. If child isn't found then an unitialized @c boost::optional<Type>
- * will be returned.
- * @param path A sequence of keys with zero or more separator characters.
- * Can indicate indirect children if path contains at least one separator
- * character.
- * @param x Translator to use to extract and convert the contained #data_type to @c Type
- * using <tt>bool translator_type::get_value(self_type const&, Type&)</tt>.
- * @return The child property tree's value at the given path relative to this
- * property tree or an unitialized @c boost::optional<Type> if that child is not
- * found or translation fails.
+ assoc_iterator not_found();
+ /** Returns the not-found iterator. Equivalent to end() in a real
+ * associative container.
*/
- template<class Type> optional<Type> get_optional(const path_type &path, const translator_type &x = translator_type()) const;
-
- /**
- * Store the given value as the data of this property tree.
- *
- * Translates @c value from @c Type to @c #data_type using the given translator, and stores the
- * result as the data value of this property tree.
- * @throw ptree_bad_data If the given value cannot be translated to @c #data_type.
- * @param value The parameter to store as the data of this property tree.
- * @param x Translator to use to convert @c value to an instance of @c #data_type
- * using <tt>bool translator_type::put_value(self_type&,Type const&)</tt>.
- */
- template<class Type> void put_value(const Type &value, const translator_type &x = translator_type());
-
- /**
- * Traverses the tree using given path, and inserts a new value or replaces existing one.
- * If any of the intermediate keys specified by path does not exist, it is inserted,
- * with empty data and no children, at the back of existing sequence.
- *
- * For example, if @c path is "key1.key2.key3", the function will find a child designated
- * by "key1.key2" path. This child will be checked for presence of "key3" subkey. If it
- * exists, it will be replaced with the one specified by value parameter. If it does not
- * exist, "key3" will be added at the back of existing sequence (if any). If either
- * "key1" or "key1.key2" do not exist, the function will insert them as well.
- *
- * This function is a complement to @c #get. If @c put(path,value) was called,
- * @c get(path) will return the value inserted by @c #put.
- *
- * @param path Location to place value. A sequence of keys with zero or more separator
- * characters.
- * @param value value to be inserted as the data of a child of this property tree.
- * @param do_not_replace If set to true, causes function to always insert a new key,
- * even if there already exists key with the same name.
- * @param x Translator to use to convert @c value to an instance of @c #data_type
- * using <tt>bool translator_type::put_value(self_type&,Type const&)</tt>.
- * @return Reference to the property tree where the value was inserted. It is either a
- * newly inserted property tree or an existing one if it was there prior to
- * this call.
- */
- template<class Type> self_type &put(const path_type &path, const Type &value, bool do_not_replace = false, const translator_type &x = translator_type());
-
- private:
-
- data_type m_data;
- container_type m_container;
-
- ////////////////////////////////////////////////////////////////////////////
- // Debugging
-
-#ifdef BOOST_PROPERTY_TREE_DEBUG
- private:
- static boost::detail::lightweight_mutex debug_mutex; // Mutex for syncing instances counter
- static size_type debug_instances_count; // Total number of instances of this ptree class
- public:
- static size_type debug_get_instances_count();
-#endif
-
- };
+ const_assoc_iterator not_found() const;
- ///////////////////////////////////////////////////////////////////////////
- // basic_path class template
-
- /** Class template used to represent a path containing a sequence of Key instances. */
- template<class Key>
- class basic_path
- {
-#if defined(BOOST_PROPERTY_TREE_DOXYGEN_INVOKED)
- public:
-#endif
- /**
- * Simpler way to refer to the Key::value_type type.
- * Do not use in client code; exposed only for documentation purposes.
+ /** Find a child with the given key, or not_found() if there is none.
+ * There is no guarantee about which child is returned if multiple have
+ * the same key.
*/
- typedef typename Key::value_type char_type;
-
- public:
+ assoc_iterator find(const key_type &key);
- ///////////////////////////////////////////////////////////////////////
- // Construction & destruction
-
- /** Constructs an empty basic_path<Key> instance */
- basic_path();
-
- /**
- * Constructs an path using the given path using the given separator to split it.
- * @param path The path to which to initialize the constructed instance.
- * @param separator The separator to use to split the @c path parameter.
+ /** Find a child with the given key, or not_found() if there is none.
+ * There is no guarantee about which child is returned if multiple have
+ * the same key.
*/
- basic_path(const Key &path, char_type separator = char_type('.'));
+ const_assoc_iterator find(const key_type &key) const;
- /**
- * Constructs an path using the given path using the given separator to split it.
- * @param path The path to which to initialize the constructed instance. This
- * path instance must be terminated with char_type('\\0');
- * @param separator The separator to use to split the @c path parameter.
- */
- basic_path(const char_type *path, char_type separator = char_type('.'));
+ /** Find the range of children that have the given key. */
+ std::pair<assoc_iterator, assoc_iterator>
+ equal_range(const key_type &key);
- ///////////////////////////////////////////////////////////////////////
- // Path manipulation
+ /** Find the range of children that have the given key. */
+ std::pair<const_assoc_iterator, const_assoc_iterator>
+ equal_range(const key_type &key) const;
- /**
- * Append the given path to this instance.
- * @param rhs The path to append.
- * @return A reference to this path instance after appending @c rhs.
- */
- basic_path<Key> &operator /=(const basic_path<Key> &rhs);
+ /** Count the number of direct children with the given key. */
+ size_type count(const key_type &key) const;
- /**
- * Convert this path instance to a @c std::string representation.
- * @return A string representation of this path.
+ /** Erase all direct children with the given key and return the count.
*/
- std::string to_string() const;
-
- ///////////////////////////////////////////////////////////////////////
- // Operations
+ size_type erase(const key_type &key);
- /**
- * Extract the child subtree of the given property tree at the location indicated
- * by this path instance.
- * @param root The property tree from which to extract the child subtree.
- * @return Pointer to the child subtree of the input property tree indicated by the
- * location given by this path instance. If no child exists at the indicated
- * location then NULL is returned.
+ /** Get the iterator that points to the same element as the argument.
+ * @note A valid assoc_iterator range (a, b) does not imply that
+ * (to_iterator(a), to_iterator(b)) is a valid range.
*/
- template<class C, class D, class X>
- basic_ptree<C, Key, basic_path<Key>, D, X> *get_child(basic_ptree<C, Key, basic_path<Key>, D, X> &root) const;
+ iterator to_iterator(assoc_iterator it);
- /**
- * Extract the child subtree of the given property tree at the location indicated
- * by this path instance.
- * @param root The property tree from which to extract the child subtree.
- * @return Pointer to the constant child subtree of the input property tree indicated by the
- * location given by this path instance. If no child exists at the indicated
- * location then NULL is returned.
+ /** Get the iterator that points to the same element as the argument.
+ * @note A valid const_assoc_iterator range (a, b) does not imply that
+ * (to_iterator(a), to_iterator(b)) is a valid range.
*/
- template<class C, class D, class X>
- const basic_ptree<C, Key, basic_path<Key>, D, X> *get_child(const basic_ptree<C, Key, basic_path<Key>, D, X> &root) const;
-
- /**
- * Insert or replace in the given property tree at the location indicated by this path
- * instance the second given property tree as a child.
- * @param root The property tree in which to insert or replace the child.
- * @param child The property tree to insert within the tree given by that @c root parameter.
- * @param do_not_replace If set to true, causes function to always insert a new key,
- * even if there already exists key with the same name. Otherwise
- * @return Pointer to the child property tree inserted at the given location
- * location given by this path instance. If this path is empty then return NULL.
- */
- template<class C, class D, class X>
- basic_ptree<C, Key, basic_path<Key>, D, X> *put_child(basic_ptree<C, Key, basic_path<Key>, D, X> &root,
- const basic_ptree<C, Key, basic_path<Key>, D, X> &child,
- bool do_not_replace) const;
-
- private:
-
- std::vector<Key> m_path;
-
- ///////////////////////////////////////////////////////////////////////
- // Internal
-
- template<class RanIt> void parse(RanIt begin, RanIt end, char_type separator);
+ const_iterator to_iterator(const_assoc_iterator it) const;
- };
-
- ///////////////////////////////////////////////////////////////////////////
- // translator class
-
- class translator
- {
+ // Property tree view
- public:
- /** Default construct a translator instance. */
- translator();
+ /** Reference to the actual data in this node. */
+ data_type &data();
- /**
- * Construct a translator instance setting the internal locale state using
- * the given input locale.
- * @param loc The locale to use in this instance.
- */
- translator(const std::locale &loc);
+ /** Reference to the actual data in this node. */
+ const data_type &data() const;
- /**
- * Extract data value from the given property tree and convert it to an
- * instance of type @c T.
- * @param pt Property tree from which to retrieve the data value.
- * @param[out] value The variable in which to store the retrieved data value.
- * @return @c true If the data value was sucessfully converted and retrieved.
- * Otherwise return @c false.
- */
- template<class Ptree, class T> bool get_value(const Ptree &pt, T &value) const;
+ /** Clear this tree completely, of both data and children. */
+ void clear();
- /**
- * Insert the given value as the data member in the given property tree after
- * converting it to instance of type @c Ptree::data_type.
- * @param pt Property tree in which to insert the given value as data.
- * @param value The value to store as data in the given property tree.
- * @return @c true If the data value was sucessfully converted and retrieved.
- * Otherwise return @c false.
+ /** Get the child at the given path, or throw @c ptree_bad_path.
+ * @note Depending on the path, the result at each level may not be
+ * completely determinate, i.e. if the same key appears multiple
+ * times, which child is chosen is not specified. This can lead
+ * to the path not being resolved even though there is a
+ * descendant with this path. Example:
+ * @code
+ * a -> b -> c
+ * -> b
+ * @endcode
+ * The path "a.b.c" will succeed if the resolution of "b" chooses
+ * the first such node, but fail if it chooses the second.
*/
- template<class Ptree, class T> bool put_value(Ptree &pt, const T &value) const;
-
- private:
-
- std::locale m_locale;
-
- };
-
- ///////////////////////////////////////////////////////////////////////////
- // exceptions
-
- /// Base class for all property tree errors. Derives from @c std::runtime_error.
- /// Call member function @c what to get human readable message associated with the error.
- class ptree_error: public std::runtime_error
- {
- public:
- /// Instantiate a ptree_error instance with the given message.
- /// @param what The message to associate with this error.
- ptree_error(const std::string &what);
-
- ~ptree_error() throw();
- };
+ self_type &get_child(const path_type &path);
+ /** Get the child at the given path, or throw @c ptree_bad_path. */
+ const self_type &get_child(const path_type &path) const;
- /// Error indicating that translation from given value to the property tree data_type
- /// (or vice versa) failed. Derives from ptree_error.
- class ptree_bad_data: public ptree_error
- {
- public:
- /// Instantiate a ptree_bad_data instance with the given message and data.
- /// @param what The message to associate with this error.
- /// @param data The value associated with this error that was the source of the
- /// translation failure.
- template<class T> ptree_bad_data(const std::string &what, const T &data);
-
- ~ptree_bad_data() throw();
-
- /// Retrieve the data associated with this error. This is the source value that
- /// failed to be translated.
- template<class T> T data();
- private:
- boost::any m_data;
- };
+ /** Get the child at the given path, or return @p default_value. */
+ self_type &get_child(const path_type &path, self_type &default_value);
+ /** Get the child at the given path, or return @p default_value. */
+ const self_type &get_child(const path_type &path,
+ const self_type &default_value) const;
- /// Error indicating that specified path does not exist. Derives from ptree_error.
- class ptree_bad_path: public ptree_error
- {
- public:
- /// Instantiate a ptree_bad_path with the given message and path data.
- /// @param what The message to associate with this error.
- /// @param path The path that could not be found in the property_tree.
- template<class T> ptree_bad_path(const std::string &what, const T &path);
+ /** Get the child at the given path, or return boost::null. */
+ optional<self_type &> get_child_optional(const path_type &path);
- ~ptree_bad_path() throw();
+ /** Get the child at the given path, or return boost::null. */
+ optional<const self_type &>
+ get_child_optional(const path_type &path) const;
+
+ /** Set the node at the given path to the given value. Create any
+ * missing parents. If the node at the path already exists, replace it.
+ * @return A reference to the inserted subtree.
+ * @note Because of the way paths work, it is not generally guaranteed
+ * that a node newly created can be accessed using the same path.
+ * @note If the path could refer to multiple nodes, it is unspecified
+ * which one gets replaced.
+ */
+ self_type &put_child(const path_type &path, const self_type &value);
+
+ /** Add the node at the given path. Create any missing parents. If there
+ * already is a node at the path, add another one with the same key.
+ * @param path Path to the child. The last fragment must not have an
+ * index.
+ * @return A reference to the inserted subtree.
+ * @note Because of the way paths work, it is not generally guaranteed
+ * that a node newly created can be accessed using the same path.
+ */
+ self_type &add_child(const path_type &path, const self_type &value);
+
+ /** Take the value of this node and attempt to translate it to a
+ * @c Type object using the supplied translator.
+ * @throw ptree_bad_data if the conversion fails.
+ */
+ template<class Type, class Translator>
+ typename boost::enable_if<detail::is_translator<Translator>, Type>::type
+ get_value(Translator tr) const;
+
+ /** Take the value of this node and attempt to translate it to a
+ * @c Type object using the default translator.
+ * @throw ptree_bad_data if the conversion fails.
+ */
+ template<class Type>
+ Type get_value() const;
+
+ /** Take the value of this node and attempt to translate it to a
+ * @c Type object using the supplied translator. Return @p default_value
+ * if this fails.
+ */
+ template<class Type, class Translator>
+ Type get_value(const Type &default_value, Translator tr) const;
+
+ /** Make get_value do the right thing for string literals. */
+ template <class Ch, class Translator>
+ typename boost::enable_if<
+ detail::is_character<Ch>,
+ std::basic_string<Ch>
+ >::type
+ get_value(const Ch *default_value, Translator tr) const;
+
+ /** Take the value of this node and attempt to translate it to a
+ * @c Type object using the default translator. Return @p default_value
+ * if this fails.
+ */
+ template<class Type>
+ typename boost::disable_if<detail::is_translator<Type>, Type>::type
+ get_value(const Type &default_value) const;
+
+ /** Make get_value do the right thing for string literals. */
+ template <class Ch>
+ typename boost::enable_if<
+ detail::is_character<Ch>,
+ std::basic_string<Ch>
+ >::type
+ get_value(const Ch *default_value) const;
+
+ /** Take the value of this node and attempt to translate it to a
+ * @c Type object using the supplied translator. Return boost::null if
+ * this fails.
+ */
+ template<class Type, class Translator>
+ optional<Type> get_value_optional(Translator tr) const;
+
+ /** Take the value of this node and attempt to translate it to a
+ * @c Type object using the default translator. Return boost::null if
+ * this fails.
+ */
+ template<class Type>
+ optional<Type> get_value_optional() const;
+
+ /** Replace the value at this node with the given value, translated
+ * to the tree's data type using the supplied translator.
+ * @throw ptree_bad_data if the conversion fails.
+ */
+ template<class Type, class Translator>
+ void put_value(const Type &value, Translator tr);
+
+ /** Replace the value at this node with the given value, translated
+ * to the tree's data type using the default translator.
+ * @throw ptree_bad_data if the conversion fails.
+ */
+ template<class Type>
+ void put_value(const Type &value);
+
+ /** Shorthand for get_child(path).get_value(tr). */
+ template<class Type, class Translator>
+ typename boost::enable_if<detail::is_translator<Translator>, Type>::type
+ get(const path_type &path, Translator tr) const;
+
+ /** Shorthand for get_child(path).get_value\<Type\>(). */
+ template<class Type>
+ Type get(const path_type &path) const;
+
+ /** Shorthand for get_child(path, empty_ptree())
+ * .get_value(default_value, tr).
+ * That is, return the translated value if possible, and the default
+ * value if the node doesn't exist or conversion fails.
+ */
+ template<class Type, class Translator>
+ Type get(const path_type &path,
+ const Type &default_value,
+ Translator tr) const;
+
+ /** Make get do the right thing for string literals. */
+ template <class Ch, class Translator>
+ typename boost::enable_if<
+ detail::is_character<Ch>,
+ std::basic_string<Ch>
+ >::type
+ get(const path_type &path, const Ch *default_value, Translator tr)const;
+
+ /** Shorthand for get_child(path, empty_ptree())
+ * .get_value(default_value).
+ * That is, return the translated value if possible, and the default
+ * value if the node doesn't exist or conversion fails.
+ */
+ template<class Type>
+ typename boost::disable_if<detail::is_translator<Type>, Type>::type
+ get(const path_type &path, const Type &default_value) const;
+
+ /** Make get do the right thing for string literals. */
+ template <class Ch>
+ typename boost::enable_if<
+ detail::is_character<Ch>,
+ std::basic_string<Ch>
+ >::type
+ get(const path_type &path, const Ch *default_value) const;
+
+ /** Shorthand for:
+ * @code
+ * if(optional\<self_type&\> node = get_child_optional(path))
+ * return node->get_value_optional(tr);
+ * return boost::null;
+ * @endcode
+ * That is, return the value if it exists and can be converted, or nil.
+ */
+ template<class Type, class Translator>
+ optional<Type> get_optional(const path_type &path, Translator tr) const;
+
+ /** Shorthand for:
+ * @code
+ * if(optional\<const self_type&\> node = get_child_optional(path))
+ * return node->get_value_optional();
+ * return boost::null;
+ * @endcode
+ */
+ template<class Type>
+ optional<Type> get_optional(const path_type &path) const;
+
+ /** Set the value of the node at the given path to the supplied value,
+ * translated to the tree's data type. If the node doesn't exist, it is
+ * created, including all its missing parents.
+ * @return The node that had its value changed.
+ * @throw ptree_bad_data if the conversion fails.
+ */
+ template<class Type, class Translator>
+ self_type &put(const path_type &path, const Type &value, Translator tr);
+
+ /** Set the value of the node at the given path to the supplied value,
+ * translated to the tree's data type. If the node doesn't exist, it is
+ * created, including all its missing parents.
+ * @return The node that had its value changed.
+ * @throw ptree_bad_data if the conversion fails.
+ */
+ template<class Type>
+ self_type &put(const path_type &path, const Type &value);
+
+ /** If the node identified by the path does not exist, create it,
+ * including all its missing parents.
+ * If the node already exists, add a sibling with the same key.
+ * Set the newly created node's value to the given paremeter,
+ * translated with the supplied translator.
+ * @param path Path to the child. The last fragment must not have an
+ * index.
+ * @param value The value to add.
+ * @param tr The translator to use.
+ * @return The node that was added.
+ * @throw ptree_bad_data if the conversion fails.
+ */
+ template<class Type, class Translator>
+ self_type &add(const path_type &path,
+ const Type &value,
+ Translator tr);
+
+ /** If the node identified by the path does not exist, create it,
+ * including all its missing parents.
+ * If the node already exists, add a sibling with the same key.
+ * Set the newly created node's value to the given paremeter,
+ * translated with the supplied translator.
+ * @param path Path to the child. The last fragment must not have an
+ * index.
+ * @param value The value to add.
+ * @return The node that was added.
+ * @throw ptree_bad_data if the conversion fails.
+ */
+ template<class Type>
+ self_type &add(const path_type &path, const Type &value);
- /// Retrieve the invalid path.
- template<class T> T path();
private:
- boost::any m_path;
+ // Hold the data of this node
+ data_type m_data;
+ // Hold the children - this is a void* because we can't complete the
+ // container type within the class.
+ void* m_children;
+
+ // Getter tree-walk. Not const-safe! Gets the node the path refers to,
+ // or null. Destroys p's value.
+ self_type* walk_path(path_type& p) const;
+
+ // Modifer tree-walk. Gets the parent of the node referred to by the
+ // path, creating nodes as necessary. p is the path to the remaining
+ // child.
+ self_type& force_path(path_type& p);
+
+ // This struct contains typedefs for the concrete types.
+ struct subs;
+ friend struct subs;
+ friend class iterator;
+ friend class const_iterator;
+ friend class reverse_iterator;
+ friend class const_reverse_iterator;
};
-} }
+}}
-// Include implementations
#include <boost/property_tree/detail/ptree_implementation.hpp>
-// FIXME: There's a very nasty order dependency between exceptions_impl and
-// the other two headers on compilers that do really compliant ADL, like
-// GCC 4.3.
-#include <boost/property_tree/detail/path_implementation.hpp>
-#include <boost/property_tree/detail/translator_implementation.hpp>
-#include <boost/property_tree/detail/exceptions_implementation.hpp>
#endif
Modified: trunk/boost/property_tree/ptree_fwd.hpp
==============================================================================
--- trunk/boost/property_tree/ptree_fwd.hpp (original)
+++ trunk/boost/property_tree/ptree_fwd.hpp 2009-09-01 17:27:45 EDT (Tue, 01 Sep 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
@@ -11,83 +12,131 @@
#define BOOST_PROPERTY_TREE_PTREE_FWD_HPP_INCLUDED
#include <boost/config.hpp>
-#include <boost/property_tree/detail/ptree_utils.hpp>
+#include <boost/optional/optional_fwd.hpp>
#include <functional> // for std::less
+#include <memory> // for std::allocator
+#include <string>
namespace boost { namespace property_tree
{
+ namespace detail {
+ template <typename T> struct less_nocase;
+ }
- ///////////////////////////////////////////////////////////////////////////
// Classes
- template<class C, class K, class P, class D, class X> class basic_ptree;
- template<class Key> class basic_path;
- class translator;
+ template < class Key, class Data, class KeyCompare = std::less<Key> >
+ class basic_ptree;
+
+ template <typename T>
+ struct id_translator;
+
+ template <typename String, typename Translator>
+ class string_path;
+
+ // Texas-style concepts for documentation only.
+#if 0
+ concept PropertyTreePath<class Path> {
+ // The key type for which this path works.
+ typename key_type;
+ // Return the key that the first segment of the path names.
+ // Split the head off the state.
+ key_type Path::reduce();
+
+ // Return true if the path is empty.
+ bool Path::empty() const;
+
+ // Return true if the path contains a single element.
+ bool Path::single() const;
+
+ // Dump as a std::string, for exception messages.
+ std::string Path::dump() const;
+ }
+ concept PropertyTreeKey<class Key> {
+ PropertyTreePath path;
+ requires SameType<Key, PropertyTreePath<path>::key_type>;
+ }
+ concept PropertyTreeTranslator<class Tr> {
+ typename internal_type;
+ typename external_type;
+
+ boost::optional<external_type> Tr::get_value(internal_type);
+ boost::optional<internal_type> Tr::put_value(external_type);
+ }
+#endif
+ /// If you want to use a custom key type, specialize this struct for it
+ /// and give it a 'type' typedef that specifies your path type. The path
+ /// type must conform to the Path concept described in the documentation.
+ /// This is already specialized for std::basic_string.
+ template <typename Key>
+ struct path_of;
+
+ /// Specialize this struct to specify a default translator between the data
+ /// in a tree whose data_type is Internal, and the external data_type
+ /// specified in a get_value, get, put_value or put operation.
+ /// This is already specialized for Internal being std::basic_string.
+ template <typename Internal, typename External>
+ struct translator_between;
class ptree_error;
class ptree_bad_data;
class ptree_bad_path;
- ///////////////////////////////////////////////////////////////////////////
// Typedefs
/** Implements a path using a std::string as the key. */
- typedef basic_path<std::string> path;
+ typedef string_path<std::string, id_translator<std::string> > path;
/** Implements a path using a std::wstring as the key. */
- typedef basic_path<std::wstring> wpath;
+ typedef string_path<std::wstring, id_translator<std::wstring> > wpath;
/**
- * A property tree that uses a path type based upon std::string.
- * Comparisons of keys are performed in a case-sensitive manner.
+ * A property tree with std::string for key and data, and default
+ * comparison.
*/
- typedef basic_ptree<std::less<std::string>, std::string, path, std::string, translator> ptree;
+ typedef basic_ptree<std::string, std::string> ptree;
/**
- * A property tree that uses a path type based upon std::string.
- * Comparisons of keys are performed in a case-insensitive manner.
+ * A property tree with std::string for key and data, and case-insensitive
+ * comparison.
*/
- typedef basic_ptree<detail::less_nocase<std::string>, std::string, path, std::string, translator> iptree;
+ typedef basic_ptree<std::string, std::string,
+ detail::less_nocase<std::string> >
+ iptree;
#ifndef BOOST_NO_CWCHAR
/**
- * A property tree that uses a wide-character path type based upon std::wstring.
- * Comparisons of keys are performed in a case-sensitive manner.
+ * A property tree with std::wstring for key and data, and default
+ * comparison.
* @note The type only exists if the platform supports @c wchar_t.
*/
- typedef basic_ptree<std::less<std::wstring>, std::wstring, wpath, std::wstring, translator> wptree;
+ typedef basic_ptree<std::wstring, std::wstring> wptree;
/**
- * A property tree that uses a wide-character path type based upon std::wstring.
- * Comparisons of keys are performed in a case-insensitive manner.
+ * A property tree with std::wstring for key and data, and case-insensitive
+ * comparison.
* @note The type only exists if the platform supports @c wchar_t.
*/
- typedef basic_ptree<detail::less_nocase<std::wstring>, std::wstring, wpath, std::wstring, translator> wiptree;
+ typedef basic_ptree<std::wstring, std::wstring,
+ detail::less_nocase<std::wstring> >
+ wiptree;
#endif
- ///////////////////////////////////////////////////////////////////////////
// Free functions
/**
* Swap two property tree instances.
- * @param pt1 Reference to first property tree involved in swap.
- * @param pt2 Reference to second property tree involved in swap.
- */
- template<class C, class K, class P, class D, class X>
- void swap(basic_ptree<C, K, P, D, X> &pt1, basic_ptree<C, K, P, D, X> &pt2);
-
- /**
- * Reference to empty property tree. Can be used as a default value of get_child.
- * See empty_ptree_trick.cpp for example of usage.
*/
- template<class Ptree> const Ptree &empty_ptree();
+ template<class K, class D, class C>
+ void swap(basic_ptree<K, D, C> &pt1,
+ basic_ptree<K, D, C> &pt2);
- /** Join two path objects. */
- path operator /(const path &p1, const path &p2);
+} }
- /** Join two wide-path objects. */
- wpath operator /(const wpath &p1, const wpath &p2);
-} }
+#if !defined(BOOST_PROPERTY_TREE_DOXYGEN_INVOKED)
+ // Throwing macro to avoid no return warnings portably
+# define BOOST_PROPERTY_TREE_THROW(e) { throw_exception(e); std::exit(1); }
+#endif
#endif
Modified: trunk/boost/property_tree/ptree_serialization.hpp
==============================================================================
--- trunk/boost/property_tree/ptree_serialization.hpp (original)
+++ trunk/boost/property_tree/ptree_serialization.hpp 2009-09-01 17:27:45 EDT (Tue, 01 Sep 2009)
@@ -26,69 +26,75 @@
/**
* Serialize the property tree to the given archive.
- * @note In addition to serializing to regular archives, this supports serializing to
- * archives requiring name-value pairs, e.g. XML archives. However, the output
- * format in the XML archive is not guaranteed to be the same as that when using
- * the Boost.PropertyTree library's @c boost::property_tree::xml_parser::write_xml.
- * @param ar The archive to which to save the serialized property tree. This archive
- * should conform to the concept laid out by the Boost.Serialization library.
+ * @note In addition to serializing to regular archives, this supports
+ * serializing to archives requiring name-value pairs, e.g. XML
+ * archives. However, the output format in the XML archive is not
+ * guaranteed to be the same as that when using the Boost.PropertyTree
+ * library's @c boost::property_tree::xml_parser::write_xml.
+ * @param ar The archive to which to save the serialized property tree.
+ * This archive should conform to the concept laid out by the
+ * Boost.Serialization library.
* @param t The property tree to serialize.
* @param file_version file_version for the archive.
* @post @c ar will contain the serialized form of @c t.
*/
- template<class Archive, class C, class K, class P, class D, class X>
- inline void save(Archive &ar,
- const basic_ptree<C, K, P, D, X> &t,
+ template<class Archive, class K, class D, class C>
+ inline void save(Archive &ar,
+ const basic_ptree<K, D, C> &t,
const unsigned int file_version)
{
- serialization::stl::save_collection<Archive, basic_ptree<C, K, P, D, X> >(ar, t);
- ar << serialization::make_nvp("data", t.data());
+ using namespace boost::serialization;
+ stl::save_collection<Archive, basic_ptree<K, D, C> >(ar, t);
+ ar << make_nvp("data", t.data());
}
/**
* De-serialize the property tree to the given archive.
- * @note In addition to de-serializing from regular archives, this supports loading from
- * archives requiring name-value pairs, e.g. XML archives. The format should be
- * that used by boost::property_tree::save.
- * @param ar The archive from which to load the serialized property tree. This archive
- * should conform to the concept laid out by the Boost.Serialization library.
+ * @note In addition to de-serializing from regular archives, this supports
+ * loading from archives requiring name-value pairs, e.g. XML
+ * archives. The format should be that used by
+ * boost::property_tree::save.
+ * @param ar The archive from which to load the serialized property tree.
+ * This archive should conform to the concept laid out by the
+ * Boost.Serialization library.
* @param t The property tree to de-serialize.
* @param file_version file_version for the archive.
* @post @c t will contain the de-serialized data from @c ar.
*/
- template<class Archive, class C, class K, class P, class D, class X>
- inline void load(Archive &ar,
- basic_ptree<C, K, P, D, X> &t,
+ template<class Archive, class K, class D, class C>
+ inline void load(Archive &ar,
+ basic_ptree<K, D, C> &t,
const unsigned int file_version)
{
-
+ using namespace boost::serialization;
// Load children
- boost::serialization::stl::load_collection
- <
- Archive,
- basic_ptree<C, K, P, D, X>,
- boost::serialization::stl::archive_input_seq<Archive, basic_ptree<C, K, P, D, X> >,
- boost::serialization::stl::no_reserve_imp<basic_ptree<C, K, P, D, X> >
- >(ar, t);
-
- // Load data (must be after load_collection, as it calls clear())
- ar >> serialization::make_nvp("data", t.data());
+ stl::load_collection<Archive,
+ basic_ptree<K, D, C>,
+ stl::archive_input_seq<Archive,
+ basic_ptree<K, D, C> >,
+ stl::no_reserve_imp<
+ basic_ptree<K, D, C> >
+ >(ar, t);
+ // Load data (must be after load_collection, as it calls clear())
+ ar >> make_nvp("data", t.data());
}
/**
* Load or store the property tree using the given archive.
- * @param ar The archive from which to load or save the serialized property tree.
- * The type of this archive will determine whether saving or loading is performed.
+ * @param ar The archive from which to load or save the serialized property
+ * tree. The type of this archive will determine whether saving or
+ * loading is performed.
* @param t The property tree to load or save.
* @param file_version file_version for the archive.
*/
- template<class Archive, class C, class K, class P, class D, class X>
+ template<class Archive, class K, class D, class C>
inline void serialize(Archive &ar,
- basic_ptree<C, K, P, D, X> &t,
+ basic_ptree<K, D, C> &t,
const unsigned int file_version)
{
- boost::serialization::split_free(ar, t, file_version);
+ using namespace boost::serialization;
+ split_free(ar, t, file_version);
}
} }
Modified: trunk/boost/property_tree/xml_parser.hpp
==============================================================================
--- trunk/boost/property_tree/xml_parser.hpp (original)
+++ trunk/boost/property_tree/xml_parser.hpp 2009-09-01 17:27:45 EDT (Tue, 01 Sep 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>
@@ -38,20 +27,23 @@
/**
* Reads XML from an input stream and translates it to property tree.
- * @note Clears existing contents of property tree. In case of error the property tree unmodified.
+ * @note Clears existing contents of property tree. In case of error the
+ * property tree unmodified.
* @note XML attributes are placed under keys named @c \<xmlattr\>.
* @throw xml_parser_error In case of error deserializing the property tree.
* @param stream Stream from which to read in the property tree.
* @param[out] pt The property tree to populate.
* @param flags Flags controlling the bahviour of the parser.
* The following flags are supported:
- * @li @c no_concat_text -- Prevents concatenation of text nodes into datastring
- * of property tree. Puts them in separate @c \<xmltext\>
- * strings instead.
+ * @li @c no_concat_text -- Prevents concatenation of text nodes into
+ * datastring of property tree. Puts them in
+ * separate @c \<xmltext\> strings instead.
* @li @c no_comments -- Skip XML comments.
*/
template<class Ptree>
- void read_xml(std::basic_istream<typename Ptree::key_type::value_type> &stream,
+ void read_xml(std::basic_istream<
+ typename Ptree::key_type::value_type
+ > &stream,
Ptree &pt,
int flags = 0)
{
@@ -59,17 +51,19 @@
}
/**
- * Reads XML from a file using the given locale and translates it to property tree.
- * @note Clears existing contents of property tree. In case of error the property tree unmodified.
+ * Reads XML from a file using the given locale and translates it to
+ * property tree.
+ * @note Clears existing contents of property tree. In case of error the
+ * property tree unmodified.
* @note XML attributes are placed under keys named @c \<xmlattr\>.
* @throw xml_parser_error In case of error deserializing the property tree.
* @param filename The file from which to read in the property tree.
* @param[out] pt The property tree to populate.
* @param flags Flags controlling the bahviour of the parser.
* The following flags are supported:
- * @li @c no_concat_text -- Prevents concatenation of text nodes into datastring
- * of property tree. Puts them in separate @c \<xmltext\>
- * strings instead.
+ * @li @c no_concat_text -- Prevents concatenation of text nodes into
+ * datastring of property tree. Puts them in
+ * separate @c \<xmltext\> strings instead.
* @li @c no_comments -- Skip XML comments.
* @param loc The locale to use when reading in the file contents.
*/
@@ -80,49 +74,64 @@
const std::locale &loc = std::locale())
{
BOOST_ASSERT(validate_flags(flags));
- std::basic_ifstream<typename Ptree::key_type::value_type> stream(filename.c_str());
+ std::basic_ifstream<typename Ptree::key_type::value_type>
+ stream(filename.c_str());
if (!stream)
- BOOST_PROPERTY_TREE_THROW(xml_parser_error("cannot open file", filename, 0));
+ BOOST_PROPERTY_TREE_THROW(xml_parser_error(
+ "cannot open file", filename, 0));
stream.imbue(loc);
read_xml_internal(stream, pt, flags, filename);
}
/**
- * Translates the property tree to XML and writes it the given output stream.
- * @throw xml_parser_error In case of error translating the property tree to XML
- * or writing to the output stream.
+ * Translates the property tree to XML and writes it the given output
+ * stream.
+ * @throw xml_parser_error In case of error translating the property tree to
+ * XML or writing to the output stream.
* @param stream The stream to which to write the XML representation of the
* property tree.
* @param pt The property tree to tranlsate to XML and output.
- * @param settings The settings to use when writing out the property tree as XML.
+ * @param settings The settings to use when writing out the property tree as
+ * XML.
*/
template<class Ptree>
- void write_xml(std::basic_ostream<typename Ptree::key_type::value_type> &stream,
+ void write_xml(std::basic_ostream<
+ typename Ptree::key_type::value_type
+ > &stream,
const Ptree &pt,
- const xml_writer_settings<typename Ptree::key_type::value_type> & settings = xml_writer_settings<typename Ptree::key_type::value_type>() )
+ const xml_writer_settings<
+ typename Ptree::key_type::value_type
+ > & settings = xml_writer_settings<
+ typename Ptree::key_type::value_type>() )
{
write_xml_internal(stream, pt, std::string(), settings);
}
/**
* Translates the property tree to XML and writes it the given file.
- * @throw xml_parser_error In case of error translating the property tree to XML
- * or writing to the output stream.
+ * @throw xml_parser_error In case of error translating the property tree to
+ * XML or writing to the output stream.
* @param filename The file to which to write the XML representation of the
- * property tree.
+ * property tree.
* @param pt The property tree to tranlsate to XML and output.
* @param loc The locale to use when writing the output to file.
- * @param settings The settings to use when writing out the property tree as XML.
+ * @param settings The settings to use when writing out the property tree as
+ * XML.
*/
template<class Ptree>
void write_xml(const std::string &filename,
const Ptree &pt,
const std::locale &loc = std::locale(),
- const xml_writer_settings<typename Ptree::key_type::value_type> & settings = xml_writer_settings<typename Ptree::key_type::value_type>())
+ const xml_writer_settings<
+ typename Ptree::key_type::value_type
+ > & settings = xml_writer_settings<
+ typename Ptree::key_type::value_type>())
{
- std::basic_ofstream<typename Ptree::key_type::value_type> stream(filename.c_str());
+ std::basic_ofstream<typename Ptree::key_type::value_type>
+ stream(filename.c_str());
if (!stream)
- BOOST_PROPERTY_TREE_THROW(xml_parser_error("cannot open file", filename, 0));
+ BOOST_PROPERTY_TREE_THROW(xml_parser_error(
+ "cannot open file", filename, 0));
stream.imbue(loc);
write_xml_internal(stream, pt, filename, settings);
}
Modified: trunk/libs/property_tree/doc/info_parser.qbk
==============================================================================
--- trunk/libs/property_tree/doc/info_parser.qbk (original)
+++ trunk/libs/property_tree/doc/info_parser.qbk 2009-09-01 17:27:45 EDT (Tue, 01 Sep 2009)
@@ -1,12 +1,18 @@
[section INFO Parser]
-The INFO format is a file format created by myself at the time when I was working on property tree library. It is included here for completeness, although I do not suspect many people will use it. At the very least, it can be used for visualising property trees, because it is very intuitive and easy to read by humans. Some property tree examples in this documentation are written in this format, and I think they do not need any extra explanation to be understandable. The format has some advantages:
+The INFO format was created specifically for the property tree library. It
+provides a simple, efficient format that can be used to serialize property
+trees that are otherwise only stored in memory. It can also be used for any
+other purpose, although the lack of widespread existing use may prove to be an
+impediment.
+
+INFO provides several features that make it familiar to C++ programmers and
+efficient for medium-sized datasets, especially those used for test input. It
+supports C-style character escapes, nesting via curly braces, and file inclusion
+via #include.
-* simplicity: just a "key value" string is a valid INFO,
-* efficiency: the hand-crafted parser is fast and small,
-* corresponds to property tree structure: what can be written in INFO, can be stored in property tree, and vice versa,
-* easy on programmers: has `#include`, curly brackets for nesting, C character escape sequences.
+INFO is also used for visualization of property trees in this documentation.
-And a disadvantage: it is just yet another file format. For formal grammar see [@../../examples/info_grammar_spirit.cpp infor_grammar_spirit.cpp] example file. Usually, INFO looks similar to this:
+A typical INFO file might look like this:
key1 value1
key2
@@ -18,7 +24,7 @@
key5 value5
}
-Additionally, it supports comments, `#includes`, C escape sequences, multiline values. Quite unrealistic file using all of these might look like this:
+Here's a more complicated file demonstrating all of INFO's features:
; A comment
key1 value1 ; Another comment
@@ -36,11 +42,6 @@
}
#include "file.info" ; included file
-INFO format may be also regarded as JSON with simplified semantics and relaxed syntax:
+INFO round-trips except for the loss of comments and include directives.
-* Does not support arrays, only objects
-* Does not support numeric values or literals (true, false, null), all data must be strings
-* If string does not contain whitespace or special characters, double quotes can be omitted
-* Whitespace is used instead of ':' and ',' characters: "a":"b", "c":"d" -> a b c d
-
-[endsect] [/info_parser]
\ No newline at end of file
+[endsect] [/info_parser]
Modified: trunk/libs/property_tree/doc/ini_parser.qbk
==============================================================================
--- trunk/libs/property_tree/doc/ini_parser.qbk (original)
+++ trunk/libs/property_tree/doc/ini_parser.qbk 2009-09-01 17:27:45 EDT (Tue, 01 Sep 2009)
@@ -1,6 +1,30 @@
[section INI Parser]
-[def __ini_wiki__ [@http://en.wikipedia.org/wiki/INI INI format]]
-The __ini_wiki__ was once widely used in the world of Windows. It is now deprecated, but is still used by a surprisingly large number of applications. The reason is probably its simplicity. Contrary to XML, this format is actually less rich than property tree. Because of that, there is no translation needed when reading from it. On the other hand, not every property tree can be represented as INI file - it cannot have keys with data on root level, it cannot be deeper than two levels, and there cannot be duplicate keys on any level. The write functions by default do check these conditions, and will throw when these conditions are not met. Because the check can take a fairly significant amount of time [^(O(n log n))], there is an option to disable it by using `flags` parameter.
+[def __ini__ [@http://en.wikipedia.org/wiki/INI INI format]]
+The __ini__ was once widely used in the world of Windows. It is now deprecated,
+but is still used by a surprisingly large number of applications. The reason is
+probably its simplicity, plus that Microsoft recommends using the registry as
+a replacement, which not all developers want to do.
-INI parser does not use Windows functions to read and write the file. Instead it uses a fast and small handcrafted parser. Not that I think anybody would like to parse gigabytes of INI files. But thanks to this it is portable and can be used even on non-Windows systems.
+INI is a simple key-value format with a single level of sectioning. It is thus
+less rich than the property tree dataset, which means that not all property
+trees can be serialized as INI files.
+
+The INI parser creates a tree node for every section, and a child node for
+every property in that section. All properties not in a section are directly
+added to the root node. Empty sections are ignored. (They don't round-trip, as
+described below.)
+
+The INI serializer reverses this process. It first writes out every child of the
+root that contains data, but no child nodes, as properties. Then it creates a
+section for every child that contains child nodes, but no data. The children of
+the sections must only contain data. It is an error if the root node contains
+data, or any child of the root contains both data and content, or there's more
+than three levels of hierarchy. There must also not be any duplicate keys.
+
+An empty tree node is assumed to be an empty property. There is no way to create
+empty sections.
+
+Since the Windows INI parser discards trailing spaces and does not support
+quoting, the property tree parser follows this example. This means that
+property values containing trailing spaces do not round-trip.
[endsect] [/ini_parser]
Modified: trunk/libs/property_tree/doc/json_parser.qbk
==============================================================================
--- trunk/libs/property_tree/doc/json_parser.qbk (original)
+++ trunk/libs/property_tree/doc/json_parser.qbk 2009-09-01 17:27:45 EDT (Tue, 01 Sep 2009)
@@ -1,12 +1,25 @@
[section JSON Parser]
-[def __json_wiki__ [@http://en.wikipedia.org/wiki/JSON JSON format]]
-The __json_wiki__ is a data interchange format which is a subset of Javascript language. (JSON stands for JavaScript Object Notation.) It is considerably simpler than XML, is usually more concise, easier to read by humans, and easier to parse by machines. It's not currently as widely used as XML, but if you think XML is bloated then this may be the format worth consideration.
+[def __json__ [@http://en.wikipedia.org/wiki/JSON JSON format]]
+The __json__ is a data interchange format derived from the object literal
+notation of JavaScript. (JSON stands for JavaScript Object Notation.)
+JSON is a simple, compact format for loosely structured node trees of any depth,
+very similar to the property tree dataset. It is less stuctured than XML and has
+no schema support, but has the advantage of being simpler, smaller and typed
+without the need for a complex schema.
+
+The property tree dataset is not typed, and does not support arrays as such.
+Thus, the following JSON / property tree mapping is used:
+
+* JSON objects are mapped to nodes. Each property is a child node.
+* JSON arrays are mapped to nodes. Each element is a child node with an empty
+ name. If a node has both named and unnamed child nodes, it cannot be mapped
+ to a JSON representation.
+* JSON values are mapped to nodes containing the value. However, all type
+ information is lost; numbers, as well as the literals "null", "true" and
+ "false" are simply mapped to their string form.
+* Property tree nodes containing both child nodes and data cannot be mapped.
-JSON structure is slightly different from that of property tree. The differences and the way they are dealt with are summarized below:
-
-* JSON contains 'objects' and 'arrays' - objects are collections of name-value pairs, while arrays contain only values. During parse, items of JSON arrays are translated into ptree keys with empty names. Members of objects are translated into named keys. During write, any ptree key containing only unnamed subkeys will be rendered as JSON array.
-* A JSON element cannot simultaneously have child items and data. Only one of these may be present. As a result, if property tree contains keys that have both subkeys and non-empty data, writing will fail.
-* JSON data can be a string, a numeric value, or one of literals "null", "true" and "false". During parse, any of the above is copied verbatim into ptree data string. This causes some type information to be lost, because if resulting ptree is written back into JSON format, it will only contain strings.
+JSON round-trips, except for the type information loss.
For example this JSON:
@@ -46,4 +59,4 @@
}
}
-[endsect] [/json_parser]
\ No newline at end of file
+[endsect] [/json_parser]
Modified: trunk/libs/property_tree/doc/parsers.qbk
==============================================================================
--- trunk/libs/property_tree/doc/parsers.qbk (original)
+++ trunk/libs/property_tree/doc/parsers.qbk 2009-09-01 17:27:45 EDT (Tue, 01 Sep 2009)
@@ -1,16 +1,17 @@
[section:parsers How to Populate a Property Tree]
[include xml_parser.qbk]
-[include ini_parser.qbk]
-
[include json_parser.qbk]
+[include ini_parser.qbk]
+
[include info_parser.qbk]
-[include cmd_line_parser.qbk]
+# These parsers will be dropped for now.
+#[include cmd_line_parser.qbk]
-[include windows_registry_parser.qbk]
+#[include windows_registry_parser.qbk]
-[include system_environment_parser.qbk]
+#[include system_environment_parser.qbk]
[endsect] [/parsers]
Modified: trunk/libs/property_tree/doc/xml_parser.qbk
==============================================================================
--- trunk/libs/property_tree/doc/xml_parser.qbk (original)
+++ trunk/libs/property_tree/doc/xml_parser.qbk 2009-09-01 17:27:45 EDT (Tue, 01 Sep 2009)
@@ -1,34 +1,44 @@
[section XML Parser]
-[def __xml_wiki__ [@http://en.wikipedia.org/wiki/XML XML format]]
+[def __xml__ [@http://en.wikipedia.org/wiki/XML XML format]]
[def __xml_parser.hpp__ [headerref boost/property_tree/xml_parser.hpp xml_parser.hpp]]
-[def __TinyXML__ [@http://sourceforge.net/projects/tinyxml TinyXML]]
-[def __boost_homepage__ [@http://www.boost.org Boost]]
-The __xml_wiki__ is an industry standard for storing information in textual
-form. Unfortunately, there is no XML parser in __boost_homepage__ as of the
-time of this writing. Therefore, a custom parser was created. It only supports
-a core subset of XML standard. For example, declarations and entity references
-are not supported. The parser is built with Spirit, and based on XML grammar
-sample by Daniel Nuffer. As a reinforcement to it, a parser based on
-__TinyXML__ is also provided. To enable it define
-[^BOOST_PROPERTY_TREE_XML_PARSER_TINYXML] before including the
-__xml_parser.hpp__ file. __TinyXML__ library has to be obtained separately.
+[def __RapidXML__ [@http://rapidxml.sourceforge.net/ RapidXML]]
+[def __boost__ [@http://www.boost.org Boost]]
+The __xml__ is an industry standard for storing information in textual
+form. Unfortunately, there is no XML parser in __boost__ as of the
+time of this writing. The library therefore contains the fast and tiny
+__RapidXML__ parser (currently in version 1.13) to provide XML parsing support.
+RapidXML does not fully support the XML standard; it is not capable of parsing
+DTDs and therefore cannot do full entity substitution. The parser is configured
+to trim whitespace from the edges of character data. This behaviour exists for
+compatibility with older versions of PropertyTree and will be made configurable
+in the future.
-How XML is translated to property tree (__read_xml__):
+Please note that RapidXML does not understand the encoding specification. If
+you pass it a character buffer, it assumes the data is already correctly
+encoded; if you pass it a filename, it will read the file using the character
+conversion of the locale you give it (or the global locale if you give it none).
+This means that, in order to parse a UTF-8-encoded XML file into a wptree, you
+have to supply an alternate locale, either directly or by replacing the global
+one.
-* Attributes of each XML key are stored in a subkey with name [^<xmlattr>].
- Each subkey of [^<xmlattr>] is one attribute. If [^<xmlattr>] subkey does
- not exist or is empty, there are no attributes.
-* XML comments are stored in keys named [^<xmlcomment>], unless a flag is
- specified that disables parsing of comments.
-* Data of XML node may be stored in two ways, depending on the flags parameter
- setting. The default way is to have all data nodes concatenated and put in
- data string of appropriate property tree key. The other way is to have them
- put in separate subkeys named [^<xmltext>] each.
+XML / property tree conversion schema (__read_xml__ and __write_xml__):
-Translation of property tree back into XML (__write_xml__) assumes the same
-structure as outlined above. That means, for example, that if you want to have
-attributes, you need to create [^<xmlattr>] subkey and put them there. With
-appropriate flags setting, reading an XML file and writing it back will not
-change the contents (but may change formatting), unless XML file uses some
-unsupported constructs.
+* Each XML element corresponds to a property tree node. The child elements
+ correspond to the children of the node.
+* The attributes of an XML element are stored in the subkey [^<xmlattr>]. There
+ is one child node per attribute in the attribute node. Existence of the
+ [^<xmlattr>] node is not guaranteed or necessary when there are no attributes.
+* XML comments are stored in nodes named [^<xmlcomment>], unless comment
+ ignoring is enabled via the flags.
+* Text content is stored in one of two ways, depending on the flags. The default
+ way concatenates all text nodes and stores them in a single node called
+ [^<xmltext>]. This way, the entire content can be conveniently read, but the
+ relative ordering of text and child elements is lost. The other way stores
+ each text content as a separate node, all called [^<xmltext>].
+
+The XML storage encoding does not round-trip perfectly. A read-write cycle loses
+trimmed whitespace, low-level formatting information, and the distinction
+between normal data and CDATA nodes. Comments are only preserved when enabled.
+A write-read cycle loses trimmed whitespace; that is, if the origin tree has
+string data that starts or ends with whitespace, that whitespace is lost.
[endsect] [/xml_parser]
Modified: trunk/libs/property_tree/examples/speed_test.cpp
==============================================================================
--- trunk/libs/property_tree/examples/speed_test.cpp (original)
+++ trunk/libs/property_tree/examples/speed_test.cpp 2009-09-01 17:27:45 EDT (Tue, 01 Sep 2009)
@@ -38,7 +38,6 @@
void clock_push_back(int size)
{
-
prepare_keys(size);
int max_repeats = 1000000 / size;
shared_array<ptree> pt_array(new ptree[max_repeats]);
@@ -51,7 +50,7 @@
break;
ptree &pt = pt_array[n];
for (int i = 0; i < size; ++i)
- pt.push_back(ptree::value_type(shuffled_keys[i], empty_ptree<ptree>()));
+ pt.push_back(ptree::value_type(shuffled_keys[i], ptree()));
t2 = clock();
++n;
} while (t2 - t1 < CLOCKS_PER_SEC);
@@ -62,7 +61,6 @@
void clock_find(int size)
{
-
prepare_keys(size);
ptree pt;
@@ -85,7 +83,6 @@
void clock_erase(int size)
{
-
prepare_keys(size);
int max_repeats = 100000 / size;
@@ -110,7 +107,6 @@
} while (t2 - t1 < CLOCKS_PER_SEC);
cout << " erase (" << size << "): " << double(t2 - t1) / CLOCKS_PER_SEC / n * 1000 << " ms\n";
-
}
int main()
Modified: trunk/libs/property_tree/test/Jamfile.v2
==============================================================================
--- trunk/libs/property_tree/test/Jamfile.v2 (original)
+++ trunk/libs/property_tree/test/Jamfile.v2 2009-09-01 17:27:45 EDT (Tue, 01 Sep 2009)
@@ -8,19 +8,6 @@
[ run test_ini_parser.cpp ]
[ run test_xml_parser_rapidxml.cpp ]
- # 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 ]
-
- # 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 ]
+ #[ run test_registry_parser.cpp ]
;
Deleted: trunk/libs/property_tree/test/test_cmdline_parser.cpp
==============================================================================
--- trunk/libs/property_tree/test/test_cmdline_parser.cpp 2009-09-01 17:27:45 EDT (Tue, 01 Sep 2009)
+++ (empty file)
@@ -1,116 +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
-// ----------------------------------------------------------------------------
-
-#include "test_utils.hpp"
-#include <boost/property_tree/cmdline_parser.hpp>
-#include <boost/property_tree/info_parser.hpp>
-#include <vector>
-#include <string>
-
-namespace
-{
-
- // Test arguments
- char *argv[] =
- {
- "c:\\program.exe",
- "-Isrc/include1",
- " file2.cc ",
- "/L src/lib1",
- "-Lsrc/lib2",
- "/ooutput",
- "file1.cc",
- "-g",
- "-",
- "/",
- " /Isrc/include2 ",
- " file3.cc ",
- "-I src/include3 "
- };
-
- // Test arguments count
- const int argc = sizeof(argv) / sizeof(*argv);
-
-}
-
-template<class Ptree>
-void test_cmdline_parser()
-{
-
- using namespace boost::property_tree;
- typedef typename Ptree::key_type::value_type Ch;
- typedef std::basic_string<Ch> Str;
-
- // Prepare arguments of proper char type
- std::vector<Ch *> p;
- std::vector<Str> strings;
- strings.reserve(argc);
- for (int i = 0; i < argc; ++i)
- {
- strings.push_back(detail::widen<Ch>(argv[i]));
- p.push_back(const_cast<Ch *>(strings.back().c_str()));
- }
-
- Ptree pt1;
- read_cmdline<Ptree>(argc, &p.front(), detail::widen<Ch>("-/"), pt1);
-
- // Check indices
- BOOST_CHECK(pt1.template get_optional<Str>(detail::widen<Ch>("L.0")).get() == detail::widen<Ch>("src/lib1"));
- BOOST_CHECK(pt1.template get_optional<Str>(detail::widen<Ch>("L.1")).get() == detail::widen<Ch>("src/lib2"));
- BOOST_CHECK(!pt1.template get_optional<Str>(detail::widen<Ch>("L.2")));
- BOOST_CHECK(pt1.template get_optional<Str>(detail::widen<Ch>(".0")).get() == detail::widen<Ch>("c:\\program.exe"));
- BOOST_CHECK(pt1.template get_optional<Str>(detail::widen<Ch>(".1")).get() == detail::widen<Ch>("file2.cc"));
- BOOST_CHECK(pt1.template get_optional<Str>(detail::widen<Ch>(".2")).get() == detail::widen<Ch>("file1.cc"));
- BOOST_CHECK(pt1.template get_optional<Str>(detail::widen<Ch>(".3")).get() == detail::widen<Ch>("file3.cc"));
- BOOST_CHECK(!pt1.template get_optional<Str>(detail::widen<Ch>(".4")));
-
- // Check total sizes
- //std::cerr << total_size(pt1) << " " << total_data_size(pt1) << " " << total_keys_size(pt1) << "\n";
- BOOST_CHECK(total_size(pt1) == 21);
- BOOST_CHECK(total_data_size(pt1) == 130);
- BOOST_CHECK(total_keys_size(pt1) == 19);
-
- Ptree pt2;
- read_cmdline<Ptree>(argc, &p.front(), detail::widen<Ch>("-"), pt2);
-
- // Check indices
- BOOST_CHECK(pt2.template get_optional<Str>(detail::widen<Ch>("L.0")).get() == detail::widen<Ch>("src/lib2"));
- BOOST_CHECK(!pt2.template get_optional<Str>(detail::widen<Ch>("L.1")));
-
- // Check total sizes
- //std::cerr << total_size(pt2) << " " << total_data_size(pt2) << " " << total_keys_size(pt2) << "\n";
- BOOST_CHECK(total_size(pt2) == 19);
- BOOST_CHECK(total_data_size(pt2) == 135);
- BOOST_CHECK(total_keys_size(pt2) == 17);
-
- Ptree pt3;
- read_cmdline<Ptree>(argc, &p.front(), detail::widen<Ch>("/"), pt3);
-
- // Check indices
- BOOST_CHECK(pt3.template get_optional<Str>(detail::widen<Ch>("L.0")).get() == detail::widen<Ch>("src/lib1"));
- BOOST_CHECK(!pt3.template get_optional<Str>(detail::widen<Ch>("L.1")));
-
- // Check total sizes
- //std::cerr << total_size(pt3) << " " << total_data_size(pt3) << " " << total_keys_size(pt3) << "\n";
- BOOST_CHECK(total_size(pt3) == 19);
- BOOST_CHECK(total_data_size(pt3) == 149);
- BOOST_CHECK(total_keys_size(pt3) == 17);
-
-}
-
-int test_main(int argc, char *argv[])
-{
- using namespace boost::property_tree;
- test_cmdline_parser<ptree>();
-#ifndef BOOST_NO_CWCHAR
- test_cmdline_parser<wptree>();
-#endif
- return 0;
-}
Modified: trunk/libs/property_tree/test/test_info_parser.cpp
==============================================================================
--- trunk/libs/property_tree/test/test_info_parser.cpp (original)
+++ trunk/libs/property_tree/test/test_info_parser.cpp 2009-09-01 17:27:45 EDT (Tue, 01 Sep 2009)
@@ -163,7 +163,7 @@
ReadFunc(), WriteFunc(), ok_data_1, ok_data_1_inc,
"testok1.info", "testok1_inc.info", "testok1out.info", 45, 240, 192
);
-
+
generic_parser_test_ok<Ptree, ReadFunc, WriteFunc>
(
ReadFunc(), WriteFunc(), ok_data_2, NULL,
@@ -233,7 +233,7 @@
read_info("nonexisting file.nonexisting file", pt, default_pt);
BOOST_CHECK(pt == default_pt);
}
-
+
}
int test_main(int argc, char *argv[])
Modified: trunk/libs/property_tree/test/test_ini_parser.cpp
==============================================================================
--- trunk/libs/property_tree/test/test_ini_parser.cpp (original)
+++ trunk/libs/property_tree/test/test_ini_parser.cpp 2009-09-01 17:27:45 EDT (Tue, 01 Sep 2009)
@@ -27,8 +27,7 @@
"Key 3 = Data 3 \n"
"Key4=Data4\n"
"[Section2] ;Comment\n"
- "\t \t; Comment\n"
- " \t [ Section 3 ];Comment \n";
+ "\t \tKey1=Data4\n";
// Correct data
const char *ok_data_2 =
@@ -43,6 +42,11 @@
const char *ok_data_4 =
";Comment";
+// Correct data
+const char *ok_data_5 =
+ "Key1=Data1\n" // No section
+ "Key2=Data2\n";
+
// Erroneous data
const char *error_data_1 =
"[Section1]\n"
@@ -51,11 +55,6 @@
// Erroneous data
const char *error_data_2 =
- "Key1=Data1\n" // No section
- "Key2=Data2\n";
-
-// Erroneous data
-const char *error_data_3 =
"[Section1]\n"
"Key1=Data1\n"
"=Data2\n"; // No key
@@ -106,7 +105,7 @@
generic_parser_test_ok<Ptree, ReadFunc, WriteFunc>
(
ReadFunc(), WriteFunc(), ok_data_1, NULL,
- "testok1.ini", NULL, "testok1out.ini", 8, 21, 42
+ "testok1.ini", NULL, "testok1out.ini", 8, 26, 37
);
generic_parser_test_ok<Ptree, ReadFunc, WriteFunc>
@@ -127,22 +126,22 @@
"testok4.ini", NULL, "testok4out.ini", 1, 0, 0
);
- generic_parser_test_error<Ptree, ReadFunc, WriteFunc, ini_parser_error>
+ generic_parser_test_ok<Ptree, ReadFunc, WriteFunc>
(
- ReadFunc(), WriteFunc(), error_data_1, NULL,
- "testerr1.ini", NULL, "testerr1out.ini", 2
+ ReadFunc(), WriteFunc(), ok_data_5, NULL,
+ "testok5.ini", NULL, "testok5out.ini", 3, 10, 8
);
generic_parser_test_error<Ptree, ReadFunc, WriteFunc, ini_parser_error>
(
- ReadFunc(), WriteFunc(), error_data_2, NULL,
- "testerr2.ini", NULL, "testerr2out.ini", 1
+ ReadFunc(), WriteFunc(), error_data_1, NULL,
+ "testerr1.ini", NULL, "testerr1out.ini", 2
);
generic_parser_test_error<Ptree, ReadFunc, WriteFunc, ini_parser_error>
(
- ReadFunc(), WriteFunc(), error_data_3, NULL,
- "testerr3.ini", NULL, "testerr3out.ini", 3
+ ReadFunc(), WriteFunc(), error_data_2, NULL,
+ "testerr2.ini", NULL, "testerr2out.ini", 3
);
}
@@ -165,29 +164,31 @@
// Test too deep ptrees
{
ptree pt;
- pt.put_child("section.key.bogus", empty_ptree<ptree>());
+ pt.put_child("section.key.bogus", ptree());
test_erroneous_write(pt);
}
- // Test data in sections
+ // Test duplicate sections
{
ptree pt;
- pt.put("section", 1);
+ pt.push_back(std::make_pair("section", ptree()));
+ pt.push_back(std::make_pair("section", ptree()));
test_erroneous_write(pt);
}
- // Test duplicate sections
+ // Test duplicate keys
{
ptree pt;
- pt.push_back(std::make_pair("section", ptree()));
- pt.push_back(std::make_pair("section", ptree()));
+ ptree &child = pt.put_child("section", ptree());
+ child.push_back(std::make_pair("key", ptree()));
+ child.push_back(std::make_pair("key", ptree()));
test_erroneous_write(pt);
}
- // Test duplicate keys
+ // Test mixed data and children.
{
ptree pt;
- ptree &child = pt.put_child("section", empty_ptree<ptree>());
+ ptree &child = pt.put_child("section", ptree("value"));
child.push_back(std::make_pair("key", ptree()));
child.push_back(std::make_pair("key", ptree()));
test_erroneous_write(pt);
Modified: trunk/libs/property_tree/test/test_property_tree.cpp
==============================================================================
--- trunk/libs/property_tree/test/test_property_tree.cpp (original)
+++ trunk/libs/property_tree/test/test_property_tree.cpp 2009-09-01 17:27:45 EDT (Tue, 01 Sep 2009)
@@ -49,27 +49,31 @@
};
// Custom translator that works with boost::any instead of std::string
-struct MyTranslator
+template <typename E>
+struct any_translator
{
+ typedef boost::any internal_type;
+ typedef E external_type;
- // Custom extractor - converts data from boost::any to T
- template<class Ptree, class T>
- bool get_value(const Ptree &pt, T &value) const
- {
- value = boost::any_cast<T>(pt.data());
- return true; // Success
+ boost::optional<E> get_value(const internal_type &v) {
+ if(const E *p = boost::any_cast<E>(&v)) {
+ return *p;
+ }
+ return boost::optional<E>();
}
-
- // Custom inserter - converts data from T to boost::any
- template<class Ptree, class T>
- bool put_value(Ptree &pt, const T &value) const
- {
- pt.data() = value;
- return true;
+ boost::optional<internal_type> put_value(const E &v) {
+ return boost::any(v);
}
-
};
+namespace boost { namespace property_tree {
+ template <typename E>
+ struct translator_between<boost::any, E>
+ {
+ typedef any_translator<E> type;
+ };
+}}
+
// Include char tests, case sensitive
#define CHTYPE char
#define T(s) s
@@ -161,7 +165,7 @@
test_char(pt);
test_leaks(pt); // must be a final test
}
-
+#if 0
// wchar_t tests, case sensitive
#ifndef BOOST_NO_CWCHAR
{
@@ -258,6 +262,6 @@
test_leaks(pt); // must be a final test
}
#endif
-
+#endif
return 0;
}
Modified: trunk/libs/property_tree/test/test_property_tree.hpp
==============================================================================
--- trunk/libs/property_tree/test/test_property_tree.hpp (original)
+++ trunk/libs/property_tree/test/test_property_tree.hpp 2009-09-01 17:27:45 EDT (Tue, 01 Sep 2009)
@@ -16,7 +16,7 @@
void test_debug(PTREE *)
{
-
+#if 0
// Check count
BOOST_CHECK(PTREE::debug_get_instances_count() == 0);
@@ -54,61 +54,61 @@
// Check count
BOOST_CHECK(PTREE::debug_get_instances_count() == 0);
-
+#endif
}
void test_constructor_destructor_assignment(PTREE *)
{
-
+
{
// Test constructor from string
PTREE pt1(T("data"));
BOOST_CHECK(pt1.data() == T("data"));
- BOOST_CHECK(PTREE::debug_get_instances_count() == 1);
+ //BOOST_CHECK(PTREE::debug_get_instances_count() == 1);
// Do insertions
PTREE &tmp1 = pt1.put(T("key1"), T("data1"));
PTREE &tmp2 = pt1.put(T("key2"), T("data2"));
tmp1.put(T("key3"), T("data3"));
tmp2.put(T("key4"), T("data4"));
- BOOST_CHECK(PTREE::debug_get_instances_count() == 5);
+ //BOOST_CHECK(PTREE::debug_get_instances_count() == 5);
// Make a copy using copy constructor
PTREE *pt2 = new PTREE(pt1);
BOOST_CHECK(*pt2 == pt1);
- BOOST_CHECK(PTREE::debug_get_instances_count() == 10);
+ //BOOST_CHECK(PTREE::debug_get_instances_count() == 10);
// Make a copy using = operator
PTREE *pt3 = new PTREE;
*pt3 = *pt2;
BOOST_CHECK(*pt3 == *pt2);
- BOOST_CHECK(PTREE::debug_get_instances_count() == 15);
+ //BOOST_CHECK(PTREE::debug_get_instances_count() == 15);
// Test self assignment
pt1 = pt1;
BOOST_CHECK(pt1 == *pt2);
BOOST_CHECK(pt1 == *pt3);
- BOOST_CHECK(PTREE::debug_get_instances_count() == 15);
+ //BOOST_CHECK(PTREE::debug_get_instances_count() == 15);
// Destroy
delete pt2;
- BOOST_CHECK(PTREE::debug_get_instances_count() == 10);
+ //BOOST_CHECK(PTREE::debug_get_instances_count() == 10);
// Destroy
delete pt3;
- BOOST_CHECK(PTREE::debug_get_instances_count() == 5);
-
+ //BOOST_CHECK(PTREE::debug_get_instances_count() == 5);
+
}
// Check count
- BOOST_CHECK(PTREE::debug_get_instances_count() == 0);
+ //BOOST_CHECK(PTREE::debug_get_instances_count() == 0);
}
void test_insertion(PTREE *)
{
-
+
// Do insertions
PTREE pt;
PTREE tmp1(T("data1"));
@@ -122,8 +122,8 @@
it2->second.insert(it2->second.end(), it1->second.begin(), it1->second.end());
// Check instance count
- BOOST_CHECK(PTREE::debug_get_instances_count() == 11);
-
+ //BOOST_CHECK(PTREE::debug_get_instances_count() == 11);
+
// Check contents
BOOST_CHECK(pt.get(T("key1"), T("")) == T("data1"));
BOOST_CHECK(pt.get(T("key2"), T("")) == T("data2"));
@@ -156,29 +156,29 @@
it1->second.push_back(std::make_pair(T("key"), tmp3));
it1->second.push_front(std::make_pair(T("key"), tmp4));
it2->second.insert(it2->second.end(), it1->second.begin(), it1->second.end());
-
+
// Check instance count
- BOOST_CHECK(PTREE::debug_get_instances_count() == 11);
+ //BOOST_CHECK(PTREE::debug_get_instances_count() == 11);
// Test range erase
PTREE::iterator it = it1->second.erase(it1->second.begin(), it1->second.end());
BOOST_CHECK(it == it1->second.end());
- BOOST_CHECK(PTREE::debug_get_instances_count() == 9);
+ //BOOST_CHECK(PTREE::debug_get_instances_count() == 9);
// Test single erase
PTREE::size_type n = pt.erase(T("key1"));
BOOST_CHECK(n == 1);
- BOOST_CHECK(PTREE::debug_get_instances_count() == 8);
+ //BOOST_CHECK(PTREE::debug_get_instances_count() == 8);
// Test multiple erase
n = it2->second.erase(T("key"));
BOOST_CHECK(n == 2);
- BOOST_CHECK(PTREE::debug_get_instances_count() == 6);
+ //BOOST_CHECK(PTREE::debug_get_instances_count() == 6);
// Test one more erase
n = pt.erase(T("key2"));
BOOST_CHECK(n == 1);
- BOOST_CHECK(PTREE::debug_get_instances_count() == 5);
+ //BOOST_CHECK(PTREE::debug_get_instances_count() == 5);
}
@@ -190,19 +190,19 @@
pt.push_back(std::make_pair(T("key"), PTREE(T("data"))));
// Check instance count
- BOOST_CHECK(PTREE::debug_get_instances_count() == 2);
+ //BOOST_CHECK(PTREE::debug_get_instances_count() == 2);
// Test clear
pt.clear();
BOOST_CHECK(pt.empty());
BOOST_CHECK(pt.data().empty());
- BOOST_CHECK(PTREE::debug_get_instances_count() == 1);
+ //BOOST_CHECK(PTREE::debug_get_instances_count() == 1);
}
void test_pushpop(PTREE *)
{
-
+
// Do insertions
PTREE pt;
PTREE tmp1(T("data1"));
@@ -213,9 +213,9 @@
pt.push_front(std::make_pair(T("key2"), tmp2));
pt.push_back(std::make_pair(T("key4"), tmp4));
pt.push_front(std::make_pair(T("key1"), tmp1));
-
+
// Check instance count
- BOOST_CHECK(PTREE::debug_get_instances_count() == 9);
+ //BOOST_CHECK(PTREE::debug_get_instances_count() == 9);
// Check sequence
PTREE::iterator it = pt.begin();
@@ -227,19 +227,19 @@
// Test pops
pt.pop_back();
- BOOST_CHECK(PTREE::debug_get_instances_count() == 8);
+ //BOOST_CHECK(PTREE::debug_get_instances_count() == 8);
BOOST_CHECK(pt.front().second.data() == T("data1"));
BOOST_CHECK(pt.back().second.data() == T("data3"));
pt.pop_front();
- BOOST_CHECK(PTREE::debug_get_instances_count() == 7);
+ //BOOST_CHECK(PTREE::debug_get_instances_count() == 7);
BOOST_CHECK(pt.front().second.data() == T("data2"));
BOOST_CHECK(pt.back().second.data() == T("data3"));
pt.pop_back();
- BOOST_CHECK(PTREE::debug_get_instances_count() == 6);
+ //BOOST_CHECK(PTREE::debug_get_instances_count() == 6);
BOOST_CHECK(pt.front().second.data() == T("data2"));
BOOST_CHECK(pt.back().second.data() == T("data2"));
pt.pop_front();
- BOOST_CHECK(PTREE::debug_get_instances_count() == 5);
+ //BOOST_CHECK(PTREE::debug_get_instances_count() == 5);
BOOST_CHECK(pt.empty());
}
@@ -308,7 +308,7 @@
pt1.put(T("key1.key4"), T(""));
// Check counts
- BOOST_CHECK(PTREE::debug_get_instances_count() == 6);
+ //BOOST_CHECK(PTREE::debug_get_instances_count() == 6);
BOOST_CHECK(pt1.size() == 2);
BOOST_CHECK(pt1.get_child(T("key1")).size() == 2);
BOOST_CHECK(pt2.size() == 0);
@@ -317,7 +317,7 @@
pt1.swap(pt2);
// Check counts
- BOOST_CHECK(PTREE::debug_get_instances_count() == 6);
+ //BOOST_CHECK(PTREE::debug_get_instances_count() == 6);
BOOST_CHECK(pt2.size() == 2);
BOOST_CHECK(pt2.get_child(T("key1")).size() == 2);
BOOST_CHECK(pt1.size() == 0);
@@ -326,7 +326,7 @@
swap(pt1, pt2);
// Check counts
- BOOST_CHECK(PTREE::debug_get_instances_count() == 6);
+ //BOOST_CHECK(PTREE::debug_get_instances_count() == 6);
BOOST_CHECK(pt1.size() == 2);
BOOST_CHECK(pt1.get_child(T("key1")).size() == 2);
BOOST_CHECK(pt2.size() == 0);
@@ -335,7 +335,7 @@
std::swap(pt1, pt2);
// Check counts
- BOOST_CHECK(PTREE::debug_get_instances_count() == 6);
+ //BOOST_CHECK(PTREE::debug_get_instances_count() == 6);
BOOST_CHECK(pt2.size() == 2);
BOOST_CHECK(pt2.get_child(T("key1")).size() == 2);
BOOST_CHECK(pt1.size() == 0);
@@ -370,10 +370,10 @@
// Check sequence using find to check if index is ok
{
PTREE::iterator it = pt.begin();
- BOOST_CHECK(it == pt.find(T("key3"))); ++it;
- BOOST_CHECK(it == pt.find(T("key4"))); ++it;
- BOOST_CHECK(it == pt.find(T("key1"))); ++it;
- BOOST_CHECK(it == pt.find(T("key2"))); ++it;
+ BOOST_CHECK(it == pt.to_iterator(pt.find(T("key3")))); ++it;
+ BOOST_CHECK(it == pt.to_iterator(pt.find(T("key4")))); ++it;
+ BOOST_CHECK(it == pt.to_iterator(pt.find(T("key1")))); ++it;
+ BOOST_CHECK(it == pt.to_iterator(pt.find(T("key2")))); ++it;
BOOST_CHECK(it == pt.end());
}
@@ -392,10 +392,10 @@
// Check sequence (using find to check if index is ok)
{
PTREE::iterator it = pt.begin();
- BOOST_CHECK(it == pt.find(T("key1"))); ++it;
- BOOST_CHECK(it == pt.find(T("key2"))); ++it;
- BOOST_CHECK(it == pt.find(T("key3"))); ++it;
- BOOST_CHECK(it == pt.find(T("key4"))); ++it;
+ BOOST_CHECK(it == pt.to_iterator(pt.find(T("key1")))); ++it;
+ BOOST_CHECK(it == pt.to_iterator(pt.find(T("key2")))); ++it;
+ BOOST_CHECK(it == pt.to_iterator(pt.find(T("key3")))); ++it;
+ BOOST_CHECK(it == pt.to_iterator(pt.find(T("key4")))); ++it;
BOOST_CHECK(it == pt.end());
}
@@ -414,10 +414,10 @@
// Check sequence (using find to check if index is ok)
{
PTREE::iterator it = pt.begin();
- BOOST_CHECK(it == pt.find(T("key4"))); ++it;
- BOOST_CHECK(it == pt.find(T("key3"))); ++it;
- BOOST_CHECK(it == pt.find(T("key2"))); ++it;
- BOOST_CHECK(it == pt.find(T("key1"))); ++it;
+ BOOST_CHECK(it == pt.to_iterator(pt.find(T("key4")))); ++it;
+ BOOST_CHECK(it == pt.to_iterator(pt.find(T("key3")))); ++it;
+ BOOST_CHECK(it == pt.to_iterator(pt.find(T("key2")))); ++it;
+ BOOST_CHECK(it == pt.to_iterator(pt.find(T("key1")))); ++it;
BOOST_CHECK(it == pt.end());
}
@@ -435,13 +435,13 @@
// Check findings depending on traits type
#if (NOCASE == 0)
- BOOST_CHECK(PTREE::debug_get_instances_count() == 7);
+ //BOOST_CHECK(PTREE::debug_get_instances_count() == 7);
BOOST_CHECK(pt.get(T("key1"), T("")) == T("data1"));
BOOST_CHECK(pt.get(T("key2"), T("")) == T(""));
BOOST_CHECK(pt.get(T("key1.key3"), T("")) == T(""));
BOOST_CHECK(pt.get(T("KEY1.key4"), T("")) == T("data4"));
#else
- BOOST_CHECK(PTREE::debug_get_instances_count() == 5);
+ //BOOST_CHECK(PTREE::debug_get_instances_count() == 5);
BOOST_CHECK(pt.get(T("key1"), T("1")) == pt.get(T("KEY1"), T("2")));
BOOST_CHECK(pt.get(T("key2"), T("1")) == pt.get(T("KEY2"), T("2")));
BOOST_CHECK(pt.get(T("key1.key3"), T("1")) == pt.get(T("KEY1.KEY3"), T("2")));
@@ -473,7 +473,7 @@
void test_comparison(PTREE *)
{
-
+
// Prepare original
PTREE pt_orig(T("data"));
pt_orig.put(T("key1"), T("data1"));
@@ -597,121 +597,121 @@
// Do insertions via put
PTREE pt;
- PTREE &pt1 = pt.put(T("k1"), 1); // put as int
- PTREE &pt2 = pt.put(T("k2.k"), 2.5); // put as double
- PTREE &pt3 = pt.put(T("k3.k.k"), T("ala ma kota")); // put as string
- PTREE &pt4 = pt.put(T("k4.k.k.k"), CHTYPE('c')); // put as character
- PTREE &pt5 = pt.put(T("k5.k.k.k.f"), false); // put as bool
- PTREE &pt6 = pt.put(T("k5.k.k.k.t"), true); // put as bool
+ PTREE &pt1 = pt.put(T("k1"), 1);
+ PTREE &pt2 = pt.put(T("k2.k"), 2.5);
+ PTREE &pt3 = pt.put(T("k3.k.k"), T("ala ma kota"));
+ PTREE &pt4 = pt.put(T("k4.k.k.k"), CHTYPE('c'));
+ PTREE &pt5 = pt.put(T("k5.k.k.k.f"), false);
+ PTREE &pt6 = pt.put(T("k5.k.k.k.t"), true);
// Check instances count
- BOOST_CHECK(PTREE::debug_get_instances_count() == 17);
+ //BOOST_CHECK(PTREE::debug_get_instances_count() == 17);
// Check if const char * version returns std::string
BOOST_CHECK(typeid(pt.get_value(T(""))) == typeid(str_t));
// Do extractions via get (throwing version)
- BOOST_CHECK(pt.get<int>(T("k1")) == 1); // get as int
- BOOST_CHECK(pt.get<long>(T("k1")) == 1); // get as long
- BOOST_CHECK(pt.get<double>(T("k2.k")) == 2.5); // get as double
- BOOST_CHECK(pt.get<float>(T("k2.k")) == 2.5f); // get as float
- BOOST_CHECK(pt.get<str_t>(T("k3.k.k")) == str_t(T("ala ma kota"))); // get as string
- BOOST_CHECK(pt.get<CHTYPE>(T("k4.k.k.k")) == CHTYPE('c')); // get as char
- BOOST_CHECK(pt.get<bool>(T("k5.k.k.k.f")) == false); // get as bool
- BOOST_CHECK(pt.get<bool>(T("k5.k.k.k.t")) == true); // get as bool
+ BOOST_CHECK(pt.get<int>(T("k1")) == 1);
+ BOOST_CHECK(pt.get<long>(T("k1")) == 1);
+ BOOST_CHECK(pt.get<double>(T("k2.k")) == 2.5);
+ BOOST_CHECK(pt.get<float>(T("k2.k")) == 2.5f);
+ BOOST_CHECK(pt.get<str_t>(T("k3.k.k")) == str_t(T("ala ma kota")));
+ BOOST_CHECK(pt.get<CHTYPE>(T("k4.k.k.k")) == CHTYPE('c'));
+ BOOST_CHECK(pt.get<bool>(T("k5.k.k.k.f")) == false);
+ BOOST_CHECK(pt.get<bool>(T("k5.k.k.k.t")) == true);
// Do extractions via get (default value version)
- BOOST_CHECK(pt.get(T("k1"), 0) == 1); // get as int
- BOOST_CHECK(pt.get(T("k1"), 0L) == 1); // get as long
- BOOST_CHECK(pt.get(T("k2.k"), 0.0) == 2.5); // get as double
- BOOST_CHECK(pt.get(T("k2.k"), 0.0f) == 2.5f); // get as float
- BOOST_CHECK(pt.get(T("k3.k.k"), str_t()) == str_t(T("ala ma kota"))); // get as string
- BOOST_CHECK(pt.get(T("k3.k.k"), T("")) == T("ala ma kota")); // get as const char *
- BOOST_CHECK(pt.get(T("k4.k.k.k"), CHTYPE('\0')) == CHTYPE('c')); // get as char
- BOOST_CHECK(pt.get(T("k5.k.k.k.f"), true) == false); // get as bool
- BOOST_CHECK(pt.get(T("k5.k.k.k.t"), false) == true); // get as bool
+ BOOST_CHECK(pt.get(T("k1"), 0) == 1);
+ BOOST_CHECK(pt.get(T("k1"), 0L) == 1);
+ BOOST_CHECK(pt.get(T("k2.k"), 0.0) == 2.5);
+ BOOST_CHECK(pt.get(T("k2.k"), 0.0f) == 2.5f);
+ BOOST_CHECK(pt.get(T("k3.k.k"), str_t()) == str_t(T("ala ma kota")));
+ BOOST_CHECK(pt.get(T("k3.k.k"), T("")) == T("ala ma kota"));
+ BOOST_CHECK(pt.get(T("k4.k.k.k"), CHTYPE('\0')) == CHTYPE('c'));
+ BOOST_CHECK(pt.get(T("k5.k.k.k.f"), true) == false);
+ BOOST_CHECK(pt.get(T("k5.k.k.k.t"), false) == true);
// Do extractions via get (optional version)
- opt_int = pt.get_optional<int>(T("k1")); // get as int
+ opt_int = pt.get_optional<int>(T("k1"));
BOOST_CHECK(opt_int && *opt_int == 1);
- opt_long = pt.get_optional<long>(T("k1")); // get as long
+ opt_long = pt.get_optional<long>(T("k1"));
BOOST_CHECK(opt_long && *opt_long == 1);
- opt_double = pt.get_optional<double>(T("k2.k")); // get as double
+ opt_double = pt.get_optional<double>(T("k2.k"));
BOOST_CHECK(opt_double && *opt_double == 2.5);
- opt_float = pt.get_optional<float>(T("k2.k")); // get as float
+ opt_float = pt.get_optional<float>(T("k2.k"));
BOOST_CHECK(opt_float && *opt_float == 2.5f);
- opt_string = pt.get_optional<str_t>(T("k3.k.k")); // get as string
+ opt_string = pt.get_optional<str_t>(T("k3.k.k"));
BOOST_CHECK(opt_string && *opt_string == str_t(T("ala ma kota")));
- opt_char = pt.get_optional<CHTYPE>(T("k4.k.k.k")); // get as char
+ opt_char = pt.get_optional<CHTYPE>(T("k4.k.k.k"));
BOOST_CHECK(opt_char && *opt_char == CHTYPE('c'));
- opt_bool = pt.get_optional<bool>(T("k5.k.k.k.f")); // get as bool
+ opt_bool = pt.get_optional<bool>(T("k5.k.k.k.f"));
BOOST_CHECK(opt_bool && *opt_bool == false);
- opt_bool = pt.get_optional<bool>(T("k5.k.k.k.t")); // get as bool
+ opt_bool = pt.get_optional<bool>(T("k5.k.k.k.t"));
BOOST_CHECK(opt_bool && *opt_bool == true);
// Do insertions via put_value
- pt1.put_value(short(1)); // put as short
- pt2.put_value(2.5f); // put as float
- pt3.put_value(str_t(T("ala ma kota"))); // put as string
- pt4.put_value(CHTYPE('c')); // put as character
- pt5.put_value(false); // put as bool
- pt6.put_value(true); // put as bool
+ pt1.put_value(short(1));
+ pt2.put_value(2.5f);
+ pt3.put_value(str_t(T("ala ma kota")));
+ pt4.put_value(CHTYPE('c'));
+ pt5.put_value(false);
+ pt6.put_value(true);
// Do extractions via get_value (throwing version)
- BOOST_CHECK(pt1.get_value<int>() == 1); // get as int
- BOOST_CHECK(pt1.get_value<long>() == 1); // get as long
- BOOST_CHECK(pt2.get_value<double>() == 2.5); // get as double
- BOOST_CHECK(pt2.get_value<float>() == 2.5f); // get as float
- BOOST_CHECK(pt3.get_value<str_t>() == str_t(T("ala ma kota"))); // get as string
- BOOST_CHECK(pt4.get_value<CHTYPE>() == CHTYPE('c')); // get as char
- BOOST_CHECK(pt5.get_value<bool>() == false); // get as bool
- BOOST_CHECK(pt6.get_value<bool>() == true); // get as bool
+ BOOST_CHECK(pt1.get_value<int>() == 1);
+ BOOST_CHECK(pt1.get_value<long>() == 1);
+ BOOST_CHECK(pt2.get_value<double>() == 2.5);
+ BOOST_CHECK(pt2.get_value<float>() == 2.5f);
+ BOOST_CHECK(pt3.get_value<str_t>() == str_t(T("ala ma kota")));
+ BOOST_CHECK(pt4.get_value<CHTYPE>() == CHTYPE('c'));
+ BOOST_CHECK(pt5.get_value<bool>() == false);
+ BOOST_CHECK(pt6.get_value<bool>() == true);
// Do extractions via get_value (default value version)
- BOOST_CHECK(pt1.get_value(0) == 1); // get as int
- BOOST_CHECK(pt1.get_value(0L) == 1); // get as long
- BOOST_CHECK(pt2.get_value(0.0) == 2.5); // get as double
- BOOST_CHECK(pt2.get_value(0.0f) == 2.5f); // get as float
- BOOST_CHECK(pt3.get_value(str_t()) == str_t(T("ala ma kota"))); // get as string
- BOOST_CHECK(pt3.get_value(T("")) == T("ala ma kota")); // get as const char *
- BOOST_CHECK(pt4.get_value(CHTYPE('\0')) == CHTYPE('c')); // get as char
- BOOST_CHECK(pt5.get_value(true) == false); // get as bool
- BOOST_CHECK(pt6.get_value(false) == true); // get as bool
+ BOOST_CHECK(pt1.get_value(0) == 1);
+ BOOST_CHECK(pt1.get_value(0L) == 1);
+ BOOST_CHECK(pt2.get_value(0.0) == 2.5);
+ BOOST_CHECK(pt2.get_value(0.0f) == 2.5f);
+ BOOST_CHECK(pt3.get_value(str_t()) == str_t(T("ala ma kota")));
+ BOOST_CHECK(pt3.get_value(T("")) == T("ala ma kota"));
+ BOOST_CHECK(pt4.get_value(CHTYPE('\0')) == CHTYPE('c'));
+ BOOST_CHECK(pt5.get_value(true) == false);
+ BOOST_CHECK(pt6.get_value(false) == true);
// Do extractions via get_value (optional version)
- opt_int = pt1.get_value_optional<int>(); // get as int
+ opt_int = pt1.get_value_optional<int>();
BOOST_CHECK(opt_int && *opt_int == 1);
- opt_long = pt1.get_value_optional<long>(); // get as long
+ opt_long = pt1.get_value_optional<long>();
BOOST_CHECK(opt_long && *opt_long == 1);
- opt_double = pt2.get_value_optional<double>(); // get as double
+ opt_double = pt2.get_value_optional<double>();
BOOST_CHECK(opt_double && *opt_double == 2.5);
- opt_float = pt2.get_value_optional<float>(); // get as float
+ opt_float = pt2.get_value_optional<float>();
BOOST_CHECK(opt_float && *opt_float == 2.5f);
- opt_string = pt3.get_value_optional<str_t>(); // get as string
+ opt_string = pt3.get_value_optional<str_t>();
BOOST_CHECK(opt_string && *opt_string == str_t(T("ala ma kota")));
- opt_char = pt4.get_value_optional<CHTYPE>(); // get as char
+ opt_char = pt4.get_value_optional<CHTYPE>();
BOOST_CHECK(opt_char && *opt_char == CHTYPE('c'));
- opt_bool = pt5.get_value_optional<bool>(); // get as bool
+ opt_bool = pt5.get_value_optional<bool>();
BOOST_CHECK(opt_bool && *opt_bool == false);
- opt_bool = pt6.get_value_optional<bool>(); // get as bool
+ opt_bool = pt6.get_value_optional<bool>();
BOOST_CHECK(opt_bool && *opt_bool == true);
// Do incorrect extractions (throwing version)
- try
- {
+ try
+ {
pt.get<int>(T("k2.k.bogus.path"));
BOOST_ERROR("No required exception thrown");
- }
+ }
catch (boost::property_tree::ptree_bad_path &) { }
catch (...)
{
BOOST_ERROR("Wrong exception type thrown");
}
- try
- {
+ try
+ {
pt.get<int>(T("k2.k"));
BOOST_ERROR("No required exception thrown");
- }
+ }
catch (boost::property_tree::ptree_bad_data &) { }
catch (...)
{
@@ -761,7 +761,7 @@
PTREE &child = pt.get_child(T("key.key"));
BOOST_CHECK(child.size() == 1);
BOOST_CHECK(child.count(T("key")) == 1);
- pt.put(T("key.key.key"), 2, true);
+ pt.add(T("key.key.key"), 2);
BOOST_CHECK(child.size() == 2);
BOOST_CHECK(child.count(T("key")) == 2);
}
@@ -797,15 +797,15 @@
void test_get_child_put_child(PTREE *)
{
-
+
typedef std::basic_string<CHTYPE> str_t;
PTREE pt(T("ala ma kota"));
-
+
// Do insertions via put_child
PTREE pt1, pt2, pt3;
- pt1.put_child(T("k1"), boost::property_tree::empty_ptree<PTREE>());
- pt1.put_child(T("k2.k"), boost::property_tree::empty_ptree<PTREE>());
+ pt1.put_child(T("k1"), PTREE());
+ pt1.put_child(T("k2.k"), PTREE());
pt2.put_child(T("k1"), pt);
pt2.put_child(T("k2.k"), pt);
@@ -823,14 +823,14 @@
BOOST_CHECK(cpt2.get_child(T("k2.k")) == pt);
// Do correct extractions via get_child (default value version)
- BOOST_CHECK(&pt1.get_child(T("k1"), boost::property_tree::empty_ptree<PTREE>()) != &boost::property_tree::empty_ptree<PTREE>());
- BOOST_CHECK(&pt1.get_child(T("k2.k"), boost::property_tree::empty_ptree<PTREE>()) != &boost::property_tree::empty_ptree<PTREE>());
- BOOST_CHECK(pt2.get_child(T("k1"), boost::property_tree::empty_ptree<PTREE>()) == pt);
- BOOST_CHECK(pt2.get_child(T("k2.k"), boost::property_tree::empty_ptree<PTREE>()) == pt);
- BOOST_CHECK(&cpt1.get_child(T("k1"), boost::property_tree::empty_ptree<PTREE>()) != &boost::property_tree::empty_ptree<PTREE>());
- BOOST_CHECK(&cpt1.get_child(T("k2.k"), boost::property_tree::empty_ptree<PTREE>()) != &boost::property_tree::empty_ptree<PTREE>());
- BOOST_CHECK(cpt2.get_child(T("k1"), boost::property_tree::empty_ptree<PTREE>()) == pt);
- BOOST_CHECK(cpt2.get_child(T("k2.k"), boost::property_tree::empty_ptree<PTREE>()) == pt);
+ BOOST_CHECK(pt1.get_child(T("k1"), PTREE(T("def"))) != PTREE(T("def")));
+ BOOST_CHECK(pt1.get_child(T("k2.k"), PTREE(T("def"))) != PTREE(T("def")));
+ BOOST_CHECK(pt2.get_child(T("k1"), PTREE(T("def"))) == pt);
+ BOOST_CHECK(pt2.get_child(T("k2.k"), PTREE(T("def"))) == pt);
+ BOOST_CHECK(cpt1.get_child(T("k1"), PTREE(T("def"))) != PTREE(T("def")));
+ BOOST_CHECK(cpt1.get_child(T("k2.k"), PTREE(T("def"))) != PTREE(T("def")));
+ BOOST_CHECK(cpt2.get_child(T("k1"), PTREE(T("def"))) == pt);
+ BOOST_CHECK(cpt2.get_child(T("k2.k"), PTREE(T("def"))) == pt);
// Do correct extractions via get_child (optional version)
boost::optional<PTREE &> opt;
@@ -851,13 +851,13 @@
BOOST_CHECK(copt && *copt == pt);
copt = cpt2.get_child_optional(T("k2.k"));
BOOST_CHECK(copt && *copt == pt);
-
+
// Do incorrect extractions via get_child (throwing version)
- try
- {
+ try
+ {
pt.get_child(T("k2.k.bogus.path"));
BOOST_ERROR("No required exception thrown");
- }
+ }
catch (boost::property_tree::ptree_bad_path &) { }
catch (...)
{
@@ -886,32 +886,41 @@
BOOST_CHECK(child.size() == 1);
}
- // Test multiple puts with the same key using do_not_replace
+ // Test multiple adds with the same key
{
PTREE pt, tmp1(T("data1")), tmp2(T("data2"));
- pt.put_child(T("key"), tmp1);
+ pt.add_child(T("key"), tmp1);
BOOST_CHECK(pt.size() == 1);
- pt.put_child(T("key"), tmp2, true);
+ pt.add_child(T("key"), tmp2);
BOOST_CHECK(pt.size() == 2);
BOOST_CHECK(pt.count(T("key")) == 2);
- pt.put_child(T("key.key.key"), tmp1);
+ pt.add_child(T("key.key.key"), tmp1);
PTREE &child = pt.get_child(T("key.key"));
BOOST_CHECK(child.size() == 1);
BOOST_CHECK(child.count(T("key")) == 1);
- pt.put_child(T("key.key.key"), tmp2, true);
+ pt.add_child(T("key.key.key"), tmp2);
BOOST_CHECK(child.size() == 2);
BOOST_CHECK(child.count(T("key")) == 2);
}
+ // Test assigning child to tree
+ {
+ PTREE pt;
+ pt.put(T("foo.bar"), T("baz"));
+ pt = pt.get_child(T("foo"));
+ BOOST_CHECK(pt.size() == 1);
+ BOOST_CHECK(pt.get< std::basic_string<CHTYPE> >(T("bar")) == T("baz"));
+ }
+
}
void test_path_separator(PTREE *)
{
-
+
typedef PTREE::path_type path;
-
+
// Check instances count
- BOOST_CHECK(PTREE::debug_get_instances_count() == 0);
+ //BOOST_CHECK(PTREE::debug_get_instances_count() == 0);
// Do insertions
PTREE pt;
@@ -923,7 +932,7 @@
pt.put(path(T("key6/key/key"), CHTYPE('/')), T("6"));
// Check instances count
- BOOST_CHECK(PTREE::debug_get_instances_count() == 13);
+ //BOOST_CHECK(PTREE::debug_get_instances_count() == 13);
// Do correct extractions
BOOST_CHECK(pt.get(T("key1"), 0) == 1);
@@ -943,13 +952,13 @@
void test_path(PTREE *)
{
-
+
typedef PTREE::path_type path;
-
+
// Insert
PTREE pt;
pt.put(T("key1.key2.key3"), 1);
-
+
// Test operator /=
{
path p;
@@ -963,7 +972,7 @@
p /= T("key2.key3");
BOOST_CHECK(pt.get<int>(p, 0) == 1);
}
-
+
// Test operator /=
{
path p;
@@ -990,17 +999,17 @@
void test_precision(PTREE *)
{
-
+
typedef double real;
-
+
// Quite precise PI value
real pi = real(3.1415926535897932384626433832795028841971);
-
+
// Put and get
PTREE pt;
pt.put_value(pi);
real pi2 = pt.get_value<real>();
-
+
// Test if precision is "good enough", i.e. if stream precision increase worked
using namespace std;
real error = abs(pi - pi2) *
@@ -1012,10 +1021,11 @@
void test_locale(PTREE *)
{
-
+ typedef boost::property_tree::translator_between<
+ std::basic_string<CHTYPE>, double>::type translator;
try
{
-
+
// Write strings in english and french locales
PTREE pt;
#ifdef BOOST_WINDOWS
@@ -1025,8 +1035,8 @@
std::locale loc_english("en_GB");
std::locale loc_french("fr_FR");
#endif
- pt.put(T("english"), 1.234, false, loc_english);
- pt.put(T("french"), 1.234, false, loc_french);
+ pt.put(T("english"), 1.234, translator(loc_english));
+ pt.put(T("french"), 1.234, translator(loc_french));
// Test contents
BOOST_CHECK(pt.get<PTREE::data_type>(T("english")) == T("1.234"));
@@ -1054,7 +1064,7 @@
typedef PTREE::path_type Path;
// Property_tree with boost::any as data type
- typedef boost::property_tree::basic_ptree<Comp, Str, Path, boost::any, MyTranslator> my_ptree;
+ typedef boost::property_tree::basic_ptree<Str, boost::any, Comp> my_ptree;
my_ptree pt;
// Put/get int value
@@ -1099,9 +1109,9 @@
void test_ptree_bad_path(PTREE *)
{
-
+
PTREE pt;
-
+
try
{
pt.get<int>(T("non.existent.path"));
@@ -1113,7 +1123,7 @@
BOOST_CHECK(what.find("non.existent.path") != std::string::npos);
return;
}
-
+
BOOST_ERROR("No required exception thrown");
}
@@ -1132,10 +1142,12 @@
{
PTREE::data_type data = e.data<PTREE::data_type>();
std::string what = e.what();
- BOOST_CHECK(what.find("non convertible to int") != std::string::npos);
+ // FIXME: Bring back what translation or make it more clear that it
+ // doesn't work.
+ //BOOST_CHECK(what.find("non convertible to int") != std::string::npos);
return;
}
-
+
BOOST_ERROR("No required exception thrown");
}
@@ -1150,7 +1162,7 @@
pt.put(T("key1.key12"), T("foo"));
pt.put(T("key2"), true);
pt.put(T("key2.key21.key211.key2111.key21111"), T("super deep!"));
- pt.put_child(T("empty"), boost::property_tree::empty_ptree<PTREE>());
+ pt.put_child(T("empty"), PTREE());
pt.put(T("loooooong"), PTREE::data_type(10000, CHTYPE('a')));
// Endforce const for input
@@ -1213,7 +1225,7 @@
// Test true
for (PTREE::iterator it = pt.get_child(T("bool.true")).begin(); it != pt.get_child(T("bool.true")).end(); ++it)
BOOST_CHECK(it->second.get_value<bool>() == true);
-
+
// Test invalid
for (PTREE::iterator it = pt.get_child(T("bool.invalid")).begin(); it != pt.get_child(T("bool.invalid")).end(); ++it)
{
@@ -1228,7 +1240,7 @@
// Prepare test tree
PTREE pt;
-#if WIDECHAR == 0
+#if WIDECHAR == 0
pt.put(T("char"), char('A'));
#endif
pt.put(T("signed char"), static_cast<signed char>('A'));
@@ -1239,25 +1251,31 @@
pt.put(T("unsigned char max"), (std::numeric_limits<unsigned char>::max)());
// Verify normal conversions
-#if WIDECHAR == 0
+#if WIDECHAR == 0
BOOST_CHECK(pt.get<char>(T("char")) == 'A');
#endif
- BOOST_CHECK(pt.get<signed char>(T("signed char")) == static_cast<signed char>('A'));
- BOOST_CHECK(pt.get<unsigned char>(T("unsigned char")) == static_cast<unsigned char>('A'));
-
+ BOOST_CHECK(pt.get<signed char>(T("signed char")) ==
+ static_cast<signed char>('A'));
+ BOOST_CHECK(pt.get<unsigned char>(T("unsigned char")) ==
+ static_cast<unsigned char>('A'));
+
// Verify that numbers are saved for signed and unsigned char
BOOST_CHECK(pt.get<int>(T("signed char")) == int('A'));
BOOST_CHECK(pt.get<int>(T("unsigned char")) == int('A'));
// Verify ranges
- BOOST_CHECK(pt.get<signed char>(T("signed char min")) == (std::numeric_limits<signed char>::min)());
- BOOST_CHECK(pt.get<signed char>(T("signed char max")) == (std::numeric_limits<signed char>::max)());
- BOOST_CHECK(pt.get<unsigned char>(T("unsigned char min")) == (std::numeric_limits<unsigned char>::min)());
- BOOST_CHECK(pt.get<unsigned char>(T("unsigned char max")) == (std::numeric_limits<unsigned char>::max)());
+ BOOST_CHECK(pt.get<signed char>(T("signed char min")) ==
+ (std::numeric_limits<signed char>::min)());
+ BOOST_CHECK(pt.get<signed char>(T("signed char max")) ==
+ (std::numeric_limits<signed char>::max)());
+ BOOST_CHECK(pt.get<unsigned char>(T("unsigned char min")) ==
+ (std::numeric_limits<unsigned char>::min)());
+ BOOST_CHECK(pt.get<unsigned char>(T("unsigned char max")) ==
+ (std::numeric_limits<unsigned char>::max)());
}
void test_leaks(PTREE *)
{
- BOOST_CHECK(PTREE::debug_get_instances_count() == 0);
+ //BOOST_CHECK(PTREE::debug_get_instances_count() == 0);
}
Modified: trunk/libs/property_tree/test/test_utils.hpp
==============================================================================
--- trunk/libs/property_tree/test/test_utils.hpp (original)
+++ trunk/libs/property_tree/test/test_utils.hpp 2009-09-01 17:27:45 EDT (Tue, 01 Sep 2009)
@@ -52,7 +52,6 @@
return size;
}
-template<class Ch>
class test_file
{
public:
@@ -61,12 +60,8 @@
if (test_data && filename)
{
name = filename;
- std::basic_ofstream<Ch> stream(name.c_str());
- while (*test_data)
- {
- stream << Ch(*test_data);
- ++test_data;
- }
+ std::ofstream stream(name.c_str());
+ stream.write(test_data, strlen(test_data));
BOOST_CHECK(stream.good());
}
}
@@ -109,9 +104,9 @@
typedef typename Ptree::key_type::value_type Ch;
// Create test files
- test_file<Ch> file_1(test_data_1, filename_1);
- test_file<Ch> file_2(test_data_2, filename_2);
- test_file<Ch> file_out("", filename_out);
+ test_file file_1(test_data_1, filename_1);
+ test_file file_2(test_data_2, filename_2);
+ test_file file_out("", filename_out);
rf(filename_1, pt); // Read file
wf(filename_out, pt); // Write file
@@ -142,7 +137,7 @@
std::cerr << "(progress) Starting generic parser test with test file \"" << filename_1 << "\"\n";
// Make sure no instances exist
- BOOST_CHECK(Ptree::debug_get_instances_count() == 0);
+ //BOOST_CHECK(Ptree::debug_get_instances_count() == 0);
try
{
@@ -174,7 +169,7 @@
}
// Test for leaks
- BOOST_CHECK(Ptree::debug_get_instances_count() == 0);
+ //BOOST_CHECK(Ptree::debug_get_instances_count() == 0);
}
@@ -193,7 +188,7 @@
std::cerr << "(progress) Starting generic parser test with test file \"" << filename_1 << "\"\n";
// Make sure no instances exist
- BOOST_CHECK(Ptree::debug_get_instances_count() == 0);
+ //BOOST_CHECK(Ptree::debug_get_instances_count() == 0);
{
@@ -220,7 +215,7 @@
}
// Test for leaks
- BOOST_CHECK(Ptree::debug_get_instances_count() == 0);
+ //BOOST_CHECK(Ptree::debug_get_instances_count() == 0);
}
Modified: trunk/libs/property_tree/test/test_xml_parser_common.hpp
==============================================================================
--- trunk/libs/property_tree/test/test_xml_parser_common.hpp (original)
+++ trunk/libs/property_tree/test/test_xml_parser_common.hpp 2009-09-01 17:27:45 EDT (Tue, 01 Sep 2009)
@@ -32,6 +32,10 @@
}
};
+template <typename Ch> int umlautsize();
+template <> inline int umlautsize<char>() { return 2; }
+template <> inline int umlautsize<wchar_t>() { return 1; }
+
template<class Ptree>
void test_xml_parser()
{
@@ -53,7 +57,7 @@
generic_parser_test_ok<Ptree, ReadFunc, WriteFunc>
(
ReadFunc(), WriteFunc(), ok_data_3, NULL,
- "testok3.xml", NULL, "testok3out.xml", 787, 31346, 3831
+ "testok3.xml", NULL, "testok3out.xml", 787, 31376, 3831
);
generic_parser_test_ok<Ptree, ReadFunc, WriteFunc>
@@ -62,6 +66,13 @@
"testok4.xml", NULL, "testok4out.xml", 5, 2, 20
);
+ generic_parser_test_ok<Ptree, ReadFunc, WriteFunc>
+ (
+ ReadFunc(), WriteFunc(), ok_data_5, NULL,
+ "testok5.xml", NULL, "testok5out.xml",
+ 2, umlautsize<typename Ptree::data_type::value_type>(), 3
+ );
+
generic_parser_test_error<Ptree, ReadFunc, WriteFunc, xml_parser_error>
(
ReadFunc(), WriteFunc(), error_data_1, NULL,
Deleted: trunk/libs/property_tree/test/test_xml_parser_pugxml.cpp
==============================================================================
--- trunk/libs/property_tree/test/test_xml_parser_pugxml.cpp 2009-09-01 17:27:45 EDT (Tue, 01 Sep 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;
-}
Modified: trunk/libs/property_tree/test/test_xml_parser_rapidxml.cpp
==============================================================================
--- trunk/libs/property_tree/test/test_xml_parser_rapidxml.cpp (original)
+++ trunk/libs/property_tree/test/test_xml_parser_rapidxml.cpp 2009-09-01 17:27:45 EDT (Tue, 01 Sep 2009)
@@ -9,13 +9,23 @@
// ----------------------------------------------------------------------------
#include "test_xml_parser_common.hpp"
+#include <locale>
+#define BOOST_UTF8_BEGIN_NAMESPACE namespace boost { namespace property_tree {
+#define BOOST_UTF8_END_NAMESPACE }}
+#define BOOST_UTF8_DECL
+#include <boost/detail/utf8_codecvt_facet.hpp>
+#include "../../detail/utf8_codecvt_facet.cpp"
int test_main(int argc, char *argv[])
{
using namespace boost::property_tree;
+ using std::locale;
test_xml_parser<ptree>();
test_xml_parser<iptree>();
#ifndef BOOST_NO_CWCHAR
+ // We need a UTF-8-aware global locale now.
+ locale loc(locale(), new utf8_codecvt_facet);
+ locale::global(loc);
test_xml_parser<wptree>();
test_xml_parser<wiptree>();
#endif
Deleted: trunk/libs/property_tree/test/test_xml_parser_spirit.cpp
==============================================================================
--- trunk/libs/property_tree/test/test_xml_parser_spirit.cpp 2009-09-01 17:27:45 EDT (Tue, 01 Sep 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: trunk/libs/property_tree/test/test_xml_parser_tinyxml.cpp
==============================================================================
--- trunk/libs/property_tree/test/test_xml_parser_tinyxml.cpp 2009-09-01 17:27:45 EDT (Tue, 01 Sep 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;
-}
Modified: trunk/libs/property_tree/test/xml_parser_test_data.hpp
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
==============================================================================
--- trunk/libs/property_tree/test/xml_parser_test_data.hpp (original)
+++ trunk/libs/property_tree/test/xml_parser_test_data.hpp 2009-09-01 17:27:45 EDT (Tue, 01 Sep 2009)
@@ -35,21 +35,21 @@
"\n"
"<!-- Last edited: 27 May 1999 by bent -->\n"
"<header><?Pub Dtl?>\n"
- " <title>XML Linking Language (XLink)</title>\n"
- " <version>Version 1.0</version>\n"
- " <w3c-designation>WD-xlink-19990527</w3c-designation>\n"
- " <w3c-doctype>World Wide Web Consortium Working Draft</w3c-doctype>\n"
- " <pubdate><day>29</day><month>May</month><year>1999</year></pubdate>\n"
- " <notice>\n"
- " <p>This draft is for public discussion.</p>\n"
- " </notice>\n"
- " <publoc><loc href=\"http://www.w3.org/XML/Group/1999/05/WD-xlink-current\">http://www.w3.org/XML/Group/1999/05/WD-xlink-current></publoc>\n"
- " <prevlocs>\n"
- " <!--Check: was it actually August?-->\n"
- " <loc href=\"http://www.w3.org/XML/Group/1999/05/WD-xlink-19990527\">http://www.w3.org/XML/Group/1999/05/WD-xlink-19990527>\n"
- " <loc href=\"http://www.w3.org/XML/Group/1999/05/WD-xlink-19990505\">http://www.w3.org/XML/Group/1999/05/WD-xlink-19990505>\n"
- " <loc href=\"http://www.w3.org/TR/1998/WD-xlink-19980303\">http://www.w3.org/TR/1998/WD-xlink-19980303>\n"
- " <loc href=\"http://www.w3.org/TR/WD-xml-link-970630\">http://www.w3.org/TR/WD-xml-link-970630></prevlocs>\n"
+ " <title><![CDATA[XML Linking Language (XLink)]]></title>\n"
+ " <version>Version 1.0</version>\n"
+ " <w3c-designation>WD-xlink-19990527</w3c-designation>\n"
+ " <w3c-doctype>World Wide Web Consortium Working Draft</w3c-doctype>\n"
+ " <pubdate><day>29</day><month>May</month><year>1999</year></pubdate>\n"
+ " <notice>\n"
+ " <p>This draft is for public discussion.</p>\n"
+ " </notice>\n"
+ " <publoc><loc href=\"http://www.w3.org/XML/Group/1999/05/WD-xlink-current\">http://www.w3.org/XML/Group/1999/05/WD-xlink-current></publoc>\n"
+ " <prevlocs>\n"
+ " <!--Check: was it actually August?-->\n"
+ " <loc href=\"http://www.w3.org/XML/Group/1999/05/WD-xlink-19990527\">http://www.w3.org/XML/Group/1999/05/WD-xlink-19990527>\n"
+ " <loc href=\"http://www.w3.org/XML/Group/1999/05/WD-xlink-19990505\">http://www.w3.org/XML/Group/1999/05/WD-xlink-19990505>\n"
+ " <loc href=\"http://www.w3.org/TR/1998/WD-xlink-19980303\">http://www.w3.org/TR/1998/WD-xlink-19980303>\n"
+ " <loc href=\"http://www.w3.org/TR/WD-xml-link-970630\">http://www.w3.org/TR/WD-xml-link-970630></prevlocs>\n"
"\n"
" <authlist>\n"
" <!--Updated author hrefs dorchard-->\n"
@@ -571,7 +571,6 @@
" \n"
" Based on RSS DTD originally created by\n"
" Lars Marius Garshol - larsga_at_ifi.uio.no.\n"
- " $Id$\n"
" \n"
"-->\n"
"<!ELEMENT rss (channel)>\n"
@@ -731,6 +730,15 @@
"</channel>\n"
"</rss>\n";
+// Correct, with UTF-8 data
+const char ok_data_5[] = {
+ '<', '?', 'x', 'm', 'l', ' ', 'v', 'e', 'r', 's', 'i', 'o', 'n', '=', '"',
+ '1', '.', '0', '"', ' ', 'e', 'n', 'c', 'o', 'd', 'i', 'n', 'g', '=', '"',
+ 'u', 't', 'f', '-', '8', '"', '?', '>', '\n', /*39 chars*/
+ '<', 'd', 'o', 'c', '>', 0xC3, 0xA4, '<', '/', 'd', 'o', 'c', '>',
+ 0
+};
+
// Erroneous
const char *error_data_1 =
"a"; // bogus character