Coverage Report

Created: 2026-02-14 09:37

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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: */