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 47 inline explicit ElementInfo() : mnElement( XML_TOKEN_INVALID ), mbTrimSpaces( false ) {} 48 }; 49 50 // ============================================================================ 51 52 ContextHandler2Helper::ContextHandler2Helper( bool bEnableTrimSpace ) : 53 mxContextStack( new ContextStack ), 54 mnRootStackSize( 0 ), 55 mbEnableTrimSpace( bEnableTrimSpace ) 56 { 57 pushElementInfo( XML_ROOT_CONTEXT ); 58 } 59 60 ContextHandler2Helper::ContextHandler2Helper( const ContextHandler2Helper& rParent ) : 61 mxContextStack( rParent.mxContextStack ), 62 mnRootStackSize( rParent.mxContextStack->size() ), 63 mbEnableTrimSpace( rParent.mbEnableTrimSpace ) 64 { 65 } 66 67 ContextHandler2Helper::~ContextHandler2Helper() 68 { 69 } 70 71 sal_Int32 ContextHandler2Helper::getCurrentElement() const 72 { 73 return mxContextStack->empty() ? XML_ROOT_CONTEXT : mxContextStack->back().mnElement; 74 } 75 76 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 84 bool ContextHandler2Helper::isRootElement() const 85 { 86 return mxContextStack->size() == mnRootStackSize + 1; 87 } 88 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 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 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 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 125 ContextHandlerRef ContextHandler2Helper::implCreateRecordContext( sal_Int32 nRecId, SequenceInputStream& rStrm ) 126 { 127 return onCreateRecordContext( nRecId, rStrm ); 128 } 129 130 void ContextHandler2Helper::implStartRecord( sal_Int32 nRecId, SequenceInputStream& rStrm ) 131 { 132 pushElementInfo( nRecId ); 133 onStartRecord( rStrm ); 134 } 135 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 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 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 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 178 ContextHandler2::ContextHandler2( ContextHandler2Helper& rParent ) : 179 ContextHandler( dynamic_cast< ContextHandler& >( rParent ) ), 180 ContextHandler2Helper( rParent ) 181 { 182 } 183 184 ContextHandler2::~ContextHandler2() 185 { 186 } 187 188 // com.sun.star.xml.sax.XFastContextHandler interface ------------------------- 189 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 196 void SAL_CALL ContextHandler2::startFastElement( 197 sal_Int32 nElement, const Reference< XFastAttributeList >& rxAttribs ) throw( SAXException, RuntimeException ) 198 { 199 implStartElement( nElement, rxAttribs ); 200 } 201 202 void SAL_CALL ContextHandler2::characters( const OUString& rChars ) throw( SAXException, RuntimeException ) 203 { 204 implCharacters( rChars ); 205 } 206 207 void SAL_CALL ContextHandler2::endFastElement( sal_Int32 nElement ) throw( SAXException, RuntimeException ) 208 { 209 implEndElement( nElement ); 210 } 211 212 // oox.core.RecordContext interface ------------------------------------------- 213 214 ContextHandlerRef ContextHandler2::createRecordContext( sal_Int32 nRecId, SequenceInputStream& rStrm ) 215 { 216 return implCreateRecordContext( nRecId, rStrm ); 217 } 218 219 void ContextHandler2::startRecord( sal_Int32 nRecId, SequenceInputStream& rStrm ) 220 { 221 implStartRecord( nRecId, rStrm ); 222 } 223 224 void ContextHandler2::endRecord( sal_Int32 nRecId ) 225 { 226 implEndRecord( nRecId ); 227 } 228 229 // oox.core.ContextHandler2Helper interface ----------------------------------- 230 231 ContextHandlerRef ContextHandler2::onCreateContext( sal_Int32, const AttributeList& ) 232 { 233 return 0; 234 } 235 236 void ContextHandler2::onStartElement( const AttributeList& ) 237 { 238 } 239 240 void ContextHandler2::onCharacters( const OUString& ) 241 { 242 } 243 244 void ContextHandler2::onEndElement() 245 { 246 } 247 248 ContextHandlerRef ContextHandler2::onCreateRecordContext( sal_Int32, SequenceInputStream& ) 249 { 250 return 0; 251 } 252 253 void ContextHandler2::onStartRecord( SequenceInputStream& ) 254 { 255 } 256 257 void ContextHandler2::onEndRecord() 258 { 259 } 260 261 // ============================================================================ 262 263 } // namespace core 264 } // namespace oox 265