xref: /aoo41x/main/oox/source/vml/vmlinputstream.cxx (revision ca5ec200)
1*ca5ec200SAndrew Rist /**************************************************************
2cdf0e10cSrcweir  *
3*ca5ec200SAndrew Rist  * Licensed to the Apache Software Foundation (ASF) under one
4*ca5ec200SAndrew Rist  * or more contributor license agreements.  See the NOTICE file
5*ca5ec200SAndrew Rist  * distributed with this work for additional information
6*ca5ec200SAndrew Rist  * regarding copyright ownership.  The ASF licenses this file
7*ca5ec200SAndrew Rist  * to you under the Apache License, Version 2.0 (the
8*ca5ec200SAndrew Rist  * "License"); you may not use this file except in compliance
9*ca5ec200SAndrew Rist  * with the License.  You may obtain a copy of the License at
10*ca5ec200SAndrew Rist  *
11*ca5ec200SAndrew Rist  *   http://www.apache.org/licenses/LICENSE-2.0
12*ca5ec200SAndrew Rist  *
13*ca5ec200SAndrew Rist  * Unless required by applicable law or agreed to in writing,
14*ca5ec200SAndrew Rist  * software distributed under the License is distributed on an
15*ca5ec200SAndrew Rist  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16*ca5ec200SAndrew Rist  * KIND, either express or implied.  See the License for the
17*ca5ec200SAndrew Rist  * specific language governing permissions and limitations
18*ca5ec200SAndrew Rist  * under the License.
19*ca5ec200SAndrew Rist  *
20*ca5ec200SAndrew Rist  *************************************************************/
21*ca5ec200SAndrew Rist 
22*ca5ec200SAndrew 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 
lclFindCharacter(const sal_Char * pcBeg,const sal_Char * pcEnd,sal_Char cChar)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 
lclIsWhiteSpace(sal_Char cChar)54cdf0e10cSrcweir inline bool lclIsWhiteSpace( sal_Char cChar )
55cdf0e10cSrcweir {
56cdf0e10cSrcweir     return cChar < 32;
57cdf0e10cSrcweir }
58cdf0e10cSrcweir 
lclFindWhiteSpace(const sal_Char * pcBeg,const sal_Char * pcEnd)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 
lclFindNonWhiteSpace(const sal_Char * pcBeg,const sal_Char * pcEnd)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 
lclTrimWhiteSpaceFromEnd(const sal_Char * pcBeg,const sal_Char * pcEnd)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 
lclAppendToBuffer(OStringBuffer & rBuffer,const sal_Char * pcBeg,const sal_Char * pcEnd)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 
lclProcessAttribs(OStringBuffer & rBuffer,const sal_Char * pcBeg,const sal_Char * pcEnd)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
92cdf0e10cSrcweir         to find multiple occurences 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 
143cdf0e10cSrcweir     // if no error has occured, 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 
lclProcessElement(OStringBuffer & rBuffer,const OString & rElement)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 
lclProcessCharacters(OStringBuffer & rBuffer,const OString & rChars)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 
InputStream(const Reference<XComponentContext> & rxContext,const Reference<XInputStream> & rxInStrm)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 
~InputStream()280cdf0e10cSrcweir InputStream::~InputStream()
281cdf0e10cSrcweir {
282cdf0e10cSrcweir }
283cdf0e10cSrcweir 
readBytes(Sequence<sal_Int8> & rData,sal_Int32 nBytesToRead)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 
readSomeBytes(Sequence<sal_Int8> & rData,sal_Int32 nMaxBytesToRead)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 
skipBytes(sal_Int32 nBytesToSkip)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 
available()331cdf0e10cSrcweir sal_Int32 SAL_CALL InputStream::available() throw (NotConnectedException, IOException, RuntimeException)
332cdf0e10cSrcweir {
333cdf0e10cSrcweir     updateBuffer();
334cdf0e10cSrcweir     return maBuffer.getLength() - mnBufferPos;
335cdf0e10cSrcweir }
336cdf0e10cSrcweir 
closeInput()337cdf0e10cSrcweir void SAL_CALL InputStream::closeInput() throw (NotConnectedException, IOException, RuntimeException)
338cdf0e10cSrcweir {
339cdf0e10cSrcweir     mxTextStrm->closeInput();
340cdf0e10cSrcweir }
341cdf0e10cSrcweir 
342cdf0e10cSrcweir // private --------------------------------------------------------------------
343cdf0e10cSrcweir 
updateBuffer()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 
readToElementBegin()382cdf0e10cSrcweir OString InputStream::readToElementBegin() throw (IOException, RuntimeException)
383cdf0e10cSrcweir {
384cdf0e10cSrcweir     return OUStringToOString( mxTextStrm->readString( maOpeningBracket, sal_False ), RTL_TEXTENCODING_ISO_8859_1 );
385cdf0e10cSrcweir }
386cdf0e10cSrcweir 
readToElementEnd()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