1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 
24 #ifndef OOX_CORE_CONTEXTHANDLER2_HXX
25 #define OOX_CORE_CONTEXTHANDLER2_HXX
26 
27 #include <vector>
28 #include <boost/shared_ptr.hpp>
29 #include "oox/helper/attributelist.hxx"
30 #include "oox/helper/binaryinputstream.hxx"
31 #include "oox/core/contexthandler.hxx"
32 
33 namespace oox {
34 namespace core {
35 
36 // ============================================================================
37 
38 const sal_Int32 XML_ROOT_CONTEXT    = SAL_MAX_INT32;
39 
40 // ============================================================================
41 
42 struct ElementInfo;
43 
44 /** Helper class that provides a context stack.
45 
46     Fragment handlers and context handlers derived from this helper class will
47     track the identifiers of the visited elements in a stack. The idea is to
48     use the same instance of a fragment handler or context handler to process
49     several nested elements in an XML stream. For that, the abstract function
50     onCreateContext() has to return 'this' for the passed element.
51 
52     Derived classes have to implement the createFastChildContext(),
53     startFastElement(), characters(), and endFastElement() functions from the
54     com.sun.star.xml.sax.XFastContextHandler interface by simply forwarding
55     them to the respective implCreateChildContext(), implStartElement(),
56     implCharacters(), and implEndElement() functions of this helper. This is
57     implemented already in the classes ContextHandler2 and FragmentHandler2.
58     The new abstract functions have to be implemented according to the elements
59     to be processed.
60 
61     Similarly, for binary import, derived classes have to forward the
62     createRecordContext(), startRecord(), and endRecord() functions from the
63     ContextHandler class to the implCreateRecordContext(), implStartRecord(),
64     and implEndRecord() functions of this helper. Again, this is implemented
65     already in the classes ContextHandler2 and FragmentHandler2.
66  */
67 class ContextHandler2Helper
68 {
69 public:
70     explicit            ContextHandler2Helper( bool bEnableTrimSpace );
71     explicit            ContextHandler2Helper( const ContextHandler2Helper& rParent );
72     virtual             ~ContextHandler2Helper();
73 
74     // allow instances to be stored in ::rtl::Reference
75     virtual void SAL_CALL acquire() throw() = 0;
76     virtual void SAL_CALL release() throw() = 0;
77 
78     // interface --------------------------------------------------------------
79 
80     /** Will be called to create a context handler for the passed element.
81 
82         Usually 'this' can be returned to improve performance by reusing the
83         same instance to process several elements. Used by OOXML import only.
84      */
85     virtual ContextHandlerRef onCreateContext( sal_Int32 nElement, const AttributeList& rAttribs ) = 0;
86 
87     /** Will be called when a new element has been started.
88 
89         This function is called at the context handler returned from
90         onCreateContext(), or, for root elements of an XML stream, at the
91         fragment handler itself.
92 
93         The current element identifier can be accessed with getCurrentElement()
94         or isCurrentElement(). Used by OOXML import only.
95      */
96     virtual void        onStartElement( const AttributeList& rAttribs ) = 0;
97 
98     /** Will be called before a new child element starts, or if the current
99         element is about to be left.
100 
101         This helper function collects all text fragments received by the
102         characters() function (such as encoded characters which are passed in
103         separate calls to the characters() function), and passes the
104         concatenated and trimmed string.
105 
106         The current element identifier can be accessed with getCurrentElement()
107         or isCurrentElement(). Used by OOXML import only.
108      */
109     virtual void        onCharacters( const ::rtl::OUString& rChars ) = 0;
110 
111     /** Will be called when the current element is about to be left.
112 
113         The current element identifier can be accessed with getCurrentElement()
114         or isCurrentElement(). Used by OOXML import only.
115      */
116     virtual void        onEndElement() = 0;
117 
118     /** Will be called to create a context handler for the passed record.
119 
120         Usually 'this' can be returned to improve performance by reusing the
121         same instance to process several records. Used by BIFF import only.
122      */
123     virtual ContextHandlerRef onCreateRecordContext( sal_Int32 nRecId, SequenceInputStream& rStrm ) = 0;
124 
125     /** Will be called when a new record block in a binary stream has been
126         started.
127 
128         The current record identifier can be accessed with getCurrentElement()
129         or isCurrentElement(). Used by BIFF import only.
130      */
131     virtual void        onStartRecord( SequenceInputStream& rStrm ) = 0;
132 
133     /** Will be called when the current record block is about to be left.
134 
135         The current record identifier can be accessed with getCurrentElement()
136         or isCurrentElement(). Used by BIFF import only.
137      */
138     virtual void        onEndRecord() = 0;
139 
140     // helpers ----------------------------------------------------------------
141 
142     /** Returns the identifier of the currently processed element. */
143     sal_Int32           getCurrentElement() const;
144 
145     /** Returns true, if nElement contains the identifier of the currently
146         processed element. */
isCurrentElement(sal_Int32 nElement) const147     inline bool         isCurrentElement( sal_Int32 nElement ) const
148                             { return getCurrentElement() == nElement; }
149 
150     /** Returns true, if either nElement1 or nElement2 contain the identifier
151         of the currently processed element. */
isCurrentElement(sal_Int32 nElement1,sal_Int32 nElement2) const152     inline bool         isCurrentElement( sal_Int32 nElement1, sal_Int32 nElement2 ) const
153                             { return isCurrentElement( nElement1 ) || isCurrentElement( nElement2 ); }
154 
155     /** Returns the identifier of the specified parent element. */
156     sal_Int32           getParentElement( sal_Int32 nCountBack = 1 ) const;
157 
158     /** Returns true, if nElement contains the identifier of the specified
159         parent element. */
isParentElement(sal_Int32 nElement,sal_Int32 nCountBack=1) const160     inline sal_Int32    isParentElement( sal_Int32 nElement, sal_Int32 nCountBack = 1 ) const
161                             { return getParentElement( nCountBack ) == nElement; }
162 
163     /** Returns true, if the element currently processed is the root element of
164         the context or fragment handler. */
165     bool                isRootElement() const;
166 
167     // implementation ---------------------------------------------------------
168 
169 protected:
170     /** Must be called from createFastChildContext() in derived classes. */
171     ::com::sun::star::uno::Reference< ::com::sun::star::xml::sax::XFastContextHandler >
172                         implCreateChildContext(
173                             sal_Int32 nElement,
174                             const ::com::sun::star::uno::Reference< ::com::sun::star::xml::sax::XFastAttributeList >& rxAttribs );
175 
176     /** Must be called from startFastElement() in derived classes. */
177     void                implStartElement(
178                             sal_Int32 nElement,
179                             const ::com::sun::star::uno::Reference< ::com::sun::star::xml::sax::XFastAttributeList >& rxAttribs );
180 
181     /** Must be called from characters() in derived classes. */
182     void                implCharacters( const ::rtl::OUString& rChars );
183 
184     /** Must be called from endFastElement() in derived classes. */
185     void                implEndElement( sal_Int32 nElement );
186 
187     /** Must be called from createRecordContext() in derived classes. */
188     ContextHandlerRef   implCreateRecordContext( sal_Int32 nRecId, SequenceInputStream& rStrm );
189 
190     /** Must be called from startRecord() in derived classes. */
191     void                implStartRecord( sal_Int32 nRecId, SequenceInputStream& rStrm );
192 
193     /** Must be called from endRecord() in derived classes. */
194     void                implEndRecord( sal_Int32 nRecId );
195 
196 private:
197     ContextHandler2Helper& operator=( const ContextHandler2Helper& );
198 
199     ElementInfo&        pushElementInfo( sal_Int32 nElement );
200     void                popElementInfo();
201     void                processCollectedChars();
202 
203 private:
204     typedef ::std::vector< ElementInfo >        ContextStack;
205     typedef ::boost::shared_ptr< ContextStack > ContextStackRef;
206 
207     ContextStackRef     mxContextStack;     /// Stack of all processed elements.
208     size_t              mnRootStackSize;    /// Stack size on construction time.
209     bool                mbEnableTrimSpace;  /// True = trim whitespace in characters().
210 };
211 
212 // ============================================================================
213 
214 class ContextHandler2 : public ContextHandler, public ContextHandler2Helper
215 {
216 public:
217     explicit            ContextHandler2( ContextHandler2Helper& rParent );
218     virtual             ~ContextHandler2();
219 
220     // resolve ambiguity from base classes
acquire()221     virtual void SAL_CALL acquire() throw() { ContextHandler::acquire(); }
release()222     virtual void SAL_CALL release() throw() { ContextHandler::release(); }
223 
224     // com.sun.star.xml.sax.XFastContextHandler interface ---------------------
225 
226     virtual ::com::sun::star::uno::Reference< ::com::sun::star::xml::sax::XFastContextHandler > SAL_CALL
227                         createFastChildContext(
228                             sal_Int32 nElement,
229                             const ::com::sun::star::uno::Reference< ::com::sun::star::xml::sax::XFastAttributeList >& rxAttribs )
230                             throw(  ::com::sun::star::xml::sax::SAXException,
231                                     ::com::sun::star::uno::RuntimeException );
232 
233     virtual void SAL_CALL startFastElement(
234                             sal_Int32 nElement,
235                             const ::com::sun::star::uno::Reference< ::com::sun::star::xml::sax::XFastAttributeList >& rxAttribs )
236                             throw(  ::com::sun::star::xml::sax::SAXException,
237                                     ::com::sun::star::uno::RuntimeException );
238 
239     virtual void SAL_CALL characters( const ::rtl::OUString& rChars )
240                             throw(  ::com::sun::star::xml::sax::SAXException,
241                                     ::com::sun::star::uno::RuntimeException );
242 
243     virtual void SAL_CALL endFastElement( sal_Int32 nElement )
244                             throw(  ::com::sun::star::xml::sax::SAXException,
245                                     ::com::sun::star::uno::RuntimeException );
246 
247     // oox.core.ContextHandler interface --------------------------------------
248 
249     virtual ContextHandlerRef createRecordContext( sal_Int32 nRecId, SequenceInputStream& rStrm );
250     virtual void        startRecord( sal_Int32 nRecId, SequenceInputStream& rStrm );
251     virtual void        endRecord( sal_Int32 nRecId );
252 
253     // oox.core.ContextHandler2Helper interface -------------------------------
254 
255     virtual ContextHandlerRef onCreateContext( sal_Int32 nElement, const AttributeList& rAttribs );
256     virtual void        onStartElement( const AttributeList& rAttribs );
257     virtual void        onCharacters( const ::rtl::OUString& rChars );
258     virtual void        onEndElement();
259 
260     virtual ContextHandlerRef onCreateRecordContext( sal_Int32 nRecId, SequenceInputStream& rStrm );
261     virtual void        onStartRecord( SequenceInputStream& rStrm );
262     virtual void        onEndRecord();
263 };
264 
265 // ============================================================================
266 
267 } // namespace core
268 } // namespace oox
269 
270 #endif
271