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

View File

@@ -0,0 +1,84 @@
// ----------------------------------------------------------------------------
// 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_EXCEPTIONS_HPP_INCLUDED
#define BOOST_PROPERTY_TREE_EXCEPTIONS_HPP_INCLUDED
#include <boost/property_tree/ptree_fwd.hpp>
#include <boost/any.hpp>
#include <string>
#include <stdexcept>
namespace boost { namespace property_tree
{
/// 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();
};
/// 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;
};
/// 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);
~ptree_bad_path() throw();
/// Retrieve the invalid path.
template<class T> T path();
private:
boost::any m_path;
};
}}
#include <boost/property_tree/detail/exception_implementation.hpp>
#endif

View File

@@ -0,0 +1,51 @@
// ----------------------------------------------------------------------------
// 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_ID_TRANSLATOR_HPP_INCLUDED
#define BOOST_PROPERTY_TREE_ID_TRANSLATOR_HPP_INCLUDED
#include <boost/property_tree/ptree_fwd.hpp>
#include <boost/optional.hpp>
#include <string>
namespace boost { namespace property_tree
{
/// Simple implementation of the Translator concept. It does no translation.
template <typename T>
struct id_translator
{
typedef T internal_type;
typedef T external_type;
boost::optional<T> get_value(const T &v) { return v; }
boost::optional<T> put_value(const T &v) { return v; }
};
// This is the default translator whenever you get two equal types.
template <typename T>
struct translator_between<T, T>
{
typedef id_translator<T> type;
};
// A more specific specialization for std::basic_string. Otherwise,
// stream_translator's specialization wins.
template <typename Ch, typename Traits, typename Alloc>
struct translator_between< std::basic_string<Ch, Traits, Alloc>,
std::basic_string<Ch, Traits, Alloc> >
{
typedef id_translator< std::basic_string<Ch, Traits, Alloc> > type;
};
}}
#endif

View File

@@ -0,0 +1,151 @@
// ----------------------------------------------------------------------------
// 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_INFO_PARSER_HPP_INCLUDED
#define BOOST_PROPERTY_TREE_INFO_PARSER_HPP_INCLUDED
#include <boost/property_tree/ptree.hpp>
#include <boost/property_tree/detail/info_parser_error.hpp>
#include <boost/property_tree/detail/info_parser_writer_settings.hpp>
#include <boost/property_tree/detail/info_parser_read.hpp>
#include <boost/property_tree/detail/info_parser_write.hpp>
#include <istream>
namespace boost { namespace property_tree { namespace info_parser
{
/**
* Read INFO from a the given stream and translate it to a property tree.
* @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)
{
Ptree local;
read_info_internal(stream, local, std::string(), 0);
pt.swap(local);
}
/**
* Read INFO from a the given stream and translate it to a property tree.
* @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,
const Ptree &default_ptree)
{
try {
read_info(stream, pt);
} catch(file_parser_error &) {
pt = default_ptree;
}
}
/**
* 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,
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));
}
stream.imbue(loc);
Ptree local;
read_info_internal(stream, local, filename, 0);
pt.swap(local);
}
/**
* 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,
Ptree &pt,
const Ptree &default_ptree,
const std::locale &loc = std::locale())
{
try {
read_info(filename, pt, loc);
} catch(file_parser_error &) {
pt = default_ptree;
}
}
/**
* 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,
const Ptree &pt,
const info_writer_settings<Ch> &settings =
info_writer_settings<Ch>())
{
write_info_internal(stream, pt, std::string(), settings);
}
/**
* 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.
*/
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));
}
stream.imbue(loc);
write_info_internal(stream, pt, filename, settings);
}
} } }
namespace boost { namespace property_tree
{
using info_parser::info_parser_error;
using info_parser::read_info;
using info_parser::write_info;
using info_parser::info_writer_settings;
using info_parser::info_writer_make_settings;
} }
#endif

View File

@@ -0,0 +1,310 @@
// ----------------------------------------------------------------------------
// 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_INI_PARSER_HPP_INCLUDED
#define BOOST_PROPERTY_TREE_INI_PARSER_HPP_INCLUDED
#include <boost/property_tree/ptree.hpp>
#include <boost/property_tree/detail/ptree_utils.hpp>
#include <boost/property_tree/detail/file_parser_error.hpp>
#include <fstream>
#include <string>
#include <sstream>
#include <stdexcept>
#include <locale>
namespace boost { namespace property_tree { namespace ini_parser
{
/**
* 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.
* @return true if the flags are valid, false otherwise.
*/
inline bool validate_flags(int flags)
{
return flags == 0;
}
/** Indicates an error parsing INI formatted data. */
class ini_parser_error: public file_parser_error
{
public:
/**
* 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.
*/
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 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,
Ptree &pt)
{
typedef typename Ptree::key_type::value_type Ch;
typedef std::basic_string<Ch> Str;
const Ch semicolon = stream.widen(';');
const Ch hash = stream.widen('#');
const Ch lbracket = stream.widen('[');
const Ch rbracket = stream.widen(']');
Ptree local;
unsigned long line_no = 0;
Ptree *section = 0;
Str line;
// For all lines
while (stream.good())
{
// Get line from stream
++line_no;
std::getline(stream, line);
if (!stream.good() && !stream.eof())
BOOST_PROPERTY_TREE_THROW(ini_parser_error(
"read error", "", line_no));
// If line is non-empty
line = property_tree::detail::trim(line, stream.getloc());
if (!line.empty())
{
// Comment, section or key?
if (line[0] == semicolon || line[0] == hash)
{
// Ignore comments
}
else if (line[0] == lbracket)
{
// 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 = property_tree::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
{
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));
if (eqpos == 0)
BOOST_PROPERTY_TREE_THROW(ini_parser_error(
"key expected", "", line_no));
Str key = property_tree::detail::trim(
line.substr(0, eqpos), stream.getloc());
Str data = property_tree::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);
}
/**
* 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.
* @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.
* @param loc The locale to use when reading in the file contents.
*/
template<class Ptree>
void read_ini(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(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()));
}
}
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 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.
* @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.
* No flags are currently supported.
*/
template<class Ptree>
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));
(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(
"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));
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 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.
* @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.
* @param loc The locale to use when writing the file.
*/
template<class Ptree>
void write_ini(const std::string &filename,
const Ptree &pt,
int flags = 0,
const std::locale &loc = std::locale())
{
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));
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()));
}
}
} } }
namespace boost { namespace property_tree
{
using ini_parser::ini_parser_error;
using ini_parser::read_ini;
using ini_parser::write_ini;
} }
#endif

View File

@@ -0,0 +1,139 @@
// ----------------------------------------------------------------------------
// 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_JSON_PARSER_HPP_INCLUDED
#define BOOST_PROPERTY_TREE_JSON_PARSER_HPP_INCLUDED
#include <boost/property_tree/ptree.hpp>
#include <boost/property_tree/detail/json_parser_read.hpp>
#include <boost/property_tree/detail/json_parser_write.hpp>
#include <boost/property_tree/detail/json_parser_error.hpp>
#include <fstream>
#include <string>
#include <locale>
namespace boost { namespace property_tree { namespace json_parser
{
/**
* Read JSON 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.
* @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.
* @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,
Ptree &pt)
{
read_json_internal(stream, pt, std::string());
}
/**
* Read JSON 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 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.
* @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.
*/
template<class Ptree>
void read_json(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(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.
* @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
* property tree.
* @param pt The property tree to tranlsate to JSON and output.
* @param pretty Whether to pretty-print. Defaults to true for backward
* compatibility.
*/
template<class Ptree>
void write_json(std::basic_ostream<
typename Ptree::key_type::value_type
> &stream,
const Ptree &pt,
bool pretty = true)
{
write_json_internal(stream, pt, std::string(), pretty);
}
/**
* 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.
* @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 translate to JSON and output.
* @param loc The locale to use when writing out to the output file.
* @param pretty Whether to pretty-print. Defaults to true and last place
* for backward compatibility.
*/
template<class Ptree>
void write_json(const std::string &filename,
const Ptree &pt,
const std::locale &loc = std::locale(),
bool pretty = true)
{
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));
stream.imbue(loc);
write_json_internal(stream, pt, filename, pretty);
}
} } }
namespace boost { namespace property_tree
{
using json_parser::read_json;
using json_parser::write_json;
using json_parser::json_parser_error;
} }
#endif

View File

@@ -0,0 +1,518 @@
// ----------------------------------------------------------------------------
// 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_PTREE_HPP_INCLUDED
#define BOOST_PROPERTY_TREE_PTREE_HPP_INCLUDED
#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>
#include <boost/optional.hpp>
#include <utility> // for std::pair
namespace boost { namespace 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.
*
* Key equivalency is defined by @p KeyCompare, a predicate defining a
* strict weak ordering.
*
* 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 Key, class Data, class KeyCompare>
class basic_ptree
{
#if defined(BOOST_PROPERTY_TREE_DOXYGEN_INVOKED)
public:
#endif
// Internal types
/**
* 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<Key, Data, KeyCompare> self_type;
public:
// Basic types
typedef Key key_type;
typedef Data data_type;
typedef KeyCompare key_compare;
// Container view types
typedef std::pair<const Key, self_type> value_type;
typedef std::size_t size_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;
// Associative view types
class assoc_iterator;
class const_assoc_iterator;
// Property tree view types
typedef typename path_of<Key>::type path_type;
// 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);
/** Swap with other tree. Only constant-time and nothrow if the
* data type's swap is.
*/
void swap(self_type &rhs);
// Container view functions
/** 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;
iterator begin();
const_iterator begin() const;
iterator end();
const_iterator end() const;
reverse_iterator rbegin();
const_reverse_iterator rbegin() const;
reverse_iterator rend();
const_reverse_iterator rend() const;
value_type &front();
const value_type &front() const;
value_type &back();
const value_type &back() const;
/** 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);
/** Range insert. Equivalent to:
* @code
* for(; first != last; ++first) insert(where, *first);
* @endcode
*/
template<class It> void insert(iterator where, It first, It last);
/** 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);
/** Range erase. Equivalent to:
* @code
* while(first != last;) first = erase(first);
* @endcode
*/
iterator erase(iterator first, iterator last);
/** Equivalent to insert(begin(), value). */
iterator push_front(const value_type &value);
/** Equivalent to insert(end(), value). */
iterator push_back(const value_type &value);
/** Equivalent to erase(begin()). */
void pop_front();
/** Equivalent to erase(boost::prior(end())). */
void pop_back();
/** Reverses the order of direct children in the property tree. */
void reverse();
/** Sorts the direct children of this node according to the predicate.
* The predicate is passed the whole pair of key and child.
*/
template<class Compare> void sort(Compare comp);
/** Sorts the direct children of this node according to key order. */
void sort();
// Equality
/** 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.
*/
bool operator ==(const self_type &rhs) const;
bool operator !=(const self_type &rhs) const;
// Associative view
/** Returns an iterator to the first child, in key order. */
assoc_iterator ordered_begin();
/** Returns an iterator to the first child, in key order. */
const_assoc_iterator ordered_begin() const;
/** Returns the not-found iterator. Equivalent to end() in a real
* associative container.
*/
assoc_iterator not_found();
/** Returns the not-found iterator. Equivalent to end() in a real
* associative container.
*/
const_assoc_iterator not_found() const;
/** 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.
*/
assoc_iterator find(const key_type &key);
/** 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.
*/
const_assoc_iterator find(const key_type &key) const;
/** Find the range of children that have the given key. */
std::pair<assoc_iterator, assoc_iterator>
equal_range(const key_type &key);
/** 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;
/** Count the number of direct children with the given key. */
size_type count(const key_type &key) const;
/** Erase all direct children with the given key and return the count.
*/
size_type erase(const key_type &key);
/** 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.
*/
iterator to_iterator(assoc_iterator it);
/** 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.
*/
const_iterator to_iterator(const_assoc_iterator it) const;
// Property tree view
/** Reference to the actual data in this node. */
data_type &data();
/** Reference to the actual data in this node. */
const data_type &data() const;
/** Clear this tree completely, of both data and children. */
void clear();
/** 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.
*/
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;
/** 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;
/** Get the child at the given path, or return boost::null. */
optional<self_type &> get_child_optional(const path_type &path);
/** 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
* That is, return the value if it exists and can be converted, or nil.
*/
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);
private:
// 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 <boost/property_tree/detail/ptree_implementation.hpp>
#endif

View File

@@ -0,0 +1,143 @@
// ----------------------------------------------------------------------------
// 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_PTREE_FWD_HPP_INCLUDED
#define BOOST_PROPERTY_TREE_PTREE_FWD_HPP_INCLUDED
#include <boost/config.hpp>
#include <boost/optional/optional_fwd.hpp>
#include <boost/throw_exception.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 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 string_path<std::string, id_translator<std::string> > path;
/**
* A property tree with std::string for key and data, and default
* comparison.
*/
typedef basic_ptree<std::string, std::string> ptree;
/**
* A property tree with std::string for key and data, and case-insensitive
* comparison.
*/
typedef basic_ptree<std::string, std::string,
detail::less_nocase<std::string> >
iptree;
#ifndef BOOST_NO_STD_WSTRING
/** Implements a path using a std::wstring as the key. */
typedef string_path<std::wstring, id_translator<std::wstring> > wpath;
/**
* 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::wstring, std::wstring> wptree;
/**
* 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<std::wstring, std::wstring,
detail::less_nocase<std::wstring> >
wiptree;
#endif
// Free functions
/**
* Swap two property tree instances.
*/
template<class K, class D, class C>
void swap(basic_ptree<K, D, C> &pt1,
basic_ptree<K, D, C> &pt2);
} }
#if !defined(BOOST_PROPERTY_TREE_DOXYGEN_INVOKED)
// Throwing macro to avoid no return warnings portably
# define BOOST_PROPERTY_TREE_THROW(e) BOOST_THROW_EXCEPTION(e)
#endif
#endif

View File

@@ -0,0 +1,102 @@
// ----------------------------------------------------------------------------
// 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_PTREE_SERIALIZATION_HPP_INCLUDED
#define BOOST_PROPERTY_TREE_PTREE_SERIALIZATION_HPP_INCLUDED
#include <boost/property_tree/ptree.hpp>
#include <boost/serialization/nvp.hpp>
#include <boost/serialization/collections_save_imp.hpp>
#include <boost/serialization/collections_load_imp.hpp>
#include <boost/serialization/split_free.hpp>
#include <boost/serialization/utility.hpp>
namespace boost { namespace property_tree
{
///////////////////////////////////////////////////////////////////////////
// boost::serialization support
/**
* 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.
* @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 K, class D, class C>
inline void save(Archive &ar,
const basic_ptree<K, D, C> &t,
const unsigned int file_version)
{
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.
* @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 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
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 t The property tree to load or save.
* @param file_version file_version for the archive.
*/
template<class Archive, class K, class D, class C>
inline void serialize(Archive &ar,
basic_ptree<K, D, C> &t,
const unsigned int file_version)
{
using namespace boost::serialization;
split_free(ar, t, file_version);
}
} }
#endif

View File

@@ -0,0 +1,221 @@
// ----------------------------------------------------------------------------
// 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_STREAM_TRANSLATOR_HPP_INCLUDED
#define BOOST_PROPERTY_TREE_STREAM_TRANSLATOR_HPP_INCLUDED
#include <boost/property_tree/ptree_fwd.hpp>
#include <boost/optional.hpp>
#include <boost/optional/optional_io.hpp>
#include <boost/utility/enable_if.hpp>
#include <boost/type_traits/decay.hpp>
#include <boost/type_traits/integral_constant.hpp>
#include <sstream>
#include <string>
#include <locale>
#include <limits>
namespace boost { namespace property_tree
{
template <typename Ch, typename Traits, typename E, typename Enabler = void>
struct customize_stream
{
static void insert(std::basic_ostream<Ch, Traits>& s, const E& e) {
s << e;
}
static void extract(std::basic_istream<Ch, Traits>& s, E& e) {
s >> e;
if(!s.eof()) {
s >> std::ws;
}
}
};
// No whitespace skipping for single characters.
template <typename Ch, typename Traits>
struct customize_stream<Ch, Traits, Ch, void>
{
static void insert(std::basic_ostream<Ch, Traits>& s, Ch e) {
s << e;
}
static void extract(std::basic_istream<Ch, Traits>& s, Ch& e) {
s.unsetf(std::ios_base::skipws);
s >> e;
}
};
// Ugly workaround for numeric_traits that don't have members when not
// specialized, e.g. MSVC.
namespace detail
{
template <bool is_specialized>
struct is_inexact_impl
{
template <typename T>
struct test
{
typedef boost::false_type type;
};
};
template <>
struct is_inexact_impl<true>
{
template <typename T>
struct test
{
typedef boost::integral_constant<bool,
!std::numeric_limits<T>::is_exact> type;
};
};
template <typename F>
struct is_inexact
{
typedef typename boost::decay<F>::type decayed;
typedef typename is_inexact_impl<
std::numeric_limits<decayed>::is_specialized
>::BOOST_NESTED_TEMPLATE test<decayed>::type type;
static const bool value = type::value;
};
}
template <typename Ch, typename Traits, typename F>
struct customize_stream<Ch, Traits, F,
typename boost::enable_if< detail::is_inexact<F> >::type
>
{
static void insert(std::basic_ostream<Ch, Traits>& s, const F& e) {
s.precision(std::numeric_limits<F>::digits10 + 1);
s << e;
}
static void extract(std::basic_istream<Ch, Traits>& s, F& e) {
s >> e;
if(!s.eof()) {
s >> std::ws;
}
}
};
template <typename Ch, typename Traits>
struct customize_stream<Ch, Traits, bool, void>
{
static void insert(std::basic_ostream<Ch, Traits>& s, bool e) {
s.setf(std::ios_base::boolalpha);
s << e;
}
static void extract(std::basic_istream<Ch, Traits>& s, bool& e) {
s >> e;
if(s.fail()) {
// Try again in word form.
s.clear();
s.setf(std::ios_base::boolalpha);
s >> e;
}
if(!s.eof()) {
s >> std::ws;
}
}
};
template <typename Ch, typename Traits>
struct customize_stream<Ch, Traits, signed char, void>
{
static void insert(std::basic_ostream<Ch, Traits>& s, signed char e) {
s << (int)e;
}
static void extract(std::basic_istream<Ch, Traits>& s, signed char& e) {
int i;
s >> i;
// out of range?
if(i > (std::numeric_limits<signed char>::max)() ||
i < (std::numeric_limits<signed char>::min)())
{
s.clear(); // guarantees eof to be unset
return;
}
e = (signed char)i;
if(!s.eof()) {
s >> std::ws;
}
}
};
template <typename Ch, typename Traits>
struct customize_stream<Ch, Traits, unsigned char, void>
{
static void insert(std::basic_ostream<Ch, Traits>& s, unsigned char e) {
s << (unsigned)e;
}
static void extract(std::basic_istream<Ch,Traits>& s, unsigned char& e){
unsigned i;
s >> i;
// out of range?
if(i > (std::numeric_limits<unsigned char>::max)()) {
s.clear(); // guarantees eof to be unset
return;
}
e = (unsigned char)i;
if(!s.eof()) {
s >> std::ws;
}
}
};
/// Implementation of Translator that uses the stream overloads.
template <typename Ch, typename Traits, typename Alloc, typename E>
class stream_translator
{
typedef customize_stream<Ch, Traits, E> customized;
public:
typedef std::basic_string<Ch, Traits, Alloc> internal_type;
typedef E external_type;
explicit stream_translator(std::locale loc = std::locale())
: m_loc(loc)
{}
boost::optional<E> get_value(const internal_type &v) {
std::basic_istringstream<Ch, Traits, Alloc> iss(v);
iss.imbue(m_loc);
E e;
customized::extract(iss, e);
if(iss.fail() || iss.bad() || iss.get() != Traits::eof()) {
return boost::optional<E>();
}
return e;
}
boost::optional<internal_type> put_value(const E &v) {
std::basic_ostringstream<Ch, Traits, Alloc> oss;
oss.imbue(m_loc);
customized::insert(oss, v);
if(oss) {
return oss.str();
}
return boost::optional<internal_type>();
}
private:
std::locale m_loc;
};
// This is the default translator when basic_string is the internal type.
// Unless the external type is also basic_string, in which case
// id_translator takes over.
template <typename Ch, typename Traits, typename Alloc, typename E>
struct translator_between<std::basic_string<Ch, Traits, Alloc>, E>
{
typedef stream_translator<Ch, Traits, Alloc, E> type;
};
}}
#endif

View File

@@ -0,0 +1,275 @@
// ----------------------------------------------------------------------------
// 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_STRING_PATH_HPP_INCLUDED
#define BOOST_PROPERTY_TREE_STRING_PATH_HPP_INCLUDED
#include <boost/property_tree/ptree_fwd.hpp>
#include <boost/property_tree/id_translator.hpp>
#include <boost/property_tree/exceptions.hpp>
#include <boost/property_tree/detail/ptree_utils.hpp>
#include <boost/static_assert.hpp>
#include <boost/assert.hpp>
#include <boost/type_traits/is_same.hpp>
#include <boost/optional.hpp>
#include <boost/throw_exception.hpp>
#include <algorithm>
#include <string>
#include <iterator>
namespace boost { namespace property_tree
{
namespace detail
{
template <typename Sequence, typename Iterator>
void append_and_preserve_iter(Sequence &s, const Sequence &r,
Iterator &, std::forward_iterator_tag)
{
// Here we boldly assume that anything that is not random-access
// preserves validity. This is valid for the STL sequences.
s.insert(s.end(), r.begin(), r.end());
}
template <typename Sequence, typename Iterator>
void append_and_preserve_iter(Sequence &s, const Sequence &r,
Iterator &it,
std::random_access_iterator_tag)
{
// Convert the iterator to an index, and later back.
typename std::iterator_traits<Iterator>::difference_type idx =
it - s.begin();
s.insert(s.end(), r.begin(), r.end());
it = s.begin() + idx;
}
template <typename Sequence>
inline std::string dump_sequence(const Sequence &)
{
return "<undumpable sequence>";
}
inline std::string dump_sequence(const std::string &s)
{
return s;
}
#ifndef BOOST_NO_STD_WSTRING
inline std::string dump_sequence(const std::wstring &s)
{
return narrow(s.c_str());
}
#endif
}
/// Default path class. A path is a sequence of values. Groups of values
/// are separated by the separator value, which defaults to '.' cast to
/// the sequence's value type. The group of values is then passed to the
/// translator to get a key.
///
/// If instantiated with std::string and id_translator\<std::string\>,
/// it accepts paths of the form "one.two.three.four".
///
/// @tparam String Any Sequence. If the sequence does not support random-
/// access iteration, concatenation of paths assumes that
/// insertions at the end preserve iterator validity.
/// @tparam Translator A translator with internal_type == String.
template <typename String, typename Translator>
class string_path
{
BOOST_STATIC_ASSERT((is_same<String,
typename Translator::internal_type>::value));
public:
typedef typename Translator::external_type key_type;
typedef typename String::value_type char_type;
/// Create an empty path.
explicit string_path(char_type separator = char_type('.'));
/// Create a path by parsing the given string.
/// @param value A sequence, possibly with separators, that describes
/// the path, e.g. "one.two.three".
/// @param separator The separator used in parsing. Defaults to '.'.
/// @param tr The translator used by this path to convert the individual
/// parts to keys.
string_path(const String &value, char_type separator = char_type('.'),
Translator tr = Translator());
/// Create a path by parsing the given string.
/// @param value A zero-terminated array of values. Only use if zero-
/// termination makes sense for your type, and your
/// sequence supports construction from it. Intended for
/// string literals.
/// @param separator The separator used in parsing. Defaults to '.'.
/// @param tr The translator used by this path to convert the individual
/// parts to keys.
string_path(const char_type *value,
char_type separator = char_type('.'),
Translator tr = Translator());
// Default copying doesn't do the right thing with the iterator
string_path(const string_path &o);
string_path& operator =(const string_path &o);
/// Take a single element off the path at the front and return it.
key_type reduce();
/// Test if the path is empty.
bool empty() const;
/// Test if the path contains a single element, i.e. no separators.
bool single() const;
std::string dump() const {
return detail::dump_sequence(m_value);
}
/// Append a second path to this one.
/// @pre o's separator is the same as this one's, or o has no separators
string_path& operator /=(const string_path &o) {
// If it's single, there's no separator. This allows to do
// p /= "piece";
// even for non-default separators.
BOOST_ASSERT((m_separator == o.m_separator
|| o.empty()
|| o.single())
&& "Incompatible paths.");
if(!o.empty()) {
String sub;
if(!this->empty()) {
sub.push_back(m_separator);
}
sub.insert(sub.end(), o.cstart(), o.m_value.end());
detail::append_and_preserve_iter(m_value, sub, m_start,
typename std::iterator_traits<s_iter>::iterator_category());
}
return *this;
}
private:
typedef typename String::iterator s_iter;
typedef typename String::const_iterator s_c_iter;
String m_value;
char_type m_separator;
Translator m_tr;
s_iter m_start;
s_c_iter cstart() const { return m_start; }
};
template <typename String, typename Translator> inline
string_path<String, Translator>::string_path(char_type separator)
: m_separator(separator), m_start(m_value.begin())
{}
template <typename String, typename Translator> inline
string_path<String, Translator>::string_path(const String &value,
char_type separator,
Translator tr)
: m_value(value), m_separator(separator),
m_tr(tr), m_start(m_value.begin())
{}
template <typename String, typename Translator> inline
string_path<String, Translator>::string_path(const char_type *value,
char_type separator,
Translator tr)
: m_value(value), m_separator(separator),
m_tr(tr), m_start(m_value.begin())
{}
template <typename String, typename Translator> inline
string_path<String, Translator>::string_path(const string_path &o)
: m_value(o.m_value), m_separator(o.m_separator),
m_tr(o.m_tr), m_start(m_value.begin())
{
std::advance(m_start, std::distance(o.m_value.begin(), o.cstart()));
}
template <typename String, typename Translator> inline
string_path<String, Translator>&
string_path<String, Translator>::operator =(const string_path &o)
{
m_value = o.m_value;
m_separator = o.m_separator;
m_tr = o.m_tr;
m_start = m_value.begin();
std::advance(m_start, std::distance(o.m_value.begin(), o.cstart()));
return *this;
}
template <typename String, typename Translator>
typename Translator::external_type string_path<String, Translator>::reduce()
{
BOOST_ASSERT(!empty() && "Reducing empty path");
s_iter next_sep = std::find(m_start, m_value.end(), m_separator);
String part(m_start, next_sep);
m_start = next_sep;
if(!empty()) {
// Unless we're at the end, skip the separator we found.
++m_start;
}
if(optional<key_type> key = m_tr.get_value(part)) {
return *key;
}
BOOST_PROPERTY_TREE_THROW(ptree_bad_path("Path syntax error", *this));
}
template <typename String, typename Translator> inline
bool string_path<String, Translator>::empty() const
{
return m_start == m_value.end();
}
template <typename String, typename Translator> inline
bool string_path<String, Translator>::single() const
{
return std::find(static_cast<s_c_iter>(m_start),
m_value.end(), m_separator)
== m_value.end();
}
// By default, this is the path for strings. You can override this by
// specializing path_of for a more specific form of std::basic_string.
template <typename Ch, typename Traits, typename Alloc>
struct path_of< std::basic_string<Ch, Traits, Alloc> >
{
typedef std::basic_string<Ch, Traits, Alloc> _string;
typedef string_path< _string, id_translator<_string> > type;
};
template <typename String, typename Translator> inline
string_path<String, Translator> operator /(
string_path<String, Translator> p1,
const string_path<String, Translator> &p2)
{
p1 /= p2;
return p1;
}
// These shouldn't be necessary, but GCC won't find the one above.
template <typename String, typename Translator> inline
string_path<String, Translator> operator /(
string_path<String, Translator> p1,
const typename String::value_type *p2)
{
p1 /= p2;
return p1;
}
template <typename String, typename Translator> inline
string_path<String, Translator> operator /(
const typename String::value_type *p1,
const string_path<String, Translator> &p2)
{
string_path<String, Translator> t(p1);
t /= p2;
return t;
}
}}
#endif

View File

@@ -0,0 +1,153 @@
// ----------------------------------------------------------------------------
// 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_XML_PARSER_HPP_INCLUDED
#define BOOST_PROPERTY_TREE_XML_PARSER_HPP_INCLUDED
#include <boost/property_tree/ptree.hpp>
#include <boost/property_tree/detail/xml_parser_write.hpp>
#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 <boost/property_tree/detail/xml_parser_read_rapidxml.hpp>
#include <fstream>
#include <string>
#include <locale>
namespace boost { namespace property_tree { namespace xml_parser
{
/**
* 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 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 behaviour 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_comments -- Skip XML comments.
* @li @c trim_whitespace -- Trim leading and trailing whitespace from text,
* and collapse sequences of whitespace.
*/
template<class Ptree>
void read_xml(std::basic_istream<
typename Ptree::key_type::value_type
> &stream,
Ptree &pt,
int flags = 0)
{
read_xml_internal(stream, pt, flags, std::string());
}
/**
* 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_comments -- Skip XML comments.
* @param loc The locale to use when reading in the file contents.
*/
template<class Ptree>
void read_xml(const std::string &filename,
Ptree &pt,
int flags = 0,
const std::locale &loc = std::locale())
{
BOOST_ASSERT(validate_flags(flags));
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));
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.
* @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.
*/
template<class Ptree>
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>() )
{
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.
* @param filename The file to which to write the XML representation of the
* 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.
*/
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>())
{
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));
stream.imbue(loc);
write_xml_internal(stream, pt, filename, settings);
}
} } }
namespace boost { namespace property_tree
{
using xml_parser::read_xml;
using xml_parser::write_xml;
using xml_parser::xml_parser_error;
using xml_parser::xml_writer_settings;
using xml_parser::xml_writer_make_settings;
} }
#endif