Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This file is part of the LibreOffice project.
4 : *
5 : * This Source Code Form is subject to the terms of the Mozilla Public
6 : * License, v. 2.0. If a copy of the MPL was not distributed with this
7 : * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 : */
9 : #ifndef INCLUDED_OOX_MATHML_IMPORTUTILS_HXX
10 : #define INCLUDED_OOX_MATHML_IMPORTUTILS_HXX
11 :
12 : #include <com/sun/star/xml/sax/XFastAttributeList.hpp>
13 : #include <oox/token/tokens.hxx>
14 : #include <map>
15 : #include <vector>
16 :
17 : #include <oox/dllapi.h>
18 :
19 : namespace oox
20 : {
21 :
22 : namespace formulaimport
23 : {
24 :
25 : // used to differentiate between tags that opening or closing
26 : const int TAG_OPENING = 1 << 29;
27 : const int TAG_CLOSING = 1 << 30;
28 :
29 : // you probably want to #define these to something shorter in the .cxx file,
30 : // but they must be done as macros, otherwise they wouldn't be usable for case values,
31 : // and macros cannot be namespaced
32 : #define XML_STREAM_OPENING( token ) ( TAG_OPENING | token )
33 : #define XML_STREAM_CLOSING( token ) ( TAG_CLOSING | token )
34 :
35 : /**
36 : Class for storing a stream of xml tokens.
37 :
38 : A part of an XML file can be parsed and stored in this stream, from which it can be read
39 : as if parsed linearly. The purpose of this class is to allow simpler handling of XML
40 : files, unlike the usual LO way of using callbacks, context handlers and similar needlesly
41 : complicated stuff (YMMV).
42 :
43 : The advantages of this approach is easy to read and debug code (as it is just functions
44 : reading tokens one by one and calling other functions, compared to having to use callbacks
45 : and temporary storage). The disadvantage is that the XML structure needs to be handled
46 : manually by the code.
47 :
48 : Note that tag identifiers are simply int values and the API does not care besides matching
49 : their values to XML stream contents and requiring that the values are not as high as TAG_OPENING.
50 : Be prepared for the fact that some of the functions may throw exceptions if the input
51 : stream does not match the required token (TBD).
52 :
53 : The API tries to make the common idioms as simple as possible, see the following examples.
54 :
55 : Parse <tagone attr="value"><tagtwo>text</tagtwo></tagone> , where tagtwo is optional:
56 : @code
57 : XmlStream::Tag tagoneTag = stream.ensureOpeningTag( tagone );
58 : if( attributeTag.hasAttribute( attr ))
59 : ... = attributeTag.attribute( attr, defaultValueOfTheRightType );
60 : if( XmlStream::Tag tagtwoTag = stream.checkOpeningTag( tagtwo ))
61 : {
62 : ... = tagtwoTag.text;
63 : stream.ensureClosingTag( tagtwo );
64 : }
65 : stream.ensureClosingTag( tagone );
66 : @endcode
67 :
68 : Parse an element that may contain several sub-elements of different types in random order:
69 : @code
70 : stream.ensureOpeningTag( element );
71 : while( !stream.atEnd() && stream.currentToken() != CLOSING( element ))
72 : {
73 : switch( stream.currentToken())
74 : {
75 : case OPENING( subelement1 ):
76 : handleSubElement1();
77 : break;
78 : case OPENING( subelement2 ):
79 : ... process subelement2;
80 : break;
81 : default:
82 : stream.handleUnexpectedTag();
83 : break;
84 : }
85 : stream.ensureClosingTag( element );
86 : @endcode
87 :
88 : If there may not be a zero number of sub-elements, use a helper bool variable or use a do-while loop.
89 :
90 : Parse an element that may contain an unknown number of sub-elements of the same type:
91 : @code
92 : stream.ensureOpeningTag( element );
93 : while( !stream.atEnd() && stream.findTag( OPENING( subelement )))
94 : {
95 : handleSubelement();
96 : }
97 : stream.ensureClosingTag( element );
98 : @endcode
99 :
100 : If there may not be a zero number of sub-elements, use a helper bool variable or use a do-while loop.
101 :
102 : @since 3.5
103 : */
104 0 : class OOX_DLLPUBLIC XmlStream
105 : {
106 : public:
107 : XmlStream();
108 : /**
109 : Structure representing a list of attributes.
110 : */
111 : // One could theoretically use oox::AttributeList, but that complains if the passed reference is empty,
112 : // which would be complicated to avoid here. Also, parsers apparently reuse the same instance of XFastAttributeList,
113 : // which means using oox::AttributeList would make them all point to the one instance.
114 0 : struct OOX_DLLPUBLIC AttributeList
115 : {
116 : bool hasAttribute( int token ) const;
117 : OUString& operator[] (int token);
118 : OUString attribute( int token, const OUString& def = OUString()) const;
119 : bool attribute( int token, bool def ) const;
120 : sal_Unicode attribute( int token, sal_Unicode def ) const;
121 : // when adding more attribute() overloads, add also to XmlStream itself
122 : protected:
123 : std::map< int, OUString > attrs;
124 : };
125 : /**
126 : Structure representing a tag, including its attributes and content text immediatelly following it.
127 : */
128 0 : struct OOX_DLLPUBLIC Tag
129 : {
130 : Tag( int token = XML_TOKEN_INVALID,
131 : const com::sun::star::uno::Reference< com::sun::star::xml::sax::XFastAttributeList >& attributes = com::sun::star::uno::Reference< com::sun::star::xml::sax::XFastAttributeList >(),
132 : const OUString& text = OUString());
133 : Tag( int token,
134 : const AttributeList& attribs);
135 : int token; ///< tag type, or XML_TOKEN_INVALID
136 : AttributeList attributes;
137 : OUString text;
138 : /**
139 : This function returns value of the given attribute, or the passed default value if not found.
140 : The type of the default value selects the return type (OUString here).
141 : */
142 : OUString attribute( int token, const OUString& def = OUString()) const;
143 : /**
144 : @overload
145 : */
146 : bool attribute( int token, bool def ) const;
147 : /**
148 : @overload
149 : */
150 : sal_Unicode attribute( int token, sal_Unicode def ) const;
151 : // when adding more attribute() overloads, add also to XmlStream::AttributeList and inline below
152 : /**
153 : Converts to true if the tag has a valid token, false otherwise. Allows simple
154 : usage in if(), for example 'if( XmlStream::Tag foo = stream.checkOpeningTag( footoken ))'.
155 : */
156 : operator bool() const;
157 : };
158 : /**
159 : @return true if current position is at the end of the XML stream
160 : */
161 : bool atEnd() const;
162 : /**
163 : @return data about the current tag
164 : */
165 : Tag currentTag() const;
166 : /**
167 : @return the token for the current tag
168 : */
169 : int currentToken() const;
170 : /**
171 : Moves position to the next tag.
172 : */
173 : void moveToNextTag();
174 : /**
175 : Ensures that an opening tag with the given token is read. If the current tag does not match,
176 : writes out a warning and tries to recover by skipping tags until found (or until the current element would end).
177 : If found, the position in the stream is afterwards moved to the next tag.
178 : @return the matching found opening tag, or empty tag if not found
179 : */
180 : Tag ensureOpeningTag( int token );
181 : /**
182 : Tries to find an opening tag with the given token. Works similarly like ensureOpeningTag(),
183 : but if a matching tag is not found, the position in the stream is not altered. The primary
184 : use of this function is to check for optional elements.
185 : @return the matching found opening tag, or empty tag if not found
186 : */
187 : Tag checkOpeningTag( int token );
188 : /**
189 : Ensures that a closing tag with the given token is read. Like ensureOpeningTag(),
190 : if not, writes out a warning and tries to recover by skiping tags until found (or until the current element would end).
191 : If found, the position in the stream is afterwards moved to the next tag.
192 : */
193 : void ensureClosingTag( int token );
194 : /**
195 : Tries to find the given token, until either found (returns true) or end of current element.
196 : Position in the stream is set to make the tag current (i.e. it will be the next one read).
197 : */
198 : bool findTag( int token );
199 : /**
200 : Handle the current (unexpected) tag.
201 : */
202 : void handleUnexpectedTag();
203 : protected:
204 : Tag checkTag( int token, bool optional );
205 : bool findTagInternal( int token, bool silent );
206 : void skipElementInternal( int token, bool silent );
207 : std::vector< Tag > tags;
208 : unsigned int pos;
209 : };
210 :
211 : /**
212 : This class is used for creating XmlStream.
213 :
214 : Simply use this class and then pass it as XmlStream to the consumer.
215 :
216 : @since 3.5.0
217 : */
218 0 : class OOX_DLLPUBLIC XmlStreamBuilder
219 : : public XmlStream
220 : {
221 : public:
222 : void appendOpeningTag( int token,
223 : const com::sun::star::uno::Reference< com::sun::star::xml::sax::XFastAttributeList >& attributes = com::sun::star::uno::Reference< com::sun::star::xml::sax::XFastAttributeList >());
224 : void appendOpeningTag( int token,
225 : const AttributeList& attribs );
226 : void appendClosingTag( int token );
227 : // appends the characters after the last appended token
228 : void appendCharacters( const OUString& characters );
229 : };
230 :
231 : inline
232 0 : OUString XmlStream::Tag::attribute( int t, const OUString& def ) const
233 : {
234 0 : return attributes.attribute( t, def );
235 : }
236 :
237 : inline
238 0 : bool XmlStream::Tag::attribute( int t, bool def ) const
239 : {
240 0 : return attributes.attribute( t, def );
241 : }
242 :
243 : inline
244 0 : sal_Unicode XmlStream::Tag::attribute( int t, sal_Unicode def ) const
245 : {
246 0 : return attributes.attribute( t, def );
247 : }
248 :
249 : } // namespace
250 : } // namespace
251 :
252 : #endif
253 :
254 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|