cid#1607171 Data race condition
[LibreOffice.git] / package / source / xstor / ohierarchyholder.cxx
blob66b8043748ea32323bc4b300ad6d4fa7a58f4b06
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include <sal/config.h>
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>
33 #include "ohierarchyholder.hxx"
34 #include "xstorage.hxx"
36 using namespace ::com::sun::star;
38 // OHierarchyHolder_Impl
40 uno::Reference< embed::XExtendedStorageStream > OHierarchyHolder_Impl::GetStreamHierarchically( sal_Int32 nStorageMode, std::vector<OUString>& aListPath, sal_Int32 nStreamMode, const ::comphelper::SequenceAsHashMap& aEncryptionData )
42 if ( !( nStorageMode & embed::ElementModes::WRITE ) && ( nStreamMode & embed::ElementModes::WRITE ) )
43 throw io::IOException(u"invalid storage/stream mode combo"_ustr);
45 uno::Reference< embed::XExtendedStorageStream > xResult =
46 m_xChild->GetStreamHierarchically( nStorageMode, aListPath, nStreamMode, aEncryptionData );
47 if ( !xResult.is() )
48 throw uno::RuntimeException();
50 return xResult;
53 void OHierarchyHolder_Impl::RemoveStreamHierarchically( std::vector<OUString>& aListPath )
55 m_xChild->RemoveStreamHierarchically( aListPath );
58 // static
59 std::vector<OUString> OHierarchyHolder_Impl::GetListPathFromString( std::u16string_view aPath )
61 std::vector<OUString> aResult;
62 sal_Int32 nIndex = 0;
65 OUString aName( o3tl::getToken(aPath, 0, '/', nIndex ) );
66 if ( aName.isEmpty() )
67 throw lang::IllegalArgumentException();
69 aResult.push_back( aName );
71 while ( nIndex >= 0 );
73 return aResult;
76 // OHierarchyElement_Impl
78 uno::Reference< embed::XExtendedStorageStream > OHierarchyElement_Impl::GetStreamHierarchically( sal_Int32 nStorageMode, std::vector<OUString>& aListPath, sal_Int32 nStreamMode, const ::comphelper::SequenceAsHashMap& aEncryptionData )
80 std::unique_lock aGuard( m_aMutex );
82 if ( !( nStorageMode & embed::ElementModes::WRITE ) && ( nStreamMode & embed::ElementModes::WRITE ) )
83 throw io::IOException(u"invalid storage/stream mode combo"_ustr);
85 if ( aListPath.empty() )
86 throw uno::RuntimeException();
88 OUString aNextName = *(aListPath.begin());
89 aListPath.erase( aListPath.begin() );
91 uno::Reference< embed::XExtendedStorageStream > xResult;
93 rtl::Reference< OStorage > xOwnStor = m_xOwnStorage.is() ? m_xOwnStorage
94 : m_xWeakOwnStorage.get();
95 if (!xOwnStor)
96 throw uno::RuntimeException(u"no own storage"_ustr);
98 if ( aListPath.empty() )
100 if ( aEncryptionData.empty() )
101 xResult = xOwnStor->openStreamElementByHierarchicalName( aNextName, nStreamMode );
102 else
103 xResult = xOwnStor->openEncryptedStreamByHierarchicalName( aNextName, nStreamMode, aEncryptionData.getAsConstNamedValueList() );
105 uno::Reference< embed::XTransactedObject > xTransact( xResult, uno::UNO_QUERY );
106 if ( xTransact.is() )
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 uno::Reference< embed::XTransactionBroadcaster > xTrBroadcast( xTransact, uno::UNO_QUERY_THROW );
111 xTrBroadcast->addTransactionListener( static_cast< embed::XTransactionListener* >( this ) );
113 else
115 uno::Reference< lang::XComponent > xStreamComp( xResult, uno::UNO_QUERY_THROW );
116 xStreamComp->addEventListener( static_cast< lang::XEventListener* >( this ) );
119 m_aOpenStreams.emplace_back( xResult );
121 else
123 bool bNewElement = false;
124 ::rtl::Reference< OHierarchyElement_Impl > aElement;
125 OHierarchyElementList_Impl::iterator aIter = m_aChildren.find( aNextName );
126 if ( aIter != m_aChildren.end() )
127 aElement = aIter->second;
129 if ( !aElement.is() )
131 bNewElement = true;
132 rtl::Reference< OStorage > xChildStorage = xOwnStor->openStorageElement2( aNextName, nStorageMode );
133 if ( !xChildStorage.is() )
134 throw uno::RuntimeException();
136 aElement = new OHierarchyElement_Impl( xChildStorage );
139 xResult = aElement->GetStreamHierarchically( nStorageMode, aListPath, nStreamMode, aEncryptionData );
140 if ( !xResult.is() )
141 throw uno::RuntimeException();
143 if ( bNewElement )
145 m_aChildren[aNextName] = aElement;
146 aElement->SetParent( this );
150 // the subelement was opened successfully, remember the storage to let it be locked
151 m_xOwnStorage = std::move(xOwnStor);
153 return xResult;
156 void OHierarchyElement_Impl::RemoveStreamHierarchically( std::vector<OUString>& aListPath )
158 std::unique_lock aGuard( m_aMutex );
160 if ( aListPath.empty() )
161 throw uno::RuntimeException();
163 OUString aNextName = *(aListPath.begin());
164 aListPath.erase( aListPath.begin() );
166 rtl::Reference< OStorage > xOwnStor = m_xOwnStorage.is() ? m_xOwnStorage
167 : m_xWeakOwnStorage.get();
168 if (!xOwnStor)
169 throw uno::RuntimeException(u"no own storage"_ustr);
171 if ( aListPath.empty() )
173 xOwnStor->removeElement( aNextName );
175 else
177 ::rtl::Reference< OHierarchyElement_Impl > aElement;
178 OHierarchyElementList_Impl::iterator aIter = m_aChildren.find( aNextName );
179 if ( aIter != m_aChildren.end() )
180 aElement = aIter->second;
182 if ( !aElement.is() )
184 rtl::Reference< OStorage > xChildStorage = xOwnStor->openStorageElement2( aNextName,
185 embed::ElementModes::READWRITE );
186 if ( !xChildStorage.is() )
187 throw uno::RuntimeException();
189 aElement = new OHierarchyElement_Impl( xChildStorage );
192 aElement->RemoveStreamHierarchically( aListPath );
195 xOwnStor->commit();
197 TestForClosing();
200 void OHierarchyElement_Impl::Commit()
202 ::rtl::Reference< OHierarchyElement_Impl > xKeepAlive( this );
203 ::rtl::Reference< OHierarchyElement_Impl > aParent;
204 rtl::Reference<OStorage> xOwnStor;
207 std::unique_lock aGuard( m_aMutex );
208 aParent = m_rParent;
209 xOwnStor = m_xOwnStorage;
212 if ( xOwnStor.is() )
214 xOwnStor->commit();
215 if ( aParent.is() )
216 aParent->Commit();
220 void OHierarchyElement_Impl::TestForClosing()
222 ::rtl::Reference< OHierarchyElement_Impl > xKeepAlive( this );
224 std::unique_lock aGuard( m_aMutex );
226 if ( m_aOpenStreams.empty() && m_aChildren.empty() )
228 if ( m_rParent.is() )
230 // only the root storage should not be disposed, other storages can be disposed
231 if ( m_xOwnStorage.is() )
235 m_xOwnStorage->dispose();
237 catch( uno::Exception& )
241 m_rParent->RemoveElement( this );
244 m_xOwnStorage.clear();
249 void SAL_CALL OHierarchyElement_Impl::disposing( const lang::EventObject& Source )
254 std::unique_lock aGuard(m_aMutex);
255 uno::Reference< embed::XExtendedStorageStream > xStream(Source.Source, uno::UNO_QUERY);
257 std::erase_if(m_aOpenStreams,
258 [&xStream](const OWeakStorRefVector_Impl::value_type& rxStorage) {
259 return !rxStorage.get().is() || rxStorage.get() == xStream; });
262 TestForClosing();
264 catch( uno::Exception& ex )
266 css::uno::Any anyEx = cppu::getCaughtException();
267 throw lang::WrappedTargetRuntimeException( ex.Message,
268 nullptr, anyEx ); // no exception must happen here, usually an exception means disaster
272 void OHierarchyElement_Impl::RemoveElement( const ::rtl::Reference< OHierarchyElement_Impl >& aRef )
275 std::unique_lock aGuard( m_aMutex );
276 OHierarchyElementList_Impl::iterator aIter = m_aChildren.begin();
277 while (aIter != m_aChildren.end())
279 if (aIter->second == aRef )
280 aIter = m_aChildren.erase(aIter);
281 else
282 ++aIter;
286 TestForClosing();
289 // XTransactionListener
290 void SAL_CALL OHierarchyElement_Impl::preCommit( const css::lang::EventObject& /*aEvent*/ )
294 void SAL_CALL OHierarchyElement_Impl::commited( const css::lang::EventObject& /*aEvent*/ )
298 Commit();
300 catch( const uno::Exception& )
302 css::uno::Any anyEx = cppu::getCaughtException();
303 throw lang::WrappedTargetRuntimeException(
304 u"Can not commit storage sequence!"_ustr,
305 uno::Reference< uno::XInterface >(),
306 anyEx );
310 void SAL_CALL OHierarchyElement_Impl::preRevert( const css::lang::EventObject& /*aEvent*/ )
314 void SAL_CALL OHierarchyElement_Impl::reverted( const css::lang::EventObject& /*aEvent*/ )
318 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */