/////////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 #include #include // BOOST_DEDUCED_TYPENAME // spirit stuff #include #include #include // for head_iterator test #include #include #include #include #include #include #include #include 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 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 & 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 & 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 assign_impl assign_obect(T &t){ return assign_impl(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 struct append_string { String & contents; void operator()(Iterator start, Iterator end) const { #if 0 typedef boost::archive::iterators::xml_unescape 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 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 struct append_lit { String & contents; template 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 bool basic_xml_grammar::my_parse( BOOST_DEDUCED_TYPENAME basic_xml_grammar::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 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::iterator> result = boost::spirit::parse(arg.begin(), arg.end(), rule_); return result.hit; } template bool basic_xml_grammar::parse_start_tag( BOOST_DEDUCED_TYPENAME basic_xml_grammar::IStream & is ) { if(is.fail()){ boost::throw_exception( archive_exception(archive_exception::stream_error) ); } return my_parse(is, STag); } template bool basic_xml_grammar::parse_end_tag(IStream & is) { if(is.fail()){ boost::throw_exception( archive_exception(archive_exception::stream_error) ); } return my_parse(is, ETag); } template bool basic_xml_grammar::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, 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 basic_xml_grammar::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::const_iterator >(rv.contents) ] ; // slight factoring works around ICE in msvc 6.0 CharRef1 = str_p(L"&#") >> uint_p [append_char(rv.contents)] >> L';' ; CharRef2 = str_p(L"&#x") >> hex_p [append_char(rv.contents)] >> L';' ; CharRef = CharRef1 | CharRef2 ; AmpRef = str_p(L"&")[append_lit(rv.contents)]; LTRef = str_p(L"<")[append_lit(rv.contents)]; GTRef = str_p(L">")[append_lit'>(rv.contents)]; AposRef = str_p(L"'")[append_lit(rv.contents)]; QuoteRef = str_p(L""")[append_lit(rv.contents)]; Reference = AmpRef | LTRef | GTRef | AposRef | QuoteRef | CharRef ; content = L"<" // should be end_p | (Reference | CharData) >> content ; 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"> 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"> *(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"> S >> SignatureAttribute >> S >> VersionAttribute >> !S >> L'>' ; } template void basic_xml_grammar::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 void basic_xml_grammar::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