summaryrefslogtreecommitdiff
path: root/include/oox/core/contexthandler2.hxx
blob: 13b732dec7e5c06d3f728c9bd1f093737f9fd0e8 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
 * This file is part of the LibreOffice project.
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 * This file incorporates work covered by the following license notice:
 *
 *   Licensed to the Apache Software Foundation (ASF) under one or more
 *   contributor license agreements. See the NOTICE file distributed
 *   with this work for additional information regarding copyright
 *   ownership. The ASF licenses this file to you under the Apache
 *   License, Version 2.0 (the "License"); you may not use this file
 *   except in compliance with the License. You may obtain a copy of
 *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
 */

#ifndef INCLUDED_OOX_CORE_CONTEXTHANDLER2_HXX
#define INCLUDED_OOX_CORE_CONTEXTHANDLER2_HXX

#include <cstddef>
#include <memory>
#include <vector>

#include <com/sun/star/uno/Reference.hxx>
#include <oox/core/contexthandler.hxx>
#include <oox/dllapi.h>
#include <rtl/ustring.hxx>
#include <sal/types.h>

namespace com::sun::star {
    namespace xml::sax { class XFastAttributeList; }
    namespace xml::sax { class XFastContextHandler; }
}

namespace oox {
    class AttributeList;
    class SequenceInputStream;
}

namespace oox::core {

const sal_Int32 XML_ROOT_CONTEXT    = SAL_MAX_INT32;

struct ElementInfo;

/** Helper class that provides a context stack.

    Fragment handlers and context handlers derived from this helper class will
    track the identifiers of the visited elements in a stack. The idea is to
    use the same instance of a fragment handler or context handler to process
    several nested elements in an XML stream. For that, the abstract function
    onCreateContext() has to return 'this' for the passed element.

    Derived classes have to implement the createFastChildContext(),
    startFastElement(), characters(), and endFastElement() functions from the
    com.sun.star.xml.sax.XFastContextHandler interface by simply forwarding
    them to the respective implCreateChildContext(), implStartElement(),
    implCharacters(), and implEndElement() functions of this helper. This is
    implemented already in the classes ContextHandler2 and FragmentHandler2.
    The new abstract functions have to be implemented according to the elements
    to be processed.

    Similarly, for binary import, derived classes have to forward the
    createRecordContext(), startRecord(), and endRecord() functions from the
    ContextHandler class to the implCreateRecordContext(), implStartRecord(),
    and implEndRecord() functions of this helper. Again, this is implemented
    already in the classes ContextHandler2 and FragmentHandler2.
 */
class OOX_DLLPUBLIC ContextHandler2Helper
{
public:
    explicit            ContextHandler2Helper( bool bEnableTrimSpace );
    explicit            ContextHandler2Helper( const ContextHandler2Helper& rParent );
    virtual             ~ContextHandler2Helper();

    // allow instances to be stored in ::rtl::Reference
    virtual void SAL_CALL acquire() throw() = 0;
    virtual void SAL_CALL release() throw() = 0;

    // interface --------------------------------------------------------------

    /** Will be called to create a context handler for the passed element.

        Usually 'this' can be returned to improve performance by reusing the
        same instance to process several elements. Used by OOXML import only.
     */
    virtual ContextHandlerRef onCreateContext( sal_Int32 nElement, const AttributeList& rAttribs ) = 0;

    /** Will be called when a new element has been started.

        This function is called at the context handler returned from
        onCreateContext(), or, for root elements of an XML stream, at the
        fragment handler itself.

        The current element identifier can be accessed with getCurrentElement()
        or isCurrentElement(). Used by OOXML import only.
     */
    virtual void        onStartElement( const AttributeList& rAttribs ) = 0;

    /** Will be called before a new child element starts, or if the current
        element is about to be left.

        This helper function collects all text fragments received by the
        characters() function (such as encoded characters which are passed in
        separate calls to the characters() function), and passes the
        concatenated and trimmed string.

        The current element identifier can be accessed with getCurrentElement()
        or isCurrentElement(). Used by OOXML import only.
     */
    virtual void        onCharacters( const OUString& rChars ) = 0;

    /** Will be called when the current element is about to be left.

        The current element identifier can be accessed with getCurrentElement()
        or isCurrentElement(). Used by OOXML import only.
     */
    virtual void        onEndElement() = 0;

    /** Will be called to create a context handler for the passed record.

        Usually 'this' can be returned to improve performance by reusing the
        same instance to process several records. Used by BIFF import only.
     */
    virtual ContextHandlerRef onCreateRecordContext( sal_Int32 nRecId, SequenceInputStream& rStrm ) = 0;

    /** Will be called when a new record block in a binary stream has been
        started.

        The current record identifier can be accessed with getCurrentElement()
        or isCurrentElement(). Used by BIFF import only.
     */
    virtual void        onStartRecord( SequenceInputStream& rStrm ) = 0;

    /** Will be called when the current record block is about to be left.

        The current record identifier can be accessed with getCurrentElement()
        or isCurrentElement(). Used by BIFF import only.
     */
    virtual void        onEndRecord() = 0;

    // helpers ----------------------------------------------------------------

    /** Returns the identifier of the currently processed element. Ignores MCE elements in stack */
    sal_Int32           getCurrentElement() const;

    /** Returns the identifier of the currently processed element - Including MCE root elements */
    sal_Int32           getCurrentElementWithMce() const;

    /** Returns true, if nElement contains the identifier of the currently
        processed element. */
    bool         isCurrentElement( sal_Int32 nElement ) const
                            { return getCurrentElement() == nElement; }

    /** Returns true, if either nElement1 or nElement2 contain the identifier
        of the currently processed element. */
    bool         isCurrentElement( sal_Int32 nElement1, sal_Int32 nElement2 ) const
                            { return isCurrentElement( nElement1 ) || isCurrentElement( nElement2 ); }

    /** Returns the identifier of the specified parent element. */
    sal_Int32           getParentElement( sal_Int32 nCountBack = 1 ) const;

    /** Returns true, if nElement contains the identifier of the specified
        parent element. */
    bool isParentElement( sal_Int32 nElement, sal_Int32 nCountBack = 1 ) const
                            { return getParentElement( nCountBack ) == nElement; }

    /** Returns true, if the element currently processed is the root element of
        the context or fragment handler. */
    bool                isRootElement() const;

    // implementation ---------------------------------------------------------

protected:
    /** Must be called from createFastChildContext() in derived classes. */
    css::uno::Reference< css::xml::sax::XFastContextHandler >
                        implCreateChildContext(
                            sal_Int32 nElement,
                            const css::uno::Reference< css::xml::sax::XFastAttributeList >& rxAttribs );

    /** Must be called from startFastElement() in derived classes. */
    void                implStartElement(
                            sal_Int32 nElement,
                            const css::uno::Reference< css::xml::sax::XFastAttributeList >& rxAttribs );

    /** Must be called from characters() in derived classes. */
    void                implCharacters( std::u16string_view rChars );

    /** Must be called from endFastElement() in derived classes. */
    void                implEndElement( sal_Int32 nElement );

    /** Must be called from createRecordContext() in derived classes. */
    ContextHandlerRef   implCreateRecordContext( sal_Int32 nRecId, SequenceInputStream& rStrm );

    /** Must be called from startRecord() in derived classes. */
    void                implStartRecord( sal_Int32 nRecId, SequenceInputStream& rStrm );

    /** Must be called from endRecord() in derived classes. */
    void                implEndRecord( sal_Int32 nRecId );

private:
    ContextHandler2Helper& operator=( const ContextHandler2Helper& ) = delete;

    ElementInfo&        pushElementInfo( sal_Int32 nElement );
    void                popElementInfo();
    void                processCollectedChars();

private:
    typedef std::vector< ElementInfo >        ContextStack;
    typedef std::shared_ptr< ContextStack > ContextStackRef;

    ContextStackRef     mxContextStack;     ///< Stack of all processed elements.
    size_t              mnRootStackSize;    ///< Stack size on construction time.

protected:
    bool                mbEnableTrimSpace;  ///< True = trim whitespace in characters().
};

class OOX_DLLPUBLIC ContextHandler2 : public ContextHandler, public ContextHandler2Helper
{
public:
    explicit            ContextHandler2( ContextHandler2Helper const & rParent );
    virtual             ~ContextHandler2() override;

    ContextHandler2(ContextHandler2 const &) = default;
    ContextHandler2(ContextHandler2 &&) = default;
    ContextHandler2 & operator =(ContextHandler2 const &) = delete; // due to ContextHandler
    ContextHandler2 & operator =(ContextHandler2 &&) = delete; // due to ContextHandler

    // resolve ambiguity from base classes
    virtual void SAL_CALL acquire() throw() override { ContextHandler::acquire(); }
    virtual void SAL_CALL release() throw() override { ContextHandler::release(); }

    // com.sun.star.xml.sax.XFastContextHandler interface ---------------------

    virtual css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL
                        createFastChildContext(
                            sal_Int32 nElement,
                            const css::uno::Reference< css::xml::sax::XFastAttributeList >& rxAttribs ) final override;

    virtual void SAL_CALL startFastElement(
                            sal_Int32 nElement,
                            const css::uno::Reference< css::xml::sax::XFastAttributeList >& rxAttribs ) final override;

    virtual void SAL_CALL characters( const OUString& rChars ) final override;

    virtual void SAL_CALL endFastElement( sal_Int32 nElement ) final override;

    // oox.core.ContextHandler interface --------------------------------------

    virtual ContextHandlerRef createRecordContext( sal_Int32 nRecId, SequenceInputStream& rStrm ) override;
    virtual void        startRecord( sal_Int32 nRecId, SequenceInputStream& rStrm ) override;
    virtual void        endRecord( sal_Int32 nRecId ) override;

    // oox.core.ContextHandler2Helper interface -------------------------------

    virtual ContextHandlerRef onCreateContext( sal_Int32 nElement, const AttributeList& rAttribs ) override;
    virtual void        onStartElement( const AttributeList& rAttribs ) override;
    virtual void        onCharacters( const OUString& rChars ) override;
    virtual void        onEndElement() override;

    virtual ContextHandlerRef onCreateRecordContext( sal_Int32 nRecId, SequenceInputStream& rStrm ) override;
    virtual void        onStartRecord( SequenceInputStream& rStrm ) override;
    virtual void        onEndRecord() override;
};

} // namespace oox::core

#endif

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */