• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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"&amp;")[xml::append_lit<StringType, L'&'>(rv.contents)];
305    LTRef = str_p(L"&lt;")[xml::append_lit<StringType, L'<'>(rv.contents)];
306    GTRef = str_p(L"&gt;")[xml::append_lit<StringType, L'>'>(rv.contents)];
307    AposRef = str_p(L"&apos;")[xml::append_lit<StringType, L'\''>(rv.contents)];
308    QuoteRef = str_p(L"&quot;")[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"&amp;")[xml::append_lit<StringType, L'&'>(rv.class_name)];
346    LTName = str_p(L"&lt;")[xml::append_lit<StringType, L'<'>(rv.class_name)];
347    GTName = str_p(L"&gt;")[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