1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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
);
48 throw uno::RuntimeException();
53 void OHierarchyHolder_Impl::RemoveStreamHierarchically( std::vector
<OUString
>& aListPath
)
55 m_xChild
->RemoveStreamHierarchically( aListPath
);
59 std::vector
<OUString
> OHierarchyHolder_Impl::GetListPathFromString( std::u16string_view aPath
)
61 std::vector
<OUString
> aResult
;
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 );
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();
96 throw uno::RuntimeException(u
"no own storage"_ustr
);
98 if ( aListPath
.empty() )
100 if ( aEncryptionData
.empty() )
101 xResult
= xOwnStor
->openStreamElementByHierarchicalName( aNextName
, nStreamMode
);
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 ) );
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
);
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() )
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
);
141 throw uno::RuntimeException();
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
);
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();
169 throw uno::RuntimeException(u
"no own storage"_ustr
);
171 if ( aListPath
.empty() )
173 xOwnStor
->removeElement( aNextName
);
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
);
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
);
209 xOwnStor
= m_xOwnStorage
;
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
; });
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
);
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*/ )
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
>(),
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: */