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