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
10ca5ec200SAndrew Rist *
11ca5ec200SAndrew Rist * http://www.apache.org/licenses/LICENSE-2.0
12ca5ec200SAndrew Rist *
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.
19ca5ec200SAndrew Rist *
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
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
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
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