LibreOffice Module package (master) 1
ohierarchyholder.cxx
Go to the documentation of this file.
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>
31#include <o3tl/string_view.hxx>
32
33#include "ohierarchyholder.hxx"
34
35using namespace ::com::sun::star;
36
37// OHierarchyHolder_Impl
38
39uno::Reference< embed::XExtendedStorageStream > OHierarchyHolder_Impl::GetStreamHierarchically( sal_Int32 nStorageMode, std::vector<OUString>& aListPath, sal_Int32 nStreamMode, const ::comphelper::SequenceAsHashMap& aEncryptionData )
40{
41 uno::Reference< embed::XStorage > xOwnStor( m_xWeakOwnStorage.get(), uno::UNO_QUERY_THROW );
42
43 if ( !( nStorageMode & embed::ElementModes::WRITE ) && ( nStreamMode & embed::ElementModes::WRITE ) )
44 throw io::IOException("invalid storage/stream mode combo");
45
46 uno::Reference< embed::XExtendedStorageStream > xResult =
47 m_xChild->GetStreamHierarchically( nStorageMode, aListPath, nStreamMode, aEncryptionData );
48 if ( !xResult.is() )
49 throw uno::RuntimeException();
50
51 return xResult;
52}
53
54void OHierarchyHolder_Impl::RemoveStreamHierarchically( std::vector<OUString>& aListPath )
55{
56 uno::Reference< embed::XStorage > xOwnStor( m_xWeakOwnStorage.get(), uno::UNO_QUERY_THROW );
57
58 m_xChild->RemoveStreamHierarchically( aListPath );
59}
60
61// static
62std::vector<OUString> OHierarchyHolder_Impl::GetListPathFromString( std::u16string_view aPath )
63{
64 std::vector<OUString> aResult;
65 sal_Int32 nIndex = 0;
66 do
67 {
68 OUString aName( o3tl::getToken(aPath, 0, '/', nIndex ) );
69 if ( aName.isEmpty() )
70 throw lang::IllegalArgumentException();
71
72 aResult.push_back( aName );
73 }
74 while ( nIndex >= 0 );
75
76 return aResult;
77}
78
79// OHierarchyElement_Impl
80
81uno::Reference< embed::XExtendedStorageStream > OHierarchyElement_Impl::GetStreamHierarchically( sal_Int32 nStorageMode, std::vector<OUString>& aListPath, sal_Int32 nStreamMode, const ::comphelper::SequenceAsHashMap& aEncryptionData )
82{
83 std::unique_lock aGuard( m_aMutex );
84
85 if ( !( nStorageMode & embed::ElementModes::WRITE ) && ( nStreamMode & embed::ElementModes::WRITE ) )
86 throw io::IOException("invalid storage/stream mode combo");
87
88 if ( aListPath.empty() )
89 throw uno::RuntimeException();
90
91 OUString aNextName = *(aListPath.begin());
92 aListPath.erase( aListPath.begin() );
93
94 uno::Reference< embed::XExtendedStorageStream > xResult;
95
96 uno::Reference< embed::XStorage > xOwnStor = m_xOwnStorage.is() ? m_xOwnStorage
97 : uno::Reference< embed::XStorage >( m_xWeakOwnStorage.get(), uno::UNO_QUERY_THROW );
98
99 if ( aListPath.empty() )
100 {
101 if ( aEncryptionData.empty() )
102 {
103 uno::Reference< embed::XHierarchicalStorageAccess > xHStorage( xOwnStor, uno::UNO_QUERY_THROW );
104 xResult = xHStorage->openStreamElementByHierarchicalName( aNextName, nStreamMode );
105 }
106 else
107 {
108 uno::Reference< embed::XHierarchicalStorageAccess2 > xHStorage( xOwnStor, uno::UNO_QUERY_THROW );
109 xResult = xHStorage->openEncryptedStreamByHierarchicalName( aNextName, nStreamMode, aEncryptionData.getAsConstNamedValueList() );
110 }
111
112 uno::Reference< embed::XTransactedObject > xTransact( xResult, uno::UNO_QUERY );
113 if ( xTransact.is() )
114 {
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 ) );
119 }
120 else
121 {
122 uno::Reference< lang::XComponent > xStreamComp( xResult, uno::UNO_QUERY_THROW );
123 xStreamComp->addEventListener( static_cast< lang::XEventListener* >( this ) );
124 }
125
126 m_aOpenStreams.emplace_back( xResult );
127 }
128 else
129 {
130 bool bNewElement = false;
132 OHierarchyElementList_Impl::iterator aIter = m_aChildren.find( aNextName );
133 if ( aIter != m_aChildren.end() )
134 aElement = aIter->second;
135
136 if ( !aElement.is() )
137 {
138 bNewElement = true;
139 uno::Reference< embed::XStorage > xChildStorage = xOwnStor->openStorageElement( aNextName, nStorageMode );
140 if ( !xChildStorage.is() )
141 throw uno::RuntimeException();
142
143 aElement = new OHierarchyElement_Impl( xChildStorage );
144 }
145
146 xResult = aElement->GetStreamHierarchically( nStorageMode, aListPath, nStreamMode, aEncryptionData );
147 if ( !xResult.is() )
148 throw uno::RuntimeException();
149
150 if ( bNewElement )
151 {
152 m_aChildren[aNextName] = aElement;
153 aElement->SetParent( this );
154 }
155 }
156
157 // the subelement was opened successfully, remember the storage to let it be locked
158 m_xOwnStorage = xOwnStor;
159
160 return xResult;
161}
162
163void OHierarchyElement_Impl::RemoveStreamHierarchically( std::vector<OUString>& aListPath )
164{
165 std::unique_lock aGuard( m_aMutex );
166
167 if ( aListPath.empty() )
168 throw uno::RuntimeException();
169
170 OUString aNextName = *(aListPath.begin());
171 aListPath.erase( aListPath.begin() );
172
173 uno::Reference< embed::XStorage > xOwnStor = m_xOwnStorage.is() ? m_xOwnStorage
174 : uno::Reference< embed::XStorage >( m_xWeakOwnStorage.get(), uno::UNO_QUERY_THROW );
175
176 if ( aListPath.empty() )
177 {
178 xOwnStor->removeElement( aNextName );
179 }
180 else
181 {
183 OHierarchyElementList_Impl::iterator aIter = m_aChildren.find( aNextName );
184 if ( aIter != m_aChildren.end() )
185 aElement = aIter->second;
186
187 if ( !aElement.is() )
188 {
189 uno::Reference< embed::XStorage > xChildStorage = xOwnStor->openStorageElement( aNextName,
190 embed::ElementModes::READWRITE );
191 if ( !xChildStorage.is() )
192 throw uno::RuntimeException();
193
194 aElement = new OHierarchyElement_Impl( xChildStorage );
195 }
196
197 aElement->RemoveStreamHierarchically( aListPath );
198 }
199
200 uno::Reference< embed::XTransactedObject > xTransact( xOwnStor, uno::UNO_QUERY );
201 if ( xTransact.is() )
202 xTransact->commit();
203
205}
206
208{
211 uno::Reference< embed::XStorage > xOwnStor;
212
213 {
214 std::unique_lock aGuard( m_aMutex );
215 aParent = m_rParent;
216 xOwnStor = m_xOwnStorage;
217 }
218
219 if ( xOwnStor.is() )
220 {
221 uno::Reference< embed::XTransactedObject > xTransact( xOwnStor, uno::UNO_QUERY_THROW );
222 xTransact->commit();
223 if ( aParent.is() )
224 aParent->Commit();
225 }
226}
227
229{
231 {
232 std::unique_lock aGuard( m_aMutex );
233
234 if ( m_aOpenStreams.empty() && m_aChildren.empty() )
235 {
236 if ( m_rParent.is() )
237 {
238 // only the root storage should not be disposed, other storages can be disposed
239 if ( m_xOwnStorage.is() )
240 {
241 try
242 {
243 m_xOwnStorage->dispose();
244 }
245 catch( uno::Exception& )
246 {}
247 }
248
249 m_rParent->RemoveElement( this );
250 }
251
252 m_xOwnStorage.clear();
253 }
254 }
255}
256
257void SAL_CALL OHierarchyElement_Impl::disposing( const lang::EventObject& Source )
258{
259 try
260 {
261 {
262 std::unique_lock aGuard(m_aMutex);
263 uno::Reference< embed::XExtendedStorageStream > xStream(Source.Source, uno::UNO_QUERY);
264
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());
269 }
270
272 }
273 catch( uno::Exception& ex )
274 {
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
278 }
279}
280
281void OHierarchyElement_Impl::RemoveElement( const ::rtl::Reference< OHierarchyElement_Impl >& aRef )
282{
283 {
284 std::unique_lock aGuard( m_aMutex );
285 OHierarchyElementList_Impl::iterator aIter = m_aChildren.begin();
286 while (aIter != m_aChildren.end())
287 {
288 if (aIter->second == aRef )
289 aIter = m_aChildren.erase(aIter);
290 else
291 ++aIter;
292 }
293 }
294
296}
297
298// XTransactionListener
299void SAL_CALL OHierarchyElement_Impl::preCommit( const css::lang::EventObject& /*aEvent*/ )
300{
301}
302
303void SAL_CALL OHierarchyElement_Impl::commited( const css::lang::EventObject& /*aEvent*/ )
304{
305 try
306 {
307 Commit();
308 }
309 catch( const uno::Exception& )
310 {
311 css::uno::Any anyEx = cppu::getCaughtException();
312 throw lang::WrappedTargetRuntimeException(
313 "Can not commit storage sequence!",
314 uno::Reference< uno::XInterface >(),
315 anyEx );
316 }
317}
318
319void SAL_CALL OHierarchyElement_Impl::preRevert( const css::lang::EventObject& /*aEvent*/ )
320{
321}
322
323void SAL_CALL OHierarchyElement_Impl::reverted( const css::lang::EventObject& /*aEvent*/ )
324{
325}
326
327/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
Reference< XInputStream > xStream
OHierarchyElement_Impl(css::uno::Reference< css::embed::XStorage > xStorage)
virtual void SAL_CALL preCommit(const css::lang::EventObject &aEvent) override
OWeakStorRefVector_Impl m_aOpenStreams
css::uno::WeakReference< css::embed::XStorage > m_xWeakOwnStorage
virtual void SAL_CALL disposing(const css::lang::EventObject &Source) override
::rtl::Reference< OHierarchyElement_Impl > m_rParent
OHierarchyElementList_Impl m_aChildren
css::uno::Reference< css::embed::XStorage > m_xOwnStorage
css::uno::Reference< css::embed::XExtendedStorageStream > GetStreamHierarchically(sal_Int32 nStorageMode, std::vector< OUString > &aPath, sal_Int32 nStreamMode, const ::comphelper::SequenceAsHashMap &aEncryptionData)
virtual void SAL_CALL preRevert(const css::lang::EventObject &aEvent) override
virtual void SAL_CALL reverted(const css::lang::EventObject &aEvent) override
virtual void SAL_CALL commited(const css::lang::EventObject &aEvent) override
void RemoveElement(const ::rtl::Reference< OHierarchyElement_Impl > &aRef)
void RemoveStreamHierarchically(std::vector< OUString > &aListPath)
css::uno::WeakReference< css::embed::XStorage > m_xWeakOwnStorage
css::uno::Reference< css::embed::XExtendedStorageStream > GetStreamHierarchically(sal_Int32 nStorageMode, std::vector< OUString > &aListPath, sal_Int32 nStreamMode, const ::comphelper::SequenceAsHashMap &aEncryptionData=::comphelper::SequenceAsHashMap())
void RemoveStreamHierarchically(std::vector< OUString > &aListPath)
static std::vector< OUString > GetListPathFromString(std::u16string_view aPath)
::rtl::Reference< OHierarchyElement_Impl > m_xChild
sal_Int32 nIndex
OUString aName
Any SAL_CALL getCaughtException()
std::basic_string_view< charT, traits > getToken(std::basic_string_view< charT, traits > sv, charT delimiter, std::size_t &position)