1ca5ec200SAndrew Rist /************************************************************** 2cdf0e10cSrcweir * 3ca5ec200SAndrew Rist * Licensed to the Apache Software Foundation (ASF) under one 4ca5ec200SAndrew Rist * or more contributor license agreements. See the NOTICE file 5ca5ec200SAndrew Rist * distributed with this work for additional information 6ca5ec200SAndrew Rist * regarding copyright ownership. The ASF licenses this file 7ca5ec200SAndrew Rist * to you under the Apache License, Version 2.0 (the 8ca5ec200SAndrew Rist * "License"); you may not use this file except in compliance 9ca5ec200SAndrew Rist * with the License. You may obtain a copy of the License at 10cdf0e10cSrcweir * 11ca5ec200SAndrew Rist * http://www.apache.org/licenses/LICENSE-2.0 12cdf0e10cSrcweir * 13ca5ec200SAndrew Rist * Unless required by applicable law or agreed to in writing, 14ca5ec200SAndrew Rist * software distributed under the License is distributed on an 15ca5ec200SAndrew Rist * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16ca5ec200SAndrew Rist * KIND, either express or implied. See the License for the 17ca5ec200SAndrew Rist * specific language governing permissions and limitations 18ca5ec200SAndrew Rist * under the License. 19cdf0e10cSrcweir * 20ca5ec200SAndrew Rist *************************************************************/ 21ca5ec200SAndrew Rist 22ca5ec200SAndrew Rist 23cdf0e10cSrcweir 24cdf0e10cSrcweir #include "oox/vml/vmlinputstream.hxx" 25cdf0e10cSrcweir 26cdf0e10cSrcweir #include <com/sun/star/io/XTextInputStream.hpp> 27cdf0e10cSrcweir #include <map> 28cdf0e10cSrcweir #include <string.h> 29cdf0e10cSrcweir #include <rtl/strbuf.hxx> 30cdf0e10cSrcweir #include "oox/helper/helper.hxx" 31cdf0e10cSrcweir #include "oox/helper/textinputstream.hxx" 32cdf0e10cSrcweir 33cdf0e10cSrcweir namespace oox { 34cdf0e10cSrcweir namespace vml { 35cdf0e10cSrcweir 36cdf0e10cSrcweir // ============================================================================ 37cdf0e10cSrcweir 38cdf0e10cSrcweir using namespace ::com::sun::star::io; 39cdf0e10cSrcweir using namespace ::com::sun::star::uno; 40cdf0e10cSrcweir 41cdf0e10cSrcweir using ::rtl::OString; 42cdf0e10cSrcweir using ::rtl::OStringBuffer; 43cdf0e10cSrcweir 44cdf0e10cSrcweir // ============================================================================ 45cdf0e10cSrcweir 46cdf0e10cSrcweir namespace { 47cdf0e10cSrcweir 48cdf0e10cSrcweir inline const sal_Char* lclFindCharacter( const sal_Char* pcBeg, const sal_Char* pcEnd, sal_Char cChar ) 49cdf0e10cSrcweir { 50cdf0e10cSrcweir sal_Int32 nIndex = rtl_str_indexOfChar_WithLength( pcBeg, static_cast< sal_Int32 >( pcEnd - pcBeg ), cChar ); 51cdf0e10cSrcweir return (nIndex < 0) ? pcEnd : (pcBeg + nIndex); 52cdf0e10cSrcweir } 53cdf0e10cSrcweir 54cdf0e10cSrcweir inline bool lclIsWhiteSpace( sal_Char cChar ) 55cdf0e10cSrcweir { 56cdf0e10cSrcweir return cChar < 32; 57cdf0e10cSrcweir } 58cdf0e10cSrcweir 59cdf0e10cSrcweir const sal_Char* lclFindWhiteSpace( const sal_Char* pcBeg, const sal_Char* pcEnd ) 60cdf0e10cSrcweir { 61cdf0e10cSrcweir for( ; pcBeg < pcEnd; ++pcBeg ) 62cdf0e10cSrcweir if( lclIsWhiteSpace( *pcBeg ) ) 63cdf0e10cSrcweir return pcBeg; 64cdf0e10cSrcweir return pcEnd; 65cdf0e10cSrcweir } 66cdf0e10cSrcweir 67cdf0e10cSrcweir const sal_Char* lclFindNonWhiteSpace( const sal_Char* pcBeg, const sal_Char* pcEnd ) 68cdf0e10cSrcweir { 69cdf0e10cSrcweir for( ; pcBeg < pcEnd; ++pcBeg ) 70cdf0e10cSrcweir if( !lclIsWhiteSpace( *pcBeg ) ) 71cdf0e10cSrcweir return pcBeg; 72cdf0e10cSrcweir return pcEnd; 73cdf0e10cSrcweir } 74cdf0e10cSrcweir 75cdf0e10cSrcweir const sal_Char* lclTrimWhiteSpaceFromEnd( const sal_Char* pcBeg, const sal_Char* pcEnd ) 76cdf0e10cSrcweir { 77cdf0e10cSrcweir while( (pcBeg < pcEnd) && lclIsWhiteSpace( pcEnd[ -1 ] ) ) 78cdf0e10cSrcweir --pcEnd; 79cdf0e10cSrcweir return pcEnd; 80cdf0e10cSrcweir } 81cdf0e10cSrcweir 82cdf0e10cSrcweir inline void lclAppendToBuffer( OStringBuffer& rBuffer, const sal_Char* pcBeg, const sal_Char* pcEnd ) 83cdf0e10cSrcweir { 84cdf0e10cSrcweir rBuffer.append( pcBeg, static_cast< sal_Int32 >( pcEnd - pcBeg ) ); 85cdf0e10cSrcweir } 86cdf0e10cSrcweir 87cdf0e10cSrcweir // ---------------------------------------------------------------------------- 88cdf0e10cSrcweir 89cdf0e10cSrcweir void lclProcessAttribs( OStringBuffer& rBuffer, const sal_Char* pcBeg, const sal_Char* pcEnd ) 90cdf0e10cSrcweir { 91cdf0e10cSrcweir /* Map attribute names to char-pointer of all attributes. This map is used 92*a893be29SPedro Giffuni to find multiple occurrences of attributes with the same name. The 93cdf0e10cSrcweir mapped pointers are used as map key in the next map below. */ 94cdf0e10cSrcweir typedef ::std::map< OString, const sal_Char* > AttributeNameMap; 95cdf0e10cSrcweir AttributeNameMap aAttributeNames; 96cdf0e10cSrcweir 97cdf0e10cSrcweir /* Map the char-pointers of all attributes to the full attribute definition 98cdf0e10cSrcweir string. This preserves the original order of the used attributes. */ 99cdf0e10cSrcweir typedef ::std::map< const sal_Char*, OString > AttributeDataMap; 100cdf0e10cSrcweir AttributeDataMap aAttributes; 101cdf0e10cSrcweir 102cdf0e10cSrcweir bool bOk = true; 103cdf0e10cSrcweir const sal_Char* pcNameBeg = pcBeg; 104cdf0e10cSrcweir while( bOk && (pcNameBeg < pcEnd) ) 105cdf0e10cSrcweir { 106cdf0e10cSrcweir // pcNameBeg points to begin of attribute name, find equality sign 107cdf0e10cSrcweir const sal_Char* pcEqualSign = lclFindCharacter( pcNameBeg, pcEnd, '=' ); 108cdf0e10cSrcweir if( (bOk = pcEqualSign < pcEnd) == true ) 109cdf0e10cSrcweir { 110cdf0e10cSrcweir // find end of attribute name (ignore whitespace between name and equality sign) 111cdf0e10cSrcweir const sal_Char* pcNameEnd = lclTrimWhiteSpaceFromEnd( pcNameBeg, pcEqualSign ); 112cdf0e10cSrcweir if( (bOk = pcNameBeg < pcNameEnd) == true ) 113cdf0e10cSrcweir { 114cdf0e10cSrcweir // find begin of attribute value (must be single or double quote) 115cdf0e10cSrcweir const sal_Char* pcValueBeg = lclFindNonWhiteSpace( pcEqualSign + 1, pcEnd ); 116cdf0e10cSrcweir if( (bOk = (pcValueBeg < pcEnd) && ((*pcValueBeg == '\'') || (*pcValueBeg == '"'))) == true ) 117cdf0e10cSrcweir { 118cdf0e10cSrcweir // find end of attribute value (matching quote character) 119cdf0e10cSrcweir const sal_Char* pcValueEnd = lclFindCharacter( pcValueBeg + 1, pcEnd, *pcValueBeg ); 120cdf0e10cSrcweir if( (bOk = pcValueEnd < pcEnd) == true ) 121cdf0e10cSrcweir { 122cdf0e10cSrcweir ++pcValueEnd; 123cdf0e10cSrcweir OString aAttribName( pcNameBeg, static_cast< sal_Int32 >( pcNameEnd - pcNameBeg ) ); 124cdf0e10cSrcweir OString aAttribData( pcNameBeg, static_cast< sal_Int32 >( pcValueEnd - pcNameBeg ) ); 125cdf0e10cSrcweir // search for an existing attribute with the same name 126cdf0e10cSrcweir AttributeNameMap::iterator aIt = aAttributeNames.find( aAttribName ); 127cdf0e10cSrcweir // remove its definition from the data map 128cdf0e10cSrcweir if( aIt != aAttributeNames.end() ) 129cdf0e10cSrcweir aAttributes.erase( aIt->second ); 130cdf0e10cSrcweir // insert the attribute into both maps 131cdf0e10cSrcweir aAttributeNames[ aAttribName ] = pcNameBeg; 132cdf0e10cSrcweir aAttributes[ pcNameBeg ] = aAttribData; 133cdf0e10cSrcweir // continue with next attribute (skip whitespace after this attribute) 134cdf0e10cSrcweir pcNameBeg = pcValueEnd; 135cdf0e10cSrcweir if( (pcNameBeg < pcEnd) && ((bOk = lclIsWhiteSpace( *pcNameBeg )) == true) ) 136cdf0e10cSrcweir pcNameBeg = lclFindNonWhiteSpace( pcNameBeg + 1, pcEnd ); 137cdf0e10cSrcweir } 138cdf0e10cSrcweir } 139cdf0e10cSrcweir } 140cdf0e10cSrcweir } 141cdf0e10cSrcweir } 142cdf0e10cSrcweir 143*a893be29SPedro Giffuni // if no error has occurred, build the resulting attribute list 144cdf0e10cSrcweir if( bOk ) 145cdf0e10cSrcweir for( AttributeDataMap::iterator aIt = aAttributes.begin(), aEnd = aAttributes.end(); aIt != aEnd; ++aIt ) 146cdf0e10cSrcweir rBuffer.append( ' ' ).append( aIt->second ); 147cdf0e10cSrcweir // on error, just append the complete passed string 148cdf0e10cSrcweir else 149cdf0e10cSrcweir lclAppendToBuffer( rBuffer, pcBeg, pcEnd ); 150cdf0e10cSrcweir } 151cdf0e10cSrcweir 152cdf0e10cSrcweir void lclProcessElement( OStringBuffer& rBuffer, const OString& rElement ) 153cdf0e10cSrcweir { 154cdf0e10cSrcweir // check that passed string starts and ends with the brackets of an XML element 155cdf0e10cSrcweir sal_Int32 nElementLen = rElement.getLength(); 156cdf0e10cSrcweir if( nElementLen == 0 ) 157cdf0e10cSrcweir return; 158cdf0e10cSrcweir 159cdf0e10cSrcweir const sal_Char* pcOpen = rElement.getStr(); 160cdf0e10cSrcweir const sal_Char* pcClose = pcOpen + nElementLen - 1; 161cdf0e10cSrcweir 162cdf0e10cSrcweir // no complete element found 163cdf0e10cSrcweir if( (pcOpen >= pcClose) || (*pcOpen != '<') || (*pcClose != '>') ) 164cdf0e10cSrcweir { 165cdf0e10cSrcweir // just append all passed characters 166cdf0e10cSrcweir rBuffer.append( rElement ); 167cdf0e10cSrcweir } 168cdf0e10cSrcweir 169cdf0e10cSrcweir // skip parser instructions: '<![...]>' 170cdf0e10cSrcweir else if( (nElementLen >= 5) && (pcOpen[ 1 ] == '!') && (pcOpen[ 2 ] == '[') && (pcClose[ -1 ] == ']') ) 171cdf0e10cSrcweir { 172cdf0e10cSrcweir // do nothing 173cdf0e10cSrcweir } 174cdf0e10cSrcweir 175cdf0e10cSrcweir // replace '<br>' element with newline 176cdf0e10cSrcweir else if( (nElementLen >= 4) && (pcOpen[ 1 ] == 'b') && (pcOpen[ 2 ] == 'r') && (lclFindNonWhiteSpace( pcOpen + 3, pcClose ) == pcClose) ) 177cdf0e10cSrcweir { 178cdf0e10cSrcweir rBuffer.append( '\n' ); 179cdf0e10cSrcweir } 180cdf0e10cSrcweir 181cdf0e10cSrcweir // check start elements and simple elements for repeated attributes 182cdf0e10cSrcweir else if( pcOpen[ 1 ] != '/' ) 183cdf0e10cSrcweir { 184cdf0e10cSrcweir // find positions of text content inside brackets, exclude '/' in '<simpleelement/>' 185cdf0e10cSrcweir const sal_Char* pcContentBeg = pcOpen + 1; 186cdf0e10cSrcweir bool bIsEmptyElement = pcClose[ -1 ] == '/'; 187cdf0e10cSrcweir const sal_Char* pcContentEnd = bIsEmptyElement ? (pcClose - 1) : pcClose; 188cdf0e10cSrcweir // append opening bracket and element name to buffer 189cdf0e10cSrcweir const sal_Char* pcWhiteSpace = lclFindWhiteSpace( pcContentBeg, pcContentEnd ); 190cdf0e10cSrcweir lclAppendToBuffer( rBuffer, pcOpen, pcWhiteSpace ); 191cdf0e10cSrcweir // find begin of attributes, and process all attributes 192cdf0e10cSrcweir const sal_Char* pcAttribBeg = lclFindNonWhiteSpace( pcWhiteSpace, pcContentEnd ); 193cdf0e10cSrcweir if( pcAttribBeg < pcContentEnd ) 194cdf0e10cSrcweir lclProcessAttribs( rBuffer, pcAttribBeg, pcContentEnd ); 195cdf0e10cSrcweir // close the element 196cdf0e10cSrcweir if( bIsEmptyElement ) 197cdf0e10cSrcweir rBuffer.append( '/' ); 198cdf0e10cSrcweir rBuffer.append( '>' ); 199cdf0e10cSrcweir } 200cdf0e10cSrcweir 201cdf0e10cSrcweir // append end elements without further processing 202cdf0e10cSrcweir else 203cdf0e10cSrcweir { 204cdf0e10cSrcweir rBuffer.append( rElement ); 205cdf0e10cSrcweir } 206cdf0e10cSrcweir } 207cdf0e10cSrcweir 208cdf0e10cSrcweir bool lclProcessCharacters( OStringBuffer& rBuffer, const OString& rChars ) 209cdf0e10cSrcweir { 210cdf0e10cSrcweir /* MSO has a very weird way to store and handle whitespaces. The stream 211cdf0e10cSrcweir may contain lots of spaces, tabs, and newlines which have to be handled 212cdf0e10cSrcweir as single space character. This will be done in this function. 213cdf0e10cSrcweir 214cdf0e10cSrcweir If the element text contains a literal line break, it will be stored as 215cdf0e10cSrcweir <br> tag (without matching </br> element). This input stream wrapper 216cdf0e10cSrcweir will replace this element with a literal LF character (see below). 217cdf0e10cSrcweir 218cdf0e10cSrcweir A single space character for its own is stored as is. Example: The 219cdf0e10cSrcweir element 220cdf0e10cSrcweir <font> </font> 221cdf0e10cSrcweir represents a single space character. The XML parser will ignore this 222cdf0e10cSrcweir space character completely without issuing a 'characters' event. The 223cdf0e10cSrcweir VML import filter implementation has to react on this case manually. 224cdf0e10cSrcweir 225cdf0e10cSrcweir A single space character following another character is stored 226cdf0e10cSrcweir literally and must not be stipped away here. Example: The element 227cdf0e10cSrcweir <font>abc </font> 228cdf0e10cSrcweir contains the three letters a, b, and c, followed by a space character. 229cdf0e10cSrcweir 230cdf0e10cSrcweir Consecutive space characters, or a leading single space character, are 231cdf0e10cSrcweir stored in a <span> element. If there are N space characters (N > 1), 232cdf0e10cSrcweir then the <span> element contains exactly (N-1) NBSP (non-breaking 233cdf0e10cSrcweir space) characters, followed by a regular space character. Examples: 234cdf0e10cSrcweir The element 235cdf0e10cSrcweir <font><span style='mso-spacerun:yes'>\xA0\xA0\xA0 </span></font> 236cdf0e10cSrcweir represents 4 consecutive space characters. Has to be handled by the 237cdf0e10cSrcweir implementation. The element 238cdf0e10cSrcweir <font><span style='mso-spacerun:yes'> abc</span></font> 239cdf0e10cSrcweir represents a space characters followed by the letters a, b, c. These 240cdf0e10cSrcweir strings have to be handled by the VML import filter implementation. 241cdf0e10cSrcweir */ 242cdf0e10cSrcweir 243cdf0e10cSrcweir // passed string ends with the leading opening bracket of an XML element 244cdf0e10cSrcweir const sal_Char* pcBeg = rChars.getStr(); 245cdf0e10cSrcweir const sal_Char* pcEnd = pcBeg + rChars.getLength(); 246cdf0e10cSrcweir bool bHasBracket = (pcBeg < pcEnd) && (pcEnd[ -1 ] == '<'); 247cdf0e10cSrcweir if( bHasBracket ) --pcEnd; 248cdf0e10cSrcweir 249cdf0e10cSrcweir // skip leading whitespace 250cdf0e10cSrcweir const sal_Char* pcContentsBeg = lclFindNonWhiteSpace( pcBeg, pcEnd ); 251cdf0e10cSrcweir while( pcContentsBeg < pcEnd ) 252cdf0e10cSrcweir { 253cdf0e10cSrcweir const sal_Char* pcWhitespaceBeg = lclFindWhiteSpace( pcContentsBeg + 1, pcEnd ); 254cdf0e10cSrcweir lclAppendToBuffer( rBuffer, pcContentsBeg, pcWhitespaceBeg ); 255cdf0e10cSrcweir if( pcWhitespaceBeg < pcEnd ) 256cdf0e10cSrcweir rBuffer.append( ' ' ); 257cdf0e10cSrcweir pcContentsBeg = lclFindNonWhiteSpace( pcWhitespaceBeg, pcEnd ); 258cdf0e10cSrcweir } 259cdf0e10cSrcweir 260cdf0e10cSrcweir return bHasBracket; 261cdf0e10cSrcweir } 262cdf0e10cSrcweir 263cdf0e10cSrcweir } // namespace 264cdf0e10cSrcweir 265cdf0e10cSrcweir // ============================================================================ 266cdf0e10cSrcweir 267cdf0e10cSrcweir InputStream::InputStream( const Reference< XComponentContext >& rxContext, const Reference< XInputStream >& rxInStrm ) : 268cdf0e10cSrcweir // use single-byte ISO-8859-1 encoding which maps all byte characters to the first 256 Unicode characters 269cdf0e10cSrcweir mxTextStrm( TextInputStream::createXTextInputStream( rxContext, rxInStrm, RTL_TEXTENCODING_ISO_8859_1 ) ), 270cdf0e10cSrcweir maOpeningBracket( 1 ), 271cdf0e10cSrcweir maClosingBracket( 1 ), 272cdf0e10cSrcweir maOpeningCData( CREATE_OSTRING( "<![CDATA[" ) ), 273cdf0e10cSrcweir maClosingCData( CREATE_OSTRING( "]]>" ) ), 274cdf0e10cSrcweir mnBufferPos( 0 ) 275cdf0e10cSrcweir { 276cdf0e10cSrcweir maOpeningBracket[ 0 ] = '<'; 277cdf0e10cSrcweir maClosingBracket[ 0 ] = '>'; 278cdf0e10cSrcweir } 279cdf0e10cSrcweir 280cdf0e10cSrcweir InputStream::~InputStream() 281cdf0e10cSrcweir { 282cdf0e10cSrcweir } 283cdf0e10cSrcweir 284cdf0e10cSrcweir sal_Int32 SAL_CALL InputStream::readBytes( Sequence< sal_Int8 >& rData, sal_Int32 nBytesToRead ) 285cdf0e10cSrcweir throw (NotConnectedException, BufferSizeExceededException, IOException, RuntimeException) 286cdf0e10cSrcweir { 287cdf0e10cSrcweir if( nBytesToRead < 0 ) 288cdf0e10cSrcweir throw IOException(); 289cdf0e10cSrcweir 290cdf0e10cSrcweir rData.realloc( nBytesToRead ); 291cdf0e10cSrcweir sal_Int8* pcDest = rData.getArray(); 292cdf0e10cSrcweir sal_Int32 nRet = 0; 293cdf0e10cSrcweir while( (nBytesToRead > 0) && !mxTextStrm->isEOF() ) 294cdf0e10cSrcweir { 295cdf0e10cSrcweir updateBuffer(); 296cdf0e10cSrcweir sal_Int32 nReadSize = ::std::min( nBytesToRead, maBuffer.getLength() - mnBufferPos ); 297cdf0e10cSrcweir if( nReadSize > 0 ) 298cdf0e10cSrcweir { 299cdf0e10cSrcweir memcpy( pcDest + nRet, maBuffer.getStr() + mnBufferPos, static_cast< size_t >( nReadSize ) ); 300cdf0e10cSrcweir mnBufferPos += nReadSize; 301cdf0e10cSrcweir nBytesToRead -= nReadSize; 302cdf0e10cSrcweir nRet += nReadSize; 303cdf0e10cSrcweir } 304cdf0e10cSrcweir } 305cdf0e10cSrcweir if( nRet < rData.getLength() ) 306cdf0e10cSrcweir rData.realloc( nRet ); 307cdf0e10cSrcweir return nRet; 308cdf0e10cSrcweir } 309cdf0e10cSrcweir 310cdf0e10cSrcweir sal_Int32 SAL_CALL InputStream::readSomeBytes( Sequence< sal_Int8 >& rData, sal_Int32 nMaxBytesToRead ) 311cdf0e10cSrcweir throw (NotConnectedException, BufferSizeExceededException, IOException, RuntimeException) 312cdf0e10cSrcweir { 313cdf0e10cSrcweir return readBytes( rData, nMaxBytesToRead ); 314cdf0e10cSrcweir } 315cdf0e10cSrcweir 316cdf0e10cSrcweir void SAL_CALL InputStream::skipBytes( sal_Int32 nBytesToSkip ) 317cdf0e10cSrcweir throw (NotConnectedException, BufferSizeExceededException, IOException, RuntimeException) 318cdf0e10cSrcweir { 319cdf0e10cSrcweir if( nBytesToSkip < 0 ) 320cdf0e10cSrcweir throw IOException(); 321cdf0e10cSrcweir 322cdf0e10cSrcweir while( (nBytesToSkip > 0) && !mxTextStrm->isEOF() ) 323cdf0e10cSrcweir { 324cdf0e10cSrcweir updateBuffer(); 325cdf0e10cSrcweir sal_Int32 nSkipSize = ::std::min( nBytesToSkip, maBuffer.getLength() - mnBufferPos ); 326cdf0e10cSrcweir mnBufferPos += nSkipSize; 327cdf0e10cSrcweir nBytesToSkip -= nSkipSize; 328cdf0e10cSrcweir } 329cdf0e10cSrcweir } 330cdf0e10cSrcweir 331cdf0e10cSrcweir sal_Int32 SAL_CALL InputStream::available() throw (NotConnectedException, IOException, RuntimeException) 332cdf0e10cSrcweir { 333cdf0e10cSrcweir updateBuffer(); 334cdf0e10cSrcweir return maBuffer.getLength() - mnBufferPos; 335cdf0e10cSrcweir } 336cdf0e10cSrcweir 337cdf0e10cSrcweir void SAL_CALL InputStream::closeInput() throw (NotConnectedException, IOException, RuntimeException) 338cdf0e10cSrcweir { 339cdf0e10cSrcweir mxTextStrm->closeInput(); 340cdf0e10cSrcweir } 341cdf0e10cSrcweir 342cdf0e10cSrcweir // private -------------------------------------------------------------------- 343cdf0e10cSrcweir 344cdf0e10cSrcweir void InputStream::updateBuffer() throw (IOException, RuntimeException) 345cdf0e10cSrcweir { 346cdf0e10cSrcweir while( (mnBufferPos >= maBuffer.getLength()) && !mxTextStrm->isEOF() ) 347cdf0e10cSrcweir { 348cdf0e10cSrcweir // collect new contents in a string buffer 349cdf0e10cSrcweir OStringBuffer aBuffer; 350cdf0e10cSrcweir 351cdf0e10cSrcweir // read and process characters until the opening bracket of the next XML element 352cdf0e10cSrcweir OString aChars = readToElementBegin(); 353cdf0e10cSrcweir bool bHasOpeningBracket = lclProcessCharacters( aBuffer, aChars ); 354cdf0e10cSrcweir 355cdf0e10cSrcweir // read and process characters until (and including) closing bracket (an XML element) 356cdf0e10cSrcweir OSL_ENSURE( bHasOpeningBracket || mxTextStrm->isEOF(), "InputStream::updateBuffer - missing opening bracket of XML element" ); 357cdf0e10cSrcweir if( bHasOpeningBracket && !mxTextStrm->isEOF() ) 358cdf0e10cSrcweir { 359cdf0e10cSrcweir // read the element text (add the leading opening bracket manually) 360cdf0e10cSrcweir OString aElement = OString( '<' ) + readToElementEnd(); 361cdf0e10cSrcweir // check for CDATA part, starting with '<![CDATA[' 362cdf0e10cSrcweir if( aElement.match( maOpeningCData ) ) 363cdf0e10cSrcweir { 364cdf0e10cSrcweir // search the end tag ']]>' 365cdf0e10cSrcweir while( ((aElement.getLength() < maClosingCData.getLength()) || !aElement.match( maClosingCData, aElement.getLength() - maClosingCData.getLength() )) && !mxTextStrm->isEOF() ) 366cdf0e10cSrcweir aElement += readToElementEnd(); 367cdf0e10cSrcweir // copy the entire CDATA part 368cdf0e10cSrcweir aBuffer.append( aElement ); 369cdf0e10cSrcweir } 370cdf0e10cSrcweir else 371cdf0e10cSrcweir { 372cdf0e10cSrcweir // no CDATA part - process the contents of the element 373cdf0e10cSrcweir lclProcessElement( aBuffer, aElement ); 374cdf0e10cSrcweir } 375cdf0e10cSrcweir } 376cdf0e10cSrcweir 377cdf0e10cSrcweir maBuffer = aBuffer.makeStringAndClear(); 378cdf0e10cSrcweir mnBufferPos = 0; 379cdf0e10cSrcweir } 380cdf0e10cSrcweir } 381cdf0e10cSrcweir 382cdf0e10cSrcweir OString InputStream::readToElementBegin() throw (IOException, RuntimeException) 383cdf0e10cSrcweir { 384cdf0e10cSrcweir return OUStringToOString( mxTextStrm->readString( maOpeningBracket, sal_False ), RTL_TEXTENCODING_ISO_8859_1 ); 385cdf0e10cSrcweir } 386cdf0e10cSrcweir 387cdf0e10cSrcweir OString InputStream::readToElementEnd() throw (IOException, RuntimeException) 388cdf0e10cSrcweir { 389cdf0e10cSrcweir OString aText = OUStringToOString( mxTextStrm->readString( maClosingBracket, sal_False ), RTL_TEXTENCODING_ISO_8859_1 ); 390cdf0e10cSrcweir OSL_ENSURE( (aText.getLength() > 0) && (aText[ aText.getLength() - 1 ] == '>'), "InputStream::readToElementEnd - missing closing bracket of XML element" ); 391cdf0e10cSrcweir return aText; 392cdf0e10cSrcweir } 393cdf0e10cSrcweir 394cdf0e10cSrcweir // ============================================================================ 395cdf0e10cSrcweir 396cdf0e10cSrcweir } // namespace vml 397cdf0e10cSrcweir } // namespave oox 398