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