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

source code of boost/libs/serialization/src/basic_xml_grammar.ipp