Added boost header

This commit is contained in:
Christophe Riccio
2012-01-08 01:26:07 +00:00
parent 9c3faaca40
commit c7d752cdf8
8946 changed files with 1732316 additions and 0 deletions

View File

@@ -0,0 +1,83 @@
// ----------------------------------------------------------------------------
// Copyright (C) 2002-2006 Marcin Kalicinski
// Copyright (C) 2009 Sebastian Redl
//
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
//
// For more information, see www.boost.org
// ----------------------------------------------------------------------------
#ifndef BOOST_PROPERTY_TREE_DETAIL_EXCEPTIONS_IMPLEMENTATION_HPP_INCLUDED
#define BOOST_PROPERTY_TREE_DETAIL_EXCEPTIONS_IMPLEMENTATION_HPP_INCLUDED
namespace boost { namespace property_tree
{
namespace detail
{
// Helper for preparing what string in ptree_bad_path exception
template<class P> inline
std::string prepare_bad_path_what(const std::string &what,
const P &path)
{
return what + " (" + path.dump() + ")";
}
}
///////////////////////////////////////////////////////////////////////////
// ptree_error
inline ptree_error::ptree_error(const std::string &w):
std::runtime_error(w)
{
}
inline ptree_error::~ptree_error() throw()
{
}
///////////////////////////////////////////////////////////////////////////
// ptree_bad_data
template<class D> inline
ptree_bad_data::ptree_bad_data(const std::string &w, const D &d):
ptree_error(w), m_data(d)
{
}
inline ptree_bad_data::~ptree_bad_data() throw()
{
}
template<class D> inline
D ptree_bad_data::data()
{
return boost::any_cast<D>(m_data);
}
///////////////////////////////////////////////////////////////////////////
// ptree_bad_path
template<class P> inline
ptree_bad_path::ptree_bad_path(const std::string &w, const P &p):
ptree_error(detail::prepare_bad_path_what(w, p)), m_path(p)
{
}
inline ptree_bad_path::~ptree_bad_path() throw()
{
}
template<class P> inline
P ptree_bad_path::path()
{
return boost::any_cast<P>(m_path);
}
}}
#endif

View File

@@ -0,0 +1,88 @@
// ----------------------------------------------------------------------------
// Copyright (C) 2002-2006 Marcin Kalicinski
//
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
//
// For more information, see www.boost.org
// ----------------------------------------------------------------------------
#ifndef BOOST_PROPERTY_TREE_DETAIL_FILE_PARSER_ERROR_HPP_INCLUDED
#define BOOST_PROPERTY_TREE_DETAIL_FILE_PARSER_ERROR_HPP_INCLUDED
#include <boost/property_tree/ptree.hpp>
#include <string>
namespace boost { namespace property_tree
{
//! File parse error
class file_parser_error: public ptree_error
{
public:
///////////////////////////////////////////////////////////////////////
// Construction & destruction
// Construct error
file_parser_error(const std::string &msg,
const std::string &file,
unsigned long l) :
ptree_error(format_what(msg, file, l)),
m_message(msg), m_filename(file), m_line(l)
{
}
~file_parser_error() throw()
// gcc 3.4.2 complains about lack of throw specifier on compiler
// generated dtor
{
}
///////////////////////////////////////////////////////////////////////
// Data access
// Get error message (without line and file - use what() to get
// full message)
std::string message() const
{
return m_message;
}
// Get error filename
std::string filename() const
{
return m_filename;
}
// Get error line number
unsigned long line() const
{
return m_line;
}
private:
std::string m_message;
std::string m_filename;
unsigned long m_line;
// Format error message to be returned by std::runtime_error::what()
static std::string format_what(const std::string &msg,
const std::string &file,
unsigned long l)
{
std::stringstream stream;
stream << (file.empty() ? "<unspecified file>" : file.c_str());
if (l > 0)
stream << '(' << l << ')';
stream << ": " << msg;
return stream.str();
}
};
} }
#endif

View File

@@ -0,0 +1,32 @@
// ----------------------------------------------------------------------------
// Copyright (C) 2002-2006 Marcin Kalicinski
//
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
//
// For more information, see www.boost.org
// ----------------------------------------------------------------------------
#ifndef BOOST_PROPERTY_TREE_DETAIL_INFO_PARSER_ERROR_HPP_INCLUDED
#define BOOST_PROPERTY_TREE_DETAIL_INFO_PARSER_ERROR_HPP_INCLUDED
#include <boost/property_tree/detail/file_parser_error.hpp>
#include <string>
namespace boost { namespace property_tree { namespace info_parser
{
class info_parser_error: public file_parser_error
{
public:
info_parser_error(const std::string &message,
const std::string &filename,
unsigned long line) :
file_parser_error(message, filename, line)
{
}
};
} } }
#endif

View File

@@ -0,0 +1,380 @@
// ----------------------------------------------------------------------------
// Copyright (C) 2002-2006 Marcin Kalicinski
//
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
//
// For more information, see www.boost.org
// ----------------------------------------------------------------------------
#ifndef BOOST_PROPERTY_TREE_DETAIL_INFO_PARSER_READ_HPP_INCLUDED
#define BOOST_PROPERTY_TREE_DETAIL_INFO_PARSER_READ_HPP_INCLUDED
#include "boost/property_tree/ptree.hpp"
#include "boost/property_tree/detail/info_parser_error.hpp"
#include "boost/property_tree/detail/info_parser_utils.hpp"
#include <iterator>
#include <string>
#include <stack>
#include <fstream>
#include <cctype>
namespace boost { namespace property_tree { namespace info_parser
{
// Expand known escape sequences
template<class It>
std::basic_string<typename std::iterator_traits<It>::value_type>
expand_escapes(It b, It e)
{
typedef typename std::iterator_traits<It>::value_type Ch;
std::basic_string<Ch> result;
while (b != e)
{
if (*b == Ch('\\'))
{
++b;
if (b == e)
{
BOOST_PROPERTY_TREE_THROW(info_parser_error(
"character expected after backslash", "", 0));
}
else if (*b == Ch('0')) result += Ch('\0');
else if (*b == Ch('a')) result += Ch('\a');
else if (*b == Ch('b')) result += Ch('\b');
else if (*b == Ch('f')) result += Ch('\f');
else if (*b == Ch('n')) result += Ch('\n');
else if (*b == Ch('r')) result += Ch('\r');
else if (*b == Ch('t')) result += Ch('\t');
else if (*b == Ch('v')) result += Ch('\v');
else if (*b == Ch('"')) result += Ch('"');
else if (*b == Ch('\'')) result += Ch('\'');
else if (*b == Ch('\\')) result += Ch('\\');
else
BOOST_PROPERTY_TREE_THROW(info_parser_error(
"unknown escape sequence", "", 0));
}
else
result += *b;
++b;
}
return result;
}
// Advance pointer past whitespace
template<class Ch>
void skip_whitespace(const Ch *&text)
{
using namespace std;
while (isspace(*text))
++text;
}
// Extract word (whitespace delimited) and advance pointer accordingly
template<class Ch>
std::basic_string<Ch> read_word(const Ch *&text)
{
using namespace std;
skip_whitespace(text);
const Ch *start = text;
while (!isspace(*text) && *text != Ch(';') && *text != Ch('\0'))
++text;
return expand_escapes(start, text);
}
// Extract line (eol delimited) and advance pointer accordingly
template<class Ch>
std::basic_string<Ch> read_line(const Ch *&text)
{
using namespace std;
skip_whitespace(text);
const Ch *start = text;
while (*text != Ch('\0') && *text != Ch(';'))
++text;
while (text > start && isspace(*(text - 1)))
--text;
return expand_escapes(start, text);
}
// Extract string (inside ""), and advance pointer accordingly
// Set need_more_lines to true if \ continuator found
template<class Ch>
std::basic_string<Ch> read_string(const Ch *&text, bool *need_more_lines)
{
skip_whitespace(text);
if (*text == Ch('\"'))
{
// Skip "
++text;
// Find end of string, but skip escaped "
bool escaped = false;
const Ch *start = text;
while ((escaped || *text != Ch('\"')) && *text != Ch('\0'))
{
escaped = (!escaped && *text == Ch('\\'));
++text;
}
// If end of string found
if (*text == Ch('\"'))
{
std::basic_string<Ch> result = expand_escapes(start, text++);
skip_whitespace(text);
if (*text == Ch('\\'))
{
if (!need_more_lines)
BOOST_PROPERTY_TREE_THROW(info_parser_error(
"unexpected \\", "", 0));
++text;
skip_whitespace(text);
if (*text == Ch('\0') || *text == Ch(';'))
*need_more_lines = true;
else
BOOST_PROPERTY_TREE_THROW(info_parser_error(
"expected end of line after \\", "", 0));
}
else
if (need_more_lines)
*need_more_lines = false;
return result;
}
else
BOOST_PROPERTY_TREE_THROW(info_parser_error(
"unexpected end of line", "", 0));
}
else
BOOST_PROPERTY_TREE_THROW(info_parser_error("expected \"", "", 0));
}
// Extract key
template<class Ch>
std::basic_string<Ch> read_key(const Ch *&text)
{
skip_whitespace(text);
if (*text == Ch('\"'))
return read_string(text, NULL);
else
return read_word(text);
}
// Extract data
template<class Ch>
std::basic_string<Ch> read_data(const Ch *&text, bool *need_more_lines)
{
skip_whitespace(text);
if (*text == Ch('\"'))
return read_string(text, need_more_lines);
else
{
*need_more_lines = false;
return read_word(text);
}
}
// Build ptree from info stream
template<class Ptree, class Ch>
void read_info_internal(std::basic_istream<Ch> &stream,
Ptree &pt,
const std::string &filename,
int include_depth)
{
typedef std::basic_string<Ch> str_t;
// Possible parser states
enum state_t {
s_key, // Parser expects key
s_data, // Parser expects data
s_data_cont // Parser expects data continuation
};
unsigned long line_no = 0;
state_t state = s_key; // Parser state
Ptree *last = NULL; // Pointer to last created ptree
// Define line here to minimize reallocations
str_t line;
// Initialize ptree stack (used to handle nesting)
std::stack<Ptree *> stack;
stack.push(&pt); // Push root ptree on stack initially
try {
// While there are characters in the stream
while (stream.good()) {
// Read one line from stream
++line_no;
std::getline(stream, line);
if (!stream.good() && !stream.eof())
BOOST_PROPERTY_TREE_THROW(info_parser_error(
"read error", filename, line_no));
const Ch *text = line.c_str();
// If directive found
skip_whitespace(text);
if (*text == Ch('#')) {
// Determine directive type
++text; // skip #
std::basic_string<Ch> directive = read_word(text);
if (directive == convert_chtype<Ch, char>("include")) {
// #include
if (include_depth > 100) {
BOOST_PROPERTY_TREE_THROW(info_parser_error(
"include depth too large, "
"probably recursive include",
filename, line_no));
}
str_t s = read_string(text, NULL);
std::string inc_name =
convert_chtype<char, Ch>(s.c_str());
std::basic_ifstream<Ch> inc_stream(inc_name.c_str());
if (!inc_stream.good())
BOOST_PROPERTY_TREE_THROW(info_parser_error(
"cannot open include file " + inc_name,
filename, line_no));
read_info_internal(inc_stream, *stack.top(),
inc_name, include_depth + 1);
} else { // Unknown directive
BOOST_PROPERTY_TREE_THROW(info_parser_error(
"unknown directive", filename, line_no));
}
// Directive must be followed by end of line
skip_whitespace(text);
if (*text != Ch('\0')) {
BOOST_PROPERTY_TREE_THROW(info_parser_error(
"expected end of line", filename, line_no));
}
// Go to next line
continue;
}
// While there are characters left in line
while (1) {
// Stop parsing on end of line or comment
skip_whitespace(text);
if (*text == Ch('\0') || *text == Ch(';')) {
if (state == s_data) // If there was no data set state to s_key
state = s_key;
break;
}
// Process according to current parser state
switch (state)
{
// Parser expects key
case s_key:
{
if (*text == Ch('{')) // Brace opening found
{
if (!last)
BOOST_PROPERTY_TREE_THROW(info_parser_error("unexpected {", "", 0));
stack.push(last);
last = NULL;
++text;
}
else if (*text == Ch('}')) // Brace closing found
{
if (stack.size() <= 1)
BOOST_PROPERTY_TREE_THROW(info_parser_error("unmatched }", "", 0));
stack.pop();
last = NULL;
++text;
}
else // Key text found
{
std::basic_string<Ch> key = read_key(text);
last = &stack.top()->push_back(
std::make_pair(key, Ptree()))->second;
state = s_data;
}
}; break;
// Parser expects data
case s_data:
{
// Last ptree must be defined because we are going to add data to it
BOOST_ASSERT(last);
if (*text == Ch('{')) // Brace opening found
{
stack.push(last);
last = NULL;
++text;
state = s_key;
}
else if (*text == Ch('}')) // Brace closing found
{
if (stack.size() <= 1)
BOOST_PROPERTY_TREE_THROW(info_parser_error("unmatched }", "", 0));
stack.pop();
last = NULL;
++text;
state = s_key;
}
else // Data text found
{
bool need_more_lines;
std::basic_string<Ch> data = read_data(text, &need_more_lines);
last->data() = data;
state = need_more_lines ? s_data_cont : s_key;
}
}; break;
// Parser expects continuation of data after \ on previous line
case s_data_cont:
{
// Last ptree must be defined because we are going to update its data
BOOST_ASSERT(last);
if (*text == Ch('\"')) // Continuation must start with "
{
bool need_more_lines;
std::basic_string<Ch> data = read_string(text, &need_more_lines);
last->put_value(last->template get_value<std::basic_string<Ch> >() + data);
state = need_more_lines ? s_data_cont : s_key;
}
else
BOOST_PROPERTY_TREE_THROW(info_parser_error("expected \" after \\ in previous line", "", 0));
}; break;
// Should never happen
default:
BOOST_ASSERT(0);
}
}
}
// Check if stack has initial size, otherwise some {'s have not been closed
if (stack.size() != 1)
BOOST_PROPERTY_TREE_THROW(info_parser_error("unmatched {", "", 0));
}
catch (info_parser_error &e)
{
// If line undefined rethrow error with correct filename and line
if (e.line() == 0)
{
BOOST_PROPERTY_TREE_THROW(info_parser_error(e.message(), filename, line_no));
}
else
BOOST_PROPERTY_TREE_THROW(e);
}
}
} } }
#endif

View File

@@ -0,0 +1,32 @@
// ----------------------------------------------------------------------------
// Copyright (C) 2002-2006 Marcin Kalicinski
//
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
//
// For more information, see www.boost.org
// ----------------------------------------------------------------------------
#ifndef BOOST_PROPERTY_TREE_DETAIL_INFO_PARSER_CHCONV_HPP_INCLUDED
#define BOOST_PROPERTY_TREE_DETAIL_INFO_PARSER_CHCONV_HPP_INCLUDED
#include <string>
namespace boost { namespace property_tree { namespace info_parser
{
template<class ChDest, class ChSrc>
std::basic_string<ChDest> convert_chtype(const ChSrc *text)
{
std::basic_string<ChDest> result;
while (*text)
{
result += ChDest(*text);
++text;
}
return result;
}
} } }
#endif

View File

@@ -0,0 +1,147 @@
// ----------------------------------------------------------------------------
// Copyright (C) 2002-2006 Marcin Kalicinski
//
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
//
// For more information, see www.boost.org
// ----------------------------------------------------------------------------
#ifndef BOOST_PROPERTY_TREE_DETAIL_INFO_PARSER_WRITE_HPP_INCLUDED
#define BOOST_PROPERTY_TREE_DETAIL_INFO_PARSER_WRITE_HPP_INCLUDED
#include "boost/property_tree/ptree.hpp"
#include "boost/property_tree/detail/info_parser_utils.hpp"
#include <string>
namespace boost { namespace property_tree { namespace info_parser
{
template<class Ch>
void write_info_indent(std::basic_ostream<Ch> &stream,
int indent,
const info_writer_settings<Ch> &settings
)
{
stream << std::basic_string<Ch>(indent * settings.indent_count, settings.indent_char);
}
// Create necessary escape sequences from illegal characters
template<class Ch>
std::basic_string<Ch> create_escapes(const std::basic_string<Ch> &s)
{
std::basic_string<Ch> result;
typename std::basic_string<Ch>::const_iterator b = s.begin();
typename std::basic_string<Ch>::const_iterator e = s.end();
while (b != e)
{
if (*b == Ch('\0')) result += Ch('\\'), result += Ch('0');
else if (*b == Ch('\a')) result += Ch('\\'), result += Ch('a');
else if (*b == Ch('\b')) result += Ch('\\'), result += Ch('b');
else if (*b == Ch('\f')) result += Ch('\\'), result += Ch('f');
else if (*b == Ch('\n')) result += Ch('\\'), result += Ch('n');
else if (*b == Ch('\r')) result += Ch('\\'), result += Ch('r');
else if (*b == Ch('\v')) result += Ch('\\'), result += Ch('v');
else if (*b == Ch('"')) result += Ch('\\'), result += Ch('"');
else if (*b == Ch('\\')) result += Ch('\\'), result += Ch('\\');
else
result += *b;
++b;
}
return result;
}
template<class Ch>
bool is_simple_key(const std::basic_string<Ch> &key)
{
const static std::basic_string<Ch> chars = convert_chtype<Ch, char>(" \t{};\n\"");
return !key.empty() && key.find_first_of(chars) == key.npos;
}
template<class Ch>
bool is_simple_data(const std::basic_string<Ch> &data)
{
const static std::basic_string<Ch> chars = convert_chtype<Ch, char>(" \t{};\n\"");
return !data.empty() && data.find_first_of(chars) == data.npos;
}
template<class Ptree>
void write_info_helper(std::basic_ostream<typename Ptree::key_type::value_type> &stream,
const Ptree &pt,
int indent,
const info_writer_settings<typename Ptree::key_type::value_type> &settings)
{
// Character type
typedef typename Ptree::key_type::value_type Ch;
// Write data
if (indent >= 0)
{
if (!pt.data().empty())
{
std::basic_string<Ch> data = create_escapes(pt.template get_value<std::basic_string<Ch> >());
if (is_simple_data(data))
stream << Ch(' ') << data << Ch('\n');
else
stream << Ch(' ') << Ch('\"') << data << Ch('\"') << Ch('\n');
}
else if (pt.empty())
stream << Ch(' ') << Ch('\"') << Ch('\"') << Ch('\n');
else
stream << Ch('\n');
}
// Write keys
if (!pt.empty())
{
// Open brace
if (indent >= 0)
{
write_info_indent( stream, indent, settings);
stream << Ch('{') << Ch('\n');
}
// Write keys
typename Ptree::const_iterator it = pt.begin();
for (; it != pt.end(); ++it)
{
// Output key
std::basic_string<Ch> key = create_escapes(it->first);
write_info_indent( stream, indent+1, settings);
if (is_simple_key(key))
stream << key;
else
stream << Ch('\"') << key << Ch('\"');
// Output data and children
write_info_helper(stream, it->second, indent + 1, settings);
}
// Close brace
if (indent >= 0)
{
write_info_indent( stream, indent, settings);
stream << Ch('}') << Ch('\n');
}
}
}
// Write ptree to info stream
template<class Ptree>
void write_info_internal(std::basic_ostream<typename Ptree::key_type::value_type> &stream,
const Ptree &pt,
const std::string &filename,
const info_writer_settings<typename Ptree::key_type::value_type> &settings)
{
write_info_helper(stream, pt, -1, settings);
if (!stream.good())
BOOST_PROPERTY_TREE_THROW(info_parser_error("write error", filename, 0));
}
} } }
#endif

View File

@@ -0,0 +1,40 @@
// ----------------------------------------------------------------------------
// Copyright (C) 2002-2006 Marcin Kalicinski
// Copyright (C) 2007 Alexey Baskakov
//
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
//
// For more information, see www.boost.org
// ----------------------------------------------------------------------------
#ifndef BOOST_PROPERTY_TREE_DETAIL_INFO_PARSER_WRITER_SETTINGS_HPP_INCLUDED
#define BOOST_PROPERTY_TREE_DETAIL_INFO_PARSER_WRITER_SETTINGS_HPP_INCLUDED
#include <string>
namespace boost { namespace property_tree { namespace info_parser
{
template <class Ch>
class info_writer_settings
{
public:
info_writer_settings(Ch indent_char = Ch(' '), unsigned indent_count = 4):
indent_char(indent_char),
indent_count(indent_count)
{
}
Ch indent_char;
int indent_count;
};
template <class Ch>
info_writer_settings<Ch> info_writer_make_settings(Ch indent_char = Ch(' '), unsigned indent_count = 4)
{
return info_writer_settings<Ch>(indent_char, indent_count);
}
} } }
#endif

View File

@@ -0,0 +1,33 @@
// ----------------------------------------------------------------------------
// Copyright (C) 2002-2006 Marcin Kalicinski
//
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
//
// For more information, see www.boost.org
// ----------------------------------------------------------------------------
#ifndef BOOST_PROPERTY_TREE_DETAIL_JSON_PARSER_ERROR_HPP_INCLUDED
#define BOOST_PROPERTY_TREE_DETAIL_JSON_PARSER_ERROR_HPP_INCLUDED
#include <boost/property_tree/detail/file_parser_error.hpp>
#include <string>
namespace boost { namespace property_tree { namespace json_parser
{
//! Json parser error
class json_parser_error: public file_parser_error
{
public:
json_parser_error(const std::string &message,
const std::string &filename,
unsigned long line):
file_parser_error(message, filename, line)
{
}
};
} } }
#endif

View File

@@ -0,0 +1,331 @@
// ----------------------------------------------------------------------------
// 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_JSON_PARSER_READ_HPP_INCLUDED
#define BOOST_PROPERTY_TREE_DETAIL_JSON_PARSER_READ_HPP_INCLUDED
//#define BOOST_SPIRIT_DEBUG
#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/include/classic.hpp>
#include <boost/limits.hpp>
#include <string>
#include <locale>
#include <istream>
#include <vector>
#include <algorithm>
namespace boost { namespace property_tree { namespace json_parser
{
///////////////////////////////////////////////////////////////////////
// Json parser context
template<class Ptree>
struct context
{
typedef typename Ptree::key_type::value_type Ch;
typedef std::basic_string<Ch> Str;
typedef typename std::vector<Ch>::iterator It;
Str string;
Str name;
Ptree root;
std::vector<Ptree *> stack;
struct a_object_s
{
context &c;
a_object_s(context &c): c(c) { }
void operator()(Ch) const
{
if (c.stack.empty())
c.stack.push_back(&c.root);
else
{
Ptree *parent = c.stack.back();
Ptree *child = &parent->push_back(std::make_pair(c.name, Ptree()))->second;
c.stack.push_back(child);
c.name.clear();
}
}
};
struct a_object_e
{
context &c;
a_object_e(context &c): c(c) { }
void operator()(Ch) const
{
BOOST_ASSERT(c.stack.size() >= 1);
c.stack.pop_back();
}
};
struct a_name
{
context &c;
a_name(context &c): c(c) { }
void operator()(It, It) const
{
c.name.swap(c.string);
c.string.clear();
}
};
struct a_string_val
{
context &c;
a_string_val(context &c): c(c) { }
void operator()(It, It) const
{
BOOST_ASSERT(c.stack.size() >= 1);
c.stack.back()->push_back(std::make_pair(c.name, Ptree(c.string)));
c.name.clear();
c.string.clear();
}
};
struct a_literal_val
{
context &c;
a_literal_val(context &c): c(c) { }
void operator()(It b, It e) const
{
BOOST_ASSERT(c.stack.size() >= 1);
c.stack.back()->push_back(std::make_pair(c.name, Str(b, e)));
c.name.clear();
c.string.clear();
}
};
struct a_char
{
context &c;
a_char(context &c): c(c) { }
void operator()(It b, It e) const
{
c.string += *b;
}
};
struct a_escape
{
context &c;
a_escape(context &c): c(c) { }
void operator()(Ch ch) const
{
switch (ch)
{
case Ch('\"'): c.string += Ch('\"'); break;
case Ch('\\'): c.string += Ch('\\'); break;
case Ch('/'): c.string += Ch('/'); break;
case Ch('b'): c.string += Ch('\b'); break;
case Ch('f'): c.string += Ch('\f'); break;
case Ch('n'): c.string += Ch('\n'); break;
case Ch('r'): c.string += Ch('\r'); break;
case Ch('t'): c.string += Ch('\t'); break;
default: BOOST_ASSERT(0);
}
}
};
struct a_unicode
{
context &c;
a_unicode(context &c): c(c) { }
void operator()(unsigned long u) const
{
u = (std::min)(u, static_cast<unsigned long>((std::numeric_limits<Ch>::max)()));
c.string += Ch(u);
}
};
};
///////////////////////////////////////////////////////////////////////
// Json grammar
template<class Ptree>
struct json_grammar :
public boost::spirit::classic::grammar<json_grammar<Ptree> >
{
typedef context<Ptree> Context;
typedef typename Ptree::key_type::value_type Ch;
mutable Context c;
template<class Scanner>
struct definition
{
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::classic;
// There's a boost::assertion too, so another explicit using
// here:
using boost::spirit::classic::assertion;
// Assertions
assertion<std::string> expect_root("expected object or array");
assertion<std::string> expect_eoi("expected end of input");
assertion<std::string> expect_objclose("expected ',' or '}'");
assertion<std::string> expect_arrclose("expected ',' or ']'");
assertion<std::string> expect_name("expected object name");
assertion<std::string> expect_colon("expected ':'");
assertion<std::string> expect_value("expected value");
assertion<std::string> expect_escape("invalid escape sequence");
// JSON grammar rules
root
= expect_root(object | array)
>> expect_eoi(end_p)
;
object
= ch_p('{')[typename Context::a_object_s(self.c)]
>> (ch_p('}')[typename Context::a_object_e(self.c)]
| (list_p(member, ch_p(','))
>> expect_objclose(ch_p('}')[typename Context::a_object_e(self.c)])
)
)
;
member
= expect_name(string[typename Context::a_name(self.c)])
>> expect_colon(ch_p(':'))
>> expect_value(value)
;
array
= ch_p('[')[typename Context::a_object_s(self.c)]
>> (ch_p(']')[typename Context::a_object_e(self.c)]
| (list_p(item, ch_p(','))
>> expect_arrclose(ch_p(']')[typename Context::a_object_e(self.c)])
)
)
;
item
= expect_value(value)
;
value
= string[typename Context::a_string_val(self.c)]
| (number | str_p("true") | "false" | "null")[typename Context::a_literal_val(self.c)]
| object
| array
;
number
= !ch_p("-") >>
(ch_p("0") | (range_p(Ch('1'), Ch('9')) >> *digit_p)) >>
!(ch_p(".") >> +digit_p) >>
!(chset_p(detail::widen<Ch>("eE").c_str()) >>
!chset_p(detail::widen<Ch>("-+").c_str()) >>
+digit_p)
;
string
= +(lexeme_d[confix_p('\"', *character, '\"')])
;
character
= (anychar_p - "\\" - "\"")
[typename Context::a_char(self.c)]
| ch_p("\\") >> expect_escape(escape)
;
escape
= chset_p(detail::widen<Ch>("\"\\/bfnrt").c_str())
[typename Context::a_escape(self.c)]
| 'u' >> uint_parser<unsigned long, 16, 4, 4>()
[typename Context::a_unicode(self.c)]
;
// Debug
BOOST_SPIRIT_DEBUG_RULE(root);
BOOST_SPIRIT_DEBUG_RULE(object);
BOOST_SPIRIT_DEBUG_RULE(member);
BOOST_SPIRIT_DEBUG_RULE(array);
BOOST_SPIRIT_DEBUG_RULE(item);
BOOST_SPIRIT_DEBUG_RULE(value);
BOOST_SPIRIT_DEBUG_RULE(string);
BOOST_SPIRIT_DEBUG_RULE(number);
BOOST_SPIRIT_DEBUG_RULE(escape);
BOOST_SPIRIT_DEBUG_RULE(character);
}
const boost::spirit::classic::rule<Scanner> &start() const
{
return root;
}
};
};
template<class It, class Ch>
unsigned long count_lines(It begin, It end)
{
return static_cast<unsigned long>(std::count(begin, end, Ch('\n')) + 1);
}
template<class Ptree>
void read_json_internal(std::basic_istream<typename Ptree::key_type::value_type> &stream,
Ptree &pt,
const std::string &filename)
{
using namespace boost::spirit::classic;
typedef typename Ptree::key_type::value_type Ch;
typedef typename std::vector<Ch>::iterator It;
// 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(json_parser_error("read error", filename, 0));
// Prepare grammar
json_grammar<Ptree> g;
// Parse
try
{
parse_info<It> pi = parse(v.begin(), v.end(), g,
space_p | comment_p("//") | comment_p("/*", "*/"));
if (!pi.hit || !pi.full)
BOOST_PROPERTY_TREE_THROW((parser_error<std::string, It>(v.begin(), "syntax error")));
}
catch (parser_error<std::string, It> &e)
{
BOOST_PROPERTY_TREE_THROW(json_parser_error(e.descriptor, filename, count_lines<It, Ch>(v.begin(), e.where)));
}
// Swap grammar context root and pt
pt.swap(g.c.root);
}
} } }
#endif

View File

@@ -0,0 +1,170 @@
// ----------------------------------------------------------------------------
// 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_JSON_PARSER_WRITE_HPP_INCLUDED
#define BOOST_PROPERTY_TREE_DETAIL_JSON_PARSER_WRITE_HPP_INCLUDED
#include <boost/property_tree/ptree.hpp>
#include <boost/next_prior.hpp>
#include <boost/type_traits/make_unsigned.hpp>
#include <string>
#include <ostream>
#include <iomanip>
namespace boost { namespace property_tree { namespace json_parser
{
// Create necessary escape sequences from illegal characters
template<class Ch>
std::basic_string<Ch> create_escapes(const std::basic_string<Ch> &s)
{
std::basic_string<Ch> result;
typename std::basic_string<Ch>::const_iterator b = s.begin();
typename std::basic_string<Ch>::const_iterator e = s.end();
while (b != e)
{
// This assumes an ASCII superset. But so does everything in PTree.
// We escape everything outside ASCII, because this code can't
// handle high unicode characters.
if (*b == 0x20 || *b == 0x21 || (*b >= 0x23 && *b <= 0x2E) ||
(*b >= 0x30 && *b <= 0x5B) || (*b >= 0x5D && *b <= 0xFF))
result += *b;
else if (*b == Ch('\b')) result += Ch('\\'), result += Ch('b');
else if (*b == Ch('\f')) result += Ch('\\'), result += Ch('f');
else if (*b == Ch('\n')) result += Ch('\\'), result += Ch('n');
else if (*b == Ch('\r')) result += Ch('\\'), result += Ch('r');
else if (*b == Ch('/')) result += Ch('\\'), result += Ch('/');
else if (*b == Ch('"')) result += Ch('\\'), result += Ch('"');
else if (*b == Ch('\\')) result += Ch('\\'), result += Ch('\\');
else
{
const char *hexdigits = "0123456789ABCDEF";
typedef typename make_unsigned<Ch>::type UCh;
unsigned long u = (std::min)(static_cast<unsigned long>(
static_cast<UCh>(*b)),
0xFFFFul);
int d1 = u / 4096; u -= d1 * 4096;
int d2 = u / 256; u -= d2 * 256;
int d3 = u / 16; u -= d3 * 16;
int d4 = u;
result += Ch('\\'); result += Ch('u');
result += Ch(hexdigits[d1]); result += Ch(hexdigits[d2]);
result += Ch(hexdigits[d3]); result += Ch(hexdigits[d4]);
}
++b;
}
return result;
}
template<class Ptree>
void write_json_helper(std::basic_ostream<typename Ptree::key_type::value_type> &stream,
const Ptree &pt,
int indent, bool pretty)
{
typedef typename Ptree::key_type::value_type Ch;
typedef typename std::basic_string<Ch> Str;
// Value or object or array
if (indent > 0 && pt.empty())
{
// Write value
Str data = create_escapes(pt.template get_value<Str>());
stream << Ch('"') << data << Ch('"');
}
else if (indent > 0 && pt.count(Str()) == pt.size())
{
// Write array
stream << Ch('[');
if (pretty) stream << Ch('\n');
typename Ptree::const_iterator it = pt.begin();
for (; it != pt.end(); ++it)
{
if (pretty) stream << Str(4 * (indent + 1), Ch(' '));
write_json_helper(stream, it->second, indent + 1, pretty);
if (boost::next(it) != pt.end())
stream << Ch(',');
if (pretty) stream << Ch('\n');
}
stream << Str(4 * indent, Ch(' ')) << Ch(']');
}
else
{
// Write object
stream << Ch('{');
if (pretty) stream << Ch('\n');
typename Ptree::const_iterator it = pt.begin();
for (; it != pt.end(); ++it)
{
if (pretty) stream << Str(4 * (indent + 1), Ch(' '));
stream << Ch('"') << create_escapes(it->first) << Ch('"') << Ch(':');
if (pretty) {
if (it->second.empty())
stream << Ch(' ');
else
stream << Ch('\n') << Str(4 * (indent + 1), Ch(' '));
}
write_json_helper(stream, it->second, indent + 1, pretty);
if (boost::next(it) != pt.end())
stream << Ch(',');
if (pretty) stream << Ch('\n');
}
if (pretty) stream << Str(4 * indent, Ch(' '));
stream << Ch('}');
}
}
// Verify if ptree does not contain information that cannot be written to json
template<class Ptree>
bool verify_json(const Ptree &pt, int depth)
{
typedef typename Ptree::key_type::value_type Ch;
typedef typename std::basic_string<Ch> Str;
// Root ptree cannot have data
if (depth == 0 && !pt.template get_value<Str>().empty())
return false;
// Ptree cannot have both children and data
if (!pt.template get_value<Str>().empty() && !pt.empty())
return false;
// Check children
typename Ptree::const_iterator it = pt.begin();
for (; it != pt.end(); ++it)
if (!verify_json(it->second, depth + 1))
return false;
// Success
return true;
}
// Write ptree to json stream
template<class Ptree>
void write_json_internal(std::basic_ostream<typename Ptree::key_type::value_type> &stream,
const Ptree &pt,
const std::string &filename,
bool pretty)
{
if (!verify_json(pt, 0))
BOOST_PROPERTY_TREE_THROW(json_parser_error("ptree contains data that cannot be represented in JSON format", filename, 0));
write_json_helper(stream, pt, 0, pretty);
stream << std::endl;
if (!stream.good())
BOOST_PROPERTY_TREE_THROW(json_parser_error("write error", filename, 0));
}
} } }
#endif

View File

@@ -0,0 +1,905 @@
// ----------------------------------------------------------------------------
// Copyright (C) 2002-2006 Marcin Kalicinski
// Copyright (C) 2009 Sebastian Redl
//
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
//
// For more information, see www.boost.org
// ----------------------------------------------------------------------------
#ifndef BOOST_PROPERTY_TREE_DETAIL_PTREE_IMPLEMENTATION_HPP_INCLUDED
#define BOOST_PROPERTY_TREE_DETAIL_PTREE_IMPLEMENTATION_HPP_INCLUDED
#include <boost/iterator/iterator_adaptor.hpp>
#include <boost/iterator/reverse_iterator.hpp>
#include <boost/assert.hpp>
#include <memory>
#if defined(BOOST_MSVC) && \
(_MSC_FULL_VER >= 160000000 && _MSC_FULL_VER < 170000000)
#define BOOST_PROPERTY_TREE_PAIR_BUG
#endif
namespace boost { namespace property_tree
{
template <class K, class D, class C>
struct basic_ptree<K, D, C>::subs
{
struct by_name {};
// The actual child container.
#if defined(BOOST_PROPERTY_TREE_PAIR_BUG)
// MSVC 10 has moved std::pair's members to a base
// class. Unfortunately this does break the interface.
BOOST_STATIC_CONSTANT(unsigned,
first_offset = offsetof(value_type, first));
typedef multi_index_container<value_type,
multi_index::indexed_by<
multi_index::sequenced<>,
multi_index::ordered_non_unique<multi_index::tag<by_name>,
multi_index::member_offset<value_type, const key_type,
first_offset>,
key_compare
>
>
> base_container;
#else
typedef multi_index_container<value_type,
multi_index::indexed_by<
multi_index::sequenced<>,
multi_index::ordered_non_unique<multi_index::tag<by_name>,
multi_index::member<value_type, const key_type,
&value_type::first>,
key_compare
>
>
> base_container;
#endif
// The by-name lookup index.
typedef typename base_container::template index<by_name>::type
by_name_index;
// Access functions for getting to the children of a tree.
static base_container& ch(self_type *s) {
return *static_cast<base_container*>(s->m_children);
}
static const base_container& ch(const self_type *s) {
return *static_cast<const base_container*>(s->m_children);
}
static by_name_index& assoc(self_type *s) {
return ch(s).BOOST_NESTED_TEMPLATE get<by_name>();
}
static const by_name_index& assoc(const self_type *s) {
return ch(s).BOOST_NESTED_TEMPLATE get<by_name>();
}
};
template <class K, class D, class C>
class basic_ptree<K, D, C>::iterator : public boost::iterator_adaptor<
iterator, typename subs::base_container::iterator, value_type>
{
friend class boost::iterator_core_access;
typedef boost::iterator_adaptor<
iterator, typename subs::base_container::iterator, value_type>
baset;
public:
typedef typename baset::reference reference;
iterator() {}
explicit iterator(typename iterator::base_type b)
: iterator::iterator_adaptor_(b)
{}
reference dereference() const
{
// multi_index doesn't allow modification of its values, because
// indexes could sort by anything, and modification screws that up.
// However, we only sort by the key, and it's protected against
// modification in the value_type, so this const_cast is safe.
return const_cast<reference>(*this->base_reference());
}
};
template <class K, class D, class C>
class basic_ptree<K, D, C>::const_iterator : public boost::iterator_adaptor<
const_iterator, typename subs::base_container::const_iterator>
{
public:
const_iterator() {}
explicit const_iterator(typename const_iterator::base_type b)
: const_iterator::iterator_adaptor_(b)
{}
const_iterator(iterator b)
: const_iterator::iterator_adaptor_(b.base())
{}
};
template <class K, class D, class C>
class basic_ptree<K, D, C>::reverse_iterator
: public boost::reverse_iterator<iterator>
{
public:
reverse_iterator() {}
explicit reverse_iterator(iterator b)
: boost::reverse_iterator<iterator>(b)
{}
};
template <class K, class D, class C>
class basic_ptree<K, D, C>::const_reverse_iterator
: public boost::reverse_iterator<const_iterator>
{
public:
const_reverse_iterator() {}
explicit const_reverse_iterator(const_iterator b)
: boost::reverse_iterator<const_iterator>(b)
{}
const_reverse_iterator(
typename basic_ptree<K, D, C>::reverse_iterator b)
: boost::reverse_iterator<const_iterator>(b)
{}
};
template <class K, class D, class C>
class basic_ptree<K, D, C>::assoc_iterator
: public boost::iterator_adaptor<assoc_iterator,
typename subs::by_name_index::iterator,
value_type>
{
friend class boost::iterator_core_access;
typedef boost::iterator_adaptor<assoc_iterator,
typename subs::by_name_index::iterator,
value_type>
baset;
public:
typedef typename baset::reference reference;
assoc_iterator() {}
explicit assoc_iterator(typename assoc_iterator::base_type b)
: assoc_iterator::iterator_adaptor_(b)
{}
reference dereference() const
{
return const_cast<reference>(*this->base_reference());
}
};
template <class K, class D, class C>
class basic_ptree<K, D, C>::const_assoc_iterator
: public boost::iterator_adaptor<const_assoc_iterator,
typename subs::by_name_index::const_iterator>
{
public:
const_assoc_iterator() {}
explicit const_assoc_iterator(
typename const_assoc_iterator::base_type b)
: const_assoc_iterator::iterator_adaptor_(b)
{}
const_assoc_iterator(assoc_iterator b)
: const_assoc_iterator::iterator_adaptor_(b.base())
{}
};
// Big five
// Perhaps the children collection could be created on-demand only, to
// reduce heap traffic. But that's a lot more work to implement.
template<class K, class D, class C> inline
basic_ptree<K, D, C>::basic_ptree()
: m_children(new typename subs::base_container)
{
}
template<class K, class D, class C> inline
basic_ptree<K, D, C>::basic_ptree(const data_type &d)
: m_data(d), m_children(new typename subs::base_container)
{
}
template<class K, class D, class C> inline
basic_ptree<K, D, C>::basic_ptree(const basic_ptree<K, D, C> &rhs)
: m_data(rhs.m_data),
m_children(new typename subs::base_container(subs::ch(&rhs)))
{
}
template<class K, class D, class C>
basic_ptree<K, D, C> &
basic_ptree<K, D, C>::operator =(const basic_ptree<K, D, C> &rhs)
{
self_type(rhs).swap(*this);
return *this;
}
template<class K, class D, class C>
basic_ptree<K, D, C>::~basic_ptree()
{
delete &subs::ch(this);
}
template<class K, class D, class C> inline
void basic_ptree<K, D, C>::swap(basic_ptree<K, D, C> &rhs)
{
m_data.swap(rhs.m_data);
// Void pointers, no ADL necessary
std::swap(m_children, rhs.m_children);
}
// Container view
template<class K, class D, class C> inline
typename basic_ptree<K, D, C>::size_type
basic_ptree<K, D, C>::size() const
{
return subs::ch(this).size();
}
template<class K, class D, class C> inline
typename basic_ptree<K, D, C>::size_type
basic_ptree<K, D, C>::max_size() const
{
return subs::ch(this).max_size();
}
template<class K, class D, class C> inline
bool basic_ptree<K, D, C>::empty() const
{
return subs::ch(this).empty();
}
template<class K, class D, class C> inline
typename basic_ptree<K, D, C>::iterator
basic_ptree<K, D, C>::begin()
{
return iterator(subs::ch(this).begin());
}
template<class K, class D, class C> inline
typename basic_ptree<K, D, C>::const_iterator
basic_ptree<K, D, C>::begin() const
{
return const_iterator(subs::ch(this).begin());
}
template<class K, class D, class C> inline
typename basic_ptree<K, D, C>::iterator
basic_ptree<K, D, C>::end()
{
return iterator(subs::ch(this).end());
}
template<class K, class D, class C> inline
typename basic_ptree<K, D, C>::const_iterator
basic_ptree<K, D, C>::end() const
{
return const_iterator(subs::ch(this).end());
}
template<class K, class D, class C> inline
typename basic_ptree<K, D, C>::reverse_iterator
basic_ptree<K, D, C>::rbegin()
{
return reverse_iterator(this->end());
}
template<class K, class D, class C> inline
typename basic_ptree<K, D, C>::const_reverse_iterator
basic_ptree<K, D, C>::rbegin() const
{
return const_reverse_iterator(this->end());
}
template<class K, class D, class C> inline
typename basic_ptree<K, D, C>::reverse_iterator
basic_ptree<K, D, C>::rend()
{
return reverse_iterator(this->begin());
}
template<class K, class D, class C> inline
typename basic_ptree<K, D, C>::const_reverse_iterator
basic_ptree<K, D, C>::rend() const
{
return const_reverse_iterator(this->begin());
}
template<class K, class D, class C> inline
typename basic_ptree<K, D, C>::value_type &
basic_ptree<K, D, C>::front()
{
return const_cast<value_type&>(subs::ch(this).front());
}
template<class K, class D, class C> inline
const typename basic_ptree<K, D, C>::value_type &
basic_ptree<K, D, C>::front() const
{
return subs::ch(this).front();
}
template<class K, class D, class C> inline
typename basic_ptree<K, D, C>::value_type &
basic_ptree<K, D, C>::back()
{
return const_cast<value_type&>(subs::ch(this).back());
}
template<class K, class D, class C> inline
const typename basic_ptree<K, D, C>::value_type &
basic_ptree<K, D, C>::back() const
{
return subs::ch(this).back();
}
template<class K, class D, class C> inline
typename basic_ptree<K, D, C>::iterator
basic_ptree<K, D, C>::insert(iterator where, const value_type &value)
{
return iterator(subs::ch(this).insert(where.base(), value).first);
}
template<class K, class D, class C>
template<class It> inline
void basic_ptree<K, D, C>::insert(iterator where, It first, It last)
{
subs::ch(this).insert(where.base(), first, last);
}
template<class K, class D, class C> inline
typename basic_ptree<K, D, C>::iterator
basic_ptree<K, D, C>::erase(iterator where)
{
return iterator(subs::ch(this).erase(where.base()));
}
template<class K, class D, class C> inline
typename basic_ptree<K, D, C>::iterator
basic_ptree<K, D, C>::erase(iterator first, iterator last)
{
return iterator(subs::ch(this).erase(first.base(), last.base()));
}
template<class K, class D, class C> inline
typename basic_ptree<K, D, C>::iterator
basic_ptree<K, D, C>::push_front(const value_type &value)
{
return iterator(subs::ch(this).push_front(value).first);
}
template<class K, class D, class C> inline
typename basic_ptree<K, D, C>::iterator
basic_ptree<K, D, C>::push_back(const value_type &value)
{
return iterator(subs::ch(this).push_back(value).first);
}
template<class K, class D, class C> inline
void basic_ptree<K, D, C>::pop_front()
{
subs::ch(this).pop_front();
}
template<class K, class D, class C> inline
void basic_ptree<K, D, C>::pop_back()
{
subs::ch(this).pop_back();
}
template<class K, class D, class C> inline
void basic_ptree<K, D, C>::reverse()
{
subs::ch(this).reverse();
}
template<class K, class D, class C> inline
void basic_ptree<K, D, C>::sort()
{
subs::ch(this).sort();
}
template<class K, class D, class C>
template<class Compare> inline
void basic_ptree<K, D, C>::sort(Compare comp)
{
subs::ch(this).sort(comp);
}
// Equality
template<class K, class D, class C> inline
bool basic_ptree<K, D, C>::operator ==(
const basic_ptree<K, D, C> &rhs) const
{
// The size test is cheap, so add it as an optimization
return size() == rhs.size() && data() == rhs.data() &&
subs::ch(this) == subs::ch(&rhs);
}
template<class K, class D, class C> inline
bool basic_ptree<K, D, C>::operator !=(
const basic_ptree<K, D, C> &rhs) const
{
return !(*this == rhs);
}
// Associative view
template<class K, class D, class C> inline
typename basic_ptree<K, D, C>::assoc_iterator
basic_ptree<K, D, C>::ordered_begin()
{
return assoc_iterator(subs::assoc(this).begin());
}
template<class K, class D, class C> inline
typename basic_ptree<K, D, C>::const_assoc_iterator
basic_ptree<K, D, C>::ordered_begin() const
{
return const_assoc_iterator(subs::assoc(this).begin());
}
template<class K, class D, class C> inline
typename basic_ptree<K, D, C>::assoc_iterator
basic_ptree<K, D, C>::not_found()
{
return assoc_iterator(subs::assoc(this).end());
}
template<class K, class D, class C> inline
typename basic_ptree<K, D, C>::const_assoc_iterator
basic_ptree<K, D, C>::not_found() const
{
return const_assoc_iterator(subs::assoc(this).end());
}
template<class K, class D, class C> inline
typename basic_ptree<K, D, C>::assoc_iterator
basic_ptree<K, D, C>::find(const key_type &key)
{
return assoc_iterator(subs::assoc(this).find(key));
}
template<class K, class D, class C> inline
typename basic_ptree<K, D, C>::const_assoc_iterator
basic_ptree<K, D, C>::find(const key_type &key) const
{
return const_assoc_iterator(subs::assoc(this).find(key));
}
template<class K, class D, class C> inline
std::pair<
typename basic_ptree<K, D, C>::assoc_iterator,
typename basic_ptree<K, D, C>::assoc_iterator
> basic_ptree<K, D, C>::equal_range(const key_type &key)
{
std::pair<typename subs::by_name_index::iterator,
typename subs::by_name_index::iterator> r(
subs::assoc(this).equal_range(key));
return std::pair<assoc_iterator, assoc_iterator>(
assoc_iterator(r.first), assoc_iterator(r.second));
}
template<class K, class D, class C> inline
std::pair<
typename basic_ptree<K, D, C>::const_assoc_iterator,
typename basic_ptree<K, D, C>::const_assoc_iterator
> basic_ptree<K, D, C>::equal_range(const key_type &key) const
{
std::pair<typename subs::by_name_index::const_iterator,
typename subs::by_name_index::const_iterator> r(
subs::assoc(this).equal_range(key));
return std::pair<const_assoc_iterator, const_assoc_iterator>(
const_assoc_iterator(r.first), const_assoc_iterator(r.second));
}
template<class K, class D, class C> inline
typename basic_ptree<K, D, C>::size_type
basic_ptree<K, D, C>::count(const key_type &key) const
{
return subs::assoc(this).count(key);
}
template<class K, class D, class C> inline
typename basic_ptree<K, D, C>::size_type
basic_ptree<K, D, C>::erase(const key_type &key)
{
return subs::assoc(this).erase(key);
}
template<class K, class D, class C> inline
typename basic_ptree<K, D, C>::iterator
basic_ptree<K, D, C>::to_iterator(assoc_iterator ai)
{
return iterator(subs::ch(this).
BOOST_NESTED_TEMPLATE project<0>(ai.base()));
}
template<class K, class D, class C> inline
typename basic_ptree<K, D, C>::const_iterator
basic_ptree<K, D, C>::to_iterator(const_assoc_iterator ai) const
{
return const_iterator(subs::ch(this).
BOOST_NESTED_TEMPLATE project<0>(ai.base()));
}
// Property tree view
template<class K, class D, class C> inline
typename basic_ptree<K, D, C>::data_type &
basic_ptree<K, D, C>::data()
{
return m_data;
}
template<class K, class D, class C> inline
const typename basic_ptree<K, D, C>::data_type &
basic_ptree<K, D, C>::data() const
{
return m_data;
}
template<class K, class D, class C> inline
void basic_ptree<K, D, C>::clear()
{
m_data = data_type();
subs::ch(this).clear();
}
template<class K, class D, class C>
basic_ptree<K, D, C> &
basic_ptree<K, D, C>::get_child(const path_type &path)
{
path_type p(path);
self_type *n = walk_path(p);
if (!n) {
BOOST_PROPERTY_TREE_THROW(ptree_bad_path("No such node", path));
}
return *n;
}
template<class K, class D, class C> inline
const basic_ptree<K, D, C> &
basic_ptree<K, D, C>::get_child(const path_type &path) const
{
return const_cast<self_type*>(this)->get_child(path);
}
template<class K, class D, class C> inline
basic_ptree<K, D, C> &
basic_ptree<K, D, C>::get_child(const path_type &path,
self_type &default_value)
{
path_type p(path);
self_type *n = walk_path(p);
return n ? *n : default_value;
}
template<class K, class D, class C> inline
const basic_ptree<K, D, C> &
basic_ptree<K, D, C>::get_child(const path_type &path,
const self_type &default_value) const
{
return const_cast<self_type*>(this)->get_child(path,
const_cast<self_type&>(default_value));
}
template<class K, class D, class C>
optional<basic_ptree<K, D, C> &>
basic_ptree<K, D, C>::get_child_optional(const path_type &path)
{
path_type p(path);
self_type *n = walk_path(p);
if (!n) {
return optional<self_type&>();
}
return *n;
}
template<class K, class D, class C>
optional<const basic_ptree<K, D, C> &>
basic_ptree<K, D, C>::get_child_optional(const path_type &path) const
{
path_type p(path);
self_type *n = walk_path(p);
if (!n) {
return optional<const self_type&>();
}
return *n;
}
template<class K, class D, class C>
basic_ptree<K, D, C> &
basic_ptree<K, D, C>::put_child(const path_type &path,
const self_type &value)
{
path_type p(path);
self_type &parent = force_path(p);
// Got the parent. Now get the correct child.
key_type fragment = p.reduce();
assoc_iterator el = parent.find(fragment);
// If the new child exists, replace it.
if(el != parent.not_found()) {
return el->second = value;
} else {
return parent.push_back(value_type(fragment, value))->second;
}
}
template<class K, class D, class C>
basic_ptree<K, D, C> &
basic_ptree<K, D, C>::add_child(const path_type &path,
const self_type &value)
{
path_type p(path);
self_type &parent = force_path(p);
// Got the parent.
key_type fragment = p.reduce();
return parent.push_back(value_type(fragment, value))->second;
}
template<class K, class D, class C>
template<class Type, class Translator>
typename boost::enable_if<detail::is_translator<Translator>, Type>::type
basic_ptree<K, D, C>::get_value(Translator tr) const
{
if(boost::optional<Type> o = get_value_optional<Type>(tr)) {
return *o;
}
BOOST_PROPERTY_TREE_THROW(ptree_bad_data(
std::string("conversion of data to type \"") +
typeid(Type).name() + "\" failed", data()));
}
template<class K, class D, class C>
template<class Type> inline
Type basic_ptree<K, D, C>::get_value() const
{
return get_value<Type>(
typename translator_between<data_type, Type>::type());
}
template<class K, class D, class C>
template<class Type, class Translator> inline
Type basic_ptree<K, D, C>::get_value(const Type &default_value,
Translator tr) const
{
return get_value_optional<Type>(tr).get_value_or(default_value);
}
template<class K, class D, class C>
template <class Ch, class Translator>
typename boost::enable_if<
detail::is_character<Ch>,
std::basic_string<Ch>
>::type
basic_ptree<K, D, C>::get_value(const Ch *default_value, Translator tr)const
{
return get_value<std::basic_string<Ch>, Translator>(default_value, tr);
}
template<class K, class D, class C>
template<class Type> inline
typename boost::disable_if<detail::is_translator<Type>, Type>::type
basic_ptree<K, D, C>::get_value(const Type &default_value) const
{
return get_value(default_value,
typename translator_between<data_type, Type>::type());
}
template<class K, class D, class C>
template <class Ch>
typename boost::enable_if<
detail::is_character<Ch>,
std::basic_string<Ch>
>::type
basic_ptree<K, D, C>::get_value(const Ch *default_value) const
{
return get_value< std::basic_string<Ch> >(default_value);
}
template<class K, class D, class C>
template<class Type, class Translator> inline
optional<Type> basic_ptree<K, D, C>::get_value_optional(
Translator tr) const
{
return tr.get_value(data());
}
template<class K, class D, class C>
template<class Type> inline
optional<Type> basic_ptree<K, D, C>::get_value_optional() const
{
return get_value_optional<Type>(
typename translator_between<data_type, Type>::type());
}
template<class K, class D, class C>
template<class Type, class Translator> inline
typename boost::enable_if<detail::is_translator<Translator>, Type>::type
basic_ptree<K, D, C>::get(const path_type &path,
Translator tr) const
{
return get_child(path).BOOST_NESTED_TEMPLATE get_value<Type>(tr);
}
template<class K, class D, class C>
template<class Type> inline
Type basic_ptree<K, D, C>::get(const path_type &path) const
{
return get_child(path).BOOST_NESTED_TEMPLATE get_value<Type>();
}
template<class K, class D, class C>
template<class Type, class Translator> inline
Type basic_ptree<K, D, C>::get(const path_type &path,
const Type &default_value,
Translator tr) const
{
return get_optional<Type>(path, tr).get_value_or(default_value);
}
template<class K, class D, class C>
template <class Ch, class Translator>
typename boost::enable_if<
detail::is_character<Ch>,
std::basic_string<Ch>
>::type
basic_ptree<K, D, C>::get(
const path_type &path, const Ch *default_value, Translator tr) const
{
return get<std::basic_string<Ch>, Translator>(path, default_value, tr);
}
template<class K, class D, class C>
template<class Type> inline
typename boost::disable_if<detail::is_translator<Type>, Type>::type
basic_ptree<K, D, C>::get(const path_type &path,
const Type &default_value) const
{
return get_optional<Type>(path).get_value_or(default_value);
}
template<class K, class D, class C>
template <class Ch>
typename boost::enable_if<
detail::is_character<Ch>,
std::basic_string<Ch>
>::type
basic_ptree<K, D, C>::get(
const path_type &path, const Ch *default_value) const
{
return get< std::basic_string<Ch> >(path, default_value);
}
template<class K, class D, class C>
template<class Type, class Translator>
optional<Type> basic_ptree<K, D, C>::get_optional(const path_type &path,
Translator tr) const
{
if (optional<const self_type&> child = get_child_optional(path))
return child.get().
BOOST_NESTED_TEMPLATE get_value_optional<Type>(tr);
else
return optional<Type>();
}
template<class K, class D, class C>
template<class Type>
optional<Type> basic_ptree<K, D, C>::get_optional(
const path_type &path) const
{
if (optional<const self_type&> child = get_child_optional(path))
return child.get().BOOST_NESTED_TEMPLATE get_value_optional<Type>();
else
return optional<Type>();
}
template<class K, class D, class C>
template<class Type, class Translator>
void basic_ptree<K, D, C>::put_value(const Type &value, Translator tr)
{
if(optional<data_type> o = tr.put_value(value)) {
data() = *o;
} else {
BOOST_PROPERTY_TREE_THROW(ptree_bad_data(
std::string("conversion of type \"") + typeid(Type).name() +
"\" to data failed", boost::any()));
}
}
template<class K, class D, class C>
template<class Type> inline
void basic_ptree<K, D, C>::put_value(const Type &value)
{
put_value(value, typename translator_between<data_type, Type>::type());
}
template<class K, class D, class C>
template<class Type, typename Translator>
basic_ptree<K, D, C> & basic_ptree<K, D, C>::put(
const path_type &path, const Type &value, Translator tr)
{
if(optional<self_type &> child = get_child_optional(path)) {
child.get().put_value(value, tr);
return *child;
} else {
self_type &child2 = put_child(path, self_type());
child2.put_value(value, tr);
return child2;
}
}
template<class K, class D, class C>
template<class Type> inline
basic_ptree<K, D, C> & basic_ptree<K, D, C>::put(
const path_type &path, const Type &value)
{
return put(path, value,
typename translator_between<data_type, Type>::type());
}
template<class K, class D, class C>
template<class Type, typename Translator> inline
basic_ptree<K, D, C> & basic_ptree<K, D, C>::add(
const path_type &path, const Type &value, Translator tr)
{
self_type &child = add_child(path, self_type());
child.put_value(value, tr);
return child;
}
template<class K, class D, class C>
template<class Type> inline
basic_ptree<K, D, C> & basic_ptree<K, D, C>::add(
const path_type &path, const Type &value)
{
return add(path, value,
typename translator_between<data_type, Type>::type());
}
template<class K, class D, class C>
basic_ptree<K, D, C> *
basic_ptree<K, D, C>::walk_path(path_type &p) const
{
if(p.empty()) {
// I'm the child we're looking for.
return const_cast<basic_ptree*>(this);
}
// Recurse down the tree to find the path.
key_type fragment = p.reduce();
const_assoc_iterator el = find(fragment);
if(el == not_found()) {
// No such child.
return 0;
}
// Not done yet, recurse.
return el->second.walk_path(p);
}
template<class K, class D, class C>
basic_ptree<K, D, C> & basic_ptree<K, D, C>::force_path(path_type &p)
{
BOOST_ASSERT(!p.empty() && "Empty path not allowed for put_child.");
if(p.single()) {
// I'm the parent we're looking for.
return *this;
}
key_type fragment = p.reduce();
assoc_iterator el = find(fragment);
// If we've found an existing child, go down that path. Else
// create a new one.
self_type& child = el == not_found() ?
push_back(value_type(fragment, self_type()))->second : el->second;
return child.force_path(p);
}
// Free functions
template<class K, class D, class C>
inline void swap(basic_ptree<K, D, C> &pt1, basic_ptree<K, D, C> &pt2)
{
pt1.swap(pt2);
}
} }
#if defined(BOOST_PROPERTY_TREE_PAIR_BUG)
#undef BOOST_PROPERTY_TREE_PAIR_BUG
#endif
#endif

View File

@@ -0,0 +1,106 @@
// ----------------------------------------------------------------------------
// Copyright (C) 2002-2006 Marcin Kalicinski
//
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
//
// For more information, see www.boost.org
// ----------------------------------------------------------------------------
#ifndef BOOST_PROPERTY_TREE_DETAIL_PTREE_UTILS_HPP_INCLUDED
#define BOOST_PROPERTY_TREE_DETAIL_PTREE_UTILS_HPP_INCLUDED
#include <boost/limits.hpp>
#include <boost/type_traits/integral_constant.hpp>
#include <boost/mpl/has_xxx.hpp>
#include <boost/mpl/and.hpp>
#include <string>
#include <algorithm>
#include <locale>
namespace boost { namespace property_tree { namespace detail
{
template<class T>
struct less_nocase
{
typedef typename T::value_type Ch;
std::locale m_locale;
inline bool operator()(Ch c1, Ch c2) const
{
return std::toupper(c1, m_locale) < std::toupper(c2, m_locale);
}
inline bool operator()(const T &t1, const T &t2) const
{
return std::lexicographical_compare(t1.begin(), t1.end(),
t2.begin(), t2.end(), *this);
}
};
template <typename Ch>
struct is_character : public boost::false_type {};
template <>
struct is_character<char> : public boost::true_type {};
template <>
struct is_character<wchar_t> : public boost::true_type {};
BOOST_MPL_HAS_XXX_TRAIT_DEF(internal_type)
BOOST_MPL_HAS_XXX_TRAIT_DEF(external_type)
template <typename T>
struct is_translator : public boost::mpl::and_<
has_internal_type<T>, has_external_type<T> > {};
// Naively convert narrow string to another character type
template<class Ch>
std::basic_string<Ch> widen(const char *text)
{
std::basic_string<Ch> result;
while (*text)
{
result += Ch(*text);
++text;
}
return result;
}
// Naively convert string to narrow character type
template<class Ch>
std::string narrow(const Ch *text)
{
std::string result;
while (*text)
{
if (*text < 0 || *text > (std::numeric_limits<char>::max)())
result += '*';
else
result += char(*text);
++text;
}
return result;
}
// Remove trailing and leading spaces
template<class Ch>
std::basic_string<Ch> trim(const std::basic_string<Ch> &s,
const std::locale &loc = std::locale())
{
typename std::basic_string<Ch>::const_iterator first = s.begin();
typename std::basic_string<Ch>::const_iterator end = s.end();
while (first != end && std::isspace(*first, loc))
++first;
if (first == end)
return std::basic_string<Ch>();
typename std::basic_string<Ch>::const_iterator last = end;
do --last; while (std::isspace(*last, loc));
if (first != s.begin() || last + 1 != end)
return std::basic_string<Ch>(first, last + 1);
else
return s;
}
} } }
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,33 @@
// ----------------------------------------------------------------------------
// Copyright (C) 2002-2006 Marcin Kalicinski
//
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
//
// For more information, see www.boost.org
// ----------------------------------------------------------------------------
#ifndef BOOST_PROPERTY_TREE_DETAIL_XML_PARSER_ERROR_HPP_INCLUDED
#define BOOST_PROPERTY_TREE_DETAIL_XML_PARSER_ERROR_HPP_INCLUDED
#include <boost/property_tree/detail/file_parser_error.hpp>
#include <string>
namespace boost { namespace property_tree { namespace xml_parser
{
//! Xml parser error
class xml_parser_error: public file_parser_error
{
public:
xml_parser_error(const std::string &msg,
const std::string &file,
unsigned long l):
file_parser_error(msg, file, l)
{
}
};
} } }
#endif

View File

@@ -0,0 +1,31 @@
// ----------------------------------------------------------------------------
// Copyright (C) 2002-2006 Marcin Kalicinski
//
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
//
// For more information, see www.boost.org
// ----------------------------------------------------------------------------
#ifndef BOOST_PROPERTY_TREE_DETAIL_XML_PARSER_FLAGS_HPP_INCLUDED
#define BOOST_PROPERTY_TREE_DETAIL_XML_PARSER_FLAGS_HPP_INCLUDED
namespace boost { namespace property_tree { namespace xml_parser
{
/// Text elements should be put in separate keys,
/// not concatenated in parent data.
static const int no_concat_text = 0x1;
/// Comments should be omitted.
static const int no_comments = 0x2;
/// Whitespace should be collapsed and trimmed.
static const int trim_whitespace = 0x4;
inline bool validate_flags(int flags)
{
return (flags & ~(no_concat_text | no_comments | trim_whitespace)) == 0;
}
} } }
#endif

View File

@@ -0,0 +1,144 @@
// ----------------------------------------------------------------------------
// Copyright (C) 2007 Marcin Kalicinski
//
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
//
// For more information, see www.boost.org
// ----------------------------------------------------------------------------
#ifndef BOOST_PROPERTY_TREE_DETAIL_XML_PARSER_READ_RAPIDXML_HPP_INCLUDED
#define BOOST_PROPERTY_TREE_DETAIL_XML_PARSER_READ_RAPIDXML_HPP_INCLUDED
#include <boost/property_tree/ptree.hpp>
#include <boost/property_tree/detail/xml_parser_error.hpp>
#include <boost/property_tree/detail/xml_parser_flags.hpp>
#include <boost/property_tree/detail/xml_parser_utils.hpp>
#include <boost/property_tree/detail/rapidxml.hpp>
#include <vector>
namespace boost { namespace property_tree { namespace xml_parser
{
template<class Ptree, class Ch>
void read_xml_node(detail::rapidxml::xml_node<Ch> *node,
Ptree &pt, int flags)
{
using namespace detail::rapidxml;
switch (node->type())
{
// Element nodes
case node_element:
{
// Create node
Ptree &pt_node = pt.push_back(std::make_pair(node->name(),
Ptree()))->second;
// Copy attributes
if (node->first_attribute())
{
Ptree &pt_attr_root = pt_node.push_back(
std::make_pair(xmlattr<Ch>(), Ptree()))->second;
for (xml_attribute<Ch> *attr = node->first_attribute();
attr; attr = attr->next_attribute())
{
Ptree &pt_attr = pt_attr_root.push_back(
std::make_pair(attr->name(), Ptree()))->second;
pt_attr.data() = attr->value();
}
}
// Copy children
for (xml_node<Ch> *child = node->first_node();
child; child = child->next_sibling())
read_xml_node(child, pt_node, flags);
}
break;
// Data nodes
case node_data:
case node_cdata:
{
if (flags & no_concat_text)
pt.push_back(std::make_pair(xmltext<Ch>(),
Ptree(node->value())));
else
pt.data() += node->value();
}
break;
// Comment nodes
case node_comment:
{
if (!(flags & no_comments))
pt.push_back(std::make_pair(xmlcomment<Ch>(),
Ptree(node->value())));
}
break;
default:
// Skip other node types
break;
}
}
template<class Ptree>
void read_xml_internal(std::basic_istream<
typename Ptree::key_type::value_type> &stream,
Ptree &pt,
int flags,
const std::string &filename)
{
typedef typename Ptree::key_type::value_type Ch;
using namespace detail::rapidxml;
// Load data into vector
stream.unsetf(std::ios::skipws);
std::vector<Ch> v(std::istreambuf_iterator<Ch>(stream.rdbuf()),
std::istreambuf_iterator<Ch>());
if (!stream.good())
BOOST_PROPERTY_TREE_THROW(
xml_parser_error("read error", filename, 0));
v.push_back(0); // zero-terminate
try {
// Parse using appropriate flags
const int f_tws = parse_normalize_whitespace
| parse_trim_whitespace;
const int f_c = parse_comment_nodes;
// Some compilers don't like the bitwise or in the template arg.
const int f_tws_c = parse_normalize_whitespace
| parse_trim_whitespace
| parse_comment_nodes;
xml_document<Ch> doc;
if (flags & no_comments) {
if (flags & trim_whitespace)
doc.BOOST_NESTED_TEMPLATE parse<f_tws>(&v.front());
else
doc.BOOST_NESTED_TEMPLATE parse<0>(&v.front());
} else {
if (flags & trim_whitespace)
doc.BOOST_NESTED_TEMPLATE parse<f_tws_c>(&v.front());
else
doc.BOOST_NESTED_TEMPLATE parse<f_c>(&v.front());
}
// Create ptree from nodes
Ptree local;
for (xml_node<Ch> *child = doc.first_node();
child; child = child->next_sibling())
read_xml_node(child, local, flags);
// Swap local and result ptrees
pt.swap(local);
} catch (parse_error &e) {
long line = static_cast<long>(
std::count(&v.front(), e.where<Ch>(), Ch('\n')) + 1);
BOOST_PROPERTY_TREE_THROW(
xml_parser_error(e.what(), filename, line));
}
}
} } }
#endif

View File

@@ -0,0 +1,136 @@
// ----------------------------------------------------------------------------
// Copyright (C) 2002-2006 Marcin Kalicinski
//
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
//
// For more information, see www.boost.org
// ----------------------------------------------------------------------------
#ifndef BOOST_PROPERTY_TREE_DETAIL_XML_PARSER_UTILS_HPP_INCLUDED
#define BOOST_PROPERTY_TREE_DETAIL_XML_PARSER_UTILS_HPP_INCLUDED
#include <boost/property_tree/detail/ptree_utils.hpp>
#include <boost/property_tree/detail/xml_parser_error.hpp>
#include <boost/property_tree/detail/xml_parser_writer_settings.hpp>
#include <string>
#include <algorithm>
#include <locale>
namespace boost { namespace property_tree { namespace xml_parser
{
template<class Ch>
std::basic_string<Ch> condense(const std::basic_string<Ch> &s)
{
std::basic_string<Ch> r;
std::locale loc;
bool space = false;
typename std::basic_string<Ch>::const_iterator end = s.end();
for (typename std::basic_string<Ch>::const_iterator it = s.begin();
it != end; ++it)
{
if (isspace(*it, loc) || *it == Ch('\n'))
{
if (!space)
r += Ch(' '), space = true;
}
else
r += *it, space = false;
}
return r;
}
template<class Ch>
std::basic_string<Ch> encode_char_entities(const std::basic_string<Ch> &s)
{
// Don't do anything for empty strings.
if(s.empty()) return s;
typedef typename std::basic_string<Ch> Str;
Str r;
// To properly round-trip spaces and not uglify the XML beyond
// recognition, we have to encode them IF the text contains only spaces.
Str sp(1, Ch(' '));
if(s.find_first_not_of(sp) == Str::npos) {
// The first will suffice.
r = detail::widen<Ch>("&#32;");
r += Str(s.size() - 1, Ch(' '));
} else {
typename Str::const_iterator end = s.end();
for (typename Str::const_iterator it = s.begin(); it != end; ++it)
{
switch (*it)
{
case Ch('<'): r += detail::widen<Ch>("&lt;"); break;
case Ch('>'): r += detail::widen<Ch>("&gt;"); break;
case Ch('&'): r += detail::widen<Ch>("&amp;"); break;
case Ch('"'): r += detail::widen<Ch>("&quot;"); break;
case Ch('\''): r += detail::widen<Ch>("&apos;"); break;
default: r += *it; break;
}
}
}
return r;
}
template<class Ch>
std::basic_string<Ch> decode_char_entities(const std::basic_string<Ch> &s)
{
typedef typename std::basic_string<Ch> Str;
Str r;
typename Str::const_iterator end = s.end();
for (typename Str::const_iterator it = s.begin(); it != end; ++it)
{
if (*it == Ch('&'))
{
typename Str::const_iterator semicolon = std::find(it + 1, end, Ch(';'));
if (semicolon == end)
BOOST_PROPERTY_TREE_THROW(xml_parser_error("invalid character entity", "", 0));
Str ent(it + 1, semicolon);
if (ent == detail::widen<Ch>("lt")) r += Ch('<');
else if (ent == detail::widen<Ch>("gt")) r += Ch('>');
else if (ent == detail::widen<Ch>("amp")) r += Ch('&');
else if (ent == detail::widen<Ch>("quot")) r += Ch('"');
else if (ent == detail::widen<Ch>("apos")) r += Ch('\'');
else
BOOST_PROPERTY_TREE_THROW(xml_parser_error("invalid character entity", "", 0));
it = semicolon;
}
else
r += *it;
}
return r;
}
template<class Ch>
const std::basic_string<Ch> &xmldecl()
{
static std::basic_string<Ch> s = detail::widen<Ch>("<?xml>");
return s;
}
template<class Ch>
const std::basic_string<Ch> &xmlattr()
{
static std::basic_string<Ch> s = detail::widen<Ch>("<xmlattr>");
return s;
}
template<class Ch>
const std::basic_string<Ch> &xmlcomment()
{
static std::basic_string<Ch> s = detail::widen<Ch>("<xmlcomment>");
return s;
}
template<class Ch>
const std::basic_string<Ch> &xmltext()
{
static std::basic_string<Ch> s = detail::widen<Ch>("<xmltext>");
return s;
}
} } }
#endif

View File

@@ -0,0 +1,194 @@
// ----------------------------------------------------------------------------
// Copyright (C) 2002-2006 Marcin Kalicinski
//
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
//
// For more information, see www.boost.org
// ----------------------------------------------------------------------------
#ifndef BOOST_PROPERTY_TREE_DETAIL_XML_PARSER_WRITE_HPP_INCLUDED
#define BOOST_PROPERTY_TREE_DETAIL_XML_PARSER_WRITE_HPP_INCLUDED
#include <boost/property_tree/ptree.hpp>
#include <boost/property_tree/detail/xml_parser_utils.hpp>
#include <string>
#include <ostream>
#include <iomanip>
namespace boost { namespace property_tree { namespace xml_parser
{
template<class Ch>
void write_xml_indent(std::basic_ostream<Ch> &stream,
int indent,
const xml_writer_settings<Ch> & settings
)
{
stream << std::basic_string<Ch>(indent * settings.indent_count, settings.indent_char);
}
template<class Ch>
void write_xml_comment(std::basic_ostream<Ch> &stream,
const std::basic_string<Ch> &s,
int indent,
bool separate_line,
const xml_writer_settings<Ch> & settings
)
{
typedef typename std::basic_string<Ch> Str;
if (separate_line)
write_xml_indent(stream,indent,settings);
stream << Ch('<') << Ch('!') << Ch('-') << Ch('-');
stream << s;
stream << Ch('-') << Ch('-') << Ch('>');
if (separate_line)
stream << Ch('\n');
}
template<class Ch>
void write_xml_text(std::basic_ostream<Ch> &stream,
const std::basic_string<Ch> &s,
int indent,
bool separate_line,
const xml_writer_settings<Ch> & settings
)
{
if (separate_line)
write_xml_indent(stream,indent,settings);
stream << encode_char_entities(s);
if (separate_line)
stream << Ch('\n');
}
template<class Ptree>
void write_xml_element(std::basic_ostream<typename Ptree::key_type::value_type> &stream,
const std::basic_string<typename Ptree::key_type::value_type> &key,
const Ptree &pt,
int indent,
const xml_writer_settings<typename Ptree::key_type::value_type> & settings)
{
typedef typename Ptree::key_type::value_type Ch;
typedef typename std::basic_string<Ch> Str;
typedef typename Ptree::const_iterator It;
bool want_pretty = settings.indent_count > 0;
// Find if elements present
bool has_elements = false;
bool has_attrs_only = pt.data().empty();
for (It it = pt.begin(), end = pt.end(); it != end; ++it)
{
if (it->first != xmlattr<Ch>() )
{
has_attrs_only = false;
if (it->first != xmltext<Ch>())
{
has_elements = true;
break;
}
}
}
// Write element
if (pt.data().empty() && pt.empty()) // Empty key
{
if (indent >= 0)
{
write_xml_indent(stream,indent,settings);
stream << Ch('<') << key <<
Ch('/') << Ch('>');
if (want_pretty)
stream << Ch('\n');
}
}
else // Nonempty key
{
// Write opening tag, attributes and data
if (indent >= 0)
{
// Write opening brace and key
write_xml_indent(stream,indent,settings);
stream << Ch('<') << key;
// Write attributes
if (optional<const Ptree &> attribs = pt.get_child_optional(xmlattr<Ch>()))
for (It it = attribs.get().begin(); it != attribs.get().end(); ++it)
stream << Ch(' ') << it->first << Ch('=') <<
Ch('"') << it->second.template get_value<std::basic_string<Ch> >() << Ch('"');
if ( has_attrs_only )
{
// Write closing brace
stream << Ch('/') << Ch('>');
if (want_pretty)
stream << Ch('\n');
}
else
{
// Write closing brace
stream << Ch('>');
// Break line if needed and if we want pretty-printing
if (has_elements && want_pretty)
stream << Ch('\n');
}
}
// Write data text, if present
if (!pt.data().empty())
write_xml_text(stream,
pt.template get_value<std::basic_string<Ch> >(),
indent + 1, has_elements && want_pretty, settings);
// Write elements, comments and texts
for (It it = pt.begin(); it != pt.end(); ++it)
{
if (it->first == xmlattr<Ch>())
continue;
else if (it->first == xmlcomment<Ch>())
write_xml_comment(stream,
it->second.template get_value<std::basic_string<Ch> >(),
indent + 1, want_pretty, settings);
else if (it->first == xmltext<Ch>())
write_xml_text(stream,
it->second.template get_value<std::basic_string<Ch> >(),
indent + 1, has_elements && want_pretty, settings);
else
write_xml_element(stream, it->first, it->second,
indent + 1, settings);
}
// Write closing tag
if (indent >= 0 && !has_attrs_only)
{
if (has_elements)
write_xml_indent(stream,indent,settings);
stream << Ch('<') << Ch('/') << key << Ch('>');
if (want_pretty)
stream << Ch('\n');
}
}
}
template<class Ptree>
void write_xml_internal(std::basic_ostream<typename Ptree::key_type::value_type> &stream,
const Ptree &pt,
const std::string &filename,
const xml_writer_settings<typename Ptree::key_type::value_type> & settings)
{
typedef typename Ptree::key_type::value_type Ch;
typedef typename std::basic_string<Ch> Str;
stream << detail::widen<Ch>("<?xml version=\"1.0\" encoding=\"")
<< settings.encoding
<< detail::widen<Ch>("\"?>\n");
write_xml_element(stream, Str(), pt, -1, settings);
if (!stream)
BOOST_PROPERTY_TREE_THROW(xml_parser_error("write error", filename, 0));
}
} } }
#endif

View File

@@ -0,0 +1,62 @@
// ----------------------------------------------------------------------------
// Copyright (C) 2002-2007 Marcin Kalicinski
// Copyright (C) 2007 Alexey Baskakov
//
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
//
// For more information, see www.boost.org
// ----------------------------------------------------------------------------
#ifndef BOOST_PROPERTY_TREE_DETAIL_XML_PARSER_WRITER_SETTINGS_HPP_INCLUDED
#define BOOST_PROPERTY_TREE_DETAIL_XML_PARSER_WRITER_SETTINGS_HPP_INCLUDED
#include <string>
#include <boost/property_tree/detail/ptree_utils.hpp>
namespace boost { namespace property_tree { namespace xml_parser
{
// Naively convert narrow string to another character type
template<class Ch>
std::basic_string<Ch> widen(const char *text)
{
std::basic_string<Ch> result;
while (*text)
{
result += Ch(*text);
++text;
}
return result;
}
//! Xml writer settings. The default settings lead to no pretty printing.
template<class Ch>
class xml_writer_settings
{
public:
xml_writer_settings(Ch inchar = Ch(' '),
typename std::basic_string<Ch>::size_type incount = 0,
const std::basic_string<Ch> &enc = widen<Ch>("utf-8"))
: indent_char(inchar)
, indent_count(incount)
, encoding(enc)
{
}
Ch indent_char;
typename std::basic_string<Ch>::size_type indent_count;
std::basic_string<Ch> encoding;
};
template <class Ch>
xml_writer_settings<Ch> xml_writer_make_settings(Ch indent_char = Ch(' '),
typename std::basic_string<Ch>::size_type indent_count = 0,
const std::basic_string<Ch> &encoding = widen<Ch>("utf-8"))
{
return xml_writer_settings<Ch>(indent_char, indent_count, encoding);
}
} } }
#endif