mirror of
https://github.com/boostorg/serialization.git
synced 2026-01-26 19:12:08 +00:00
422 lines
9.9 KiB
C++
422 lines
9.9 KiB
C++
/////////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
|
|
|
|
// spirit stuff
|
|
#include <boost/spirit/core/composite/operators.hpp>
|
|
#include <boost/spirit/core/composite/actions.hpp>
|
|
#include <boost/spirit/core/primitives/numerics.hpp>
|
|
|
|
// for head_iterator test
|
|
#include <boost/bind.hpp>
|
|
#include <boost/function.hpp>
|
|
|
|
#include <boost/io/ios_state.hpp>
|
|
#include <boost/throw_exception.hpp>
|
|
#include <boost/archive/impl/basic_xml_grammar.hpp>
|
|
#include <boost/archive/basic_xml_archive.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 { // anonymous
|
|
|
|
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 & 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_obect(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 {
|
|
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 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 typename String::value_type z = c;
|
|
contents += z;
|
|
}
|
|
append_lit(String & contents_)
|
|
: contents(contents_)
|
|
{}
|
|
};
|
|
|
|
} // 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
|
|
){
|
|
if(is.fail()){
|
|
boost::throw_exception(
|
|
archive_exception(archive_exception::stream_error)
|
|
);
|
|
}
|
|
|
|
boost::io::ios_flags_saver ifs(is);
|
|
is >> std::noskipws;
|
|
|
|
std::basic_string<CharType> arg;
|
|
|
|
CharType val;
|
|
do{
|
|
val = is.get();
|
|
arg += val;
|
|
if(is.fail())
|
|
return false;
|
|
}
|
|
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
|
|
) {
|
|
if(is.fail()){
|
|
boost::throw_exception(
|
|
archive_exception(archive_exception::stream_error)
|
|
);
|
|
}
|
|
return my_parse(is, STag);
|
|
}
|
|
|
|
template<class CharType>
|
|
bool basic_xml_grammar<CharType>::parse_end_tag(IStream & is) {
|
|
if(is.fail()){
|
|
boost::throw_exception(
|
|
archive_exception(archive_exception::stream_error)
|
|
);
|
|
}
|
|
return my_parse(is, ETag);
|
|
}
|
|
|
|
template<class CharType>
|
|
bool basic_xml_grammar<CharType>::parse_string(IStream & is, StringType & s) {
|
|
if(is.fail()){
|
|
boost::throw_exception(
|
|
archive_exception(archive_exception::stream_error)
|
|
);
|
|
}
|
|
rv.contents.resize(0);
|
|
bool result = my_parse(is, CharData, '<');
|
|
// 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)
|
|
;
|
|
Name =
|
|
(Letter | '_' | ':')
|
|
>> *(NameChar)
|
|
;
|
|
|
|
|
|
Eq =
|
|
!S >> '=' >> !S
|
|
;
|
|
|
|
STag =
|
|
!S
|
|
>> '<'
|
|
>> Name [assign_obect(rv.object_name)]
|
|
>> *(S >> Attribute)
|
|
>> !S
|
|
>> '>'
|
|
;
|
|
|
|
ETag =
|
|
!S
|
|
>> "</"
|
|
>> Name [assign_obect(rv.object_name)]
|
|
>> !S
|
|
>> '>'
|
|
;
|
|
|
|
CharData =
|
|
(*(anychar_p - chset_p(L"&<"))) [
|
|
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 [append_char<StringType>(rv.contents)] >> L';'
|
|
;
|
|
CharRef2 =
|
|
str_p(L"&#x") >> hex_p [append_char<StringType>(rv.contents)] >> L';'
|
|
;
|
|
CharRef = CharRef1 | CharRef2 ;
|
|
|
|
AmpRef = str_p(L"&")[append_lit<StringType, '&'>(rv.contents)];
|
|
LTRef = str_p(L"<")[append_lit<StringType, '<'>(rv.contents)];
|
|
GTRef = str_p(L">")[append_lit<StringType, '>'>(rv.contents)];
|
|
AposRef = str_p(L"'")[append_lit<StringType, '\''>(rv.contents)];
|
|
QuoteRef = str_p(L""")[append_lit<StringType, '"'>(rv.contents)];
|
|
|
|
Reference =
|
|
AmpRef
|
|
| LTRef
|
|
| GTRef
|
|
| AposRef
|
|
| QuoteRef
|
|
| CharRef
|
|
;
|
|
|
|
content =
|
|
!CharData
|
|
>> *(Reference >> !CharData)
|
|
;
|
|
|
|
ClassIDAttribute =
|
|
str_p(CLASS_ID) >> *(NameChar)
|
|
>> Eq
|
|
>> L'"'
|
|
>> int_p [assign_obect(rv.class_id.t)]
|
|
>> L'"'
|
|
;
|
|
|
|
ObjectIDAttribute =
|
|
( str_p(OBJECT_ID) | str_p(OBJECT_REFERENCE) )
|
|
>> *(NameChar)
|
|
>> Eq
|
|
>> L'"'
|
|
>> L'_'
|
|
>> uint_p [assign_obect(rv.object_id.t)]
|
|
>> L'"'
|
|
;
|
|
|
|
ClassNameAttribute =
|
|
str_p(CLASS_NAME)
|
|
>> Eq
|
|
>> L'"'
|
|
>> Name [assign_obect(rv.class_name)]
|
|
>> L'"'
|
|
;
|
|
|
|
TrackingAttribute =
|
|
str_p(TRACKING)
|
|
>> Eq
|
|
>> L'"'
|
|
>> uint_p [assign_level(rv.tracking_level)]
|
|
>> L'"'
|
|
;
|
|
|
|
VersionAttribute =
|
|
str_p(VERSION)
|
|
>> Eq
|
|
>> L'"'
|
|
>> uint_p [assign_obect(rv.version.t)]
|
|
>> L'"'
|
|
;
|
|
|
|
UnusedAttribute =
|
|
Name
|
|
>> Eq
|
|
>> L'"'
|
|
>> CharData
|
|
>> L'"'
|
|
;
|
|
|
|
Attribute =
|
|
ClassIDAttribute
|
|
| ObjectIDAttribute
|
|
| ClassNameAttribute
|
|
| TrackingAttribute
|
|
| VersionAttribute
|
|
| UnusedAttribute
|
|
;
|
|
|
|
XMLDecl =
|
|
!S
|
|
>> str_p(L"<?xml")
|
|
>> S
|
|
>> str_p(L"version")
|
|
>> Eq
|
|
>> str_p(L"\"1.0\"")
|
|
>> *(anychar_p - chset_p(L"?>"))
|
|
>> !S
|
|
>> str_p(L"?>")
|
|
;
|
|
|
|
DocTypeDecl =
|
|
!S
|
|
>> str_p(L"<!DOCTYPE")
|
|
>> *(anychar_p - chset_p(L">"))
|
|
>> L'>'
|
|
;
|
|
|
|
SignatureAttribute =
|
|
str_p(L"signature")
|
|
>> Eq
|
|
>> L'"'
|
|
>> Name [assign_obect(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::throw_exception(
|
|
xml_archive_exception(xml_archive_exception::xml_archive_parsing_error)
|
|
);
|
|
if(! my_parse(is, DocTypeDecl))
|
|
boost::throw_exception(
|
|
xml_archive_exception(xml_archive_exception::xml_archive_parsing_error)
|
|
);
|
|
if(! my_parse(is, SerializationWrapper))
|
|
boost::throw_exception(
|
|
xml_archive_exception(xml_archive_exception::xml_archive_parsing_error)
|
|
);
|
|
if(! std::equal(rv.class_name.begin(), rv.class_name.end(), ARCHIVE_SIGNATURE))
|
|
boost::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 exception from code called by a destructor !
|
|
// so just ignore any failure.
|
|
my_parse(is, ETag);
|
|
}
|
|
|
|
} // namespace archive
|
|
} // namespace boost
|