1/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8 2// basic_xml_grammar.ipp: 3 4// (C) Copyright 2002 Robert Ramey - http://www.rrsd.com . 5// Use, modification and distribution is subject to the Boost Software 6// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at 7// http://www.boost.org/LICENSE_1_0.txt) 8 9// See http://www.boost.org for updates, documentation, and revision history. 10 11#if (defined _MSC_VER) && (_MSC_VER == 1200) 12# pragma warning (disable : 4786) // too long name, harmless warning 13#endif 14 15#include <istream> 16#include <algorithm> 17#include <boost/config.hpp> // typename 18 19#ifdef BOOST_MSVC 20# pragma warning(push) 21# pragma warning(disable : 4244 4511 4512) 22#endif 23 24#include <cerrno> // errno 25#include <cstring> // strerror(errno) 26 27// spirit stuff 28#include <boost/spirit/include/classic_operators.hpp> 29#include <boost/spirit/include/classic_actions.hpp> 30#include <boost/spirit/include/classic_numerics.hpp> 31 32#ifdef BOOST_MSVC 33#pragma warning(pop) 34#endif 35 36// for head_iterator test 37#include <boost/function.hpp> 38 39#include <boost/io/ios_state.hpp> 40#include <boost/serialization/throw_exception.hpp> 41#include <boost/archive/impl/basic_xml_grammar.hpp> 42#include <boost/archive/xml_archive_exception.hpp> 43#include <boost/archive/basic_xml_archive.hpp> 44#include <boost/archive/iterators/xml_unescape.hpp> 45 46using namespace boost::spirit::classic; 47 48namespace boost { 49namespace archive { 50 51/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8 52// template code for basic_xml_grammar of both wchar_t and char types 53 54namespace xml { // anonymous 55 56#ifdef BOOST_MSVC 57# pragma warning(push) 58# pragma warning(disable : 4511 4512) 59#endif 60 61template<class T> 62struct assign_impl { 63 T & t; 64 void operator()(const T t_) const { 65 t = t_; 66 } 67 assign_impl(T & t_) 68 : t(t_) 69 {} 70}; 71 72template<> 73struct assign_impl<std::string> { 74 std::string & t; 75 void operator()( 76 std::string::const_iterator b, 77 std::string::const_iterator e 78 ) const { 79 t.resize(0); 80 while(b != e){ 81 t += * b; 82 ++b; 83 } 84 } 85 assign_impl<std::string> & operator=( 86 assign_impl<std::string> & rhs 87 ); 88 assign_impl(std::string & t_) 89 : t(t_) 90 {} 91}; 92 93#ifndef BOOST_NO_STD_WSTRING 94template<> 95struct assign_impl<std::wstring> { 96 std::wstring & t; 97 void operator()( 98 std::wstring::const_iterator b, 99 std::wstring::const_iterator e 100 ) const { 101 t.resize(0); 102 while(b != e){ 103 t += * b; 104 ++b; 105 } 106 } 107 assign_impl(std::wstring & t_) 108 : t(t_) 109 {} 110}; 111#endif 112 113template<class T> 114assign_impl<T> assign_object(T &t){ 115 return assign_impl<T>(t); 116} 117 118struct assign_level { 119 tracking_type & tracking_level; 120 void operator()(const unsigned int tracking_level_) const { 121 tracking_level = (0 == tracking_level_) ? false : true; 122 } 123 assign_level(tracking_type & tracking_level_) 124 : tracking_level(tracking_level_) 125 {} 126}; 127 128template<class String, class Iterator> 129struct append_string { 130 String & contents; 131 void operator()(Iterator start, Iterator end) const { 132 #if 0 133 typedef boost::archive::iterators::xml_unescape<Iterator> translator; 134 contents.append( 135 translator(BOOST_MAKE_PFTO_WRAPPER(start)), 136 translator(BOOST_MAKE_PFTO_WRAPPER(end)) 137 ); 138 #endif 139 contents.append(start, end); 140 } 141 append_string(String & contents_) 142 : contents(contents_) 143 {} 144}; 145 146template<class String> 147struct append_char { 148 String & contents; 149 void operator()(const unsigned int char_value) const { 150 contents += static_cast<typename String::value_type>(char_value); 151 } 152 append_char(String & contents_) 153 : contents(contents_) 154 {} 155}; 156 157template<class String, unsigned int c> 158struct append_lit { 159 String & contents; 160 template<class X, class Y> 161 void operator()(const X & /*x*/, const Y & /*y*/) const { 162 const typename String::value_type z = c; 163 contents += z; 164 } 165 append_lit(String & contents_) 166 : contents(contents_) 167 {} 168}; 169 170#ifdef BOOST_MSVC 171#pragma warning(pop) 172#endif 173 174} // namespace anonymous 175 176template<class CharType> 177bool basic_xml_grammar<CharType>::my_parse( 178 typename basic_xml_grammar<CharType>::IStream & is, 179 const rule_t & rule_, 180 CharType delimiter 181) const { 182 if(is.fail()){ 183 return false; 184 } 185 186 is >> std::noskipws; 187 188 std::basic_string<CharType> arg; 189 190 for(;;){ 191 CharType result; 192 is.get(result); 193 if(is.fail()){ 194 boost::serialization::throw_exception( 195 boost::archive::archive_exception( 196 archive_exception::input_stream_error, 197 std::strerror(errno) 198 ) 199 ); 200 } 201 if(is.eof()) 202 return false; 203 arg += result; 204 if(result == delimiter) 205 break; 206 } 207 208 // read just one more character. This will be the newline after the tag 209 // this is so that the next operation will return fail if the archive 210 // is terminated. This will permit the archive to be used for debug 211 // and transaction data logging in the standard way. 212 213 parse_info<typename std::basic_string<CharType>::iterator> 214 result = boost::spirit::classic::parse(arg.begin(), arg.end(), rule_); 215 return result.hit; 216} 217 218template<class CharType> 219bool basic_xml_grammar<CharType>::parse_start_tag( 220 typename basic_xml_grammar<CharType>::IStream & is 221){ 222 rv.class_name.resize(0); 223 return my_parse(is, STag); 224} 225 226template<class CharType> 227bool basic_xml_grammar<CharType>::parse_end_tag(IStream & is) const { 228 return my_parse(is, ETag); 229} 230 231template<class CharType> 232bool basic_xml_grammar<CharType>::parse_string(IStream & is, StringType & s){ 233 rv.contents.resize(0); 234 bool result = my_parse(is, content, '<'); 235 // note: unget caused a problem with dinkumware. replace with 236 // is.unget(); 237 // putback another delimiter instead 238 is.putback('<'); 239 if(result) 240 s = rv.contents; 241 return result; 242} 243 244template<class CharType> 245basic_xml_grammar<CharType>::basic_xml_grammar(){ 246 init_chset(); 247 248 S = 249 +(Sch) 250 ; 251 252 // refactoring to workaround template depth on darwin 253 NameHead = (Letter | '_' | ':'); 254 NameTail = *NameChar ; 255 Name = 256 NameHead >> NameTail 257 ; 258 259 Eq = 260 !S >> '=' >> !S 261 ; 262 263 AttributeList = 264 *(S >> Attribute) 265 ; 266 267 STag = 268 !S 269 >> '<' 270 >> Name [xml::assign_object(rv.object_name)] 271 >> AttributeList 272 >> !S 273 >> '>' 274 ; 275 276 ETag = 277 !S 278 >> "</" 279 >> Name [xml::assign_object(rv.object_name)] 280 >> !S 281 >> '>' 282 ; 283 284 // refactoring to workaround template depth on darwin 285 CharDataChars = +(anychar_p - chset_p(L"&<")); 286 CharData = 287 CharDataChars [ 288 xml::append_string< 289 StringType, 290 typename std::basic_string<CharType>::const_iterator 291 >(rv.contents) 292 ] 293 ; 294 295 // slight factoring works around ICE in msvc 6.0 296 CharRef1 = 297 str_p(L"&#") >> uint_p [xml::append_char<StringType>(rv.contents)] >> L';' 298 ; 299 CharRef2 = 300 str_p(L"&#x") >> hex_p [xml::append_char<StringType>(rv.contents)] >> L';' 301 ; 302 CharRef = CharRef1 | CharRef2 ; 303 304 AmpRef = str_p(L"&")[xml::append_lit<StringType, L'&'>(rv.contents)]; 305 LTRef = str_p(L"<")[xml::append_lit<StringType, L'<'>(rv.contents)]; 306 GTRef = str_p(L">")[xml::append_lit<StringType, L'>'>(rv.contents)]; 307 AposRef = str_p(L"'")[xml::append_lit<StringType, L'\''>(rv.contents)]; 308 QuoteRef = str_p(L""")[xml::append_lit<StringType, L'"'>(rv.contents)]; 309 310 Reference = 311 AmpRef 312 | LTRef 313 | GTRef 314 | AposRef 315 | QuoteRef 316 | CharRef 317 ; 318 319 content = 320 L"<" // should be end_p 321 | +(Reference | CharData) >> L"<" 322 ; 323 324 ClassIDAttribute = 325 str_p(BOOST_ARCHIVE_XML_CLASS_ID()) >> NameTail 326 >> Eq 327 >> L'"' 328 >> int_p [xml::assign_object(rv.class_id)] 329 >> L'"' 330 ; 331 332 ObjectIDAttribute = ( 333 str_p(BOOST_ARCHIVE_XML_OBJECT_ID()) 334 | 335 str_p(BOOST_ARCHIVE_XML_OBJECT_REFERENCE()) 336 ) 337 >> NameTail 338 >> Eq 339 >> L'"' 340 >> L'_' 341 >> uint_p [xml::assign_object(rv.object_id)] 342 >> L'"' 343 ; 344 345 AmpName = str_p(L"&")[xml::append_lit<StringType, L'&'>(rv.class_name)]; 346 LTName = str_p(L"<")[xml::append_lit<StringType, L'<'>(rv.class_name)]; 347 GTName = str_p(L">")[xml::append_lit<StringType, L'>'>(rv.class_name)]; 348 ClassNameChar = 349 AmpName 350 | LTName 351 | GTName 352 | (anychar_p - chset_p(L"\"")) [xml::append_char<StringType>(rv.class_name)] 353 ; 354 355 ClassName = 356 * ClassNameChar 357 ; 358 359 ClassNameAttribute = 360 str_p(BOOST_ARCHIVE_XML_CLASS_NAME()) 361 >> Eq 362 >> L'"' 363 >> ClassName 364 >> L'"' 365 ; 366 367 TrackingAttribute = 368 str_p(BOOST_ARCHIVE_XML_TRACKING()) 369 >> Eq 370 >> L'"' 371 >> uint_p [xml::assign_level(rv.tracking_level)] 372 >> L'"' 373 ; 374 375 VersionAttribute = 376 str_p(BOOST_ARCHIVE_XML_VERSION()) 377 >> Eq 378 >> L'"' 379 >> uint_p [xml::assign_object(rv.version)] 380 >> L'"' 381 ; 382 383 UnusedAttribute = 384 Name 385 >> Eq 386 >> L'"' 387 >> !CharData 388 >> L'"' 389 ; 390 391 Attribute = 392 ClassIDAttribute 393 | ObjectIDAttribute 394 | ClassNameAttribute 395 | TrackingAttribute 396 | VersionAttribute 397 | UnusedAttribute 398 ; 399 400 XMLDeclChars = *(anychar_p - chset_p(L"?>")); 401 XMLDecl = 402 !S 403 >> str_p(L"<?xml") 404 >> S 405 >> str_p(L"version") 406 >> Eq 407 >> str_p(L"\"1.0\"") 408 >> XMLDeclChars 409 >> !S 410 >> str_p(L"?>") 411 ; 412 413 DocTypeDeclChars = *(anychar_p - chset_p(L">")); 414 DocTypeDecl = 415 !S 416 >> str_p(L"<!DOCTYPE") 417 >> DocTypeDeclChars 418 >> L'>' 419 ; 420 421 SignatureAttribute = 422 str_p(L"signature") 423 >> Eq 424 >> L'"' 425 >> Name [xml::assign_object(rv.class_name)] 426 >> L'"' 427 ; 428 429 SerializationWrapper = 430 !S 431 >> str_p(L"<boost_serialization") 432 >> S 433 >> ( (SignatureAttribute >> S >> VersionAttribute) 434 | (VersionAttribute >> S >> SignatureAttribute) 435 ) 436 >> !S 437 >> L'>' 438 ; 439} 440 441template<class CharType> 442void basic_xml_grammar<CharType>::init(IStream & is){ 443 init_chset(); 444 if(! my_parse(is, XMLDecl)) 445 boost::serialization::throw_exception( 446 xml_archive_exception(xml_archive_exception::xml_archive_parsing_error) 447 ); 448 if(! my_parse(is, DocTypeDecl)) 449 boost::serialization::throw_exception( 450 xml_archive_exception(xml_archive_exception::xml_archive_parsing_error) 451 ); 452 if(! my_parse(is, SerializationWrapper)) 453 boost::serialization::throw_exception( 454 xml_archive_exception(xml_archive_exception::xml_archive_parsing_error) 455 ); 456 if(! std::equal(rv.class_name.begin(), rv.class_name.end(), BOOST_ARCHIVE_SIGNATURE())) 457 boost::serialization::throw_exception( 458 archive_exception(archive_exception::invalid_signature) 459 ); 460} 461 462template<class CharType> 463bool basic_xml_grammar<CharType>::windup(IStream & is) { 464 return my_parse(is, ETag); 465} 466 467} // namespace archive 468} // namespace boost 469