1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 #include "oox/helper/textinputstream.hxx"
29 
30 #include <com/sun/star/io/XActiveDataSink.hpp>
31 #include <com/sun/star/io/XTextInputStream.hpp>
32 #include <cppuhelper/implbase1.hxx>
33 #include <rtl/tencinfo.h>
34 #include "oox/helper/binaryinputstream.hxx"
35 
36 namespace oox {
37 
38 // ============================================================================
39 
40 using namespace ::com::sun::star::io;
41 using namespace ::com::sun::star::lang;
42 using namespace ::com::sun::star::uno;
43 
44 using ::rtl::OUString;
45 
46 // ============================================================================
47 
48 namespace {
49 
50 typedef ::cppu::WeakImplHelper1< XInputStream > UnoBinaryInputStream_BASE;
51 
52 /** Implementation of a UNO input stream wrapping a binary input stream.
53  */
54 class UnoBinaryInputStream : public UnoBinaryInputStream_BASE
55 {
56 public:
57     explicit            UnoBinaryInputStream( BinaryInputStream& rInStrm );
58 
59     virtual sal_Int32 SAL_CALL readBytes( Sequence< sal_Int8 >& rData, sal_Int32 nBytesToRead )
60                         throw (NotConnectedException, BufferSizeExceededException, IOException, RuntimeException);
61     virtual sal_Int32 SAL_CALL readSomeBytes( Sequence< sal_Int8 >& rData, sal_Int32 nMaxBytesToRead )
62                         throw (NotConnectedException, BufferSizeExceededException, IOException, RuntimeException);
63     virtual void SAL_CALL skipBytes( sal_Int32 nBytesToSkip )
64                         throw (NotConnectedException, BufferSizeExceededException, IOException, RuntimeException);
65     virtual sal_Int32 SAL_CALL available()
66                         throw (NotConnectedException, IOException, RuntimeException);
67     virtual void SAL_CALL closeInput()
68                         throw (NotConnectedException, IOException, RuntimeException);
69 
70 private:
71     void                ensureConnected() const throw (NotConnectedException);
72 
73 private:
74     BinaryInputStream*  mpInStrm;
75 };
76 
77 // ----------------------------------------------------------------------------
78 
79 UnoBinaryInputStream::UnoBinaryInputStream( BinaryInputStream& rInStrm ) :
80     mpInStrm( &rInStrm )
81 {
82 }
83 
84 sal_Int32 SAL_CALL UnoBinaryInputStream::readBytes( Sequence< sal_Int8 >& rData, sal_Int32 nBytesToRead )
85         throw (NotConnectedException, BufferSizeExceededException, IOException, RuntimeException)
86 {
87     ensureConnected();
88     return mpInStrm->readData( rData, nBytesToRead, 1 );
89 }
90 
91 sal_Int32 SAL_CALL UnoBinaryInputStream::readSomeBytes( Sequence< sal_Int8 >& rData, sal_Int32 nMaxBytesToRead )
92         throw (NotConnectedException, BufferSizeExceededException, IOException, RuntimeException)
93 {
94     ensureConnected();
95     return mpInStrm->readData( rData, nMaxBytesToRead, 1 );
96 }
97 
98 void SAL_CALL UnoBinaryInputStream::skipBytes( sal_Int32 nBytesToSkip )
99         throw (NotConnectedException, BufferSizeExceededException, IOException, RuntimeException)
100 {
101     ensureConnected();
102     mpInStrm->skip( nBytesToSkip, 1 );
103 }
104 
105 sal_Int32 SAL_CALL UnoBinaryInputStream::available() throw (NotConnectedException, IOException, RuntimeException)
106 {
107     ensureConnected();
108     throw RuntimeException( CREATE_OUSTRING( "Functionality not supported" ), Reference< XInputStream >() );
109 }
110 
111 void SAL_CALL UnoBinaryInputStream::closeInput() throw (NotConnectedException, IOException, RuntimeException)
112 {
113     ensureConnected();
114     mpInStrm->close();
115     mpInStrm = 0;
116 }
117 
118 void UnoBinaryInputStream::ensureConnected() const throw (NotConnectedException)
119 {
120     if( !mpInStrm )
121         throw NotConnectedException( CREATE_OUSTRING( "Stream closed" ), Reference< XInterface >() );
122 }
123 
124 } // namespace
125 
126 // ============================================================================
127 
128 TextInputStream::TextInputStream( const Reference< XComponentContext >& rxContext, const Reference< XInputStream >& rxInStrm, rtl_TextEncoding eTextEnc )
129 {
130     init( rxContext, rxInStrm, eTextEnc );
131 }
132 
133 TextInputStream::TextInputStream( const Reference< XComponentContext >& rxContext, BinaryInputStream& rInStrm, rtl_TextEncoding eTextEnc )
134 {
135     init( rxContext, new UnoBinaryInputStream( rInStrm ), eTextEnc );
136 }
137 
138 TextInputStream::~TextInputStream()
139 {
140 }
141 
142 bool TextInputStream::isEof() const
143 {
144     if( mxTextStrm.is() ) try
145     {
146         return mxTextStrm->isEOF();
147     }
148     catch( Exception& )
149     {
150     }
151     return true;
152 }
153 
154 OUString TextInputStream::readLine()
155 {
156     if( mxTextStrm.is() ) try
157     {
158         /*  The function createFinalString() adds a character that may have
159             been buffered in the previous call of readToChar() (see below). */
160         return createFinalString( mxTextStrm->readLine() );
161     }
162     catch( Exception& )
163     {
164         mxTextStrm.clear();
165     }
166     return OUString();
167 }
168 
169 OUString TextInputStream::readToChar( sal_Unicode cChar, bool bIncludeChar )
170 {
171     if( mxTextStrm.is() ) try
172     {
173         Sequence< sal_Unicode > aDelimiters( 1 );
174         aDelimiters[ 0 ] = cChar;
175         /*  Always get the delimiter character from the UNO text input stream.
176             In difference to this implementation, it will not return it in the
177             next call but silently skip it. If caller specifies to exclude the
178             character in this call, it will be returned in the next call of one
179             of the own member functions. The function createFinalString() adds
180             a character that has been buffered in the previous call. */
181         OUString aString = createFinalString( mxTextStrm->readString( aDelimiters, sal_False ) );
182         // remove last character from string and remember it for next call
183         if( !bIncludeChar && (aString.getLength() > 0) && (aString[ aString.getLength() - 1 ] == cChar) )
184         {
185             mcPendingChar = cChar;
186             aString = aString.copy( 0, aString.getLength() - 1 );
187         }
188         return aString;
189     }
190     catch( Exception& )
191     {
192         mxTextStrm.clear();
193     }
194     return OUString();
195 }
196 
197 /*static*/ Reference< XTextInputStream > TextInputStream::createXTextInputStream(
198         const Reference< XComponentContext >& rxContext, const Reference< XInputStream >& rxInStrm, rtl_TextEncoding eTextEnc )
199 {
200     Reference< XTextInputStream > xTextStrm;
201     const char* pcCharset = rtl_getMimeCharsetFromTextEncoding( eTextEnc );
202     OSL_ENSURE( pcCharset, "TextInputStream::createXTextInputStream - unsupported text encoding" );
203     if( rxContext.is() && rxInStrm.is() && pcCharset ) try
204     {
205         Reference< XMultiServiceFactory > xFactory( rxContext->getServiceManager(), UNO_QUERY_THROW );
206         Reference< XActiveDataSink > xDataSink( xFactory->createInstance( CREATE_OUSTRING( "com.sun.star.io.TextInputStream" ) ), UNO_QUERY_THROW );
207         xDataSink->setInputStream( rxInStrm );
208         xTextStrm.set( xDataSink, UNO_QUERY_THROW );
209         xTextStrm->setEncoding( OUString::createFromAscii( pcCharset ) );
210     }
211     catch( Exception& )
212     {
213     }
214     return xTextStrm;
215 }
216 
217 // private --------------------------------------------------------------------
218 
219 OUString TextInputStream::createFinalString( const OUString& rString )
220 {
221     if( mcPendingChar == 0 )
222         return rString;
223 
224     OUString aString = OUString( mcPendingChar ) + rString;
225     mcPendingChar = 0;
226     return aString;
227 }
228 
229 void TextInputStream::init( const Reference< XComponentContext >& rxContext, const Reference< XInputStream >& rxInStrm, rtl_TextEncoding eTextEnc )
230 {
231     mcPendingChar = 0;
232     mxTextStrm = createXTextInputStream( rxContext, rxInStrm, eTextEnc );
233 }
234 
235 // ============================================================================
236 
237 } // namespace oox
238