xref: /AOO41X/main/oox/source/vml/vmlinputstream.cxx (revision cdf0e10c4e3984b49a9502b011690b615761d4a3)
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