Coverage Report

Created: 2025-07-07 10:01

/src/libreoffice/connectivity/source/drivers/file/FConnection.cxx
Line
Count
Source (jump to first uncovered line)
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 <sal/config.h>
21
22
#include <comphelper/processfactory.hxx>
23
#include <comphelper/servicehelper.hxx>
24
#include <file/FConnection.hxx>
25
#include <file/FDatabaseMetaData.hxx>
26
#include <file/FDriver.hxx>
27
#include <file/FStatement.hxx>
28
#include <file/FPreparedStatement.hxx>
29
#include <com/sun/star/container/XChild.hpp>
30
#include <com/sun/star/ucb/ContentCreationException.hpp>
31
#include <com/sun/star/ucb/XContent.hpp>
32
#include <com/sun/star/ucb/XContentIdentifier.hpp>
33
#include <tools/urlobj.hxx>
34
#include <file/FCatalog.hxx>
35
#include <comphelper/configuration.hxx>
36
#include <unotools/pathoptions.hxx>
37
#include <ucbhelper/content.hxx>
38
#include <connectivity/dbcharset.hxx>
39
#include <connectivity/dbexception.hxx>
40
#include <o3tl/any.hxx>
41
#include <osl/thread.h>
42
#include <strings.hrc>
43
44
using namespace connectivity::file;
45
using namespace dbtools;
46
47
using namespace com::sun::star::uno;
48
using namespace com::sun::star::lang;
49
using namespace com::sun::star::beans;
50
using namespace com::sun::star::sdbc;
51
using namespace com::sun::star::sdbcx;
52
using namespace com::sun::star::container;
53
using namespace com::sun::star::ucb;
54
using namespace ::ucbhelper;
55
typedef connectivity::OMetaConnection OConnection_BASE;
56
57
OConnection::OConnection(OFileDriver*   _pDriver)
58
9.91k
    : m_pDriver(_pDriver)
59
9.91k
    , m_bAutoCommit(false)
60
9.91k
    , m_bReadOnly(false)
61
9.91k
    , m_bShowDeleted(false)
62
9.91k
    , m_bCaseSensitiveExtension( true )
63
9.91k
    , m_bCheckSQL92(false)
64
9.91k
    , m_bDefaultTextEncoding(false)
65
9.91k
{
66
9.91k
    m_nTextEncoding = RTL_TEXTENCODING_DONTKNOW;
67
9.91k
}
68
69
OConnection::~OConnection()
70
9.91k
{
71
9.91k
    if(!isClosed(  ))
72
0
        close();
73
9.91k
}
74
75
bool OConnection::matchesExtension( const OUString& _rExt ) const
76
39.2k
{
77
39.2k
    if ( isCaseSensitiveExtension() )
78
39.2k
        return ( getExtension() == _rExt );
79
80
0
    OUString sMyExtension( getExtension().toAsciiLowerCase() );
81
0
    OUString sExt( _rExt.toAsciiLowerCase() );
82
83
0
    return sMyExtension == sExt;
84
39.2k
}
85
86
87
void OConnection::construct(const OUString& url,const Sequence< PropertyValue >& info)
88
9.91k
{
89
9.91k
    osl_atomic_increment( &m_refCount );
90
91
9.91k
    OUString aExt;
92
9.91k
    const PropertyValue *pIter  = info.getConstArray();
93
9.91k
    const PropertyValue *pEnd    = pIter + info.getLength();
94
29.7k
    for(;pIter != pEnd;++pIter)
95
19.8k
    {
96
19.8k
        if( pIter->Name == "Extension" )
97
9.91k
            OSL_VERIFY( pIter->Value >>= aExt );
98
9.91k
        else if( pIter->Name == "CharSet" )
99
9.91k
        {
100
9.91k
            if (auto const numeric = o3tl::tryAccess<sal_uInt16>(pIter->Value))
101
9.91k
            {
102
9.91k
                m_nTextEncoding = *numeric;
103
9.91k
            }
104
0
            else
105
0
            {
106
0
                OUString sIanaName;
107
0
                OSL_VERIFY( pIter->Value >>= sIanaName );
108
109
0
                ::dbtools::OCharsetMap aLookupIanaName;
110
0
                ::dbtools::OCharsetMap::const_iterator aLookup = aLookupIanaName.findIanaName(sIanaName);
111
0
                if (aLookup != aLookupIanaName.end())
112
0
                    m_nTextEncoding = (*aLookup).getEncoding();
113
0
                else
114
0
                    m_nTextEncoding = RTL_TEXTENCODING_DONTKNOW;
115
0
            }
116
9.91k
        }
117
0
        else if( pIter->Name == "ShowDeleted" )
118
0
        {
119
0
            OSL_VERIFY( pIter->Value >>= m_bShowDeleted );
120
0
        }
121
0
        else if( pIter->Name == "EnableSQL92Check" )
122
0
        {
123
0
            pIter->Value >>= m_bCheckSQL92;
124
0
        }
125
19.8k
    } // for(;pIter != pEnd;++pIter)
126
127
9.91k
    {
128
9.91k
        sal_Int32 nLen = url.indexOf(':');
129
9.91k
        nLen = url.indexOf(':',nLen+1);
130
9.91k
        OUString aDSN(url.copy(nLen+1));
131
132
9.91k
        OUString aFileName = aDSN;
133
9.91k
        INetURLObject aURL;
134
9.91k
        aURL.SetSmartProtocol(INetProtocol::File);
135
9.91k
        if (!comphelper::IsFuzzing())
136
0
        {
137
0
            SvtPathOptions aPathOptions;
138
0
            aFileName = aPathOptions.SubstituteVariable(aFileName);
139
0
        }
140
141
9.91k
        aURL.SetSmartURL(aFileName);
142
143
9.91k
        setURL(aURL.GetMainURL(INetURLObject::DecodeMechanism::NONE));
144
9.91k
    }
145
146
9.91k
    if ( m_nTextEncoding == RTL_TEXTENCODING_DONTKNOW )
147
0
    {
148
        //m_nTextEncoding = osl_getTextEncodingFromLocale(NULL);
149
0
        m_nTextEncoding = osl_getThreadTextEncoding();
150
0
        m_bDefaultTextEncoding = true;
151
0
    }
152
153
9.91k
    if ( !aExt.isEmpty() )
154
9.91k
        m_aFilenameExtension = aExt;
155
156
9.91k
    try
157
9.91k
    {
158
9.91k
        ::ucbhelper::Content aFile;
159
9.91k
        try
160
9.91k
        {
161
9.91k
            aFile = ::ucbhelper::Content(getURL(), Reference< XCommandEnvironment >(), comphelper::getProcessComponentContext());
162
9.91k
        }
163
9.91k
        catch(ContentCreationException& e)
164
9.91k
        {
165
0
            throwUrlNotValid(getURL(),e.Message);
166
0
        }
167
168
        // set fields to fetch
169
9.91k
        Sequence< OUString > aProps { u"Title"_ustr };
170
171
9.91k
        try
172
9.91k
        {
173
9.91k
            if (aFile.isFolder())
174
9.91k
            {
175
9.91k
                m_xDir = aFile.createDynamicCursor(aProps, ::ucbhelper::INCLUDE_DOCUMENTS_ONLY );
176
9.91k
                m_xContent = aFile.get();
177
9.91k
            }
178
0
            else if (aFile.isDocument())
179
0
            {
180
0
                Reference<XContent> xParent(Reference<XChild>(aFile.get(),UNO_QUERY_THROW)->getParent(),UNO_QUERY_THROW);
181
0
                Reference<XContentIdentifier> xIdent = xParent->getIdentifier();
182
0
                m_xContent = std::move(xParent);
183
184
0
                ::ucbhelper::Content aParent(xIdent->getContentIdentifier(), Reference< XCommandEnvironment >(), comphelper::getProcessComponentContext());
185
0
                m_xDir = aParent.createDynamicCursor(aProps, ::ucbhelper::INCLUDE_DOCUMENTS_ONLY );
186
0
            }
187
0
            else
188
0
            {
189
0
                OSL_FAIL("OConnection::construct: ::ucbhelper::Content is neither a folder nor a document! How's that?!");
190
0
                throw SQLException();
191
0
            }
192
9.91k
        }
193
9.91k
        catch(Exception& e) // an exception is thrown when no file exists
194
9.91k
        {
195
0
            throwUrlNotValid(getURL(),e.Message);
196
0
        }
197
9.91k
        if(!m_xDir.is() || !m_xContent.is())
198
0
            throwUrlNotValid(getURL(),OUString());
199
200
9.91k
        if (m_aFilenameExtension.indexOf('*') >= 0 || m_aFilenameExtension.indexOf('?') >= 0)
201
0
            throw SQLException();
202
9.91k
    }
203
9.91k
    catch(const Exception&)
204
9.91k
    {
205
0
        osl_atomic_decrement( &m_refCount );
206
0
        throw;
207
0
    }
208
209
9.91k
    osl_atomic_decrement( &m_refCount );
210
9.91k
}
211
// XServiceInfo
212
213
IMPLEMENT_SERVICE_INFO(OConnection, u"com.sun.star.sdbc.drivers.file.Connection"_ustr, u"com.sun.star.sdbc.Connection"_ustr)
214
215
216
Reference< XStatement > SAL_CALL OConnection::createStatement(  )
217
0
{
218
0
    ::osl::MutexGuard aGuard( m_aMutex );
219
0
    checkDisposed(OConnection_BASE::rBHelper.bDisposed);
220
221
222
0
    Reference< XStatement > xReturn = new OStatement(this);
223
0
    m_aStatements.push_back(WeakReferenceHelper(xReturn));
224
0
    return xReturn;
225
0
}
226
227
Reference< XPreparedStatement > SAL_CALL OConnection::prepareStatement( const OUString& sql )
228
0
{
229
0
    ::osl::MutexGuard aGuard( m_aMutex );
230
0
    checkDisposed(OConnection_BASE::rBHelper.bDisposed);
231
232
233
0
    rtl::Reference<OPreparedStatement> pStmt = new OPreparedStatement(this);
234
0
    pStmt->construct(sql);
235
0
    m_aStatements.push_back(WeakReferenceHelper(*pStmt));
236
0
    return pStmt;
237
0
}
238
239
Reference< XPreparedStatement > SAL_CALL OConnection::prepareCall( const OUString& /*sql*/ )
240
0
{
241
0
    throwFeatureNotImplementedSQLException( u"XConnection::prepareCall"_ustr, *this );
242
0
}
243
244
OUString SAL_CALL OConnection::nativeSQL( const OUString& sql )
245
0
{
246
0
    return sql;
247
0
}
248
249
void SAL_CALL OConnection::setAutoCommit( sal_Bool autoCommit )
250
0
{
251
0
    ::osl::MutexGuard aGuard( m_aMutex );
252
0
    checkDisposed(OConnection_BASE::rBHelper.bDisposed);
253
254
0
    m_bAutoCommit = autoCommit;
255
0
}
256
257
sal_Bool SAL_CALL OConnection::getAutoCommit(  )
258
0
{
259
0
    ::osl::MutexGuard aGuard( m_aMutex );
260
0
    checkDisposed(OConnection_BASE::rBHelper.bDisposed);
261
262
0
    return m_bAutoCommit;
263
0
}
264
265
void SAL_CALL OConnection::commit(  )
266
0
{
267
0
}
268
269
void SAL_CALL OConnection::rollback(  )
270
0
{
271
0
}
272
273
sal_Bool SAL_CALL OConnection::isClosed(  )
274
9.91k
{
275
9.91k
    ::osl::MutexGuard aGuard( m_aMutex );
276
277
9.91k
    return OConnection_BASE::rBHelper.bDisposed;
278
9.91k
}
279
280
Reference< XDatabaseMetaData > SAL_CALL OConnection::getMetaData(  )
281
0
{
282
0
    ::osl::MutexGuard aGuard( m_aMutex );
283
0
    checkDisposed(OConnection_BASE::rBHelper.bDisposed);
284
285
286
0
    Reference< XDatabaseMetaData > xMetaData = m_xMetaData;
287
0
    if(!xMetaData.is())
288
0
    {
289
0
        xMetaData = new ODatabaseMetaData(this);
290
0
        m_xMetaData = xMetaData;
291
0
    }
292
293
0
    return xMetaData;
294
0
}
295
296
void SAL_CALL OConnection::setReadOnly( sal_Bool readOnly )
297
0
{
298
0
    ::osl::MutexGuard aGuard( m_aMutex );
299
0
    checkDisposed(OConnection_BASE::rBHelper.bDisposed);
300
301
302
0
    m_bReadOnly = readOnly;
303
0
}
304
305
sal_Bool SAL_CALL OConnection::isReadOnly(  )
306
0
{
307
0
    ::osl::MutexGuard aGuard( m_aMutex );
308
0
    checkDisposed(OConnection_BASE::rBHelper.bDisposed);
309
310
311
0
    return m_bReadOnly;
312
0
}
313
314
void SAL_CALL OConnection::setCatalog( const OUString& /*catalog*/ )
315
0
{
316
0
    throwFeatureNotImplementedSQLException( u"XConnection::setCatalog"_ustr, *this );
317
0
}
318
319
OUString SAL_CALL OConnection::getCatalog(  )
320
0
{
321
0
    return OUString();
322
0
}
323
324
void SAL_CALL OConnection::setTransactionIsolation( sal_Int32 /*level*/ )
325
0
{
326
0
    throwFeatureNotImplementedSQLException( u"XConnection::setTransactionIsolation"_ustr, *this );
327
0
}
328
329
sal_Int32 SAL_CALL OConnection::getTransactionIsolation(  )
330
0
{
331
0
    return 0;
332
0
}
333
334
Reference< XNameAccess > SAL_CALL OConnection::getTypeMap(  )
335
0
{
336
0
    return nullptr;
337
0
}
338
339
void SAL_CALL OConnection::setTypeMap( const Reference< XNameAccess >& /*typeMap*/ )
340
0
{
341
0
}
342
343
// XCloseable
344
void SAL_CALL OConnection::close(  )
345
0
{
346
0
    {
347
0
        ::osl::MutexGuard aGuard( m_aMutex );
348
0
        checkDisposed(OConnection_BASE::rBHelper.bDisposed);
349
350
0
    }
351
0
    dispose();
352
0
}
353
354
// XWarningsSupplier
355
Any SAL_CALL OConnection::getWarnings(  )
356
0
{
357
0
    return Any();
358
0
}
359
360
void SAL_CALL OConnection::clearWarnings(  )
361
0
{
362
0
}
363
364
void OConnection::disposing()
365
9.91k
{
366
9.91k
    ::osl::MutexGuard aGuard(m_aMutex);
367
9.91k
    OConnection_BASE::disposing();
368
369
9.91k
    m_xDir.clear();
370
9.91k
    m_xContent.clear();
371
9.91k
    m_xCatalog.clear();
372
9.91k
}
373
374
Reference< XTablesSupplier > OConnection::createCatalog()
375
0
{
376
0
    ::osl::MutexGuard aGuard( m_aMutex );
377
0
    rtl::Reference< connectivity::sdbcx::OCatalog > xTab = m_xCatalog.get();
378
0
    if(!xTab.is())
379
0
    {
380
0
        xTab = new OFileCatalog(this);
381
0
        m_xCatalog = xTab.get();
382
0
    }
383
0
    return xTab;
384
0
}
385
386
Reference< XDynamicResultSet > OConnection::getDir() const
387
98.0k
{
388
98.0k
    Reference<XDynamicResultSet> xContent;
389
98.0k
    Sequence< OUString > aProps { u"Title"_ustr };
390
98.0k
    try
391
98.0k
    {
392
98.0k
        Reference<XContentIdentifier> xIdent = getContent()->getIdentifier();
393
98.0k
        ::ucbhelper::Content aParent(xIdent->getContentIdentifier(), Reference< XCommandEnvironment >(), comphelper::getProcessComponentContext());
394
98.0k
        xContent = aParent.createDynamicCursor(aProps, ::ucbhelper::INCLUDE_DOCUMENTS_ONLY );
395
98.0k
    }
396
98.0k
    catch(Exception&)
397
98.0k
    {
398
0
    }
399
98.0k
    return xContent;
400
98.0k
}
401
402
sal_Int64 SAL_CALL OConnection::getSomething( const Sequence< sal_Int8 >& rId )
403
0
{
404
0
    return comphelper::getSomethingImpl(rId, this);
405
0
}
406
407
const Sequence< sal_Int8 > & OConnection::getUnoTunnelId()
408
0
{
409
0
    static const comphelper::UnoIdInit implId;
410
0
    return implId.getSeq();
411
0
}
412
413
void OConnection::throwUrlNotValid(const OUString & _rsUrl,const OUString & _rsMessage)
414
0
{
415
0
    XConnection* context = this;
416
0
    css::uno::Any next;
417
0
    if (!_rsMessage.isEmpty())
418
0
        next <<= SQLException(_rsMessage, context, OUString(), 0, Any());
419
0
    SQLException aError(
420
0
        getResources().getResourceStringWithSubstitution(STR_NO_VALID_FILE_URL, "$URL$", _rsUrl),
421
0
        context, u"S1000"_ustr, 0, next);
422
423
0
    throw aError;
424
0
}
425
426
427
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */