Coverage Report

Created: 2025-07-07 10:01

/src/libreoffice/comphelper/source/misc/configuration.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
10
#include <sal/config.h>
11
12
#include <cassert>
13
#include <map>
14
#include <memory>
15
#include <mutex>
16
#include <string_view>
17
18
#include <com/sun/star/beans/PropertyAttribute.hpp>
19
#include <com/sun/star/configuration/ReadOnlyAccess.hpp>
20
#include <com/sun/star/configuration/ReadWriteAccess.hpp>
21
#include <com/sun/star/configuration/XReadWriteAccess.hpp>
22
#include <com/sun/star/configuration/theDefaultProvider.hpp>
23
#include <com/sun/star/container/XHierarchicalNameAccess.hpp>
24
#include <com/sun/star/container/XHierarchicalNameReplace.hpp>
25
#include <com/sun/star/container/XNameAccess.hpp>
26
#include <com/sun/star/container/XNameContainer.hpp>
27
#include <com/sun/star/lang/XLocalizable.hpp>
28
#include <com/sun/star/uno/Any.hxx>
29
#include <com/sun/star/uno/Reference.hxx>
30
#include <comphelper/solarmutex.hxx>
31
#include <comphelper/configuration.hxx>
32
#include <comphelper/configurationlistener.hxx>
33
#include <rtl/ustring.hxx>
34
#include <sal/log.hxx>
35
#include <i18nlangtag/languagetag.hxx>
36
37
namespace com::sun::star::uno { class XComponentContext; }
38
39
namespace {
40
41
OUString getDefaultLocale(
42
    css::uno::Reference< css::uno::XComponentContext > const & context)
43
58.3k
{
44
58.3k
    return LanguageTag(
45
58.3k
        css::uno::Reference< css::lang::XLocalizable >(
46
58.3k
            css::configuration::theDefaultProvider::get(context),
47
58.3k
            css::uno::UNO_QUERY_THROW)->
48
58.3k
        getLocale()).getBcp47(false);
49
58.3k
}
50
51
0
OUString extendLocalizedPath(std::u16string_view path, OUString const & locale) {
52
0
    SAL_WARN_IF(
53
0
        locale.match("*"), "comphelper",
54
0
        "Locale \"" << locale << "\" starts with \"*\"");
55
0
    assert(locale.indexOf('&') == -1);
56
0
    assert(locale.indexOf('"') == -1);
57
0
    assert(locale.indexOf('\'') == -1);
58
0
    return OUString::Concat(path) + "/['*" + locale + "']";
59
0
}
60
61
}
62
63
std::shared_ptr< comphelper::ConfigurationChanges >
64
comphelper::ConfigurationChanges::create(
65
    css::uno::Reference<css::uno::XComponentContext> const & context)
66
0
{
67
0
    return detail::ConfigurationWrapper::get(context).createChanges();
68
0
}
69
70
0
comphelper::ConfigurationChanges::~ConfigurationChanges() {}
71
72
0
void comphelper::ConfigurationChanges::commit() const {
73
0
    access_->commitChanges();
74
0
}
75
76
comphelper::ConfigurationChanges::ConfigurationChanges(
77
    css::uno::Reference< css::uno::XComponentContext > const & context):
78
    access_(
79
0
        css::configuration::ReadWriteAccess::create(
80
0
            context, getDefaultLocale(context)))
81
0
{}
82
83
void comphelper::ConfigurationChanges::setPropertyValue(
84
    OUString const & path, css::uno::Any const & value) const
85
0
{
86
0
    access_->replaceByHierarchicalName(path, value);
87
0
}
88
89
css::uno::Reference< css::container::XHierarchicalNameReplace >
90
comphelper::ConfigurationChanges::getGroup(OUString const & path) const
91
0
{
92
0
    return css::uno::Reference< css::container::XHierarchicalNameReplace >(
93
0
        access_->getByHierarchicalName(path), css::uno::UNO_QUERY_THROW);
94
0
}
95
96
css::uno::Reference< css::container::XNameContainer >
97
comphelper::ConfigurationChanges::getSet(OUString const & path) const
98
0
{
99
0
    return css::uno::Reference< css::container::XNameContainer >(
100
0
        access_->getByHierarchicalName(path), css::uno::UNO_QUERY_THROW);
101
0
}
102
103
comphelper::detail::ConfigurationWrapper const &
104
comphelper::detail::ConfigurationWrapper::get(
105
    css::uno::Reference<css::uno::XComponentContext> const & context)
106
58.3k
{
107
58.3k
    static comphelper::detail::ConfigurationWrapper WRAPPER(context);
108
58.3k
    return WRAPPER;
109
58.3k
}
110
111
comphelper::detail::ConfigurationWrapper::ConfigurationWrapper(
112
    css::uno::Reference<css::uno::XComponentContext> const & context):
113
7
    context_(context.is() ? context : comphelper::getProcessComponentContext()),
114
7
    access_(css::configuration::ReadWriteAccess::create(context_, u"*"_ustr))
115
7
{}
116
117
7
comphelper::detail::ConfigurationWrapper::~ConfigurationWrapper() {}
118
119
bool comphelper::detail::ConfigurationWrapper::isReadOnly(OUString const & path)
120
    const
121
0
{
122
0
    return
123
0
        (access_->getPropertyByHierarchicalName(path).Attributes
124
0
         & css::beans::PropertyAttribute::READONLY)
125
0
        != 0;
126
0
}
127
128
css::uno::Any comphelper::detail::ConfigurationWrapper::getPropertyValue(std::u16string_view path) const
129
0
{
130
    // should be short-circuited in ConfigurationProperty::get()
131
0
    assert(!comphelper::IsFuzzing());
132
133
    // Cache the configuration access, since some of the keys are used in hot code.
134
    // Note that this cache is only used by the officecfg:: auto-generated code, using it for anything
135
    // else would be unwise because the cache could end up containing stale entries.
136
0
    static std::mutex gMutex;
137
0
    static std::map<OUString, css::uno::Reference< css::container::XNameAccess >> gAccessMap;
138
139
0
    sal_Int32 idx = path.rfind('/');
140
0
    assert(idx!=-1);
141
0
    OUString parentPath(path.substr(0, idx));
142
0
    OUString childName(path.substr(idx+1));
143
144
0
    std::scoped_lock aGuard(gMutex);
145
146
    // check cache
147
0
    auto it = gAccessMap.find(parentPath);
148
0
    if (it == gAccessMap.end())
149
0
    {
150
        // not in the cache, look it up
151
0
        css::uno::Reference<css::container::XNameAccess> access(
152
0
            access_->getByHierarchicalName(parentPath), css::uno::UNO_QUERY_THROW);
153
0
        it = gAccessMap.emplace(parentPath, access).first;
154
0
    }
155
0
    return it->second->getByName(childName);
156
0
}
157
158
void comphelper::detail::ConfigurationWrapper::setPropertyValue(
159
    std::shared_ptr< ConfigurationChanges > const & batch,
160
    OUString const & path, css::uno::Any const & value)
161
0
{
162
0
    assert(batch);
163
0
    batch->setPropertyValue(path, value);
164
0
}
165
166
css::uno::Any
167
comphelper::detail::ConfigurationWrapper::getLocalizedPropertyValue(
168
    std::u16string_view path) const
169
0
{
170
0
    return access_->getByHierarchicalName(
171
0
        extendLocalizedPath(path, getDefaultLocale(context_)));
172
0
}
173
174
void comphelper::detail::ConfigurationWrapper::setLocalizedPropertyValue(
175
    std::shared_ptr< ConfigurationChanges > const & batch,
176
    OUString const & path, css::uno::Any const & value)
177
0
{
178
0
    assert(batch);
179
0
    batch->setPropertyValue(path, value);
180
0
}
181
182
css::uno::Reference< css::container::XHierarchicalNameAccess >
183
comphelper::detail::ConfigurationWrapper::getGroupReadOnly(
184
    OUString const & path) const
185
0
{
186
0
    return css::uno::Reference< css::container::XHierarchicalNameAccess >(
187
0
        (css::configuration::ReadOnlyAccess::create(
188
0
            context_, getDefaultLocale(context_))->
189
0
         getByHierarchicalName(path)),
190
0
        css::uno::UNO_QUERY_THROW);
191
0
}
192
193
css::uno::Reference< css::container::XHierarchicalNameReplace >
194
comphelper::detail::ConfigurationWrapper::getGroupReadWrite(
195
    std::shared_ptr< ConfigurationChanges > const & batch,
196
    OUString const & path)
197
0
{
198
0
    assert(batch);
199
0
    return batch->getGroup(path);
200
0
}
201
202
css::uno::Reference< css::container::XNameAccess >
203
comphelper::detail::ConfigurationWrapper::getSetReadOnly(
204
    OUString const & path) const
205
58.3k
{
206
58.3k
    return css::uno::Reference< css::container::XNameAccess >(
207
58.3k
        (css::configuration::ReadOnlyAccess::create(
208
58.3k
            context_, getDefaultLocale(context_))->
209
58.3k
         getByHierarchicalName(path)),
210
58.3k
        css::uno::UNO_QUERY_THROW);
211
58.3k
}
212
213
css::uno::Reference< css::container::XNameContainer >
214
comphelper::detail::ConfigurationWrapper::getSetReadWrite(
215
    std::shared_ptr< ConfigurationChanges > const & batch,
216
    OUString const & path)
217
0
{
218
0
    assert(batch);
219
0
    return batch->getSet(path);
220
0
}
221
222
std::shared_ptr< comphelper::ConfigurationChanges >
223
0
comphelper::detail::ConfigurationWrapper::createChanges() const {
224
0
    return std::shared_ptr< ConfigurationChanges >(
225
0
        new ConfigurationChanges(context_));
226
0
}
227
228
void comphelper::ConfigurationListener::addListener(ConfigurationListenerPropertyBase *pListener)
229
0
{
230
0
    maListeners.push_back( pListener );
231
0
    mxConfig->addPropertyChangeListener( pListener->maName, this );
232
0
    pListener->setProperty( mxConfig->getPropertyValue( pListener->maName ) );
233
0
}
234
235
void comphelper::ConfigurationListener::removeListener(ConfigurationListenerPropertyBase *pListener)
236
0
{
237
0
    auto it = std::find( maListeners.begin(), maListeners.end(), pListener );
238
0
    if ( it != maListeners.end() )
239
0
    {
240
0
        maListeners.erase( it );
241
0
        mxConfig->removePropertyChangeListener( pListener->maName, this );
242
0
    }
243
0
}
244
245
void comphelper::ConfigurationListener::dispose()
246
0
{
247
0
    for (auto const& listener : maListeners)
248
0
    {
249
0
        mxConfig->removePropertyChangeListener( listener->maName, this );
250
0
        listener->dispose();
251
0
    }
252
0
    maListeners.clear();
253
0
    mxConfig.clear();
254
0
    mbDisposed = true;
255
0
}
256
257
void SAL_CALL comphelper::ConfigurationListener::disposing(css::lang::EventObject const &)
258
0
{
259
0
    dispose();
260
0
}
261
262
void SAL_CALL comphelper::ConfigurationListener::propertyChange(
263
    css::beans::PropertyChangeEvent const &rEvt )
264
0
{
265
    // Code is commonly used inside the SolarMutexGuard
266
    // so to avoid concurrent writes to the property,
267
    // and allow fast, lock-less access, guard here.
268
    //
269
    // Note that we are abusing rtl::Reference here to do acquire/release because,
270
    // unlike osl::Guard, it is tolerant of null pointers, and on some code paths, the
271
    // SolarMutex does not exist.
272
0
    rtl::Reference<comphelper::SolarMutex> xMutexGuard( comphelper::SolarMutex::get() );
273
274
0
    assert( rEvt.Source == mxConfig );
275
0
    for (auto const& listener : maListeners)
276
0
    {
277
0
        if ( listener->maName == rEvt.PropertyName )
278
0
        {
279
            // ignore rEvt.NewValue - in theory it could be stale => not set.
280
0
            css::uno::Any aValue = mxConfig->getPropertyValue( listener->maName );
281
0
            listener->setProperty( aValue );
282
0
        }
283
0
    }
284
0
}
285
286
namespace comphelper {
287
288
static bool bIsFuzzing = false;
289
290
#if !defined(FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION)
291
bool IsFuzzing()
292
{
293
    return bIsFuzzing;
294
}
295
#endif
296
297
void EnableFuzzing()
298
106
{
299
106
    bIsFuzzing = true;
300
106
    LanguageTag::disable_lt_tag_parse();
301
106
}
302
303
}
304
305
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */