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:
parent
8328424af5
commit
efdc5d6f08
25 changed files with 4671 additions and 0 deletions
85
boost/property_tree/cmdline_parser.hpp
Normal file
85
boost/property_tree/cmdline_parser.hpp
Normal 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
|
88
boost/property_tree/detail/file_parser_error.hpp
Normal file
88
boost/property_tree/detail/file_parser_error.hpp
Normal 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
|
32
boost/property_tree/detail/info_parser_error.hpp
Normal file
32
boost/property_tree/detail/info_parser_error.hpp
Normal 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
|
369
boost/property_tree/detail/info_parser_read.hpp
Normal file
369
boost/property_tree/detail/info_parser_read.hpp
Normal 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
|
32
boost/property_tree/detail/info_parser_utils.hpp
Normal file
32
boost/property_tree/detail/info_parser_utils.hpp
Normal 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
|
131
boost/property_tree/detail/info_parser_write.hpp
Normal file
131
boost/property_tree/detail/info_parser_write.hpp
Normal 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
|
33
boost/property_tree/detail/json_parser_error.hpp
Normal file
33
boost/property_tree/detail/json_parser_error.hpp
Normal 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
|
316
boost/property_tree/detail/json_parser_read.hpp
Normal file
316
boost/property_tree/detail/json_parser_read.hpp
Normal 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
|
163
boost/property_tree/detail/json_parser_write.hpp
Normal file
163
boost/property_tree/detail/json_parser_write.hpp
Normal 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
|
996
boost/property_tree/detail/ptree_implementation.hpp
Normal file
996
boost/property_tree/detail/ptree_implementation.hpp
Normal 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
|
198
boost/property_tree/detail/ptree_interface.hpp
Normal file
198
boost/property_tree/detail/ptree_interface.hpp
Normal 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
|
72
boost/property_tree/detail/ptree_utils.hpp
Normal file
72
boost/property_tree/detail/ptree_utils.hpp
Normal 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
|
33
boost/property_tree/detail/xml_parser_error.hpp
Normal file
33
boost/property_tree/detail/xml_parser_error.hpp
Normal 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
|
26
boost/property_tree/detail/xml_parser_flags.hpp
Normal file
26
boost/property_tree/detail/xml_parser_flags.hpp
Normal 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
|
729
boost/property_tree/detail/xml_parser_read_spirit.hpp
Normal file
729
boost/property_tree/detail/xml_parser_read_spirit.hpp
Normal 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
|
79
boost/property_tree/detail/xml_parser_read_tinyxml.hpp
Normal file
79
boost/property_tree/detail/xml_parser_read_tinyxml.hpp
Normal 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
|
119
boost/property_tree/detail/xml_parser_utils.hpp
Normal file
119
boost/property_tree/detail/xml_parser_utils.hpp
Normal 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>("<"); break;
|
||||
case Ch('>'): r += detail::widen<Ch>(">"); break;
|
||||
case Ch('&'): r += detail::widen<Ch>("&"); 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
|
145
boost/property_tree/detail/xml_parser_write.hpp
Normal file
145
boost/property_tree/detail/xml_parser_write.hpp
Normal 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
|
77
boost/property_tree/info_parser.hpp
Normal file
77
boost/property_tree/info_parser.hpp
Normal 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
|
196
boost/property_tree/ini_parser.hpp
Normal file
196
boost/property_tree/ini_parser.hpp
Normal 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
|
76
boost/property_tree/json_parser.hpp
Normal file
76
boost/property_tree/json_parser.hpp
Normal 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
|
16
boost/property_tree/ptree.hpp
Normal file
16
boost/property_tree/ptree.hpp
Normal 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
|
54
boost/property_tree/ptree_fwd.hpp
Normal file
54
boost/property_tree/ptree_fwd.hpp
Normal 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
|
520
boost/property_tree/registry_parser.hpp
Normal file
520
boost/property_tree/registry_parser.hpp
Normal 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
|
86
boost/property_tree/xml_parser.hpp
Normal file
86
boost/property_tree/xml_parser.hpp
Normal 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
|
Loading…
Reference in a new issue