This is boost::property headers only library. It was accepted into main boost ditribution, but for now we use our own copy.

This commit is contained in:
Artem Pavlenko 2006-10-03 08:49:51 +00:00
parent 8328424af5
commit efdc5d6f08
25 changed files with 4671 additions and 0 deletions

View file

@ -0,0 +1,85 @@
// ----------------------------------------------------------------------------
// Copyright (C) 2002-2005 Marcin Kalicinski
//
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
//
// For more information, see www.boost.org
// ----------------------------------------------------------------------------
#ifndef BOOST_PROPERTY_TREE_CMDLINE_PARSER_HPP_INCLUDED
#define BOOST_PROPERTY_TREE_CMDLINE_PARSER_HPP_INCLUDED
#include <boost/property_tree/ptree.hpp>
#include <boost/property_tree/detail/ptree_utils.hpp>
namespace boost { namespace property_tree { namespace cmdline_parser
{
template<class Ptree>
void read_cmdline(int argc,
typename Ptree::char_type *argv[],
const std::basic_string<typename Ptree::char_type> &metachars,
Ptree &pt)
{
typedef typename Ptree::char_type Ch;
typedef std::basic_string<Ch> Str;
Ptree local;
// For all arguments
for (int i = 0; i < argc; ++i)
{
Str text = detail::trim<Ch>(argv[i]);
if (!text.empty())
if (metachars.find(text[0]) != Str::npos)
{
if (text.size() == 1)
{
Ptree &child = local.put(text, Str());
Str key;
if (child.size() < 10)
key.push_back(typename Ptree::char_type('0' + child.size()));
child.push_back(std::make_pair(key, Ptree(child.data())));
}
else if (text.size() == 2)
{
Ptree &child = local.put(text.substr(1, 1), Str());
Str key;
if (child.size() < 10)
key.push_back(typename Ptree::char_type('0' + child.size()));
child.push_back(std::make_pair(key, Ptree(child.data())));
}
else
{
Ptree &child = local.put(text.substr(1, 1), detail::trim<Ch>(text.substr(2, Str::npos)));
Str key;
if (child.size() < 10)
key.push_back(typename Ptree::char_type('0' + child.size()));
child.push_back(std::make_pair(key, Ptree(child.data())));
}
}
else
{
Ptree &child = local.put(Str(), detail::trim<Ch>(text));
Str key;
if (child.size() < 10)
key.push_back(typename Ptree::char_type('0' + child.size()));
child.push_back(std::make_pair(key, Ptree(child.data())));
}
}
// Swap local and pt
pt.swap(local);
}
} } }
namespace boost { namespace property_tree
{
using cmdline_parser::read_cmdline;
} }
#endif

View file

@ -0,0 +1,88 @@
// ----------------------------------------------------------------------------
// Copyright (C) 2002-2005 Marcin Kalicinski
//
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
//
// For more information, see www.boost.org
// ----------------------------------------------------------------------------
#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 &message,
const std::string &filename,
unsigned long line):
ptree_error(format_what(message, filename, line)),
m_message(message), m_filename(filename), m_line(line)
{
}
~file_parser_error() throw()
// gcc 3.4.2 complains about lack of throw specifier on compiler generated dtor
{
}
///////////////////////////////////////////////////////////////////////
// Data access
// Get error message (without line and file - use what() to get full message)
std::string message()
{
return m_message;
}
// Get error filename
std::string filename()
{
return m_filename;
}
// Get error line number
unsigned long line()
{
return m_line;
}
private:
std::string m_message;
std::string m_filename;
unsigned long m_line;
// Format error message to be returned by std::runtime_error::what()
std::string format_what(const std::string &message,
const std::string &filename,
unsigned long line)
{
std::stringstream stream;
if (line > 0)
stream << (filename.empty() ? "<unspecified file>" : filename.c_str()) <<
'(' << line << "): " << message;
else
stream << (filename.empty() ? "<unspecified file>" : filename.c_str()) <<
": " << message;
return stream.str();
}
};
} }
#endif

View file

@ -0,0 +1,32 @@
// ----------------------------------------------------------------------------
// Copyright (C) 2002-2005 Marcin Kalicinski
//
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
//
// For more information, see www.boost.org
// ----------------------------------------------------------------------------
#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,369 @@
// ----------------------------------------------------------------------------
// Copyright (C) 2002-2005 Marcin Kalicinski
//
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
//
// For more information, see www.boost.org
// ----------------------------------------------------------------------------
#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)
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
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)
throw info_parser_error("unexpected \\", "", 0);
++text;
skip_whitespace(text);
if (*text == Ch('\0') || *text == Ch(';'))
*need_more_lines = true;
else
throw info_parser_error("expected end of line after \\", "", 0);
}
else
if (need_more_lines)
*need_more_lines = false;
return result;
}
else
throw info_parser_error("unexpected end of line", "", 0);
}
else
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>
void read_info_internal(std::basic_istream<typename Ptree::char_type> &stream,
Ptree &pt,
const std::string &filename,
int include_depth)
{
// Character type
typedef typename Ptree::char_type Ch;
// 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
std::basic_string<Ch> line; // Define line here to minimize reallocations
// 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())
throw info_parser_error("read error", "", 0);
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)
throw info_parser_error("include depth too large, probably recursive include", "", 0);
std::basic_string<Ch> s = read_string(text, NULL);
std::string inc_name = convert_chtype<char, Ch>(s.c_str());
std::basic_ifstream<Ch> inc_stream(inc_name.c_str());
if (!inc_stream.good())
throw info_parser_error("cannot open include file " + inc_name, "", 0);
read_info_internal(inc_stream, *stack.top(), inc_name, include_depth + 1);
}
else // Unknown directive
throw info_parser_error("unknown directive", "", 0);
// Directive must be followed by end of line
skip_whitespace(text);
if (*text != Ch('\0'))
throw info_parser_error("expected end of line", "", 0);
// 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)
throw info_parser_error("unexpected {", "", 0);
stack.push(last);
last = NULL;
++text;
}
else if (*text == Ch('}')) // Brace closing found
{
if (stack.size() <= 1)
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)
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_own(last->template get_own<std::basic_string<Ch> >() + data);
state = need_more_lines ? s_data_cont : s_key;
}
else
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)
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)
throw info_parser_error(e.message(), filename, line_no);
else
throw e;
}
}
} } }
#endif

View file

@ -0,0 +1,32 @@
// ----------------------------------------------------------------------------
// Copyright (C) 2002-2005 Marcin Kalicinski
//
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
//
// For more information, see www.boost.org
// ----------------------------------------------------------------------------
#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,131 @@
// ----------------------------------------------------------------------------
// Copyright (C) 2002-2005 Marcin Kalicinski
//
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
//
// For more information, see www.boost.org
// ----------------------------------------------------------------------------
#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
{
// 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::char_type> &stream,
const Ptree &pt,
int indent)
{
// Character type
typedef typename Ptree::char_type Ch;
// Write data
if (indent >= 0)
{
if (!pt.data().empty())
{
std::basic_string<Ch> data = create_escapes(pt.template get_own<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)
stream << std::basic_string<Ch>(4 * indent, Ch(' ')) << 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);
stream << std::basic_string<Ch>(4 * (indent + 1), Ch(' '));
if (is_simple_key(key))
stream << key;
else
stream << Ch('\"') << key << Ch('\"');
// Output data and children
write_info_helper(stream, it->second, indent + 1);
}
// Close brace
if (indent >= 0)
stream << std::basic_string<Ch>(4 * indent, Ch(' ')) << Ch('}') << Ch('\n');
}
}
// Write ptree to info stream
template<class Ptree>
void write_info_internal(std::basic_ostream<typename Ptree::char_type> &stream,
const Ptree &pt,
const std::string &filename)
{
write_info_helper(stream, pt, -1);
if (!stream.good())
throw info_parser_error("write error", filename, 0);
}
} } }
#endif

View file

@ -0,0 +1,33 @@
// ----------------------------------------------------------------------------
// Copyright (C) 2002-2005 Marcin Kalicinski
//
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
//
// For more information, see www.boost.org
// ----------------------------------------------------------------------------
#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,316 @@
// ----------------------------------------------------------------------------
// Copyright (C) 2002-2005 Marcin Kalicinski
//
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
//
// For more information, see www.boost.org
// ----------------------------------------------------------------------------
#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.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::char_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('0'): c.string += Ch('\0'); 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::grammar<json_grammar<Ptree> >
{
typedef context<Ptree> Context;
typedef typename Ptree::char_type Ch;
mutable Context c;
template<class Scanner>
struct definition
{
boost::spirit::rule<Scanner> root, object, member, array, item, value, string, number;
boost::spirit::rule<typename boost::spirit::lexeme_scanner<Scanner>::type> character, escape;
definition(const json_grammar &self)
{
using namespace boost::spirit;
// Assertions
assertion<std::string> expect_object("expected object");
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_object(object)
>> 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
= strict_real_p
| int_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>("\"\\0bfnrt").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::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::char_type> &stream,
Ptree &pt,
const std::string &filename)
{
using namespace boost::spirit;
typedef typename Ptree::char_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())
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)
throw parser_error<std::string, It>(v.begin(), "syntax error");
}
catch (parser_error<std::string, It> &e)
{
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,163 @@
// ----------------------------------------------------------------------------
// Copyright (C) 2002-2005 Marcin Kalicinski
//
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
//
// For more information, see www.boost.org
// ----------------------------------------------------------------------------
#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 <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,
const std::locale &loc)
{
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('\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 (std::isprint(*b, loc))
result += *b;
else
{
const char *hexdigits = "0123456789ABCDEF";
unsigned long u = (std::min)(static_cast<unsigned long>(*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::char_type> &stream,
const Ptree &pt,
int indent)
{
typedef typename Ptree::char_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_own<Str>(), stream.getloc());
stream << Ch('"') << data << Ch('"');
}
else if (indent > 0 && pt.count(Str()) == pt.size())
{
// Write array
stream << Ch('[') << Ch('\n');
typename Ptree::const_iterator it = pt.begin();
for (; it != pt.end(); ++it)
{
stream << Str(4 * (indent + 1), Ch(' '));
write_json_helper(stream, it->second, indent + 1);
if (boost::next(it) != pt.end())
stream << Ch(',');
stream << Ch('\n');
}
stream << Str(4 * indent, Ch(' ')) << Ch(']');
}
else
{
// Write object
stream << Ch('{') << Ch('\n');
typename Ptree::const_iterator it = pt.begin();
for (; it != pt.end(); ++it)
{
stream << Str(4 * (indent + 1), Ch(' '));
stream << Ch('"') << create_escapes(it->first, stream.getloc()) << Ch('"') << Ch(':');
if (it->second.empty())
stream << Ch(' ');
else
stream << Ch('\n') << Str(4 * (indent + 1), Ch(' '));
write_json_helper(stream, it->second, indent + 1);
if (boost::next(it) != pt.end())
stream << Ch(',');
stream << Ch('\n');
}
stream << Str(4 * indent, Ch(' ')) << 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::char_type Ch;
typedef typename std::basic_string<Ch> Str;
// Root ptree cannot have data
if (depth == 0 && !pt.template get_own<Str>().empty())
return false;
// Ptree cannot have both children and data
if (!pt.template get_own<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::char_type> &stream,
const Ptree &pt,
const std::string &filename)
{
if (!verify_json(pt, 0))
throw json_parser_error("ptree contains data that cannot be represented in JSON format", filename, 0);
write_json_helper(stream, pt, 0);
stream << std::endl;
if (!stream.good())
throw json_parser_error("write error", filename, 0);
}
} } }
#endif

View file

@ -0,0 +1,996 @@
// ----------------------------------------------------------------------------
// Copyright (C) 2002-2005 Marcin Kalicinski
//
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
//
// For more information, see www.boost.org
// ----------------------------------------------------------------------------
#ifndef BOOST_PROPERTY_TREE_DETAIL_PTREE_IMPLEMENTATION_HPP_INCLUDED
#define BOOST_PROPERTY_TREE_DETAIL_PTREE_IMPLEMENTATION_HPP_INCLUDED
#include <sstream>
#include <locale>
#include <algorithm>
#include <limits>
#include <stdexcept>
#include <functional> // for std::less
#include <memory> // for std::auto_ptr
#include <boost/assert.hpp>
#include <boost/static_assert.hpp>
#include <boost/type_traits.hpp>
#include <boost/utility.hpp> // for boost::prior
#include <boost/property_tree/detail/ptree_utils.hpp>
//////////////////////////////////////////////////////////////////////////////
// Debug macros
#ifdef BOOST_PROPERTY_TREE_DEBUG
// Increment instances counter
#define BOOST_PROPERTY_TREE_DEBUG_INCREMENT_INSTANCES_COUNT() \
{ \
typedef boost::detail::lightweight_mutex::scoped_lock lock; \
lock l(debug_mutex); \
++debug_instances_count; \
}
// Decrement instances counter
#define BOOST_PROPERTY_TREE_DEBUG_DECREMENT_INSTANCES_COUNT() \
{ \
typedef boost::detail::lightweight_mutex::scoped_lock lock; \
lock l(debug_mutex); \
BOOST_ASSERT(debug_instances_count > 0); \
--debug_instances_count; \
}
#else // BOOST_PROPERTY_TREE_DEBUG
#define BOOST_PROPERTY_TREE_DEBUG_INCREMENT_INSTANCES_COUNT() static_cast<void>(0)
#define BOOST_PROPERTY_TREE_DEBUG_DECREMENT_INSTANCES_COUNT() static_cast<void>(0)
#endif // BOOST_PROPERTY_TREE_DEBUG
namespace boost { namespace property_tree
{
namespace detail
{
template<class T>
struct array_to_pointer_decay
{
typedef T type;
};
template<class T, std::size_t N>
struct array_to_pointer_decay<T[N]>
{
typedef const T *type;
};
////////////////////////////////////////////////////////////////////////////
// Extractor and inserter
template<class Ch, class Type>
struct extractor
{
inline bool operator()(const std::basic_string<Ch> &data,
Type &extracted,
const std::locale &loc) const
{
std::basic_istringstream<Ch> stream(data);
stream.imbue(loc);
stream >> extracted >> std::ws;
return stream.eof() && !stream.fail() && !stream.bad();
}
};
template<class Ch>
struct extractor<Ch, std::basic_string<Ch> >
{
inline bool operator()(const std::basic_string<Ch> &data,
std::basic_string<Ch> &extracted,
const std::locale &loc) const
{
extracted = data;
return true;
}
};
template<class Ch, class Type>
struct inserter
{
inline bool operator()(std::basic_string<Ch> &data,
const Type &to_insert,
const std::locale &loc) const
{
typedef typename detail::array_to_pointer_decay<Type>::type Type2;
std::basic_ostringstream<Ch> stream;
stream.imbue(loc);
if (std::numeric_limits<Type2>::is_specialized)
stream.precision(std::numeric_limits<Type2>::digits10 + 1);
stream << to_insert;
data = stream.str();
return !stream.fail() && !stream.bad();
}
};
template<class Ch>
struct inserter<Ch, std::basic_string<Ch> >
{
inline bool operator()(std::basic_string<Ch> &data,
const std::basic_string<Ch> &to_insert,
const std::locale &loc) const
{
data = to_insert;
return true;
}
};
}
///////////////////////////////////////////////////////////////////////////
// Impl
template<class Tr>
struct basic_ptree<Tr>::impl
{
data_type m_data;
container_type m_container;
index_type m_index;
};
////////////////////////////////////////////////////////////////////////////
// Traits
template<class Ch>
struct ptree_traits
{
typedef Ch char_type;
typedef std::basic_string<Ch> key_type;
typedef std::basic_string<Ch> data_type;
template<class Type>
struct extractor: public detail::extractor<Ch, Type> { };
template<class Type>
struct inserter: public detail::inserter<Ch, Type> { };
inline bool operator()(const key_type &key1,
const key_type &key2) const
{
return key1 < key2;
}
};
template<class Ch>
struct iptree_traits
{
std::locale loc;
typedef Ch char_type;
typedef std::basic_string<Ch> key_type;
typedef std::basic_string<Ch> data_type;
template<class Type>
struct extractor: public detail::extractor<Ch, Type> { };
template<class Type>
struct inserter: public detail::inserter<Ch, Type> { };
inline bool operator()(Ch c1, Ch c2) const // Helper for comparing characters
{
return std::toupper(c1, loc) < std::toupper(c2, loc);
}
inline bool operator()(const key_type &key1,
const key_type &key2) const
{
return std::lexicographical_compare(key1.begin(), key1.end(), key2.begin(), key2.end(), *this);
}
};
///////////////////////////////////////////////////////////////////////////
// Exceptions
class ptree_error: public std::runtime_error
{
public:
ptree_error(const std::string &what): std::runtime_error(what) { }
~ptree_error() throw() { }
};
class ptree_bad_data: public ptree_error
{
public:
ptree_bad_data(const std::string &what): ptree_error(what) { }
~ptree_bad_data() throw() { }
};
class ptree_bad_path: public ptree_error
{
public:
ptree_bad_path(const std::string &what): ptree_error(what) { }
~ptree_bad_path() throw() { }
};
///////////////////////////////////////////////////////////////////////////
// Construction & destruction
template<class Tr>
basic_ptree<Tr>::basic_ptree()
{
m_impl = new impl;
BOOST_PROPERTY_TREE_DEBUG_INCREMENT_INSTANCES_COUNT();
}
template<class Tr>
basic_ptree<Tr>::basic_ptree(const data_type &rhs)
{
std::auto_ptr<impl> tmp(new impl);
tmp->m_data = rhs;
m_impl = tmp.release();
BOOST_PROPERTY_TREE_DEBUG_INCREMENT_INSTANCES_COUNT();
}
template<class Tr>
basic_ptree<Tr>::basic_ptree(const basic_ptree<Tr> &rhs)
{
std::auto_ptr<impl> tmp(new impl);
tmp->m_data = rhs.data();
m_impl = tmp.get();
insert(end(), rhs.begin(), rhs.end());
tmp.release();
BOOST_PROPERTY_TREE_DEBUG_INCREMENT_INSTANCES_COUNT();
}
template<class Tr>
basic_ptree<Tr>::~basic_ptree()
{
BOOST_PROPERTY_TREE_DEBUG_DECREMENT_INSTANCES_COUNT();
delete m_impl;
}
///////////////////////////////////////////////////////////////////////////
// Iterator access
template<class Tr>
typename basic_ptree<Tr>::iterator
basic_ptree<Tr>::begin()
{
return m_impl->m_container.begin();
}
template<class Tr>
typename basic_ptree<Tr>::const_iterator
basic_ptree<Tr>::begin() const
{
return m_impl->m_container.begin();
}
template<class Tr>
typename basic_ptree<Tr>::iterator
basic_ptree<Tr>::end()
{
return m_impl->m_container.end();
}
template<class Tr>
typename basic_ptree<Tr>::const_iterator
basic_ptree<Tr>::end() const
{
return m_impl->m_container.end();
}
template<class Tr>
typename basic_ptree<Tr>::reverse_iterator
basic_ptree<Tr>::rbegin()
{
return m_impl->m_container.rbegin();
}
template<class Tr>
typename basic_ptree<Tr>::const_reverse_iterator
basic_ptree<Tr>::rbegin() const
{
return m_impl->m_container.rbegin();
}
template<class Tr>
typename basic_ptree<Tr>::reverse_iterator
basic_ptree<Tr>::rend()
{
return m_impl->m_container.rend();
}
template<class Tr>
typename basic_ptree<Tr>::const_reverse_iterator
basic_ptree<Tr>::rend() const
{
return m_impl->m_container.rend();
}
///////////////////////////////////////////////////////////////////////////
// Data access
template<class Tr>
typename basic_ptree<Tr>::size_type
basic_ptree<Tr>::size() const
{
return m_impl->m_index.size();
}
template<class Tr>
bool basic_ptree<Tr>::empty() const
{
return m_impl->m_index.empty();
}
template<class Tr>
typename basic_ptree<Tr>::data_type &
basic_ptree<Tr>::data()
{
return m_impl->m_data;
}
template<class Tr>
const typename basic_ptree<Tr>::data_type &
basic_ptree<Tr>::data() const
{
return m_impl->m_data;
}
template<class Tr>
typename basic_ptree<Tr>::value_type &
basic_ptree<Tr>::front()
{
return m_impl->m_container.front();
}
template<class Tr>
const typename basic_ptree<Tr>::value_type &
basic_ptree<Tr>::front() const
{
return m_impl->m_container.front();
}
template<class Tr>
typename basic_ptree<Tr>::value_type &
basic_ptree<Tr>::back()
{
return m_impl->m_container.back();
}
template<class Tr>
const typename basic_ptree<Tr>::value_type &
basic_ptree<Tr>::back() const
{
return m_impl->m_container.back();
}
///////////////////////////////////////////////////////////////////////////
// Operators
template<class Tr>
basic_ptree<Tr> &
basic_ptree<Tr>::operator =(const basic_ptree<Tr> &rhs)
{
if (&rhs != this)
{
clear();
data() = rhs.data();
insert(end(), rhs.begin(), rhs.end());
}
return *this;
}
template<class Tr>
bool basic_ptree<Tr>::operator ==(const basic_ptree<Tr> &rhs) const
{
// Data and sizes must be equal
if (size() != rhs.size() || data() != rhs.data())
return false;
// Keys and children must be equal
Tr tr;
const_iterator it = begin();
const_iterator it_rhs = rhs.begin();
const_iterator it_end = end();
for (; it != it_end; ++it, ++it_rhs)
if (tr(it->first, it_rhs->first) ||
tr(it_rhs->first, it->first) ||
it->second != it_rhs->second)
return false;
// Equal
return true;
}
template<class Tr>
bool basic_ptree<Tr>::operator !=(const basic_ptree<Tr> &rhs) const
{
return !operator ==(rhs);
}
///////////////////////////////////////////////////////////////////////////
// Container operations
template<class Tr>
typename basic_ptree<Tr>::iterator
basic_ptree<Tr>::find(const key_type &key)
{
typename index_type::iterator it = m_impl->m_index.find(key);
return it == m_impl->m_index.end() ? end() : it->second;
}
template<class Tr>
typename basic_ptree<Tr>::const_iterator
basic_ptree<Tr>::find(const key_type &key) const
{
typename index_type::const_iterator it = m_impl->m_index.find(key);
return it == m_impl->m_index.end() ? end() : it->second;
}
template<class Tr>
typename basic_ptree<Tr>::size_type
basic_ptree<Tr>::count(const key_type &key) const
{
return m_impl->m_index.count(key);
}
template<class Tr>
void basic_ptree<Tr>::clear()
{
m_impl->m_data = data_type();
m_impl->m_container.clear();
m_impl->m_index.clear();
}
template<class Tr>
typename basic_ptree<Tr>::iterator
basic_ptree<Tr>::insert(iterator where,
const value_type &value)
{
// Insert new value into container. If that throws nothing needs to be rolled back
where = m_impl->m_container.insert(where, value);
// Update index. If that throws we need to rollback the insert
try {
m_impl->m_index.insert(typename index_type::value_type(where->first, where));
}
catch (...) {
m_impl->m_container.erase(where); // rollback the insert
throw;
}
return where;
}
template<class Tr>
template<class It>
void basic_ptree<Tr>::insert(iterator where,
It first,
It last)
{
for (; first != last; ++first, ++where)
where = insert(where, value_type(first->first, first->second));
}
template<class Tr>
typename basic_ptree<Tr>::iterator
basic_ptree<Tr>::erase(iterator where)
{
// Remove from index
typename index_type::iterator lo = m_impl->m_index.lower_bound(where->first);
typename index_type::iterator hi = m_impl->m_index.upper_bound(where->first);
for (; lo != hi; ++lo)
if (lo->second == where)
{
m_impl->m_index.erase(lo);
break;
}
// Remove from container
return m_impl->m_container.erase(where);
}
template<class Tr>
typename basic_ptree<Tr>::size_type
basic_ptree<Tr>::erase(const key_type &key)
{
size_type count = 0;
typename index_type::iterator lo = m_impl->m_index.lower_bound(key);
if (lo != m_impl->m_index.end())
{
typename index_type::iterator hi = m_impl->m_index.upper_bound(key);
while (lo != hi)
{
typename index_type::iterator it = lo++;
erase(it->second);
++count;
}
}
return count;
}
template<class Tr>
template<class It>
typename basic_ptree<Tr>::iterator
basic_ptree<Tr>::erase(It first,
It last)
{
while (first != last)
first = erase(first);
return first;
}
template<class Tr>
typename basic_ptree<Tr>::iterator
basic_ptree<Tr>::push_front(const value_type &value)
{
return insert(begin(), value);
}
template<class Tr>
typename basic_ptree<Tr>::iterator
basic_ptree<Tr>::push_back(const value_type &value)
{
return insert(end(), value);
}
template<class Tr>
void basic_ptree<Tr>::pop_front()
{
erase(begin());
}
template<class Tr>
void basic_ptree<Tr>::pop_back()
{
erase(boost::prior(end()));
}
template<class Tr>
void basic_ptree<Tr>::swap(basic_ptree<Tr> &rhs)
{
std::swap(m_impl, rhs.m_impl);
}
template<class Tr>
void basic_ptree<Tr>::reverse()
{
m_impl->m_container.reverse();
}
template<class Tr>
template<class SortTr>
void basic_ptree<Tr>::sort(SortTr tr)
{
m_impl->m_container.sort(tr);
}
///////////////////////////////////////////////////////////////////////////
// ptree operations
// Get child ptree with custom separator
template<class Tr>
basic_ptree<Tr> &
basic_ptree<Tr>::get_child(char_type separator,
const key_type &path)
{
if (optional<basic_ptree<Tr> &> result = get_child_optional(separator, path))
return result.get();
else
throw ptree_bad_path("key \"" + detail::narrow(path.c_str()) + "\" does not exist");
}
// Get child ptree with custom separator
template<class Tr>
const basic_ptree<Tr> &
basic_ptree<Tr>::get_child(char_type separator,
const key_type &path) const
{
basic_ptree<Tr> *nc_this = const_cast<basic_ptree<Tr> *>(this);
return nc_this->get_child(separator, path);
}
// Get child ptree with custom separator
template<class Tr>
basic_ptree<Tr> &
basic_ptree<Tr>::get_child(char_type separator,
const key_type &path,
basic_ptree<Tr> &default_value)
{
if (optional<basic_ptree<Tr> &> result = get_child_optional(separator, path))
return result.get();
else
return default_value;
}
// Get child ptree with custom separator
template<class Tr>
const basic_ptree<Tr> &
basic_ptree<Tr>::get_child(char_type separator,
const key_type &path,
const basic_ptree<Tr> &default_value) const
{
basic_ptree<Tr> *nc_this = const_cast<basic_ptree<Tr> *>(this);
basic_ptree<Tr> &nc_default_value = const_cast<basic_ptree<Tr> &>(default_value);
return nc_this->get_child(separator, path, nc_default_value);
}
// Get child ptree with custom separator
template<class Tr>
optional<basic_ptree<Tr> &>
basic_ptree<Tr>::get_child_optional(char_type separator,
const key_type &path)
{
typename key_type::size_type n = path.find(separator);
if (n != key_type::npos)
{
key_type head = path.substr(0, n);
key_type tail = path.substr(n + 1, key_type::npos);
iterator it = find(head);
if (it != end())
return it->second.get_child_optional(separator, tail);
else
return optional<basic_ptree<Tr> &>();
}
else
{
iterator it = find(path);
if (it != end())
return it->second;
else
return optional<basic_ptree<Tr> &>();
}
}
// Get child ptree with custom separator
template<class Tr>
optional<const basic_ptree<Tr> &>
basic_ptree<Tr>::get_child_optional(char_type separator, const key_type &path) const
{
basic_ptree<Tr> *nc_this = const_cast<basic_ptree<Tr> *>(this);
optional<basic_ptree<Tr> &> tmp = nc_this->get_child_optional(separator, path);
if (tmp)
return optional<const basic_ptree<Tr> &>(tmp.get());
else
return optional<const basic_ptree<Tr> &>();
}
// Get child ptree with default separator
template<class Tr>
basic_ptree<Tr> &
basic_ptree<Tr>::get_child(const key_type &path)
{
return get_child(char_type('.'), path);
}
// Get child ptree with default separator
template<class Tr>
const basic_ptree<Tr> &
basic_ptree<Tr>::get_child(const key_type &path) const
{
return get_child(char_type('.'), path);
}
// Get child ptree with default separator
template<class Tr>
basic_ptree<Tr> &
basic_ptree<Tr>::get_child(const key_type &path,
basic_ptree<Tr> &default_value)
{
return get_child(char_type('.'), path, default_value);
}
// Get child ptree with default separator
template<class Tr>
const basic_ptree<Tr> &
basic_ptree<Tr>::get_child(const key_type &path,
const basic_ptree<Tr> &default_value) const
{
return get_child(char_type('.'), path, default_value);
}
// Get child ptree with default separator
template<class Tr>
optional<basic_ptree<Tr> &>
basic_ptree<Tr>::get_child_optional(const key_type &path)
{
return get_child_optional(char_type('.'), path);
}
// Get child ptree with default separator
template<class Tr>
optional<const basic_ptree<Tr> &>
basic_ptree<Tr>::get_child_optional(const key_type &path) const
{
return get_child_optional(char_type('.'), path);
}
// Put child ptree with custom separator
template<class Tr>
basic_ptree<Tr> &
basic_ptree<Tr>::put_child(char_type separator,
const key_type &path,
const basic_ptree<Tr> &value,
bool do_not_replace)
{
typename key_type::size_type n = path.find(separator);
if (n == key_type::npos)
{
if (do_not_replace)
return push_back(value_type(path, value))->second;
else
{
iterator it = find(path);
if (it == end())
return push_back(value_type(path, value))->second;
else
{
it->second = value;
return it->second;
}
}
}
else
{
key_type head = path.substr(0, n);
key_type tail = path.substr(n + 1, key_type::npos);
iterator it = find(head);
if (it == end())
it = push_back(value_type(head, basic_ptree<Tr>()));
return it->second.put_child(separator, tail, value, do_not_replace);
}
}
// Put child ptree with default separator
template<class Tr>
basic_ptree<Tr> &
basic_ptree<Tr>::put_child(const key_type &path,
const basic_ptree<Tr> &value,
bool do_not_replace)
{
return put_child(char_type('.'), path, value, do_not_replace);
}
// Get value from data of ptree
template<class Tr>
template<class Type>
Type basic_ptree<Tr>::get_own(const std::locale &loc) const
{
if (optional<Type> result = get_own_optional<Type>(loc))
return result.get();
else
throw ptree_bad_data(std::string("conversion of data into type '") +
typeid(Type).name() + "' failed");
}
// Get value from data of ptree
template<class Tr>
template<class Type>
Type basic_ptree<Tr>::get_own(const Type &default_value,
const std::locale &loc) const
{
if (optional<Type> result = get_own_optional<Type>(loc))
return result.get();
else
return default_value;
}
// Get value from data of ptree
template<class Tr>
template<class CharType>
std::basic_string<CharType>
basic_ptree<Tr>::get_own(const CharType *default_value,
const std::locale &loc) const
{
BOOST_STATIC_ASSERT((boost::is_same<char_type, CharType>::value == true)); // Character types must match
return get_own(std::basic_string<CharType>(default_value), loc);
}
// Get value from data of ptree
template<class Tr>
template<class Type>
optional<Type>
basic_ptree<Tr>::get_own_optional(const std::locale &loc) const
{
BOOST_STATIC_ASSERT(boost::is_pointer<Type>::value == false); // Disallow pointer types, they are unsafe
Type tmp;
if (typename traits_type::template extractor<Type>()(m_impl->m_data, tmp, loc))
{
return optional<Type>(tmp);
}
else
return optional<Type>();
}
// Get value from data of child ptree (custom path separator)
template<class Tr>
template<class Type>
Type basic_ptree<Tr>::get(char_type separator,
const key_type &path,
const std::locale &loc) const
{
return get_child(separator, path).get_own<Type>(loc);
}
// Get value from data of child ptree (custom path separator)
template<class Tr>
template<class Type>
Type basic_ptree<Tr>::get(char_type separator,
const key_type &path,
const Type &default_value,
const std::locale &loc) const
{
if (optional<Type> result = get_optional<Type>(separator, path, loc))
return *result;
else
return default_value;
}
// Get value from data of child ptree (custom path separator)
template<class Tr>
template<class CharType>
std::basic_string<CharType>
basic_ptree<Tr>::get(char_type separator,
const key_type &path,
const CharType *default_value,
const std::locale &loc) const
{
BOOST_STATIC_ASSERT((boost::is_same<char_type, CharType>::value == true)); // Character types must match
return get(separator, path, std::basic_string<CharType>(default_value), loc);
}
// Get value from data of child ptree (custom path separator)
template<class Tr>
template<class Type>
optional<Type>
basic_ptree<Tr>::get_optional(char_type separator,
const key_type &path,
const std::locale &loc) const
{
if (optional<const basic_ptree<Tr> &> child = get_child_optional(separator, path))
return child.get().get_own_optional<Type>(loc);
else
return optional<Type>();
}
// Get value from data of child ptree (default path separator)
template<class Tr>
template<class Type>
Type basic_ptree<Tr>::get(const key_type &path,
const std::locale &loc) const
{
return get<Type>(char_type('.'), path, loc);
}
// Get value from data of child ptree (default path separator)
template<class Tr>
template<class Type>
Type basic_ptree<Tr>::get(const key_type &path,
const Type &default_value,
const std::locale &loc) const
{
return get(char_type('.'), path, default_value, loc);
}
// Get value from data of child ptree (default path separator)
template<class Tr>
template<class CharType>
std::basic_string<CharType>
basic_ptree<Tr>::get(const key_type &path,
const CharType *default_value,
const std::locale &loc) const
{
return get(char_type('.'), path, default_value, loc);
}
// Get value from data of child ptree (default path separator)
template<class Tr>
template<class Type>
optional<Type>
basic_ptree<Tr>::get_optional(const key_type &path,
const std::locale &loc) const
{
return get_optional<Type>(char_type('.'), path, loc);
}
// Put value in data of ptree
template<class Tr>
template<class Type>
void basic_ptree<Tr>::put_own(const Type &value, const std::locale &loc)
{
using namespace boost;
// Make sure that no pointer other than char_type * is allowed
BOOST_STATIC_ASSERT((is_pointer<Type>::value == false ||
is_same<char_type, typename remove_const<typename remove_pointer<Type>::type>::type>::value == true));
typename traits_type::template inserter<Type>()(m_impl->m_data, value, loc);
}
// Put value in data of child ptree (custom path separator)
template<class Tr>
template<class Type>
basic_ptree<Tr> &
basic_ptree<Tr>::put(char_type separator,
const key_type &path,
const Type &value,
bool do_not_replace,
const std::locale &loc)
{
optional<basic_ptree<Tr> &> child;
if (!do_not_replace &&
(child = get_child_optional(separator, path)))
{
child.get().put_own(value, loc);
return *child;
}
else
{
basic_ptree<Tr> &child2 = put_child(separator, path, empty_ptree<basic_ptree<Tr> >(), do_not_replace);
child2.put_own(value, loc);
return child2;
}
}
// Put value in data of child ptree (default path separator)
template<class Tr>
template<class Type>
basic_ptree<Tr> &
basic_ptree<Tr>::put(const key_type &path,
const Type &value,
bool do_not_replace,
const std::locale &loc)
{
return put(char_type('.'), path, value, do_not_replace, loc);
}
////////////////////////////////////////////////////////////////////////////
// Debugging
#ifdef BOOST_PROPERTY_TREE_DEBUG
template<class Tr>
typename basic_ptree<Tr>::size_type
basic_ptree<Tr>::debug_get_instances_count()
{
empty_ptree<basic_ptree<Tr> >(); // Make sure empty ptree exists
return debug_instances_count - 1; // Do not count empty ptree
}
template<class Tr>
typename basic_ptree<Tr>::size_type
basic_ptree<Tr>::debug_instances_count;
template<class Tr>
boost::detail::lightweight_mutex
basic_ptree<Tr>::debug_mutex;
#endif
///////////////////////////////////////////////////////////////////////////
// Free functions
template<class Ptree>
inline const Ptree &empty_ptree()
{
static Ptree pt;
return pt;
}
template<class Tr>
inline void swap(basic_ptree<Tr> &pt1, basic_ptree<Tr> &pt2)
{
pt1.swap(pt2);
}
} }
// Undefine debug macros
#ifdef BOOST_PROPERTY_TREE_DEBUG
# undef BOOST_PROPERTY_TREE_DEBUG_INCREMENT_INSTANCES_COUNT
# undef BOOST_PROPERTY_TREE_DEBUG_DECREMENT_INSTANCES_COUNT
#endif
#endif

View file

@ -0,0 +1,198 @@
// ----------------------------------------------------------------------------
// Copyright (C) 2002-2005 Marcin Kalicinski
//
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
//
// For more information, see www.boost.org
// ----------------------------------------------------------------------------
#ifndef BOOST_PROPERTY_TREE_DETAIL_PTREE_INTERFACE_HPP_INCLUDED
#define BOOST_PROPERTY_TREE_DETAIL_PTREE_INTERFACE_HPP_INCLUDED
#include <boost/config.hpp>
#include <boost/optional.hpp>
#include <string>
#include <list>
#include <map>
#include <utility> // For std::pair
#include <locale>
#include "boost/property_tree/ptree_fwd.hpp"
#ifdef BOOST_PROPERTY_TREE_DEBUG
# include <boost/detail/lightweight_mutex.hpp> // For syncing debug instances counter
#endif
namespace boost { namespace property_tree
{
///////////////////////////////////////////////////////////////////////////
// basic_ptree class template
template<class Tr>
class basic_ptree
{
public:
// Basic types
typedef Tr traits_type;
typedef typename traits_type::char_type char_type;
typedef typename traits_type::key_type key_type;
typedef typename traits_type::data_type data_type;
// Container-related types
typedef std::pair<key_type, basic_ptree<Tr> > value_type;
typedef std::list<value_type> container_type;
typedef typename container_type::size_type size_type;
typedef typename container_type::iterator iterator;
typedef typename container_type::const_iterator const_iterator;
typedef typename container_type::reverse_iterator reverse_iterator;
typedef typename container_type::const_reverse_iterator const_reverse_iterator;
///////////////////////////////////////////////////////////////////////////
// Construction & destruction
basic_ptree();
explicit basic_ptree(const data_type &data);
basic_ptree(const basic_ptree<Tr> &rhs);
~basic_ptree();
///////////////////////////////////////////////////////////////////////////
// Iterator access
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;
///////////////////////////////////////////////////////////////////////////
// Data access
size_type size() const;
bool empty() const;
data_type &data();
const data_type &data() const;
value_type &front();
const value_type &front() const;
value_type &back();
const value_type &back() const;
///////////////////////////////////////////////////////////////////////////
// Operators
basic_ptree<Tr> &operator =(const basic_ptree<Tr> &rhs);
bool operator ==(const basic_ptree<Tr> &rhs) const;
bool operator !=(const basic_ptree<Tr> &rhs) const;
///////////////////////////////////////////////////////////////////////////
// Container operations
iterator find(const key_type &key);
const_iterator find(const key_type &key) const;
size_type count(const key_type &key) const;
void clear();
iterator insert(iterator where, const value_type &value);
template<class It> void insert(iterator where, It first, It last);
iterator erase(iterator where);
size_type erase(const key_type &key);
template<class It> iterator erase(It first, It last);
iterator push_front(const value_type &value);
iterator push_back(const value_type &value);
void pop_front();
void pop_back();
void swap(basic_ptree<Tr> &rhs);
void reverse();
template<class SortTr> void sort(SortTr tr);
///////////////////////////////////////////////////////////////////////////
// ptree operations
// Get child ptree with custom separator
basic_ptree<Tr> &get_child(char_type separator, const key_type &path);
const basic_ptree<Tr> &get_child(char_type separator, const key_type &path) const;
basic_ptree<Tr> &get_child(char_type separator, const key_type &path, basic_ptree<Tr> &default_value);
const basic_ptree<Tr> &get_child(char_type separator, const key_type &path, const basic_ptree<Tr> &default_value) const;
optional<basic_ptree<Tr> &> get_child_optional(char_type separator, const key_type &path);
optional<const basic_ptree<Tr> &> get_child_optional(char_type separator, const key_type &path) const;
// Get child ptree with default separator
basic_ptree<Tr> &get_child(const key_type &path);
const basic_ptree<Tr> &get_child(const key_type &path) const;
basic_ptree<Tr> &get_child(const key_type &path, basic_ptree<Tr> &default_value);
const basic_ptree<Tr> &get_child(const key_type &path, const basic_ptree<Tr> &default_value) const;
optional<basic_ptree<Tr> &> get_child_optional(const key_type &path);
optional<const basic_ptree<Tr> &> get_child_optional(const key_type &path) const;
// Put child ptree with custom separator
basic_ptree<Tr> &put_child(char_type separator, const key_type &path, const basic_ptree<Tr> &value, bool do_not_replace = false);
// Put child ptree with default separator
basic_ptree<Tr> &put_child(const key_type &path, const basic_ptree<Tr> &value, bool do_not_replace = false);
// Get value from data of ptree
template<class Type> Type get_own(const std::locale &loc = std::locale()) const;
template<class Type> Type get_own(const Type &default_value, const std::locale &loc = std::locale()) const;
template<class CharType> std::basic_string<CharType> get_own(const CharType *default_value, const std::locale &loc = std::locale()) const;
template<class Type> optional<Type> get_own_optional(const std::locale &loc = std::locale()) const;
// Get value from data of child ptree (custom path separator)
template<class Type> Type get(char_type separator, const key_type &path, const std::locale &loc = std::locale()) const;
template<class Type> Type get(char_type separator, const key_type &path, const Type &default_value, const std::locale &loc = std::locale()) const;
template<class CharType> std::basic_string<CharType> get(char_type separator, const key_type &path, const CharType *default_value, const std::locale &loc = std::locale()) const;
template<class Type> optional<Type> get_optional(char_type separator, const key_type &path, const std::locale &loc = std::locale()) const;
// Get value from data of child ptree (default path separator)
template<class Type> Type get(const key_type &path, const std::locale &loc = std::locale()) const;
template<class Type> Type get(const key_type &path, const Type &default_value, const std::locale &loc = std::locale()) const;
template<class CharType> std::basic_string<CharType> get(const key_type &path, const CharType *default_value, const std::locale &loc = std::locale()) const;
template<class Type> optional<Type> get_optional(const key_type &path, const std::locale &loc = std::locale()) const;
// Put value in data of ptree
template<class Type> void put_own(const Type &value, const std::locale &loc = std::locale());
// Put value in data of child ptree (custom path separator)
template<class Type> basic_ptree<Tr> &put(char_type separator, const key_type &path, const Type &value, bool do_not_replace = false, const std::locale &loc = std::locale());
// Put value in data of child ptree (default path separator)
template<class Type> basic_ptree<Tr> &put(const key_type &path, const Type &value, bool do_not_replace = false, const std::locale &loc = std::locale());
private:
typedef std::multimap<key_type, iterator, Tr> index_type;
struct impl;
impl *m_impl;
////////////////////////////////////////////////////////////////////////////
// Debugging
#ifdef BOOST_PROPERTY_TREE_DEBUG
private:
static boost::detail::lightweight_mutex debug_mutex; // Mutex for syncing instances counter
static size_type debug_instances_count; // Total number of instances of this ptree class
public:
static size_type debug_get_instances_count();
#endif
};
} }
#endif

View file

@ -0,0 +1,72 @@
// ----------------------------------------------------------------------------
// Copyright (C) 2002-2005 Marcin Kalicinski
//
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
//
// For more information, see www.boost.org
// ----------------------------------------------------------------------------
#ifndef BOOST_PROPERTY_TREE_DETAIL_PTREE_UTILS_HPP_INCLUDED
#define BOOST_PROPERTY_TREE_DETAIL_PTREE_UTILS_HPP_INCLUDED
#include <boost/property_tree/ptree.hpp>
#include <string>
#include <locale>
namespace boost { namespace property_tree { namespace detail
{
// Naively convert narrow string to another character type
template<class Ch>
std::basic_string<Ch> widen(const char *text)
{
std::locale loc;
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::locale loc;
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

View file

@ -0,0 +1,33 @@
// ----------------------------------------------------------------------------
// Copyright (C) 2002-2005 Marcin Kalicinski
//
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
//
// For more information, see www.boost.org
// ----------------------------------------------------------------------------
#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 &message,
const std::string &filename,
unsigned long line):
file_parser_error(message, filename, line)
{
}
};
} } }
#endif

View file

@ -0,0 +1,26 @@
// ----------------------------------------------------------------------------
// Copyright (C) 2002-2005 Marcin Kalicinski
//
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
//
// For more information, see www.boost.org
// ----------------------------------------------------------------------------
#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
{
static const int no_concat_text = 1; // Text elements should be put in separate keys, not concatenated in parent data
static const int no_comments = 2; // Comments should be omitted
inline bool validate_flags(int flags)
{
return (flags & ~(no_concat_text | no_comments)) == 0;
}
} } }
#endif

View file

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

View file

@ -0,0 +1,79 @@
// ----------------------------------------------------------------------------
// Copyright (C) 2002-2005 Marcin Kalicinski
//
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
//
// For more information, see www.boost.org
// ----------------------------------------------------------------------------
#ifndef BOOST_PROPERTY_TREE_DETAIL_XML_PARSER_READ_TINYXML_HPP_INCLUDED
#define BOOST_PROPERTY_TREE_DETAIL_XML_PARSER_READ_TINYXML_HPP_INCLUDED
#include <boost/property_tree/ptree.hpp>
#include <boost/property_tree/detail/xml_parser_error.hpp>
#include <boost/property_tree/detail/xml_parser_flags.hpp>
#include <boost/property_tree/detail/xml_parser_utils.hpp>
#define TIXML_USE_STL
#include <tinyxml.h>
namespace boost { namespace property_tree { namespace xml_parser
{
template<class Ptree>
void read_xml_node(TiXmlNode *node, Ptree &pt, int flags)
{
typedef typename Ptree::char_type Ch;
if (TiXmlElement *elem = node->ToElement())
{
Ptree &tmp = pt.push_back(std::make_pair(elem->Value(), Ptree()))->second;
for (TiXmlAttribute *attr = elem->FirstAttribute(); attr; attr = attr->Next())
tmp.put(Ch('/'), xmlattr<Ch>() + "/" + attr->Name(), attr->Value());
for (TiXmlNode *child = node->FirstChild(); child; child = child->NextSibling())
read_xml_node(child, tmp, flags);
}
else if (TiXmlText *text = node->ToText())
{
if (flags & no_concat_text)
pt.push_back(std::make_pair(xmltext<Ch>(), Ptree(text->Value())));
else
pt.data() += text->Value();
}
else if (TiXmlComment *comment = node->ToComment())
{
if (!(flags & no_comments))
pt.push_back(std::make_pair(xmlcomment<Ch>(), Ptree(comment->Value())));
}
}
template<class Ptree>
void read_xml_internal(std::basic_istream<typename Ptree::char_type> &stream,
Ptree &pt,
int flags,
const std::string &filename)
{
// Create and load document from stream
TiXmlDocument doc;
stream >> doc;
if (!stream.good())
throw xml_parser_error("read error", filename, 0);
if (doc.Error())
throw xml_parser_error(doc.ErrorDesc(), filename, doc.ErrorRow());
// Create ptree from nodes
Ptree local;
for (TiXmlNode *child = doc.FirstChild(); child; child = child->NextSibling())
read_xml_node(child, local, flags);
// Swap local and result ptrees
pt.swap(local);
}
} } }
#endif

View file

@ -0,0 +1,119 @@
// ----------------------------------------------------------------------------
// Copyright (C) 2002-2005 Marcin Kalicinski
//
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
//
// For more information, see www.boost.org
// ----------------------------------------------------------------------------
#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 <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)
{
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)
{
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;
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)
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
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,145 @@
// ----------------------------------------------------------------------------
// Copyright (C) 2002-2005 Marcin Kalicinski
//
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
//
// For more information, see www.boost.org
// ----------------------------------------------------------------------------
#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_comment(std::basic_ostream<Ch> &stream,
const std::basic_string<Ch> &s,
int indent)
{
typedef typename std::basic_string<Ch> Str;
stream << Str(4 * indent, Ch(' '));
stream << Ch('<') << Ch('!') << Ch('-') << Ch('-');
stream << s;
stream << Ch('-') << Ch('-') << Ch('>') << std::endl;
}
template<class Ch>
void write_xml_text(std::basic_ostream<Ch> &stream,
const std::basic_string<Ch> &s,
int indent,
bool separate_line)
{
typedef typename std::basic_string<Ch> Str;
if (separate_line)
stream << Str(4 * indent, Ch(' '));
stream << encode_char_entities(s);
if (separate_line)
stream << Ch('\n');
}
template<class Ptree>
void write_xml_element(std::basic_ostream<typename Ptree::char_type> &stream,
const std::basic_string<typename Ptree::char_type> &key,
const Ptree &pt,
int indent)
{
typedef typename Ptree::char_type Ch;
typedef typename std::basic_string<Ch> Str;
typedef typename Ptree::const_iterator It;
// Find if elements present
bool has_elements = false;
for (It it = pt.begin(), end = pt.end(); it != end; ++it)
if (it->first != xmlattr<Ch>() &&
it->first != xmltext<Ch>())
{
has_elements = true;
break;
}
// Write element
if (pt.data().empty() && pt.empty()) // Empty key
{
if (indent >= 0)
stream << Str(4 * indent, Ch(' ')) << Ch('<') << key <<
Ch('/') << Ch('>') << std::endl;
}
else // Nonempty key
{
// Write opening tag, attributes and data
if (indent >= 0)
{
// Write opening brace and key
stream << Str(4 * indent, Ch(' '));
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_own<std::basic_string<Ch> >() << Ch('"');
// Write closing brace
stream << Ch('>');
// Break line if needed
if (has_elements)
stream << Ch('\n');
}
// Write data text, if present
if (!pt.data().empty())
write_xml_text(stream, pt.template get_own<std::basic_string<Ch> >(), indent + 1, has_elements);
// 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_own<std::basic_string<Ch> >(), indent + 1);
else if (it->first == xmltext<Ch>())
write_xml_text(stream, it->second.template get_own<std::basic_string<Ch> >(), indent + 1, has_elements);
else
write_xml_element(stream, it->first, it->second, indent + 1);
}
// Write closing tag
if (indent >= 0)
{
if (has_elements)
stream << Str(4 * indent, Ch(' '));
stream << Ch('<') << Ch('/') << key << Ch('>') << std::endl;
}
}
}
template<class Ptree>
void write_xml_internal(std::basic_ostream<typename Ptree::char_type> &stream,
const Ptree &pt,
const std::string &filename)
{
typedef typename Ptree::char_type Ch;
typedef typename std::basic_string<Ch> Str;
stream << detail::widen<Ch>("<?xml version=\"1.0\" encoding=\"utf-8\"?>\n");
write_xml_element(stream, Str(), pt, -1);
if (!stream)
throw xml_parser_error("write error", filename, 0);
}
} } }
#endif

View file

@ -0,0 +1,77 @@
// ----------------------------------------------------------------------------
// Copyright (C) 2002-2005 Marcin Kalicinski
//
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
//
// For more information, see www.boost.org
// ----------------------------------------------------------------------------
#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_read.hpp>
#include <boost/property_tree/detail/info_parser_write.hpp>
#include <istream>
namespace boost { namespace property_tree { namespace info_parser
{
// Read info from stream
template<class Ptree>
void read_info(std::basic_istream<typename Ptree::char_type> &stream,
Ptree &pt)
{
Ptree local;
read_info_internal(stream, local, std::string(), 0);
pt.swap(local);
}
// Read info from file
template<class Ptree>
void read_info(const std::string &filename,
Ptree &pt,
const std::locale &loc = std::locale())
{
std::basic_ifstream<typename Ptree::char_type> stream(filename.c_str());
if (!stream)
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);
}
// Write info to stream
template<class Ptree>
void write_info(std::basic_ostream<typename Ptree::char_type> &stream,
const Ptree &pt)
{
write_info_internal(stream, pt, std::string());
}
// Write info to file
template<class Ptree>
void write_info(const std::string &filename,
const Ptree &pt,
const std::locale &loc = std::locale())
{
std::basic_ofstream<typename Ptree::char_type> stream(filename.c_str());
if (!stream)
throw info_parser_error("cannot open file for writing", filename, 0);
stream.imbue(loc);
write_info_internal(stream, pt, filename);
}
} } }
namespace boost { namespace property_tree
{
using info_parser::info_parser_error;
using info_parser::read_info;
using info_parser::write_info;
} }
#endif

View file

@ -0,0 +1,196 @@
// ----------------------------------------------------------------------------
// Copyright (C) 2002-2005 Marcin Kalicinski
//
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
//
// For more information, see www.boost.org
// ----------------------------------------------------------------------------
#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 <istream>
#include <string>
#include <sstream>
#include <stdexcept>
#include <locale>
namespace boost { namespace property_tree { namespace ini_parser
{
static const int skip_ini_validity_check = 1; // Skip check if ptree is a valid ini
inline bool validate_flags(int flags)
{
return (flags & ~skip_ini_validity_check) == 0;
}
//! Ini parser error
class ini_parser_error: public file_parser_error
{
public:
ini_parser_error(const std::string &message,
const std::string &filename,
unsigned long line):
file_parser_error(message, filename, line)
{
}
};
//! Read ini from stream
template<class Ptree>
void read_ini(std::basic_istream<typename Ptree::char_type> &stream,
Ptree &pt)
{
typedef typename Ptree::char_type Ch;
typedef std::basic_string<Ch> Str;
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())
throw ini_parser_error("read error", "", line_no);
// If line is non-empty
line = detail::trim(line, stream.getloc());
if (!line.empty())
{
// Comment, section or key?
if (line[0] == Ch(';'))
{
// Ignore comments
}
else if (line[0] == Ch('['))
{
typename Str::size_type end = line.find(Ch(']'));
if (end == Str::npos)
throw ini_parser_error("unmatched '['", "", line_no);
Str key = detail::trim(line.substr(1, end - 1), stream.getloc());
if (local.find(key) != local.end())
throw ini_parser_error("duplicate section name", "", line_no);
section = &local.push_back(std::make_pair(key, Ptree()))->second;
}
else
{
if (!section)
throw ini_parser_error("section expected", "", line_no);
typename Str::size_type eqpos = line.find(Ch('='));
if (eqpos == Str::npos)
throw ini_parser_error("'=' character not found in line", "", line_no);
if (eqpos == 0)
throw ini_parser_error("key expected", "", line_no);
Str key = detail::trim(line.substr(0, eqpos), stream.getloc());
Str data = detail::trim(line.substr(eqpos + 1, Str::npos), stream.getloc());
if (section->find(key) != section->end())
throw ini_parser_error("duplicate key name", "", line_no);
section->push_back(std::make_pair(key, Ptree(data)));
}
}
}
// Swap local ptree with result ptree
pt.swap(local);
}
//! Read ini from file
template<class Ptree>
void read_ini(const std::string &filename,
Ptree &pt,
const std::locale &loc = std::locale())
{
std::basic_ifstream<typename Ptree::char_type> stream(filename.c_str());
if (!stream)
throw ini_parser_error("cannot open file", filename, 0);
stream.imbue(loc);
try {
read_ini(stream, pt);
}
catch (ini_parser_error &e) {
throw ini_parser_error(e.message(), filename, e.line());
}
}
//! Write ini to stream
template<class Ptree>
void write_ini(std::basic_ostream<typename Ptree::char_type> &stream,
const Ptree &pt,
int flags = 0)
{
typedef typename Ptree::char_type Ch;
typedef std::basic_string<Ch> Str;
BOOST_ASSERT(validate_flags(flags));
// Verify if ptree is not too rich to be saved as ini
if (!(flags & skip_ini_validity_check))
for (typename Ptree::const_iterator it = pt.begin(), end = pt.end(); it != end; ++it)
{
if (!it->second.data().empty())
throw ini_parser_error("ptree has data on root level keys", "", 0);
if (pt.count(it->first) > 1)
throw ini_parser_error("duplicate section name", "", 0);
for (typename Ptree::const_iterator it2 = it->second.begin(), end2 = it->second.end(); it2 != end2; ++it2)
{
if (!it2->second.empty())
throw ini_parser_error("ptree is too deep", "", 0);
if (it->second.count(it2->first) > 1)
throw ini_parser_error("duplicate key name", "", 0);
}
}
// Write ini
for (typename Ptree::const_iterator it = pt.begin(), end = pt.end(); it != end; ++it)
{
stream << Ch('[') << it->first << Ch(']') << Ch('\n');
for (typename Ptree::const_iterator it2 = it->second.begin(), end2 = it->second.end(); it2 != end2; ++it2)
stream << it2->first << Ch('=') << it2->second.template get_own<std::basic_string<Ch> >() << Ch('\n');
}
}
// Write ini to 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::char_type> stream(filename.c_str());
if (!stream)
throw ini_parser_error("cannot open file", filename, 0);
stream.imbue(loc);
try {
write_ini(stream, pt, flags);
}
catch (ini_parser_error &e) {
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,76 @@
// ----------------------------------------------------------------------------
// Copyright (C) 2002-2005 Marcin Kalicinski
//
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
//
// For more information, see www.boost.org
// ----------------------------------------------------------------------------
#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 stream
template<class Ptree>
void read_json(std::basic_istream<typename Ptree::char_type> &stream,
Ptree &pt)
{
read_json_internal(stream, pt, std::string());
}
// Read json from file
template<class Ptree>
void read_json(const std::string &filename,
Ptree &pt,
const std::locale &loc = std::locale())
{
std::basic_ifstream<typename Ptree::char_type> stream(filename.c_str());
if (!stream)
throw json_parser_error("cannot open file", filename, 0);
stream.imbue(loc);
read_json_internal(stream, pt, filename);
}
// Write json to stream
template<class Ptree>
void write_json(std::basic_ostream<typename Ptree::char_type> &stream,
const Ptree &pt)
{
write_json_internal(stream, pt, std::string());
}
// Write json to file
template<class Ptree>
void write_json(const std::string &filename,
const Ptree &pt,
const std::locale &loc = std::locale())
{
std::basic_ofstream<typename Ptree::char_type> stream(filename.c_str());
if (!stream)
throw json_parser_error("cannot open file", filename, 0);
stream.imbue(loc);
write_json_internal(stream, pt, filename);
}
} } }
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,16 @@
// ----------------------------------------------------------------------------
// Copyright (C) 2002-2005 Marcin Kalicinski
//
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
//
// For more information, see www.boost.org
// ----------------------------------------------------------------------------
#ifndef BOOST_PROPERTY_TREE_PTREE_HPP_INCLUDED
#define BOOST_PROPERTY_TREE_PTREE_HPP_INCLUDED
#include <boost/property_tree/detail/ptree_interface.hpp>
#include <boost/property_tree/detail/ptree_implementation.hpp>
#endif

View file

@ -0,0 +1,54 @@
// ----------------------------------------------------------------------------
// Copyright (C) 2002-2005 Marcin Kalicinski
//
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
//
// For more information, see www.boost.org
// ----------------------------------------------------------------------------
#ifndef BOOST_PROPERTY_TREE_PTREE_FWD_HPP_INCLUDED
#define BOOST_PROPERTY_TREE_PTREE_FWD_HPP_INCLUDED
#include <boost/config.hpp>
namespace boost { namespace property_tree
{
////////////////////////////////////////////////////////////////////////////
// Traits
template<class Ch> struct ptree_traits;
template<class Ch> struct iptree_traits;
///////////////////////////////////////////////////////////////////////////
// Exceptions
class ptree_error;
class bad_ptree_data;
class bad_ptree_path;
///////////////////////////////////////////////////////////////////////////
// basic_ptree class template
template<class Tr> class basic_ptree;
////////////////////////////////////////////////////////////////////////////
// Typedefs
typedef basic_ptree<ptree_traits<char> > ptree; // case sensitive, narrow char
typedef basic_ptree<iptree_traits<char> > iptree; // case insensitive, narrow char
#ifndef BOOST_NO_CWCHAR
typedef basic_ptree<ptree_traits<wchar_t> > wptree; // case sensitive, wide char
typedef basic_ptree<iptree_traits<wchar_t> > wiptree; // case insensitive, wide char
#endif
///////////////////////////////////////////////////////////////////////////
// Free functions
template<class Tr> void swap(basic_ptree<Tr> &pt1, basic_ptree<Tr> &pt2);
template<class Ptree> const Ptree &empty_ptree();
} }
#endif

View file

@ -0,0 +1,520 @@
// ----------------------------------------------------------------------------
// Copyright (C) 2002-2005 Marcin Kalicinski
//
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
//
// For more information, see www.boost.org
// ----------------------------------------------------------------------------
#ifndef BOOST_PROPERTY_TREE_REGISTRY_PARSER_HPP_INCLUDED
#define BOOST_PROPERTY_TREE_REGISTRY_PARSER_HPP_INCLUDED
// Include minimal version of windows.h if not included yet
#ifndef _WINDOWS_
#ifndef NOMINMAX
#define NOMINMAX
#endif
#define STRICT
#define WIN32_LEAN_AND_MEAN
#define VC_EXTRALEAN
#define NOGDICAPMASKS
#define NOVIRTUALKEYCODES
#define NOWINMESSAGES
#define NOWINSTYLES
#define NOSYSMETRICS
#define NOMENUS
#define NOICONS
#define NOKEYSTATES
#define NOSYSCOMMANDS
#define NORASTEROPS
#define NOSHOWWINDOW
#define OEMRESOURCE
#define NOATOM
#define NOCLIPBOARD
#define NOCOLOR
#define NOCTLMGR
#define NODRAWTEXT
#define NOGDI
#define NOKERNEL
#define NOUSER
#define NONLS
#define NOMB
#define NOMEMMGR
#define NOMETAFILE
#define NOMSG
#define NOOPENFILE
#define NOSCROLL
#define NOSERVICE
#define NOSOUND
#define NOTEXTMETRIC
#define NOWH
#define NOWINOFFSETS
#define NOCOMM
#define NOKANJI
#define NOHELP
#define NOPROFILER
#define NODEFERWINDOWPOS
#define NOMCX
#include <windows.h>
#endif
#include <boost/property_tree/ptree.hpp>
#include <boost/property_tree/detail/ptree_utils.hpp>
#include <boost/cstdint.hpp> // for 64 bit int
#include <sstream>
#include <iomanip>
#include <string>
#include <vector>
#include <stdexcept>
namespace boost { namespace property_tree { namespace registry_parser
{
//! Registry parser error
class registry_parser_error: public ptree_error
{
public:
// Construct error
registry_parser_error(const std::string &message, DWORD windows_error):
ptree_error(format_what(message, windows_error)),
m_windows_error(windows_error)
{
}
// Get windows error
DWORD windows_error()
{
return m_windows_error;
}
private:
DWORD m_windows_error;
// Format error message to be returned by std::runtime_error::what()
std::string format_what(const std::string &message,
DWORD windows_error)
{
std::stringstream stream;
if (windows_error)
stream << message << " (windows error 0x" << std::hex << windows_error << ")";
else
stream << message;
return stream.str();
}
};
// Translate from binary buffer to string
template<class Ch>
std::basic_string<Ch> translate(DWORD type, const std::vector<BYTE> &data)
{
typedef std::basic_string<Ch> Str;
typedef std::basic_stringstream<Ch> Stream;
Str value;
switch (type)
{
// No data
case REG_NONE:
break;
// Binary data
case REG_BINARY:
if (!data.empty())
{
Stream stream;
stream << std::hex << std::setfill(Ch('0'));
for (std::vector<BYTE>::const_iterator it = data.begin(), end = data.end();
it != end; ++it)
stream << std::setw(2) << static_cast<int>(*it) << Ch(' ');
value = stream.str();
value.resize(value.size() - 1); // remove final space
}
break;
// DWORD value
case REG_DWORD:
if (!data.empty())
{
Stream stream;
stream << *reinterpret_cast<const DWORD *>(&data.front());
value = stream.str();
}
break;
// QWORD value
case REG_QWORD:
if (!data.empty())
{
Stream stream;
stream << *reinterpret_cast<const boost::uint64_t *>(&data.front());
value = stream.str();
}
break;
// Zero terminated string
case REG_SZ: case REG_EXPAND_SZ:
if (!data.empty())
value.assign(reinterpret_cast<const Ch *>(&data.front()));
break;
// Unknown data type
default:
throw registry_parser_error("unsupported data type", 0);
};
return value;
}
// Translate from string to binary buffer
template<class Ch>
std::vector<BYTE> translate(DWORD type, const std::basic_string<Ch> &s)
{
typedef std::basic_string<Ch> Str;
typedef std::basic_stringstream<Ch> Stream;
std::vector<BYTE> data;
switch (type)
{
// No data
case REG_NONE:
break;
// Binary data
case REG_BINARY:
{
int v;
Stream stream(s);
stream >> std::hex;
while (1)
{
stream >> v >> std::ws;
if (stream.fail() || stream.bad())
throw registry_parser_error("bad REG_BINARY value", 0);
data.push_back(v);
if (stream.eof())
break;
}
}
break;
// DWORD value
case REG_DWORD:
{
DWORD v;
Stream stream(s);
stream >> v >> std::ws;
if (!stream.eof() || stream.fail() || stream.bad())
throw registry_parser_error("bad REG_DWORD value", 0);
for (size_t i = 0; i < sizeof(v); ++i)
data.push_back(*(reinterpret_cast<BYTE *>(&v) + i));
}
break;
// QWORD value
case REG_QWORD:
{
boost::uint64_t v;
Stream stream(s);
stream >> v;
if (!stream.eof() || stream.fail() || stream.bad())
throw registry_parser_error("bad REG_QWORD value", 0);
for (size_t i = 0; i < sizeof(v); ++i)
data.push_back(*(reinterpret_cast<BYTE *>(&v) + i));
}
break;
// Zero terminated string
case REG_SZ: case REG_EXPAND_SZ:
{
const Ch *sz = s.c_str();
size_t len = (s.size() + 1) * sizeof(Ch);
for (size_t i = 0; i < len; ++i)
data.push_back(*(reinterpret_cast<const BYTE *>(sz) + i));
}
break;
// Unknown data type
default:
throw registry_parser_error("unsupported data type", 0);
};
return data;
}
/////////////////////////////////////////////////////////////////////////////
// Registry functions wrappers
template<class Ch>
inline LONG reg_create_key_ex(HKEY hkey, const Ch *subkey, REGSAM sam, HKEY *result);
template<>
inline LONG reg_create_key_ex<char>(HKEY hkey, const char *subkey, REGSAM sam, HKEY *result)
{
return RegCreateKeyExA(hkey, subkey, 0, NULL, REG_OPTION_NON_VOLATILE, sam, NULL, result, NULL);
}
template<>
inline LONG reg_create_key_ex<wchar_t>(HKEY hkey, const wchar_t *subkey, REGSAM sam, HKEY *result)
{
return RegCreateKeyExW(hkey, subkey, 0, NULL, REG_OPTION_NON_VOLATILE, sam, NULL, result, NULL);
}
template<class Ch>
inline LONG reg_set_value_ex(HKEY hkey, const Ch *name, DWORD type, const BYTE *data, DWORD size);
template<>
inline LONG reg_set_value_ex<char>(HKEY hkey, const char *name, DWORD type, const BYTE *data, DWORD size)
{
return RegSetValueExA(hkey, name, 0, type, data, size);
}
template<>
inline LONG reg_set_value_ex<wchar_t>(HKEY hkey, const wchar_t *name, DWORD type, const BYTE *data, DWORD size)
{
return RegSetValueExW(hkey, name, 0, type, data, size);
}
template<class Ch>
inline LONG reg_open_key_ex(HKEY hkey, const Ch *subkey, REGSAM sam, HKEY *result);
template<>
inline LONG reg_open_key_ex<char>(HKEY hkey, const char *subkey, REGSAM sam, HKEY *result)
{
return RegOpenKeyExA(hkey, subkey, 0, sam, result);
}
template<>
inline LONG reg_open_key_ex<wchar_t>(HKEY hkey, const wchar_t *subkey, REGSAM sam, HKEY *result)
{
return RegOpenKeyExW(hkey, subkey, 0, sam, result);
}
template<class Ch>
inline LONG reg_enum_key_ex(HKEY hkey, DWORD index, Ch *name, DWORD *size);
template<>
inline LONG reg_enum_key_ex<char>(HKEY hkey, DWORD index, char *name, DWORD *size)
{
FILETIME ft;
return RegEnumKeyExA(hkey, index, name, size, 0, NULL, NULL, &ft);
}
template<>
inline LONG reg_enum_key_ex<wchar_t>(HKEY hkey, DWORD index, wchar_t *name, DWORD *size)
{
FILETIME ft;
return RegEnumKeyExW(hkey, index, name, size, 0, NULL, NULL, &ft);
}
template<class Ch>
inline LONG reg_enum_value(HKEY hkey, DWORD index, Ch *name, DWORD *name_size, DWORD *type, BYTE *data, DWORD *data_size);
template<>
inline LONG reg_enum_value<char>(HKEY hkey, DWORD index, char *name, DWORD *name_size, DWORD *type, BYTE *data, DWORD *data_size)
{
return RegEnumValueA(hkey, index, name, name_size, NULL, type, data, data_size);
}
template<>
inline LONG reg_enum_value<wchar_t>(HKEY hkey, DWORD index, wchar_t *name, DWORD *name_size, DWORD *type, BYTE *data, DWORD *data_size)
{
return RegEnumValueW(hkey, index, name, name_size, NULL, type, data, data_size);
}
template<class Ch>
inline LONG reg_query_info_key(HKEY hkey, DWORD *max_subkey_len, DWORD *max_name_len, DWORD *max_value_len);
template<>
inline LONG reg_query_info_key<char>(HKEY hkey, DWORD *max_subkey_len, DWORD *max_name_len, DWORD *max_value_len)
{
return RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, max_subkey_len, NULL, NULL, max_name_len, max_value_len, NULL, NULL);
}
template<>
inline LONG reg_query_info_key<wchar_t>(HKEY hkey, DWORD *max_subkey_len, DWORD *max_name_len, DWORD *max_value_len)
{
return RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, max_subkey_len, NULL, NULL, max_name_len, max_value_len, NULL, NULL);
}
/////////////////////////////////////////////////////////////////////////////
// Registry key handle wrapper
template<class Ch>
class reg_key
{
public:
typedef std::basic_string<Ch> Str;
reg_key(HKEY root, const std::basic_string<Ch> &key, bool create):
hkey(0)
{
if (create)
{
LONG result = reg_create_key_ex(root, key.c_str(), KEY_WRITE, &hkey);
if (result != ERROR_SUCCESS)
throw registry_parser_error("RegCreateKeyEx failed", result);
}
else
{
LONG result = reg_open_key_ex(root, key.c_str(), KEY_READ, &hkey);
if (result != ERROR_SUCCESS)
throw registry_parser_error("RegOpenKeyEx failed", result);
}
BOOST_ASSERT(hkey);
}
~reg_key()
{
BOOST_ASSERT(hkey);
RegCloseKey(hkey);
}
HKEY handle()
{
BOOST_ASSERT(hkey);
return hkey;
}
private:
HKEY hkey;
};
/////////////////////////////////////////////////////////////////////////////
// Registry parser
//! Read registry
template<class Ptree>
void read_registry(HKEY root,
const std::basic_string<typename Ptree::char_type> &key,
Ptree &pt)
{
typedef typename Ptree::char_type Ch;
typedef std::basic_string<Ch> Str;
typedef std::basic_stringstream<Ch> Stream;
Ptree local;
// Open key
reg_key<Ch> rk(root, key, false);
// Query key info
DWORD max_subkey_len, max_name_len, max_value_len;
LONG result = reg_query_info_key<Ch>(rk.handle(), &max_subkey_len, &max_name_len, &max_value_len);
if (result != ERROR_SUCCESS)
throw registry_parser_error("RegQueryInfoKey failed", result);
// For all subkeys
std::vector<Ch> subkey(max_subkey_len + 1);
for (DWORD index = 0; true; ++index)
{
// Get subkey name
DWORD size = static_cast<DWORD>(subkey.size());
LONG result = reg_enum_key_ex(rk.handle(), index, &subkey.front(), &size);
if (result == ERROR_NO_MORE_ITEMS)
break;
if (result != ERROR_SUCCESS)
throw registry_parser_error("RegEnumKeyEx failed", result);
// Parse recursively
Ptree &child = local.push_back(typename Ptree::value_type(&subkey.front(), Ptree()))->second;
read_registry<Ptree>(rk.handle(), &subkey.front(), child);
}
// For all values
for (DWORD index = 0; true; ++index)
{
// Resize data to max size
std::vector<Ch> name(max_name_len + 1);
std::vector<BYTE> data(max_value_len + 1);
// Get name and value from registry
DWORD name_size = static_cast<DWORD>(name.size());
DWORD data_size = static_cast<DWORD>(data.size());
DWORD type;
result = reg_enum_value<Ch>(rk.handle(), index, &name.front(), &name_size, &type, &data.front(), &data_size);
if (result == ERROR_NO_MORE_ITEMS)
break;
if (result != ERROR_SUCCESS)
throw registry_parser_error("RegEnumValue failed", result);
// Truncate data to actual size
name.resize(name_size + 1);
data.resize(data_size);
// Translate and put value in tree
Str value = translate<Ch>(type, data);
if (name_size > 0)
{
local.put(Str(detail::widen<Ch>("\\values.") + &name.front()), value);
local.put(Str(detail::widen<Ch>("\\types.") + &name.front()), type);
}
else
local.data() = value;
}
// Swap pt and local
pt.swap(local);
}
//! Write registry
template<class Ptree>
void write_registry(HKEY root,
const std::basic_string<typename Ptree::char_type> &key,
const Ptree &pt)
{
typedef typename Ptree::char_type Ch;
typedef std::basic_string<Ch> Str;
typedef std::basic_stringstream<Ch> Stream;
// Create key
reg_key<Ch> rk(root, key, true);
// Set default key value
if (!pt.data().empty())
{
std::vector<BYTE> data = translate<Ch>(REG_SZ, pt.data());
reg_set_value_ex<Ch>(rk.handle(), NULL, REG_SZ,
data.empty() ? NULL : &data.front(),
static_cast<DWORD>(data.size()));
}
// Create values
const Ptree &values = pt.get_child(detail::widen<Ch>("\\values"), empty_ptree<Ptree>());
const Ptree &types = pt.get_child(detail::widen<Ch>("\\types"), empty_ptree<Ptree>());
for (typename Ptree::const_iterator it = values.begin(), end = values.end(); it != end; ++it)
{
DWORD type = types.get(it->first, REG_SZ);
std::vector<BYTE> data = translate<Ch>(type, it->second.data());
reg_set_value_ex<Ch>(rk.handle(), it->first.c_str(), type,
data.empty() ? NULL : &data.front(),
static_cast<DWORD>(data.size()));
}
// Create subkeys
for (typename Ptree::const_iterator it = pt.begin(), end = pt.end(); it != end; ++it)
if (&it->second != &values && &it->second != &types)
write_registry(rk.handle(), it->first, it->second);
}
} } }
namespace boost { namespace property_tree
{
using registry_parser::read_registry;
using registry_parser::write_registry;
using registry_parser::registry_parser_error;
} }
#endif

View file

@ -0,0 +1,86 @@
// ----------------------------------------------------------------------------
// Copyright (C) 2002-2005 Marcin Kalicinski
//
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
//
// For more information, see www.boost.org
// ----------------------------------------------------------------------------
#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_flags.hpp>
// Include proper parser
#ifdef BOOST_PROPERTY_TREE_XML_PARSER_TINYXML
#include <boost/property_tree/detail/xml_parser_read_tinyxml.hpp>
#else
#include <boost/property_tree/detail/xml_parser_read_spirit.hpp>
#endif
#include <fstream>
#include <string>
#include <locale>
namespace boost { namespace property_tree { namespace xml_parser
{
// Read XML from stream
template<class Ptree>
void read_xml(std::basic_istream<typename Ptree::char_type> &stream,
Ptree &pt,
int flags = 0)
{
read_xml_internal(stream, pt, flags, std::string());
}
// Read XML from file
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::char_type> stream(filename.c_str());
if (!stream)
throw xml_parser_error("cannot open file", filename, 0);
stream.imbue(loc);
read_xml_internal(stream, pt, flags, filename);
}
// Write XML to stream
template<class Ptree>
void write_xml(std::basic_ostream<typename Ptree::char_type> &stream,
const Ptree &pt)
{
write_xml_internal(stream, pt, std::string());
}
// Write XML to file
template<class Ptree>
void write_xml(const std::string &filename,
const Ptree &pt,
const std::locale &loc = std::locale())
{
std::basic_ofstream<typename Ptree::char_type> stream(filename.c_str());
if (!stream)
throw xml_parser_error("cannot open file", filename, 0);
stream.imbue(loc);
write_xml_internal(stream, pt, filename);
}
} } }
namespace boost { namespace property_tree
{
using xml_parser::read_xml;
using xml_parser::write_xml;
using xml_parser::xml_parser_error;
} }
#endif