Coverage Report

Created: 2025-07-07 10:01

/src/libreoffice/package/source/xstor/ohierarchyholder.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 <com/sun/star/io/IOException.hpp>
23
#include <com/sun/star/uno/Reference.hxx>
24
#include <com/sun/star/embed/ElementModes.hpp>
25
#include <com/sun/star/embed/XHierarchicalStorageAccess2.hpp>
26
#include <com/sun/star/embed/XTransactedObject.hpp>
27
#include <com/sun/star/embed/XTransactionBroadcaster.hpp>
28
#include <com/sun/star/lang/IllegalArgumentException.hpp>
29
#include <com/sun/star/lang/WrappedTargetRuntimeException.hpp>
30
#include <cppuhelper/exc_hlp.hxx>
31
#include <o3tl/string_view.hxx>
32
33
#include "ohierarchyholder.hxx"
34
#include "xstorage.hxx"
35
36
using namespace ::com::sun::star;
37
38
// OHierarchyHolder_Impl
39
40
uno::Reference< embed::XExtendedStorageStream > OHierarchyHolder_Impl::GetStreamHierarchically( sal_Int32 nStorageMode, std::vector<OUString>& aListPath, sal_Int32 nStreamMode, const ::comphelper::SequenceAsHashMap& aEncryptionData )
41
44.6k
{
42
44.6k
    if ( !( nStorageMode & embed::ElementModes::WRITE ) && ( nStreamMode & embed::ElementModes::WRITE ) )
43
0
        throw io::IOException(u"invalid storage/stream mode combo"_ustr);
44
45
44.6k
    uno::Reference< embed::XExtendedStorageStream > xResult =
46
44.6k
        m_xChild->GetStreamHierarchically( nStorageMode, aListPath, nStreamMode, aEncryptionData );
47
44.6k
    if ( !xResult.is() )
48
0
        throw uno::RuntimeException();
49
50
44.6k
    return xResult;
51
44.6k
}
52
53
void OHierarchyHolder_Impl::RemoveStreamHierarchically( std::vector<OUString>& aListPath )
54
0
{
55
0
    m_xChild->RemoveStreamHierarchically( aListPath );
56
0
}
57
58
// static
59
std::vector<OUString> OHierarchyHolder_Impl::GetListPathFromString( std::u16string_view aPath )
60
89.2k
{
61
89.2k
    std::vector<OUString> aResult;
62
89.2k
    sal_Int32 nIndex = 0;
63
89.2k
    do
64
137k
    {
65
137k
        OUString aName( o3tl::getToken(aPath, 0, '/', nIndex ) );
66
137k
        if ( aName.isEmpty() )
67
0
            throw lang::IllegalArgumentException();
68
69
137k
        aResult.push_back( aName );
70
137k
    }
71
137k
    while ( nIndex >= 0 );
72
73
89.2k
    return aResult;
74
89.2k
}
75
76
// OHierarchyElement_Impl
77
78
uno::Reference< embed::XExtendedStorageStream > OHierarchyElement_Impl::GetStreamHierarchically( sal_Int32 nStorageMode, std::vector<OUString>& aListPath, sal_Int32 nStreamMode, const ::comphelper::SequenceAsHashMap& aEncryptionData )
79
92.9k
{
80
92.9k
    std::unique_lock aGuard( m_aMutex );
81
82
92.9k
    if ( !( nStorageMode & embed::ElementModes::WRITE ) && ( nStreamMode & embed::ElementModes::WRITE ) )
83
0
        throw io::IOException(u"invalid storage/stream mode combo"_ustr);
84
85
92.9k
    if ( aListPath.empty() )
86
0
        throw uno::RuntimeException();
87
88
92.9k
    OUString aNextName = *(aListPath.begin());
89
92.9k
    aListPath.erase( aListPath.begin() );
90
91
92.9k
    uno::Reference< embed::XExtendedStorageStream > xResult;
92
93
92.9k
    rtl::Reference< OStorage > xOwnStor = m_xOwnStorage.is() ? m_xOwnStorage
94
92.9k
                : m_xWeakOwnStorage.get();
95
92.9k
    if (!xOwnStor)
96
0
        throw uno::RuntimeException(u"no own storage"_ustr);
97
98
92.9k
    if ( aListPath.empty() )
99
44.6k
    {
100
44.6k
        if ( aEncryptionData.empty() )
101
44.6k
            xResult = xOwnStor->openStreamElementByHierarchicalName( aNextName, nStreamMode );
102
0
        else
103
0
            xResult = xOwnStor->openEncryptedStreamByHierarchicalName( aNextName, nStreamMode, aEncryptionData.getAsConstNamedValueList() );
104
105
44.6k
        uno::Reference< embed::XTransactedObject > xTransact( xResult, uno::UNO_QUERY );
106
44.6k
        if ( xTransact.is() )
107
0
        {
108
            // the existence of the transacted object means that the stream is opened for writing also
109
            // so the whole chain must be committed
110
0
            uno::Reference< embed::XTransactionBroadcaster > xTrBroadcast( xTransact, uno::UNO_QUERY_THROW );
111
0
            xTrBroadcast->addTransactionListener( static_cast< embed::XTransactionListener* >( this ) );
112
0
        }
113
44.6k
        else
114
44.6k
        {
115
44.6k
            uno::Reference< lang::XComponent > xStreamComp( xResult, uno::UNO_QUERY_THROW );
116
44.6k
            xStreamComp->addEventListener( static_cast< lang::XEventListener* >( this ) );
117
44.6k
        }
118
119
44.6k
        m_aOpenStreams.emplace_back( xResult );
120
44.6k
    }
121
48.3k
    else
122
48.3k
    {
123
48.3k
        bool bNewElement = false;
124
48.3k
        ::rtl::Reference< OHierarchyElement_Impl > aElement;
125
48.3k
        OHierarchyElementList_Impl::iterator aIter = m_aChildren.find( aNextName );
126
48.3k
        if ( aIter != m_aChildren.end() )
127
30.7k
            aElement = aIter->second;
128
129
48.3k
        if ( !aElement.is() )
130
17.5k
        {
131
17.5k
            bNewElement = true;
132
17.5k
            rtl::Reference< OStorage > xChildStorage = xOwnStor->openStorageElement2( aNextName, nStorageMode );
133
17.5k
            if ( !xChildStorage.is() )
134
0
                throw uno::RuntimeException();
135
136
17.5k
            aElement = new OHierarchyElement_Impl( xChildStorage );
137
17.5k
        }
138
139
48.3k
        xResult = aElement->GetStreamHierarchically( nStorageMode, aListPath, nStreamMode, aEncryptionData );
140
48.3k
        if ( !xResult.is() )
141
0
            throw uno::RuntimeException();
142
143
48.3k
        if ( bNewElement )
144
13.8k
        {
145
13.8k
            m_aChildren[aNextName] = aElement;
146
13.8k
            aElement->SetParent( this );
147
13.8k
        }
148
48.3k
    }
149
150
    // the subelement was opened successfully, remember the storage to let it be locked
151
92.9k
    m_xOwnStorage = std::move(xOwnStor);
152
153
92.9k
    return xResult;
154
92.9k
}
155
156
void OHierarchyElement_Impl::RemoveStreamHierarchically( std::vector<OUString>& aListPath )
157
0
{
158
0
    std::unique_lock aGuard( m_aMutex );
159
160
0
    if ( aListPath.empty() )
161
0
        throw uno::RuntimeException();
162
163
0
    OUString aNextName = *(aListPath.begin());
164
0
    aListPath.erase( aListPath.begin() );
165
166
0
    rtl::Reference< OStorage > xOwnStor = m_xOwnStorage.is() ? m_xOwnStorage
167
0
                : m_xWeakOwnStorage.get();
168
0
    if (!xOwnStor)
169
0
        throw uno::RuntimeException(u"no own storage"_ustr);
170
171
0
    if ( aListPath.empty() )
172
0
    {
173
0
        xOwnStor->removeElement( aNextName );
174
0
    }
175
0
    else
176
0
    {
177
0
        ::rtl::Reference< OHierarchyElement_Impl > aElement;
178
0
        OHierarchyElementList_Impl::iterator aIter = m_aChildren.find( aNextName );
179
0
        if ( aIter != m_aChildren.end() )
180
0
            aElement = aIter->second;
181
182
0
        if ( !aElement.is() )
183
0
        {
184
0
            rtl::Reference< OStorage > xChildStorage = xOwnStor->openStorageElement2( aNextName,
185
0
                                                                                            embed::ElementModes::READWRITE );
186
0
            if ( !xChildStorage.is() )
187
0
                throw uno::RuntimeException();
188
189
0
            aElement = new OHierarchyElement_Impl( xChildStorage );
190
0
        }
191
192
0
        aElement->RemoveStreamHierarchically( aListPath );
193
0
    }
194
195
0
    xOwnStor->commit();
196
197
0
    TestForClosing();
198
0
}
199
200
void OHierarchyElement_Impl::Commit()
201
0
{
202
0
    ::rtl::Reference< OHierarchyElement_Impl > xKeepAlive( this );
203
0
    ::rtl::Reference< OHierarchyElement_Impl > aParent;
204
0
    rtl::Reference<OStorage> xOwnStor;
205
206
0
    {
207
0
        std::unique_lock aGuard( m_aMutex );
208
0
        aParent = m_rParent;
209
0
        xOwnStor = m_xOwnStorage;
210
0
    }
211
212
0
    if ( xOwnStor.is() )
213
0
    {
214
0
        xOwnStor->commit();
215
0
        if ( aParent.is() )
216
0
            aParent->Commit();
217
0
    }
218
0
}
219
220
void OHierarchyElement_Impl::TestForClosing()
221
44.5k
{
222
44.5k
    ::rtl::Reference< OHierarchyElement_Impl > xKeepAlive( this );
223
44.5k
    {
224
44.5k
        std::unique_lock aGuard( m_aMutex );
225
226
44.5k
        if ( m_aOpenStreams.empty() && m_aChildren.empty() )
227
24.4k
        {
228
24.4k
            if ( m_rParent.is() )
229
13.8k
            {
230
                // only the root storage should not be disposed, other storages can be disposed
231
13.8k
                if ( m_xOwnStorage.is() )
232
13.8k
                {
233
13.8k
                    try
234
13.8k
                    {
235
13.8k
                        m_xOwnStorage->dispose();
236
13.8k
                    }
237
13.8k
                    catch( uno::Exception& )
238
13.8k
                    {}
239
13.8k
                }
240
241
13.8k
                m_rParent->RemoveElement( this );
242
13.8k
            }
243
244
24.4k
            m_xOwnStorage.clear();
245
24.4k
        }
246
44.5k
    }
247
44.5k
}
248
249
void SAL_CALL OHierarchyElement_Impl::disposing( const lang::EventObject& Source )
250
30.6k
{
251
30.6k
    try
252
30.6k
    {
253
30.6k
        {
254
30.6k
            std::unique_lock aGuard(m_aMutex);
255
30.6k
            uno::Reference< embed::XExtendedStorageStream > xStream(Source.Source, uno::UNO_QUERY);
256
257
30.6k
            std::erase_if(m_aOpenStreams,
258
48.0k
                [&xStream](const OWeakStorRefVector_Impl::value_type& rxStorage) {
259
48.0k
                return !rxStorage.get().is() || rxStorage.get() == xStream; });
260
30.6k
        }
261
262
30.6k
        TestForClosing();
263
30.6k
    }
264
30.6k
    catch( uno::Exception& ex )
265
30.6k
    {
266
0
        css::uno::Any anyEx = cppu::getCaughtException();
267
0
        throw lang::WrappedTargetRuntimeException( ex.Message,
268
0
                        nullptr, anyEx ); // no exception must happen here, usually an exception means disaster
269
0
    }
270
30.6k
}
271
272
void OHierarchyElement_Impl::RemoveElement( const ::rtl::Reference< OHierarchyElement_Impl >& aRef )
273
13.8k
{
274
13.8k
    {
275
13.8k
        std::unique_lock aGuard( m_aMutex );
276
13.8k
        OHierarchyElementList_Impl::iterator aIter = m_aChildren.begin();
277
28.7k
        while (aIter != m_aChildren.end())
278
14.9k
        {
279
14.9k
            if (aIter->second == aRef )
280
13.8k
                aIter = m_aChildren.erase(aIter);
281
1.07k
            else
282
1.07k
                ++aIter;
283
14.9k
        }
284
13.8k
    }
285
286
13.8k
    TestForClosing();
287
13.8k
}
288
289
// XTransactionListener
290
void SAL_CALL OHierarchyElement_Impl::preCommit( const css::lang::EventObject& /*aEvent*/ )
291
0
{
292
0
}
293
294
void SAL_CALL OHierarchyElement_Impl::commited( const css::lang::EventObject& /*aEvent*/ )
295
0
{
296
0
    try
297
0
    {
298
0
        Commit();
299
0
    }
300
0
    catch( const uno::Exception& )
301
0
    {
302
0
        css::uno::Any anyEx = cppu::getCaughtException();
303
0
        throw lang::WrappedTargetRuntimeException(
304
0
                            u"Can not commit storage sequence!"_ustr,
305
0
                            uno::Reference< uno::XInterface >(),
306
0
                            anyEx );
307
0
    }
308
0
}
309
310
void SAL_CALL OHierarchyElement_Impl::preRevert( const css::lang::EventObject& /*aEvent*/ )
311
0
{
312
0
}
313
314
void SAL_CALL OHierarchyElement_Impl::reverted( const css::lang::EventObject& /*aEvent*/ )
315
0
{
316
0
}
317
318
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */