1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  * This file is part of the LibreOffice project.
4  *
5  * This Source Code Form is subject to the terms of the Mozilla Public
6  * License, v. 2.0. If a copy of the MPL was not distributed with this
7  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8  *
9  * This file incorporates work covered by the following license notice:
10  *
11  *   Licensed to the Apache Software Foundation (ASF) under one or more
12  *   contributor license agreements. See the NOTICE file distributed
13  *   with this work for additional information regarding copyright
14  *   ownership. The ASF licenses this file to you under the Apache
15  *   License, Version 2.0 (the "License"); you may not use this file
16  *   except in compliance with the License. You may obtain a copy of
17  *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
18  */
19 
20 #include <oox/helper/textinputstream.hxx>
21 
22 #include <com/sun/star/io/NotConnectedException.hpp>
23 #include <com/sun/star/io/TextInputStream.hpp>
24 #include <cppuhelper/implbase.hxx>
25 #include <osl/diagnose.h>
26 #include <rtl/tencinfo.h>
27 #include <oox/helper/binaryinputstream.hxx>
28 
29 namespace oox {
30 
31 using namespace ::com::sun::star::io;
32 using namespace ::com::sun::star::lang;
33 using namespace ::com::sun::star::uno;
34 
35 namespace {
36 
37 /** Implementation of a UNO input stream wrapping a binary input stream.
38  */
39 class UnoBinaryInputStream : public ::cppu::WeakImplHelper< XInputStream >
40 {
41 public:
42     explicit            UnoBinaryInputStream( BinaryInputStream& rInStrm );
43 
44     virtual sal_Int32 SAL_CALL readBytes( Sequence< sal_Int8 >& rData, sal_Int32 nBytesToRead ) override;
45     virtual sal_Int32 SAL_CALL readSomeBytes( Sequence< sal_Int8 >& rData, sal_Int32 nMaxBytesToRead ) override;
46     virtual void SAL_CALL skipBytes( sal_Int32 nBytesToSkip ) override;
47     virtual sal_Int32 SAL_CALL available() override;
48     virtual void SAL_CALL closeInput() override;
49 
50 private:
51     /// @throws NotConnectedException
52     void                ensureConnected() const;
53 
54 private:
55     BinaryInputStream*  mpInStrm;
56 };
57 
UnoBinaryInputStream(BinaryInputStream & rInStrm)58 UnoBinaryInputStream::UnoBinaryInputStream( BinaryInputStream& rInStrm ) :
59     mpInStrm( &rInStrm )
60 {
61 }
62 
readBytes(Sequence<sal_Int8> & rData,sal_Int32 nBytesToRead)63 sal_Int32 SAL_CALL UnoBinaryInputStream::readBytes( Sequence< sal_Int8 >& rData, sal_Int32 nBytesToRead )
64 {
65     ensureConnected();
66     return mpInStrm->readData( rData, nBytesToRead );
67 }
68 
readSomeBytes(Sequence<sal_Int8> & rData,sal_Int32 nMaxBytesToRead)69 sal_Int32 SAL_CALL UnoBinaryInputStream::readSomeBytes( Sequence< sal_Int8 >& rData, sal_Int32 nMaxBytesToRead )
70 {
71     ensureConnected();
72     return mpInStrm->readData( rData, nMaxBytesToRead );
73 }
74 
skipBytes(sal_Int32 nBytesToSkip)75 void SAL_CALL UnoBinaryInputStream::skipBytes( sal_Int32 nBytesToSkip )
76 {
77     ensureConnected();
78     mpInStrm->skip( nBytesToSkip );
79 }
80 
available()81 sal_Int32 SAL_CALL UnoBinaryInputStream::available()
82 {
83     ensureConnected();
84     throw RuntimeException( "Functionality not supported", Reference< XInputStream >() );
85 }
86 
closeInput()87 void SAL_CALL UnoBinaryInputStream::closeInput()
88 {
89     ensureConnected();
90     mpInStrm->close();
91     mpInStrm = nullptr;
92 }
93 
ensureConnected() const94 void UnoBinaryInputStream::ensureConnected() const
95 {
96     if( !mpInStrm )
97         throw NotConnectedException( "Stream closed" );
98 }
99 
100 } // namespace
101 
TextInputStream(const Reference<XComponentContext> & rxContext,const Reference<XInputStream> & rxInStrm,rtl_TextEncoding eTextEnc)102 TextInputStream::TextInputStream( const Reference< XComponentContext >& rxContext, const Reference< XInputStream >& rxInStrm, rtl_TextEncoding eTextEnc )
103 {
104     init( rxContext, rxInStrm, eTextEnc );
105 }
106 
TextInputStream(const Reference<XComponentContext> & rxContext,BinaryInputStream & rInStrm,rtl_TextEncoding eTextEnc)107 TextInputStream::TextInputStream( const Reference< XComponentContext >& rxContext, BinaryInputStream& rInStrm, rtl_TextEncoding eTextEnc )
108 {
109     init( rxContext, new UnoBinaryInputStream( rInStrm ), eTextEnc );
110 }
111 
~TextInputStream()112 TextInputStream::~TextInputStream()
113 {
114 }
115 
isEof() const116 bool TextInputStream::isEof() const
117 {
118     if( mxTextStrm.is() ) try
119     {
120         return mxTextStrm->isEOF();
121     }
122     catch (const Exception&)
123     {
124     }
125     return true;
126 }
127 
readLine()128 OUString TextInputStream::readLine()
129 {
130     if( mxTextStrm.is() ) try
131     {
132         /*  The function createFinalString() adds a character that may have
133             been buffered in the previous call of readToChar() (see below). */
134         return createFinalString( mxTextStrm->readLine() );
135     }
136     catch (const Exception&)
137     {
138         mxTextStrm.clear();
139     }
140     return OUString();
141 }
142 
readToChar(sal_Unicode cChar,bool bIncludeChar)143 OUString TextInputStream::readToChar( sal_Unicode cChar, bool bIncludeChar )
144 {
145     if( mxTextStrm.is() ) try
146     {
147         Sequence< sal_Unicode > aDelimiters( 1 );
148         aDelimiters[ 0 ] = cChar;
149         /*  Always get the delimiter character from the UNO text input stream.
150             In difference to this implementation, it will not return it in the
151             next call but silently skip it. If caller specifies to exclude the
152             character in this call, it will be returned in the next call of one
153             of the own member functions. The function createFinalString() adds
154             a character that has been buffered in the previous call. */
155         OUString aString = createFinalString( mxTextStrm->readString( aDelimiters, false ) );
156         // remove last character from string and remember it for next call
157         if( !bIncludeChar && !aString.isEmpty() && (aString[ aString.getLength() - 1 ] == cChar) )
158         {
159             mcPendingChar = cChar;
160             aString = aString.copy( 0, aString.getLength() - 1 );
161         }
162         return aString;
163     }
164     catch (const Exception&)
165     {
166         mxTextStrm.clear();
167     }
168     return OUString();
169 }
170 
createXTextInputStream(const Reference<XComponentContext> & rxContext,const Reference<XInputStream> & rxInStrm,rtl_TextEncoding eTextEnc)171 Reference< XTextInputStream2 > TextInputStream::createXTextInputStream(
172         const Reference< XComponentContext >& rxContext, const Reference< XInputStream >& rxInStrm, rtl_TextEncoding eTextEnc )
173 {
174     Reference< XTextInputStream2 > xTextStrm;
175     const char* pcCharset = rtl_getBestMimeCharsetFromTextEncoding( eTextEnc );
176     OSL_ENSURE( pcCharset, "TextInputStream::createXTextInputStream - unsupported text encoding" );
177     if( rxContext.is() && rxInStrm.is() && pcCharset ) try
178     {
179         xTextStrm = css::io::TextInputStream::create( rxContext );
180         xTextStrm->setInputStream( rxInStrm );
181         xTextStrm->setEncoding( OUString::createFromAscii( pcCharset ) );
182     }
183     catch (const Exception&)
184     {
185     }
186     return xTextStrm;
187 }
188 
189 // private --------------------------------------------------------------------
190 
createFinalString(const OUString & rString)191 OUString TextInputStream::createFinalString( const OUString& rString )
192 {
193     if( mcPendingChar == 0 )
194         return rString;
195 
196     OUString aString = OUStringChar( mcPendingChar ) + rString;
197     mcPendingChar = 0;
198     return aString;
199 }
200 
init(const Reference<XComponentContext> & rxContext,const Reference<XInputStream> & rxInStrm,rtl_TextEncoding eTextEnc)201 void TextInputStream::init( const Reference< XComponentContext >& rxContext, const Reference< XInputStream >& rxInStrm, rtl_TextEncoding eTextEnc )
202 {
203     mcPendingChar = 0;
204     mxTextStrm = createXTextInputStream( rxContext, rxInStrm, eTextEnc );
205 }
206 
207 } // namespace oox
208 
209 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
210