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