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