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