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 #include "oox/core/contexthandler2.hxx"
25 #include <rtl/ustrbuf.hxx>
26 
27 namespace oox {
28 namespace core {
29 
30 // ============================================================================
31 
32 using namespace ::com::sun::star::uno;
33 using namespace ::com::sun::star::xml::sax;
34 
35 using ::rtl::OUString;
36 using ::rtl::OUStringBuffer;
37 
38 // ============================================================================
39 
40 /** Information about a processed element. */
41 struct ElementInfo
42 {
43     OUStringBuffer      maChars;            /// Collected element characters.
44     sal_Int32           mnElement;          /// The element identifier.
45     bool                mbTrimSpaces;       /// True = trims leading/trailing spaces from text data.
46 
ElementInfooox::core::ElementInfo47     inline explicit     ElementInfo() : mnElement( XML_TOKEN_INVALID ), mbTrimSpaces( false ) {}
48 };
49 
50 // ============================================================================
51 
ContextHandler2Helper(bool bEnableTrimSpace)52 ContextHandler2Helper::ContextHandler2Helper( bool bEnableTrimSpace ) :
53     mxContextStack( new ContextStack ),
54     mnRootStackSize( 0 ),
55     mbEnableTrimSpace( bEnableTrimSpace )
56 {
57     pushElementInfo( XML_ROOT_CONTEXT );
58 }
59 
ContextHandler2Helper(const ContextHandler2Helper & rParent)60 ContextHandler2Helper::ContextHandler2Helper( const ContextHandler2Helper& rParent ) :
61     mxContextStack( rParent.mxContextStack ),
62     mnRootStackSize( rParent.mxContextStack->size() ),
63     mbEnableTrimSpace( rParent.mbEnableTrimSpace )
64 {
65 }
66 
~ContextHandler2Helper()67 ContextHandler2Helper::~ContextHandler2Helper()
68 {
69 }
70 
getCurrentElement() const71 sal_Int32 ContextHandler2Helper::getCurrentElement() const
72 {
73     return mxContextStack->empty() ? XML_ROOT_CONTEXT : mxContextStack->back().mnElement;
74 }
75 
getParentElement(sal_Int32 nCountBack) const76 sal_Int32 ContextHandler2Helper::getParentElement( sal_Int32 nCountBack ) const
77 {
78     if( (nCountBack < 0) || (mxContextStack->size() < static_cast< size_t >( nCountBack )) )
79         return XML_TOKEN_INVALID;
80     return (mxContextStack->size() == static_cast< size_t >( nCountBack )) ?
81         XML_ROOT_CONTEXT : (*mxContextStack)[ mxContextStack->size() - nCountBack - 1 ].mnElement;
82 }
83 
isRootElement() const84 bool ContextHandler2Helper::isRootElement() const
85 {
86     return mxContextStack->size() == mnRootStackSize + 1;
87 }
88 
implCreateChildContext(sal_Int32 nElement,const Reference<XFastAttributeList> & rxAttribs)89 Reference< XFastContextHandler > ContextHandler2Helper::implCreateChildContext(
90         sal_Int32 nElement, const Reference< XFastAttributeList >& rxAttribs )
91 {
92     // #i76091# process collected characters (calls onCharacters() if needed)
93     processCollectedChars();
94     ContextHandlerRef xContext = onCreateContext( nElement, AttributeList( rxAttribs ) );
95     return Reference< XFastContextHandler >( xContext.get() );
96 }
97 
implStartElement(sal_Int32 nElement,const Reference<XFastAttributeList> & rxAttribs)98 void ContextHandler2Helper::implStartElement( sal_Int32 nElement, const Reference< XFastAttributeList >& rxAttribs )
99 {
100     AttributeList aAttribs( rxAttribs );
101     pushElementInfo( nElement ).mbTrimSpaces = aAttribs.getToken( XML_TOKEN( space ), XML_TOKEN_INVALID ) != XML_preserve;
102     onStartElement( aAttribs );
103 }
104 
implCharacters(const OUString & rChars)105 void ContextHandler2Helper::implCharacters( const OUString& rChars )
106 {
107     // #i76091# collect characters until new element starts or this element ends
108     if( !mxContextStack->empty() )
109         mxContextStack->back().maChars.append( rChars );
110 }
111 
implEndElement(sal_Int32 nElement)112 void ContextHandler2Helper::implEndElement( sal_Int32 nElement )
113 {
114     (void)nElement;     // prevent "unused parameter" warning in product build
115     OSL_ENSURE( getCurrentElement() == nElement, "ContextHandler2Helper::implEndElement - context stack broken" );
116     if( !mxContextStack->empty() )
117     {
118         // #i76091# process collected characters (calls onCharacters() if needed)
119         processCollectedChars();
120         onEndElement();
121         popElementInfo();
122     }
123 }
124 
implCreateRecordContext(sal_Int32 nRecId,SequenceInputStream & rStrm)125 ContextHandlerRef ContextHandler2Helper::implCreateRecordContext( sal_Int32 nRecId, SequenceInputStream& rStrm )
126 {
127     return onCreateRecordContext( nRecId, rStrm );
128 }
129 
implStartRecord(sal_Int32 nRecId,SequenceInputStream & rStrm)130 void ContextHandler2Helper::implStartRecord( sal_Int32 nRecId, SequenceInputStream& rStrm )
131 {
132     pushElementInfo( nRecId );
133     onStartRecord( rStrm );
134 }
135 
implEndRecord(sal_Int32 nRecId)136 void ContextHandler2Helper::implEndRecord( sal_Int32 nRecId )
137 {
138     (void)nRecId;   // prevent "unused parameter" warning in product build
139     OSL_ENSURE( getCurrentElement() == nRecId, "ContextHandler2Helper::implEndRecord - context stack broken" );
140     if( !mxContextStack->empty() )
141     {
142         onEndRecord();
143         popElementInfo();
144     }
145 }
146 
pushElementInfo(sal_Int32 nElement)147 ElementInfo& ContextHandler2Helper::pushElementInfo( sal_Int32 nElement )
148 {
149     mxContextStack->resize( mxContextStack->size() + 1 );
150     ElementInfo& rInfo = mxContextStack->back();
151     rInfo.mnElement = nElement;
152     return rInfo;
153 }
154 
popElementInfo()155 void ContextHandler2Helper::popElementInfo()
156 {
157     OSL_ENSURE( !mxContextStack->empty(), "ContextHandler2Helper::popElementInfo - context stack broken" );
158     if( !mxContextStack->empty() )
159         mxContextStack->pop_back();
160 }
161 
processCollectedChars()162 void ContextHandler2Helper::processCollectedChars()
163 {
164     OSL_ENSURE( !mxContextStack->empty(), "ContextHandler2Helper::processCollectedChars - no context info" );
165     ElementInfo& rInfo = mxContextStack->back();
166     if( rInfo.maChars.getLength() > 0 )
167     {
168         OUString aChars = rInfo.maChars.makeStringAndClear();
169         if( mbEnableTrimSpace && rInfo.mbTrimSpaces )
170             aChars = aChars.trim();
171         if( aChars.getLength() > 0 )
172             onCharacters( aChars );
173     }
174 }
175 
176 // ============================================================================
177 
ContextHandler2(ContextHandler2Helper & rParent)178 ContextHandler2::ContextHandler2( ContextHandler2Helper& rParent ) :
179     ContextHandler( dynamic_cast< ContextHandler& >( rParent ) ),
180     ContextHandler2Helper( rParent )
181 {
182 }
183 
~ContextHandler2()184 ContextHandler2::~ContextHandler2()
185 {
186 }
187 
188 // com.sun.star.xml.sax.XFastContextHandler interface -------------------------
189 
createFastChildContext(sal_Int32 nElement,const Reference<XFastAttributeList> & rxAttribs)190 Reference< XFastContextHandler > SAL_CALL ContextHandler2::createFastChildContext(
191         sal_Int32 nElement, const Reference< XFastAttributeList >& rxAttribs ) throw( SAXException, RuntimeException )
192 {
193     return implCreateChildContext( nElement, rxAttribs );
194 }
195 
startFastElement(sal_Int32 nElement,const Reference<XFastAttributeList> & rxAttribs)196 void SAL_CALL ContextHandler2::startFastElement(
197         sal_Int32 nElement, const Reference< XFastAttributeList >& rxAttribs ) throw( SAXException, RuntimeException )
198 {
199     implStartElement( nElement, rxAttribs );
200 }
201 
characters(const OUString & rChars)202 void SAL_CALL ContextHandler2::characters( const OUString& rChars ) throw( SAXException, RuntimeException )
203 {
204     implCharacters( rChars );
205 }
206 
endFastElement(sal_Int32 nElement)207 void SAL_CALL ContextHandler2::endFastElement( sal_Int32 nElement ) throw( SAXException, RuntimeException )
208 {
209     implEndElement( nElement );
210 }
211 
212 // oox.core.RecordContext interface -------------------------------------------
213 
createRecordContext(sal_Int32 nRecId,SequenceInputStream & rStrm)214 ContextHandlerRef ContextHandler2::createRecordContext( sal_Int32 nRecId, SequenceInputStream& rStrm )
215 {
216     return implCreateRecordContext( nRecId, rStrm );
217 }
218 
startRecord(sal_Int32 nRecId,SequenceInputStream & rStrm)219 void ContextHandler2::startRecord( sal_Int32 nRecId, SequenceInputStream& rStrm )
220 {
221     implStartRecord( nRecId, rStrm );
222 }
223 
endRecord(sal_Int32 nRecId)224 void ContextHandler2::endRecord( sal_Int32 nRecId )
225 {
226     implEndRecord( nRecId );
227 }
228 
229 // oox.core.ContextHandler2Helper interface -----------------------------------
230 
onCreateContext(sal_Int32,const AttributeList &)231 ContextHandlerRef ContextHandler2::onCreateContext( sal_Int32, const AttributeList& )
232 {
233     return 0;
234 }
235 
onStartElement(const AttributeList &)236 void ContextHandler2::onStartElement( const AttributeList& )
237 {
238 }
239 
onCharacters(const OUString &)240 void ContextHandler2::onCharacters( const OUString& )
241 {
242 }
243 
onEndElement()244 void ContextHandler2::onEndElement()
245 {
246 }
247 
onCreateRecordContext(sal_Int32,SequenceInputStream &)248 ContextHandlerRef ContextHandler2::onCreateRecordContext( sal_Int32, SequenceInputStream& )
249 {
250     return 0;
251 }
252 
onStartRecord(SequenceInputStream &)253 void ContextHandler2::onStartRecord( SequenceInputStream& )
254 {
255 }
256 
onEndRecord()257 void ContextHandler2::onEndRecord()
258 {
259 }
260 
261 // ============================================================================
262 
263 } // namespace core
264 } // namespace oox
265