Coverage Report

Created: 2026-08-14 10:22

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libreoffice/ucbhelper/source/provider/providerhelper.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
#include <sal/config.h>
21
22
#include <com/sun/star/beans/IllegalTypeException.hpp>
23
#include <com/sun/star/beans/PropertyExistException.hpp>
24
#include <com/sun/star/beans/XPropertyAccess.hpp>
25
#include <com/sun/star/container/XNameAccess.hpp>
26
#include <com/sun/star/container/XNamed.hpp>
27
#include <com/sun/star/ucb/Store.hpp>
28
#include <com/sun/star/ucb/XPropertySetRegistry.hpp>
29
#include <com/sun/star/ucb/XPropertySetRegistryFactory.hpp>
30
#include <cppuhelper/supportsservice.hxx>
31
#include <ucbhelper/contenthelper.hxx>
32
#include <ucbhelper/providerhelper.hxx>
33
34
#include <osl/diagnose.h>
35
#include <osl/mutex.hxx>
36
#include <cppuhelper/weakref.hxx>
37
38
#include <unordered_map>
39
#include <utility>
40
41
using namespace com::sun::star;
42
43
namespace ucbhelper_impl
44
{
45
46
typedef std::unordered_map
47
<
48
    OUString,
49
    uno::WeakReference< ucb::XContent >
50
>
51
Contents;
52
53
struct ContentProviderImplHelper_Impl
54
{
55
    uno::Reference< css::ucb::XPropertySetRegistry >  m_xPropertySetRegistry;
56
    Contents                                          m_aContents;
57
};
58
59
} // namespace ucbhelper_impl
60
61
namespace ucbhelper {
62
63
ContentProviderImplHelper::ContentProviderImplHelper(
64
    uno::Reference< uno::XComponentContext > xContext )
65
10.9k
: m_pImpl( new ucbhelper_impl::ContentProviderImplHelper_Impl ),
66
10.9k
  m_xContext(std::move( xContext ))
67
10.9k
{
68
10.9k
}
69
70
// virtual
71
ContentProviderImplHelper::~ContentProviderImplHelper()
72
10.9k
{
73
10.9k
}
74
75
// virtual
76
sal_Bool SAL_CALL ContentProviderImplHelper::supportsService(
77
                                            const OUString& ServiceName )
78
0
{
79
0
    return cppu::supportsService(this, ServiceName);
80
0
}
81
82
// virtual
83
sal_Int32 SAL_CALL ContentProviderImplHelper::compareContentIds(
84
        const uno::Reference< css::ucb::XContentIdentifier >& Id1,
85
        const uno::Reference< css::ucb::XContentIdentifier >& Id2 )
86
0
{
87
    // Simply do a string compare.
88
89
0
    OUString aURL1( Id1->getContentIdentifier() );
90
0
    OUString aURL2( Id2->getContentIdentifier() );
91
92
0
    return aURL1.compareTo( aURL2 );
93
0
}
94
95
void ContentProviderImplHelper::cleanupRegisteredContents()
96
4.27k
{
97
4.27k
    osl::MutexGuard aGuard( m_aMutex );
98
99
4.27k
    ucbhelper_impl::Contents::iterator it
100
4.27k
        = m_pImpl->m_aContents.begin();
101
4.27k
    while( it != m_pImpl->m_aContents.end() )
102
0
    {
103
0
        uno::Reference< ucb::XContent > xContent( (*it).second );
104
0
        if ( !xContent.is() )
105
0
        {
106
0
            ucbhelper_impl::Contents::iterator tmp = it;
107
0
            ++it;
108
0
            m_pImpl->m_aContents.erase( tmp );
109
0
        }
110
0
        else
111
0
        {
112
0
            ++it;
113
0
        }
114
0
    }
115
4.27k
}
116
117
void ContentProviderImplHelper::removeContent( ContentImplHelper* pContent )
118
0
{
119
0
    osl::MutexGuard aGuard( m_aMutex );
120
121
0
    cleanupRegisteredContents();
122
123
0
    const OUString aURL(
124
0
        pContent->getIdentifier()->getContentIdentifier() );
125
126
0
    ucbhelper_impl::Contents::iterator it = m_pImpl->m_aContents.find( aURL );
127
128
0
    if ( it != m_pImpl->m_aContents.end() )
129
0
        m_pImpl->m_aContents.erase( it );
130
0
}
131
132
rtl::Reference< ContentImplHelper >
133
ContentProviderImplHelper::queryExistingContent(
134
    const uno::Reference< css::ucb::XContentIdentifier >& Identifier )
135
4.27k
{
136
4.27k
    return queryExistingContent( Identifier->getContentIdentifier() );
137
4.27k
}
138
139
rtl::Reference< ContentImplHelper >
140
ContentProviderImplHelper::queryExistingContent( const OUString& rURL )
141
4.27k
{
142
4.27k
    osl::MutexGuard aGuard( m_aMutex );
143
144
4.27k
    cleanupRegisteredContents();
145
146
    // Check, if a content with given id already exists...
147
148
4.27k
    ucbhelper_impl::Contents::const_iterator it
149
4.27k
        = m_pImpl->m_aContents.find( rURL );
150
4.27k
    if ( it != m_pImpl->m_aContents.end() )
151
0
    {
152
0
        uno::Reference< ucb::XContent > xContent( (*it).second );
153
0
        if ( xContent.is() )
154
0
        {
155
0
            return rtl::Reference< ContentImplHelper >(
156
0
                static_cast< ContentImplHelper * >( xContent.get() ) );
157
0
        }
158
0
    }
159
4.27k
    return rtl::Reference< ContentImplHelper >();
160
4.27k
}
161
162
void ContentProviderImplHelper::queryExistingContents(
163
        ContentRefList& rContents )
164
0
{
165
0
    osl::MutexGuard aGuard( m_aMutex );
166
167
0
    cleanupRegisteredContents();
168
169
0
    for ( const auto& rContent : m_pImpl->m_aContents )
170
0
    {
171
0
        uno::Reference< ucb::XContent > xContent( rContent.second );
172
0
        if ( xContent.is() )
173
0
        {
174
0
            rContents.emplace_back(
175
0
                    static_cast< ContentImplHelper * >( xContent.get() ) );
176
0
        }
177
0
    }
178
0
}
179
180
void ContentProviderImplHelper::registerNewContent(
181
    const uno::Reference< ucb::XContent > & xContent )
182
0
{
183
0
    if ( !xContent.is() )
184
0
        return;
185
186
0
    osl::MutexGuard aGuard( m_aMutex );
187
188
0
    cleanupRegisteredContents();
189
190
0
    const OUString aURL(
191
0
        xContent->getIdentifier()->getContentIdentifier() );
192
0
    ucbhelper_impl::Contents::const_iterator it
193
0
        = m_pImpl->m_aContents.find( aURL );
194
0
    if ( it == m_pImpl->m_aContents.end() )
195
0
        m_pImpl->m_aContents[ aURL ] = xContent;
196
0
}
197
198
uno::Reference< css::ucb::XPropertySetRegistry >
199
ContentProviderImplHelper::getAdditionalPropertySetRegistry()
200
0
{
201
    // Get propertyset registry.
202
203
0
    osl::MutexGuard aGuard( m_aMutex );
204
205
0
    if ( !m_pImpl->m_xPropertySetRegistry.is() )
206
0
    {
207
0
        uno::Reference< css::ucb::XPropertySetRegistryFactory >
208
0
            xRegFac = css::ucb::Store::create( m_xContext );
209
210
        // Open/create a registry.
211
0
        m_pImpl->m_xPropertySetRegistry
212
0
            = xRegFac->createPropertySetRegistry( OUString() );
213
214
0
        OSL_ENSURE( m_pImpl->m_xPropertySetRegistry.is(),
215
0
                "ContentProviderImplHelper::getAdditionalPropertySet - "
216
0
                "Error opening registry!" );
217
0
    }
218
219
0
    return m_pImpl->m_xPropertySetRegistry;
220
0
}
221
222
uno::Reference< css::ucb::XPersistentPropertySet >
223
ContentProviderImplHelper::getAdditionalPropertySet(
224
    const OUString& rKey, bool bCreate )
225
0
{
226
    // Get propertyset registry.
227
0
    getAdditionalPropertySetRegistry();
228
229
0
    if ( m_pImpl->m_xPropertySetRegistry.is() )
230
0
    {
231
        // Open/create persistent property set.
232
0
        return m_pImpl->m_xPropertySetRegistry->openPropertySet(
233
0
                rKey, bCreate );
234
0
    }
235
236
0
    return uno::Reference< css::ucb::XPersistentPropertySet >();
237
0
}
238
239
bool ContentProviderImplHelper::renameAdditionalPropertySet(
240
    const OUString& rOldKey,
241
    const OUString& rNewKey,
242
    bool bRecursive )
243
0
{
244
0
    if ( rOldKey == rNewKey )
245
0
        return true;
246
247
0
    osl::MutexGuard aGuard( m_aMutex );
248
249
0
    if ( bRecursive )
250
0
    {
251
        // Get propertyset registry.
252
0
        getAdditionalPropertySetRegistry();
253
254
0
        if ( !m_pImpl->m_xPropertySetRegistry.is() )
255
0
            return false;
256
257
0
        uno::Reference< container::XNameAccess > xNameAccess(
258
0
            m_pImpl->m_xPropertySetRegistry, uno::UNO_QUERY );
259
0
        if ( !xNameAccess.is() )
260
0
            return false;
261
262
0
        const uno::Sequence< OUString > aKeys
263
0
            = xNameAccess->getElementNames();
264
0
        if ( aKeys.hasElements() )
265
0
        {
266
0
            OUString aOldKeyWithSlash = rOldKey;
267
0
            OUString aOldKeyWithoutSlash;
268
0
            if ( !aOldKeyWithSlash.endsWith("/") )
269
0
            {
270
0
                aOldKeyWithSlash += "/";
271
0
                aOldKeyWithoutSlash = rOldKey;
272
0
            }
273
0
            else if ( !rOldKey.isEmpty() )
274
0
                aOldKeyWithoutSlash
275
0
                    = rOldKey.copy( 0, rOldKey.getLength() - 1 );
276
277
0
            for ( const OUString& rKey : aKeys )
278
0
            {
279
0
                if ( rKey.startsWith( aOldKeyWithSlash )
280
0
                     || rKey == aOldKeyWithoutSlash )
281
0
                {
282
0
                    OUString aNewKey
283
0
                        = rKey.replaceAt(
284
0
                            0, rOldKey.getLength(), rNewKey );
285
0
                    if ( !renameAdditionalPropertySet(
286
0
                            rKey, aNewKey, false ) )
287
0
                        return false;
288
0
                }
289
0
            }
290
0
        }
291
0
    }
292
0
    else
293
0
    {
294
        // Get old property set, if exists.
295
0
        uno::Reference< css::ucb::XPersistentPropertySet > xOldSet
296
0
            = getAdditionalPropertySet( rOldKey, false );
297
0
        if ( xOldSet.is() )
298
0
        {
299
            // Rename property set.
300
0
            uno::Reference< container::XNamed > xNamed(
301
0
                xOldSet, uno::UNO_QUERY );
302
0
            if ( !xNamed.is() )
303
0
                return false;
304
305
            // ??? throws no exceptions and has no return value ???
306
0
            xNamed->setName( rNewKey );
307
0
        }
308
0
    }
309
0
    return true;
310
0
}
311
312
bool ContentProviderImplHelper::copyAdditionalPropertySet(
313
    const OUString& rSourceKey,
314
    const OUString& rTargetKey,
315
    bool bRecursive )
316
0
{
317
0
    if ( rSourceKey == rTargetKey )
318
0
        return true;
319
320
0
    osl::MutexGuard aGuard( m_aMutex );
321
322
0
    if ( bRecursive )
323
0
    {
324
        // Get propertyset registry.
325
0
        getAdditionalPropertySetRegistry();
326
327
0
        if ( !m_pImpl->m_xPropertySetRegistry.is() )
328
0
            return false;
329
330
0
        uno::Reference< container::XNameAccess > xNameAccess(
331
0
            m_pImpl->m_xPropertySetRegistry, uno::UNO_QUERY );
332
0
        if ( !xNameAccess.is() )
333
0
            return false;
334
335
0
        const uno::Sequence< OUString > aKeys
336
0
            = xNameAccess->getElementNames();
337
0
        if ( aKeys.hasElements() )
338
0
        {
339
0
            OUString aSrcKeyWithSlash = rSourceKey;
340
0
            OUString aSrcKeyWithoutSlash;
341
0
            if ( !aSrcKeyWithSlash.endsWith("/") )
342
0
            {
343
0
                aSrcKeyWithSlash += "/";
344
0
                aSrcKeyWithoutSlash = rSourceKey;
345
0
            }
346
0
            else if ( !rSourceKey.isEmpty() )
347
0
                aSrcKeyWithoutSlash = rSourceKey.copy(
348
0
                    0, rSourceKey.getLength() - 1 );
349
350
0
            for ( const OUString& rKey : aKeys )
351
0
            {
352
0
                if ( rKey.startsWith(aSrcKeyWithSlash )
353
0
                     || rKey == aSrcKeyWithoutSlash )
354
0
                {
355
0
                    OUString aNewKey
356
0
                        = rKey.replaceAt(
357
0
                            0, rSourceKey.getLength(), rTargetKey );
358
0
                    if ( !copyAdditionalPropertySet(
359
0
                            rKey, aNewKey, false ) )
360
0
                        return false;
361
0
                }
362
0
            }
363
0
        }
364
0
    }
365
0
    else
366
0
    {
367
        // Get old property set, if exists.
368
0
        uno::Reference< css::ucb::XPersistentPropertySet >
369
0
            xOldPropSet = getAdditionalPropertySet( rSourceKey, false );
370
0
        if ( !xOldPropSet.is() )
371
0
            return false;
372
373
0
        uno::Reference< beans::XPropertySetInfo > xPropSetInfo
374
0
            = xOldPropSet->getPropertySetInfo();
375
0
        if ( !xPropSetInfo.is() )
376
0
            return false;
377
378
0
        uno::Reference< beans::XPropertyAccess > xOldPropAccess(
379
0
            xOldPropSet, uno::UNO_QUERY );
380
0
        if ( !xOldPropAccess.is() )
381
0
            return false;
382
383
        // Obtain all values from old set.
384
0
        const uno::Sequence< beans::PropertyValue > aValues
385
0
            = xOldPropAccess->getPropertyValues();
386
387
0
        const uno::Sequence< beans::Property > aProps
388
0
            = xPropSetInfo->getProperties();
389
390
0
        if ( aValues.hasElements() )
391
0
        {
392
            // Fail, if property set with new key already exists.
393
0
            uno::Reference< css::ucb::XPersistentPropertySet >
394
0
                xNewPropSet
395
0
                    = getAdditionalPropertySet( rTargetKey, false );
396
0
            if ( xNewPropSet.is() )
397
0
                return false;
398
399
            // Create new, empty set.
400
0
            xNewPropSet = getAdditionalPropertySet( rTargetKey, true );
401
0
            if ( !xNewPropSet.is() )
402
0
                return false;
403
404
0
            uno::Reference< beans::XPropertyContainer > xNewPropContainer(
405
0
                xNewPropSet, uno::UNO_QUERY );
406
0
            if ( !xNewPropContainer.is() )
407
0
                return false;
408
409
0
            for ( const beans::PropertyValue& rValue : aValues )
410
0
            {
411
0
                sal_Int16 nAttribs = 0;
412
0
                auto pProp = std::find_if(aProps.begin(), aProps.end(),
413
0
                    [&rValue](const beans::Property& rProp) { return rProp.Name == rValue.Name; });
414
0
                if (pProp != aProps.end())
415
0
                    nAttribs = pProp->Attributes;
416
417
0
                try
418
0
                {
419
0
                    xNewPropContainer->addProperty(
420
0
                        rValue.Name, nAttribs, rValue.Value );
421
0
                }
422
0
                catch ( beans::PropertyExistException & )
423
0
                {
424
0
                }
425
0
                   catch ( beans::IllegalTypeException & )
426
0
                {
427
0
                }
428
0
                catch ( lang::IllegalArgumentException & )
429
0
                {
430
0
                }
431
0
            }
432
0
        }
433
0
    }
434
0
    return true;
435
0
}
436
437
bool ContentProviderImplHelper::removeAdditionalPropertySet(
438
    const OUString& rKey, bool bRecursive )
439
0
{
440
0
    osl::MutexGuard aGuard( m_aMutex );
441
442
0
    if ( bRecursive )
443
0
    {
444
        // Get propertyset registry.
445
0
        getAdditionalPropertySetRegistry();
446
447
0
        if ( !m_pImpl->m_xPropertySetRegistry.is() )
448
0
            return false;
449
450
0
        uno::Reference< container::XNameAccess > xNameAccess(
451
0
            m_pImpl->m_xPropertySetRegistry, uno::UNO_QUERY );
452
0
        if ( !xNameAccess.is() )
453
0
            return false;
454
455
0
        const uno::Sequence< OUString > aKeys
456
0
            = xNameAccess->getElementNames();
457
0
        if ( aKeys.hasElements() )
458
0
        {
459
0
            OUString aKeyWithSlash = rKey;
460
0
            OUString aKeyWithoutSlash;
461
0
            if ( !aKeyWithSlash.endsWith("/") )
462
0
            {
463
0
                aKeyWithSlash += "/";
464
0
                aKeyWithoutSlash = rKey;
465
0
            }
466
0
            else if ( !rKey.isEmpty() )
467
0
                aKeyWithoutSlash
468
0
                    = rKey.copy( 0, rKey.getLength() - 1 );
469
470
0
            for ( const OUString& rCurrKey : aKeys )
471
0
            {
472
0
                if ( rCurrKey.startsWith(aKeyWithSlash )
473
0
                     || rCurrKey == aKeyWithoutSlash )
474
0
                {
475
0
                    if ( !removeAdditionalPropertySet(
476
0
                             rCurrKey, false ) )
477
0
                        return false;
478
0
                }
479
0
            }
480
0
        }
481
0
    }
482
0
    else
483
0
    {
484
        // Get propertyset registry.
485
0
        getAdditionalPropertySetRegistry();
486
487
0
        if ( !m_pImpl->m_xPropertySetRegistry.is() )
488
0
            return false;
489
490
0
        m_pImpl->m_xPropertySetRegistry->removePropertySet( rKey );
491
0
    }
492
0
    return true;
493
0
}
494
495
} // namespace ucbhelper
496
497
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */