| /////////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"&")[xml::append_lit<StringType, L'&'>(rv.contents)]; |
| LTRef = str_p(L"<")[xml::append_lit<StringType, L'<'>(rv.contents)]; |
| GTRef = str_p(L">")[xml::append_lit<StringType, L'>'>(rv.contents)]; |
| AposRef = str_p(L"'")[xml::append_lit<StringType, L'\''>(rv.contents)]; |
| QuoteRef = str_p(L""")[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"&")[xml::append_lit<StringType, L'&'>(rv.class_name)]; |
| LTName = str_p(L"<")[xml::append_lit<StringType, L'<'>(rv.class_name)]; |
| GTName = str_p(L">")[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 |