blob: 312cd5260bc984ba975b5a887c0923975e01687f [file] [log] [blame]
/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
// basic_xml_grammar.ipp:
// (C) Copyright 2002 Robert Ramey - http://www.rrsd.com .
// Use, modification and distribution is subject to 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)
// See http://www.boost.org for updates, documentation, and revision history.
#if (defined _MSC_VER) && (_MSC_VER == 1200)
# pragma warning (disable : 4786) // too long name, harmless warning
#endif
#include <istream>
#include <algorithm>
#include <boost/config.hpp> // BOOST_DEDUCED_TYPENAME
#ifdef BOOST_MSVC
# pragma warning(push)
# pragma warning(disable : 4511 4512)
#endif
// spirit stuff
#include <boost/spirit/core/composite/operators.hpp>
#include <boost/spirit/core/composite/actions.hpp>
#include <boost/spirit/core/primitives/numerics.hpp>
#ifdef BOOST_MSVC
#pragma warning(pop)
#endif
// for head_iterator test
//#include <boost/bind.hpp>
#include <boost/function.hpp>
#include <boost/serialization/pfto.hpp>
#include <boost/io/ios_state.hpp>
#include <boost/serialization/throw_exception.hpp>
#include <boost/archive/impl/basic_xml_grammar.hpp>
#include <boost/archive/xml_archive_exception.hpp>
#include <boost/archive/basic_xml_archive.hpp>
#include <boost/archive/iterators/xml_unescape.hpp>
using namespace boost::spirit;
namespace boost {
namespace archive {
/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
// template code for basic_xml_grammar of both wchar_t and char types
namespace xml { // anonymous
#ifdef BOOST_MSVC
# pragma warning(push)
# pragma warning(disable : 4511 4512)
#endif
template<class T>
struct assign_impl {
T & t;
void operator()(const T t_) const {
t = t_;
}
assign_impl(T & t_)
: t(t_)
{}
};
template<>
struct assign_impl<std::string> {
std::string & t;
void operator()(
std::string::const_iterator b,
std::string::const_iterator e
) const {
t.resize(0);
while(b != e){
t += * b;
++b;
}
}
assign_impl<std::string> & operator=(
assign_impl<std::string> & rhs
);
assign_impl(std::string & t_)
: t(t_)
{}
};
#ifndef BOOST_NO_STD_WSTRING
template<>
struct assign_impl<std::wstring> {
std::wstring & t;
void operator()(
std::wstring::const_iterator b,
std::wstring::const_iterator e
) const {
t.resize(0);
while(b != e){
t += * b;
++b;
}
}
assign_impl(std::wstring & t_)
: t(t_)
{}
};
#endif
template<class T>
assign_impl<T> assign_object(T &t){
return assign_impl<T>(t);
}
struct assign_level {
tracking_type & tracking_level;
void operator()(const unsigned int tracking_level_) const {
tracking_level = (0 == tracking_level_) ? false : true;
}
assign_level(tracking_type & tracking_level_)
: tracking_level(tracking_level_)
{}
};
template<class String, class Iterator>
struct append_string {
String & contents;
void operator()(Iterator start, Iterator end) const {
#if 0
typedef boost::archive::iterators::xml_unescape<Iterator> translator;
contents.append(
translator(BOOST_MAKE_PFTO_WRAPPER(start)),
translator(BOOST_MAKE_PFTO_WRAPPER(end))
);
#endif
contents.append(start, end);
}
append_string(String & contents_)
: contents(contents_)
{}
};
template<class String>
struct append_char {
String & contents;
void operator()(const unsigned int char_value) const {
const BOOST_DEDUCED_TYPENAME String::value_type z = char_value;
contents += z;
}
append_char(String & contents_)
: contents(contents_)
{}
};
template<class String, unsigned int c>
struct append_lit {
String & contents;
template<class X, class Y>
void operator()(const X & /*x*/, const Y & /*y*/) const {
const BOOST_DEDUCED_TYPENAME String::value_type z = c;
contents += z;
}
append_lit(String & contents_)
: contents(contents_)
{}
};
#ifdef BOOST_MSVC
#pragma warning(pop)
#endif
} // namespace anonymous
template<class CharType>
bool basic_xml_grammar<CharType>::my_parse(
BOOST_DEDUCED_TYPENAME basic_xml_grammar<CharType>::IStream & is,
const rule_t & rule_,
CharType delimiter
) const {
if(is.fail()){
boost::serialization::throw_exception(
archive_exception(archive_exception::input_stream_error)
);
}
boost::io::ios_flags_saver ifs(is);
is >> std::noskipws;
std::basic_string<CharType> arg;
CharType val;
do{
BOOST_DEDUCED_TYPENAME basic_xml_grammar<CharType>::IStream::int_type
result = is.get();
if(is.fail())
return false;
val = static_cast<CharType>(result);
arg += val;
}
while(val != delimiter);
// read just one more character. This will be the newline after the tag
// this is so that the next operation will return fail if the archive
// is terminated. This will permit the archive to be used for debug
// and transaction data logging in the standard way.
parse_info<BOOST_DEDUCED_TYPENAME std::basic_string<CharType>::iterator>
result = boost::spirit::parse(arg.begin(), arg.end(), rule_);
return result.hit;
}
template<class CharType>
bool basic_xml_grammar<CharType>::parse_start_tag(
BOOST_DEDUCED_TYPENAME basic_xml_grammar<CharType>::IStream & is
){
rv.class_name.resize(0);
return my_parse(is, STag);
}
template<class CharType>
bool basic_xml_grammar<CharType>::parse_end_tag(IStream & is) const {
return my_parse(is, ETag);
}
template<class CharType>
bool basic_xml_grammar<CharType>::parse_string(IStream & is, StringType & s){
rv.contents.resize(0);
bool result = my_parse(is, content, '<');
// note: unget caused a problem with dinkumware. replace with
// is.unget();
// putback another dilimiter instead
is.putback('<');
if(result)
s = rv.contents;
return result;
}
template<class CharType>
basic_xml_grammar<CharType>::basic_xml_grammar(){
init_chset();
S =
+(Sch)
;
// refactoring to workaround template depth on darwin
NameHead = (Letter | '_' | ':');
NameTail = *NameChar ;
Name =
NameHead >> NameTail
;
Eq =
!S >> '=' >> !S
;
AttributeList =
*(S >> Attribute)
;
STag =
!S
>> '<'
>> Name [xml::assign_object(rv.object_name)]
>> AttributeList
>> !S
>> '>'
;
ETag =
!S
>> "</"
>> Name [xml::assign_object(rv.object_name)]
>> !S
>> '>'
;
// refactoring to workaround template depth on darwin
CharDataChars = +(anychar_p - chset_p(L"&<"));
CharData =
CharDataChars [
xml::append_string<
StringType,
BOOST_DEDUCED_TYPENAME std::basic_string<CharType>::const_iterator
>(rv.contents)
]
;
// slight factoring works around ICE in msvc 6.0
CharRef1 =
str_p(L"&#") >> uint_p [xml::append_char<StringType>(rv.contents)] >> L';'
;
CharRef2 =
str_p(L"&#x") >> hex_p [xml::append_char<StringType>(rv.contents)] >> L';'
;
CharRef = CharRef1 | CharRef2 ;
AmpRef = str_p(L"&amp;")[xml::append_lit<StringType, L'&'>(rv.contents)];
LTRef = str_p(L"&lt;")[xml::append_lit<StringType, L'<'>(rv.contents)];
GTRef = str_p(L"&gt;")[xml::append_lit<StringType, L'>'>(rv.contents)];
AposRef = str_p(L"&apos;")[xml::append_lit<StringType, L'\''>(rv.contents)];
QuoteRef = str_p(L"&quot;")[xml::append_lit<StringType, L'"'>(rv.contents)];
Reference =
AmpRef
| LTRef
| GTRef
| AposRef
| QuoteRef
| CharRef
;
content =
L"<" // should be end_p
| +(Reference | CharData) >> L"<"
;
ClassIDAttribute =
str_p(BOOST_ARCHIVE_XML_CLASS_ID()) >> NameTail
>> Eq
>> L'"'
>> int_p [xml::assign_object(rv.class_id)]
>> L'"'
;
ObjectIDAttribute = (
str_p(BOOST_ARCHIVE_XML_OBJECT_ID())
|
str_p(BOOST_ARCHIVE_XML_OBJECT_REFERENCE())
)
>> NameTail
>> Eq
>> L'"'
>> L'_'
>> uint_p [xml::assign_object(rv.object_id)]
>> L'"'
;
AmpName = str_p(L"&amp;")[xml::append_lit<StringType, L'&'>(rv.class_name)];
LTName = str_p(L"&lt;")[xml::append_lit<StringType, L'<'>(rv.class_name)];
GTName = str_p(L"&gt;")[xml::append_lit<StringType, L'>'>(rv.class_name)];
ClassNameChar =
AmpName
| LTName
| GTName
| (anychar_p - chset_p(L"\"")) [xml::append_char<StringType>(rv.class_name)]
;
ClassName =
* ClassNameChar
;
ClassNameAttribute =
str_p(BOOST_ARCHIVE_XML_CLASS_NAME())
>> Eq
>> L'"'
>> ClassName
>> L'"'
;
TrackingAttribute =
str_p(BOOST_ARCHIVE_XML_TRACKING())
>> Eq
>> L'"'
>> uint_p [xml::assign_level(rv.tracking_level)]
>> L'"'
;
VersionAttribute =
str_p(BOOST_ARCHIVE_XML_VERSION())
>> Eq
>> L'"'
>> uint_p [xml::assign_object(rv.version)]
>> L'"'
;
UnusedAttribute =
Name
>> Eq
>> L'"'
>> !CharData
>> L'"'
;
Attribute =
ClassIDAttribute
| ObjectIDAttribute
| ClassNameAttribute
| TrackingAttribute
| VersionAttribute
| UnusedAttribute
;
XMLDeclChars = *(anychar_p - chset_p(L"?>"));
XMLDecl =
!S
>> str_p(L"<?xml")
>> S
>> str_p(L"version")
>> Eq
>> str_p(L"\"1.0\"")
>> XMLDeclChars
>> !S
>> str_p(L"?>")
;
DocTypeDeclChars = *(anychar_p - chset_p(L">"));
DocTypeDecl =
!S
>> str_p(L"<!DOCTYPE")
>> DocTypeDeclChars
>> L'>'
;
SignatureAttribute =
str_p(L"signature")
>> Eq
>> L'"'
>> Name [xml::assign_object(rv.class_name)]
>> L'"'
;
SerializationWrapper =
!S
>> str_p(L"<boost_serialization")
>> S
>> SignatureAttribute
>> S
>> VersionAttribute
>> !S
>> L'>'
;
}
template<class CharType>
void basic_xml_grammar<CharType>::init(IStream & is){
init_chset();
if(! my_parse(is, XMLDecl))
boost::serialization::throw_exception(
xml_archive_exception(xml_archive_exception::xml_archive_parsing_error)
);
if(! my_parse(is, DocTypeDecl))
boost::serialization::throw_exception(
xml_archive_exception(xml_archive_exception::xml_archive_parsing_error)
);
if(! my_parse(is, SerializationWrapper))
boost::serialization::throw_exception(
xml_archive_exception(xml_archive_exception::xml_archive_parsing_error)
);
if(! std::equal(rv.class_name.begin(), rv.class_name.end(), BOOST_ARCHIVE_SIGNATURE()))
boost::serialization::throw_exception(
archive_exception(archive_exception::invalid_signature)
);
}
template<class CharType>
void basic_xml_grammar<CharType>::windup(IStream & is){
if(is.fail())
return;
// uh-oh - don't throw exception from code called by a destructor !
// so just ignore any failure.
my_parse(is, ETag);
}
} // namespace archive
} // namespace boost