Avoid potential negative array index access to cached text.
[LibreOffice.git] / io / source / TextOutputStream / TextOutputStream.cxx
blob1271c4d09c96cc9b401845c01debc787b8926888
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
22 #include <cppuhelper/implbase.hxx>
23 #include <cppuhelper/supportsservice.hxx>
25 #include <rtl/textenc.h>
26 #include <rtl/tencinfo.h>
28 #include <com/sun/star/io/IOException.hpp>
29 #include <com/sun/star/io/XTextOutputStream2.hpp>
30 #include <com/sun/star/lang/XServiceInfo.hpp>
32 namespace com::sun::star::uno { class XComponentContext; }
34 using namespace ::osl;
35 using namespace ::cppu;
36 using namespace ::com::sun::star::uno;
37 using namespace ::com::sun::star::lang;
38 using namespace ::com::sun::star::io;
40 // Implementation XTextOutputStream
42 namespace {
44 class OTextOutputStream : public WeakImplHelper< XTextOutputStream2, XServiceInfo >
46 Reference< XOutputStream > mxStream;
48 // Encoding
49 bool mbEncodingInitialized;
50 rtl_UnicodeToTextConverter mConvUnicode2Text;
51 rtl_UnicodeToTextContext mContextUnicode2Text;
53 Sequence<sal_Int8> implConvert( const OUString& rSource );
54 /// @throws IOException
55 void checkOutputStream() const;
57 public:
58 OTextOutputStream();
59 virtual ~OTextOutputStream() override;
61 // Methods XTextOutputStream
62 virtual void SAL_CALL writeString( const OUString& aString ) override;
63 virtual void SAL_CALL setEncoding( const OUString& Encoding ) override;
65 // Methods XOutputStream
66 virtual void SAL_CALL writeBytes( const Sequence< sal_Int8 >& aData ) override;
67 virtual void SAL_CALL flush( ) override;
68 virtual void SAL_CALL closeOutput( ) override;
70 // Methods XActiveDataSource
71 virtual void SAL_CALL setOutputStream( const Reference< XOutputStream >& aStream ) override;
72 virtual Reference< XOutputStream > SAL_CALL getOutputStream( ) override;
74 // Methods XServiceInfo
75 virtual OUString SAL_CALL getImplementationName() override;
76 virtual Sequence< OUString > SAL_CALL getSupportedServiceNames() override;
77 virtual sal_Bool SAL_CALL supportsService(const OUString& ServiceName) override;
82 OTextOutputStream::OTextOutputStream()
83 : mbEncodingInitialized(false)
84 , mConvUnicode2Text(nullptr)
85 , mContextUnicode2Text(nullptr)
89 OTextOutputStream::~OTextOutputStream()
91 if( mbEncodingInitialized )
93 rtl_destroyUnicodeToTextContext( mConvUnicode2Text, mContextUnicode2Text );
94 rtl_destroyUnicodeToTextConverter( mConvUnicode2Text );
98 Sequence<sal_Int8> OTextOutputStream::implConvert( const OUString& rSource )
100 const sal_Unicode *puSource = rSource.getStr();
101 sal_Int32 nSourceSize = rSource.getLength();
103 sal_Size nTargetCount = 0;
104 sal_Size nSourceCount = 0;
106 sal_uInt32 uiInfo;
107 sal_Size nSrcCvtChars;
109 // take nSourceSize * 3 as preference
110 // this is an upper boundary for converting to utf8,
111 // which most often used as the target.
112 sal_Int32 nSeqSize = nSourceSize * 3;
114 Sequence<sal_Int8> seqText( nSeqSize );
115 char *pTarget = reinterpret_cast<char *>(seqText.getArray());
116 while( true )
118 nTargetCount += rtl_convertUnicodeToText(
119 mConvUnicode2Text,
120 mContextUnicode2Text,
121 &( puSource[nSourceCount] ),
122 nSourceSize - nSourceCount ,
123 &( pTarget[nTargetCount] ),
124 nSeqSize - nTargetCount,
125 RTL_UNICODETOTEXT_FLAGS_UNDEFINED_DEFAULT |
126 RTL_UNICODETOTEXT_FLAGS_INVALID_DEFAULT ,
127 &uiInfo,
128 &nSrcCvtChars);
129 nSourceCount += nSrcCvtChars;
131 if( uiInfo & RTL_UNICODETOTEXT_INFO_DESTBUFFERTOSMALL )
133 nSeqSize *= 2;
134 seqText.realloc( nSeqSize ); // double array size
135 pTarget = reinterpret_cast<char*>(seqText.getArray());
136 continue;
138 break;
141 // reduce the size of the buffer (fast, no copy necessary)
142 seqText.realloc( nTargetCount );
143 return seqText;
147 // XTextOutputStream
149 void OTextOutputStream::writeString( const OUString& aString )
151 checkOutputStream();
152 if( !mbEncodingInitialized )
154 setEncoding( "utf8" );
156 if( !mbEncodingInitialized )
157 return;
159 Sequence<sal_Int8> aByteSeq = implConvert( aString );
160 mxStream->writeBytes( aByteSeq );
163 void OTextOutputStream::setEncoding( const OUString& Encoding )
165 OString aOEncodingStr = OUStringToOString( Encoding, RTL_TEXTENCODING_ASCII_US );
166 rtl_TextEncoding encoding = rtl_getTextEncodingFromMimeCharset( aOEncodingStr.getStr() );
167 if( RTL_TEXTENCODING_DONTKNOW == encoding )
168 return;
170 mbEncodingInitialized = true;
171 mConvUnicode2Text = rtl_createUnicodeToTextConverter( encoding );
172 mContextUnicode2Text = rtl_createUnicodeToTextContext( mConvUnicode2Text );
176 // XOutputStream
177 void OTextOutputStream::writeBytes( const Sequence< sal_Int8 >& aData )
179 checkOutputStream();
180 mxStream->writeBytes( aData );
183 void OTextOutputStream::flush( )
185 checkOutputStream();
186 mxStream->flush();
189 void OTextOutputStream::closeOutput( )
191 checkOutputStream();
192 mxStream->closeOutput();
196 void OTextOutputStream::checkOutputStream() const
198 if (! mxStream.is() )
199 throw IOException("output stream is not initialized, you have to use setOutputStream first");
203 // XActiveDataSource
205 void OTextOutputStream::setOutputStream( const Reference< XOutputStream >& aStream )
207 mxStream = aStream;
210 Reference< XOutputStream > OTextOutputStream::getOutputStream()
212 return mxStream;
215 OUString OTextOutputStream::getImplementationName()
217 return "com.sun.star.comp.io.TextOutputStream";
220 sal_Bool OTextOutputStream::supportsService(const OUString& ServiceName)
222 return cppu::supportsService(this, ServiceName);
225 Sequence< OUString > OTextOutputStream::getSupportedServiceNames()
227 return { "com.sun.star.io.TextOutputStream" };
232 extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
233 io_OTextOutputStream_get_implementation(
234 css::uno::XComponentContext* , css::uno::Sequence<css::uno::Any> const&)
236 return cppu::acquire(new OTextOutputStream());
239 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */