Coverage Report

Created: 2026-03-31 11:00

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libreoffice/io/source/TextOutputStream/TextOutputStream.cxx
Line
Count
Source
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
21
22
#include <cppuhelper/implbase.hxx>
23
#include <cppuhelper/supportsservice.hxx>
24
25
#include <rtl/textenc.h>
26
#include <rtl/tencinfo.h>
27
28
#include <com/sun/star/io/IOException.hpp>
29
#include <com/sun/star/io/XTextOutputStream2.hpp>
30
#include <com/sun/star/lang/IllegalArgumentException.hpp>
31
#include <com/sun/star/lang/XServiceInfo.hpp>
32
33
#include <optional>
34
35
namespace com::sun::star::uno { class XComponentContext; }
36
37
using namespace ::cppu;
38
using namespace ::com::sun::star::uno;
39
using namespace ::com::sun::star::lang;
40
using namespace ::com::sun::star::io;
41
42
// Implementation XTextOutputStream
43
44
namespace {
45
46
class OTextOutputStream : public WeakImplHelper< XTextOutputStream2, XServiceInfo >
47
{
48
    Reference< XOutputStream > mxStream;
49
50
    struct Encoding_t
51
    {
52
        rtl_UnicodeToTextConverter  mConvUnicode2Text;
53
        rtl_UnicodeToTextContext    mContextUnicode2Text;
54
        Encoding_t(rtl_TextEncoding encoding)
55
0
        {
56
0
            mConvUnicode2Text = rtl_createUnicodeToTextConverter(encoding);
57
0
            mContextUnicode2Text = rtl_createUnicodeToTextContext(mConvUnicode2Text);
58
0
        }
59
        ~Encoding_t()
60
0
        {
61
0
            rtl_destroyUnicodeToTextContext(mConvUnicode2Text, mContextUnicode2Text);
62
0
            rtl_destroyUnicodeToTextConverter(mConvUnicode2Text);
63
0
        }
64
    };
65
    std::optional<Encoding_t> moEncoding;
66
67
    Sequence<sal_Int8> implConvert( const OUString& rSource );
68
    /// @throws IOException
69
    void checkOutputStream() const;
70
71
public:
72
    // Methods XTextOutputStream
73
    virtual void SAL_CALL writeString( const OUString& aString ) override;
74
    virtual void SAL_CALL setEncoding( const OUString& Encoding ) override;
75
76
    // Methods XOutputStream
77
    virtual void SAL_CALL writeBytes( const Sequence< sal_Int8 >& aData ) override;
78
    virtual void SAL_CALL flush(  ) override;
79
    virtual void SAL_CALL closeOutput(  ) override;
80
81
    // Methods XActiveDataSource
82
    virtual void SAL_CALL setOutputStream( const Reference< XOutputStream >& aStream ) override;
83
    virtual Reference< XOutputStream > SAL_CALL getOutputStream(  ) override;
84
85
    // Methods XServiceInfo
86
        virtual OUString              SAL_CALL getImplementationName() override;
87
        virtual Sequence< OUString >  SAL_CALL getSupportedServiceNames() override;
88
        virtual sal_Bool              SAL_CALL supportsService(const OUString& ServiceName) override;
89
};
90
91
}
92
93
Sequence<sal_Int8> OTextOutputStream::implConvert( const OUString& rSource )
94
0
{
95
0
    const sal_Unicode *puSource = rSource.getStr();
96
0
    sal_Int32 nSourceSize = rSource.getLength();
97
98
0
    sal_Size nTargetCount = 0;
99
0
    sal_Size nSourceCount = 0;
100
101
0
    sal_uInt32 uiInfo;
102
0
    sal_Size nSrcCvtChars;
103
104
    // take nSourceSize * 3 as preference
105
    // this is an upper boundary for converting to utf8,
106
    // which most often used as the target.
107
0
    sal_Int32 nSeqSize =  nSourceSize * 3;
108
109
0
    Sequence<sal_Int8> seqText( nSeqSize );
110
0
    char *pTarget = reinterpret_cast<char *>(seqText.getArray());
111
0
    while( true )
112
0
    {
113
0
        nTargetCount += rtl_convertUnicodeToText(
114
0
                                    moEncoding->mConvUnicode2Text,
115
0
                                    moEncoding->mContextUnicode2Text,
116
0
                                    &( puSource[nSourceCount] ),
117
0
                                    nSourceSize - nSourceCount ,
118
0
                                    &( pTarget[nTargetCount] ),
119
0
                                    nSeqSize - nTargetCount,
120
0
                                    RTL_UNICODETOTEXT_FLAGS_UNDEFINED_DEFAULT |
121
0
                                    RTL_UNICODETOTEXT_FLAGS_INVALID_DEFAULT ,
122
0
                                    &uiInfo,
123
0
                                    &nSrcCvtChars);
124
0
        nSourceCount += nSrcCvtChars;
125
126
0
        if( uiInfo & RTL_UNICODETOTEXT_INFO_DESTBUFFERTOSMALL )
127
0
        {
128
0
            nSeqSize *= 2;
129
0
            seqText.realloc( nSeqSize );  // double array size
130
0
            pTarget = reinterpret_cast<char*>(seqText.getArray());
131
0
            continue;
132
0
        }
133
0
        break;
134
0
    }
135
136
    // reduce the size of the buffer (fast, no copy necessary)
137
0
    seqText.realloc( nTargetCount );
138
0
    return seqText;
139
0
}
140
141
142
// XTextOutputStream
143
144
void OTextOutputStream::writeString( const OUString& aString )
145
0
{
146
0
    checkOutputStream();
147
0
    if (!moEncoding)
148
0
    {
149
0
        setEncoding( u"utf8"_ustr );
150
0
    }
151
152
0
    Sequence<sal_Int8> aByteSeq = implConvert( aString );
153
0
    mxStream->writeBytes( aByteSeq );
154
0
}
155
156
void OTextOutputStream::setEncoding( const OUString& Encoding )
157
0
{
158
0
    OString aOEncodingStr = OUStringToOString( Encoding, RTL_TEXTENCODING_ASCII_US );
159
0
    rtl_TextEncoding encoding = rtl_getTextEncodingFromMimeCharset( aOEncodingStr.getStr() );
160
0
    if( RTL_TEXTENCODING_DONTKNOW == encoding )
161
0
        throw IllegalArgumentException("Unknown encoding '" + Encoding + "'", getXWeak(), 0);
162
163
0
    moEncoding.emplace(encoding);
164
0
}
165
166
167
// XOutputStream
168
void OTextOutputStream::writeBytes( const Sequence< sal_Int8 >& aData )
169
0
{
170
0
    checkOutputStream();
171
0
    mxStream->writeBytes( aData );
172
0
}
173
174
void OTextOutputStream::flush(  )
175
0
{
176
0
    checkOutputStream();
177
0
    mxStream->flush();
178
0
}
179
180
void OTextOutputStream::closeOutput(  )
181
0
{
182
0
    checkOutputStream();
183
0
    mxStream->closeOutput();
184
0
}
185
186
187
void OTextOutputStream::checkOutputStream() const
188
0
{
189
0
    if (! mxStream.is() )
190
0
        throw IOException(u"output stream is not initialized, you have to use setOutputStream first"_ustr);
191
0
}
192
193
194
// XActiveDataSource
195
196
void OTextOutputStream::setOutputStream( const Reference< XOutputStream >& aStream )
197
0
{
198
0
    mxStream = aStream;
199
0
}
200
201
Reference< XOutputStream > OTextOutputStream::getOutputStream()
202
0
{
203
0
    return mxStream;
204
0
}
205
206
OUString OTextOutputStream::getImplementationName()
207
0
{
208
0
    return u"com.sun.star.comp.io.TextOutputStream"_ustr;
209
0
}
210
211
sal_Bool OTextOutputStream::supportsService(const OUString& ServiceName)
212
0
{
213
0
    return cppu::supportsService(this, ServiceName);
214
0
}
215
216
Sequence< OUString > OTextOutputStream::getSupportedServiceNames()
217
0
{
218
0
    return { u"com.sun.star.io.TextOutputStream"_ustr };
219
0
}
220
221
222
223
extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
224
io_OTextOutputStream_get_implementation(
225
    css::uno::XComponentContext* , css::uno::Sequence<css::uno::Any> const&)
226
0
{
227
0
    return cppu::acquire(new OTextOutputStream);
228
0
}
229
230
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */