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"
35 using namespace ::com::sun::star
;
37 // OHierarchyHolder_Impl
39 uno::Reference
< embed::XExtendedStorageStream
> OHierarchyHolder_Impl::GetStreamHierarchically( sal_Int32 nStorageMode
, std::vector
<OUString
>& aListPath
, sal_Int32 nStreamMode
, const ::comphelper::SequenceAsHashMap
& aEncryptionData
)
41 uno::Reference
< embed::XStorage
> xOwnStor( m_xWeakOwnStorage
.get(), uno::UNO_QUERY_THROW
);
43 if ( !( nStorageMode
& embed::ElementModes::WRITE
) && ( nStreamMode
& embed::ElementModes::WRITE
) )
44 throw io::IOException("invalid storage/stream mode combo");
46 uno::Reference
< embed::XExtendedStorageStream
> xResult
=
47 m_xChild
->GetStreamHierarchically( nStorageMode
, aListPath
, nStreamMode
, aEncryptionData
);
49 throw uno::RuntimeException();
54 void OHierarchyHolder_Impl::RemoveStreamHierarchically( std::vector
<OUString
>& aListPath
)
56 uno::Reference
< embed::XStorage
> xOwnStor( m_xWeakOwnStorage
.get(), uno::UNO_QUERY_THROW
);
58 m_xChild
->RemoveStreamHierarchically( aListPath
);
62 std::vector
<OUString
> OHierarchyHolder_Impl::GetListPathFromString( std::u16string_view aPath
)
64 std::vector
<OUString
> aResult
;
68 OUString
aName( o3tl::getToken(aPath
, 0, '/', nIndex
) );
69 if ( aName
.isEmpty() )
70 throw lang::IllegalArgumentException();
72 aResult
.push_back( aName
);
74 while ( nIndex
>= 0 );
79 // OHierarchyElement_Impl
81 uno::Reference
< embed::XExtendedStorageStream
> OHierarchyElement_Impl::GetStreamHierarchically( sal_Int32 nStorageMode
, std::vector
<OUString
>& aListPath
, sal_Int32 nStreamMode
, const ::comphelper::SequenceAsHashMap
& aEncryptionData
)
83 std::unique_lock
aGuard( m_aMutex
);
85 if ( !( nStorageMode
& embed::ElementModes::WRITE
) && ( nStreamMode
& embed::ElementModes::WRITE
) )
86 throw io::IOException("invalid storage/stream mode combo");
88 if ( aListPath
.empty() )
89 throw uno::RuntimeException();
91 OUString aNextName
= *(aListPath
.begin());
92 aListPath
.erase( aListPath
.begin() );
94 uno::Reference
< embed::XExtendedStorageStream
> xResult
;
96 uno::Reference
< embed::XStorage
> xOwnStor
= m_xOwnStorage
.is() ? m_xOwnStorage
97 : uno::Reference
< embed::XStorage
>( m_xWeakOwnStorage
.get(), uno::UNO_QUERY_THROW
);
99 if ( aListPath
.empty() )
101 if ( aEncryptionData
.empty() )
103 uno::Reference
< embed::XHierarchicalStorageAccess
> xHStorage( xOwnStor
, uno::UNO_QUERY_THROW
);
104 xResult
= xHStorage
->openStreamElementByHierarchicalName( aNextName
, nStreamMode
);
108 uno::Reference
< embed::XHierarchicalStorageAccess2
> xHStorage( xOwnStor
, uno::UNO_QUERY_THROW
);
109 xResult
= xHStorage
->openEncryptedStreamByHierarchicalName( aNextName
, nStreamMode
, aEncryptionData
.getAsConstNamedValueList() );
112 uno::Reference
< embed::XTransactedObject
> xTransact( xResult
, uno::UNO_QUERY
);
113 if ( xTransact
.is() )
115 // the existence of the transacted object means that the stream is opened for writing also
116 // so the whole chain must be committed
117 uno::Reference
< embed::XTransactionBroadcaster
> xTrBroadcast( xTransact
, uno::UNO_QUERY_THROW
);
118 xTrBroadcast
->addTransactionListener( static_cast< embed::XTransactionListener
* >( this ) );
122 uno::Reference
< lang::XComponent
> xStreamComp( xResult
, uno::UNO_QUERY_THROW
);
123 xStreamComp
->addEventListener( static_cast< lang::XEventListener
* >( this ) );
126 m_aOpenStreams
.emplace_back( xResult
);
130 bool bNewElement
= false;
131 ::rtl::Reference
< OHierarchyElement_Impl
> aElement
;
132 OHierarchyElementList_Impl::iterator aIter
= m_aChildren
.find( aNextName
);
133 if ( aIter
!= m_aChildren
.end() )
134 aElement
= aIter
->second
;
136 if ( !aElement
.is() )
139 uno::Reference
< embed::XStorage
> xChildStorage
= xOwnStor
->openStorageElement( aNextName
, nStorageMode
);
140 if ( !xChildStorage
.is() )
141 throw uno::RuntimeException();
143 aElement
= new OHierarchyElement_Impl( xChildStorage
);
146 xResult
= aElement
->GetStreamHierarchically( nStorageMode
, aListPath
, nStreamMode
, aEncryptionData
);
148 throw uno::RuntimeException();
152 m_aChildren
[aNextName
] = aElement
;
153 aElement
->SetParent( this );
157 // the subelement was opened successfully, remember the storage to let it be locked
158 m_xOwnStorage
= xOwnStor
;
163 void OHierarchyElement_Impl::RemoveStreamHierarchically( std::vector
<OUString
>& aListPath
)
165 std::unique_lock
aGuard( m_aMutex
);
167 if ( aListPath
.empty() )
168 throw uno::RuntimeException();
170 OUString aNextName
= *(aListPath
.begin());
171 aListPath
.erase( aListPath
.begin() );
173 uno::Reference
< embed::XStorage
> xOwnStor
= m_xOwnStorage
.is() ? m_xOwnStorage
174 : uno::Reference
< embed::XStorage
>( m_xWeakOwnStorage
.get(), uno::UNO_QUERY_THROW
);
176 if ( aListPath
.empty() )
178 xOwnStor
->removeElement( aNextName
);
182 ::rtl::Reference
< OHierarchyElement_Impl
> aElement
;
183 OHierarchyElementList_Impl::iterator aIter
= m_aChildren
.find( aNextName
);
184 if ( aIter
!= m_aChildren
.end() )
185 aElement
= aIter
->second
;
187 if ( !aElement
.is() )
189 uno::Reference
< embed::XStorage
> xChildStorage
= xOwnStor
->openStorageElement( aNextName
,
190 embed::ElementModes::READWRITE
);
191 if ( !xChildStorage
.is() )
192 throw uno::RuntimeException();
194 aElement
= new OHierarchyElement_Impl( xChildStorage
);
197 aElement
->RemoveStreamHierarchically( aListPath
);
200 uno::Reference
< embed::XTransactedObject
> xTransact( xOwnStor
, uno::UNO_QUERY
);
201 if ( xTransact
.is() )
207 void OHierarchyElement_Impl::Commit()
209 ::rtl::Reference
< OHierarchyElement_Impl
> xKeepAlive( this );
210 ::rtl::Reference
< OHierarchyElement_Impl
> aParent
;
211 uno::Reference
< embed::XStorage
> xOwnStor
;
214 std::unique_lock
aGuard( m_aMutex
);
216 xOwnStor
= m_xOwnStorage
;
221 uno::Reference
< embed::XTransactedObject
> xTransact( xOwnStor
, uno::UNO_QUERY_THROW
);
228 void OHierarchyElement_Impl::TestForClosing()
230 ::rtl::Reference
< OHierarchyElement_Impl
> xKeepAlive( this );
232 std::unique_lock
aGuard( m_aMutex
);
234 if ( m_aOpenStreams
.empty() && m_aChildren
.empty() )
236 if ( m_rParent
.is() )
238 // only the root storage should not be disposed, other storages can be disposed
239 if ( m_xOwnStorage
.is() )
243 m_xOwnStorage
->dispose();
245 catch( uno::Exception
& )
249 m_rParent
->RemoveElement( this );
252 m_xOwnStorage
.clear();
257 void SAL_CALL
OHierarchyElement_Impl::disposing( const lang::EventObject
& Source
)
262 std::unique_lock
aGuard(m_aMutex
);
263 uno::Reference
< embed::XExtendedStorageStream
> xStream(Source
.Source
, uno::UNO_QUERY
);
265 m_aOpenStreams
.erase(std::remove_if(m_aOpenStreams
.begin(), m_aOpenStreams
.end(),
266 [&xStream
](const OWeakStorRefVector_Impl::value_type
& rxStorage
) {
267 return !rxStorage
.get().is() || rxStorage
.get() == xStream
; }),
268 m_aOpenStreams
.end());
273 catch( uno::Exception
& ex
)
275 css::uno::Any anyEx
= cppu::getCaughtException();
276 throw lang::WrappedTargetRuntimeException( ex
.Message
,
277 nullptr, anyEx
); // no exception must happen here, usually an exception means disaster
281 void OHierarchyElement_Impl::RemoveElement( const ::rtl::Reference
< OHierarchyElement_Impl
>& aRef
)
284 std::unique_lock
aGuard( m_aMutex
);
285 OHierarchyElementList_Impl::iterator aIter
= m_aChildren
.begin();
286 while (aIter
!= m_aChildren
.end())
288 if (aIter
->second
== aRef
)
289 aIter
= m_aChildren
.erase(aIter
);
298 // XTransactionListener
299 void SAL_CALL
OHierarchyElement_Impl::preCommit( const css::lang::EventObject
& /*aEvent*/ )
303 void SAL_CALL
OHierarchyElement_Impl::commited( const css::lang::EventObject
& /*aEvent*/ )
309 catch( const uno::Exception
& )
311 css::uno::Any anyEx
= cppu::getCaughtException();
312 throw lang::WrappedTargetRuntimeException(
313 "Can not commit storage sequence!",
314 uno::Reference
< uno::XInterface
>(),
319 void SAL_CALL
OHierarchyElement_Impl::preRevert( const css::lang::EventObject
& /*aEvent*/ )
323 void SAL_CALL
OHierarchyElement_Impl::reverted( const css::lang::EventObject
& /*aEvent*/ )
327 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */