/////////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 #ifdef BOOST_MSVC # pragma warning(push) # pragma warning(disable : 4511 4512) #endif // spirit stuff #include #include #include #ifdef BOOST_MSVC #pragma warning(pop) #endif // for head_iterator test //#include #include #include #include #include #include #include #include #include using namespace boost::spirit::classic; 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 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 & operator=( assign_impl & rhs ); 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_object(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 BOOST_DEDUCED_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 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 bool basic_xml_grammar::my_parse( BOOST_DEDUCED_TYPENAME basic_xml_grammar::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 arg; CharType val; do{ BOOST_DEDUCED_TYPENAME basic_xml_grammar::IStream::int_type result = is.get(); if(is.fail()) return false; val = static_cast(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::iterator> result = boost::spirit::classic::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 ){ rv.class_name.resize(0); return my_parse(is, STag); } template bool basic_xml_grammar::parse_end_tag(IStream & is) const { return my_parse(is, ETag); } template bool basic_xml_grammar::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 basic_xml_grammar::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::const_iterator >(rv.contents) ] ; // slight factoring works around ICE in msvc 6.0 CharRef1 = str_p(L"&#") >> uint_p [xml::append_char(rv.contents)] >> L';' ; CharRef2 = str_p(L"&#x") >> hex_p [xml::append_char(rv.contents)] >> L';' ; CharRef = CharRef1 | CharRef2 ; AmpRef = str_p(L"&")[xml::append_lit(rv.contents)]; LTRef = str_p(L"<")[xml::append_lit(rv.contents)]; GTRef = str_p(L">")[xml::append_lit'>(rv.contents)]; AposRef = str_p(L"'")[xml::append_lit(rv.contents)]; QuoteRef = str_p(L""")[xml::append_lit(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(rv.class_name)]; LTName = str_p(L"<")[xml::append_lit(rv.class_name)]; GTName = str_p(L">")[xml::append_lit'>(rv.class_name)]; ClassNameChar = AmpName | LTName | GTName | (anychar_p - chset_p(L"\"")) [xml::append_char(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"> 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"> DocTypeDeclChars >> L'>' ; SignatureAttribute = str_p(L"signature") >> Eq >> L'"' >> Name [xml::assign_object(rv.class_name)] >> L'"' ; SerializationWrapper = !S >> str_p(L"> S >> ( (SignatureAttribute >> S >> VersionAttribute) | (VersionAttribute >> S >> SignatureAttribute) ) >> !S >> L'>' ; } template void basic_xml_grammar::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 void basic_xml_grammar::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