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