1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_package.hxx"
26 #include <com/sun/star/uno/Reference.hxx>
27 #include <com/sun/star/embed/ElementModes.hpp>
28 #include <com/sun/star/embed/XHierarchicalStorageAccess2.hpp>
29 #include <com/sun/star/lang/WrappedTargetRuntimeException.hpp>
30 
31 #include "ohierarchyholder.hxx"
32 
33 using namespace ::com::sun::star;
34 
35 //===============================================
36 // OHierarchyHolder_Impl
37 //===============================================
38 
39 //-----------------------------------------------
GetStreamHierarchically(sal_Int32 nStorageMode,OStringList_Impl & aListPath,sal_Int32 nStreamMode,const::comphelper::SequenceAsHashMap & aEncryptionData)40 uno::Reference< embed::XExtendedStorageStream > OHierarchyHolder_Impl::GetStreamHierarchically( sal_Int32 nStorageMode, OStringList_Impl& aListPath, sal_Int32 nStreamMode, const ::comphelper::SequenceAsHashMap& aEncryptionData )
41 {
42 	uno::Reference< embed::XStorage > xOwnStor( m_xWeakOwnStorage.get(), uno::UNO_QUERY_THROW );
43 
44 	if ( !( nStorageMode & embed::ElementModes::WRITE ) && ( nStreamMode & embed::ElementModes::WRITE ) )
45 		throw io::IOException();
46 
47 	uno::Reference< embed::XExtendedStorageStream > xResult =
48 		m_xChild->GetStreamHierarchically( nStorageMode, aListPath, nStreamMode, aEncryptionData );
49 	if ( !xResult.is() )
50 		throw uno::RuntimeException();
51 
52 	return xResult;
53 }
54 
55 //-----------------------------------------------
RemoveStreamHierarchically(OStringList_Impl & aListPath)56 void OHierarchyHolder_Impl::RemoveStreamHierarchically( OStringList_Impl& aListPath )
57 {
58 	uno::Reference< embed::XStorage > xOwnStor( m_xWeakOwnStorage.get(), uno::UNO_QUERY_THROW );
59 
60 	m_xChild->RemoveStreamHierarchically( aListPath );
61 }
62 
63 //-----------------------------------------------
64 // static
GetListPathFromString(const::rtl::OUString & aPath)65 OStringList_Impl OHierarchyHolder_Impl::GetListPathFromString( const ::rtl::OUString& aPath )
66 {
67 	OStringList_Impl aResult;
68 	sal_Int32 nIndex = 0;
69 	do
70 	{
71 		::rtl::OUString aName = aPath.getToken( 0, '/', nIndex );
72 		if ( !aName.getLength() )
73 			throw lang::IllegalArgumentException();
74 
75 		aResult.push_back( aName );
76 	}
77 	while ( nIndex >= 0 );
78 
79 	return aResult;
80 }
81 
82 //===============================================
83 // OHierarchyElement_Impl
84 //===============================================
85 
86 //-----------------------------------------------
GetStreamHierarchically(sal_Int32 nStorageMode,OStringList_Impl & aListPath,sal_Int32 nStreamMode,const::comphelper::SequenceAsHashMap & aEncryptionData)87 uno::Reference< embed::XExtendedStorageStream > OHierarchyElement_Impl::GetStreamHierarchically( sal_Int32 nStorageMode, OStringList_Impl& aListPath, sal_Int32 nStreamMode, const ::comphelper::SequenceAsHashMap& aEncryptionData )
88 {
89 	::osl::MutexGuard aGuard( m_aMutex );
90 
91 	if ( !( nStorageMode & embed::ElementModes::WRITE ) && ( nStreamMode & embed::ElementModes::WRITE ) )
92 		throw io::IOException();
93 
94 	if ( !aListPath.size() )
95 		throw uno::RuntimeException();
96 
97 	::rtl::OUString aNextName = *(aListPath.begin());
98 	aListPath.erase( aListPath.begin() );
99 
100 	uno::Reference< embed::XExtendedStorageStream > xResult;
101 
102 	uno::Reference< embed::XStorage > xOwnStor = m_xOwnStorage.is() ? m_xOwnStorage
103 				: uno::Reference< embed::XStorage >( m_xWeakOwnStorage.get(), uno::UNO_QUERY );
104 	if ( !xOwnStor.is() )
105 		throw uno::RuntimeException();
106 
107 	if ( !aListPath.size() )
108 	{
109 		if ( !aEncryptionData.size() )
110         {
111             uno::Reference< embed::XHierarchicalStorageAccess > xHStorage( xOwnStor, uno::UNO_QUERY_THROW );
112 			xResult = xHStorage->openStreamElementByHierarchicalName( aNextName, nStreamMode );
113         }
114 		else
115         {
116             uno::Reference< embed::XHierarchicalStorageAccess2 > xHStorage( xOwnStor, uno::UNO_QUERY_THROW );
117 			xResult = xHStorage->openEncryptedStreamByHierarchicalName( aNextName, nStreamMode, aEncryptionData.getAsConstNamedValueList() );
118         }
119 
120 		uno::Reference< embed::XTransactedObject > xTransact( xResult, uno::UNO_QUERY );
121 		if ( xTransact.is() )
122 		{
123 			// the existence of the transacted object means that the stream is opened for writing also
124 			// so the whole chain must be committed
125 			uno::Reference< embed::XTransactionBroadcaster > xTrBroadcast( xTransact, uno::UNO_QUERY_THROW );
126 			xTrBroadcast->addTransactionListener( static_cast< embed::XTransactionListener* >( this ) );
127 		}
128 		else
129 		{
130 			uno::Reference< lang::XComponent > xStreamComp( xResult, uno::UNO_QUERY_THROW );
131 			xStreamComp->addEventListener( static_cast< lang::XEventListener* >( this ) );
132 		}
133 
134 		m_aOpenStreams.push_back( uno::WeakReference< embed::XExtendedStorageStream >( xResult ) );
135 	}
136 	else
137 	{
138 		sal_Bool bNewElement = sal_False;
139 		::rtl::Reference< OHierarchyElement_Impl > aElement;
140 		OHierarchyElementList_Impl::iterator aIter = m_aChildren.find( aNextName );
141 		if ( aIter != m_aChildren.end() )
142 			aElement = aIter->second;
143 
144 		if ( !aElement.is() )
145 		{
146 			bNewElement = sal_True;
147 			uno::Reference< embed::XStorage > xChildStorage = xOwnStor->openStorageElement( aNextName, nStorageMode );
148 			if ( !xChildStorage.is() )
149 				throw uno::RuntimeException();
150 
151 			aElement = new OHierarchyElement_Impl( NULL, xChildStorage );
152 		}
153 
154 		xResult = aElement->GetStreamHierarchically( nStorageMode, aListPath, nStreamMode, aEncryptionData );
155 		if ( !xResult.is() )
156 			throw uno::RuntimeException();
157 
158 		if ( bNewElement )
159 		{
160 			m_aChildren[aNextName] = aElement;
161 			aElement->SetParent( this );
162 		}
163 	}
164 
165 	// the subelement was opened successfully, remember the storage to let it be locked
166 	m_xOwnStorage = xOwnStor;
167 
168 	return xResult;
169 }
170 
171 //-----------------------------------------------
RemoveStreamHierarchically(OStringList_Impl & aListPath)172 void OHierarchyElement_Impl::RemoveStreamHierarchically( OStringList_Impl& aListPath )
173 {
174 	::osl::MutexGuard aGuard( m_aMutex );
175 
176 	if ( !aListPath.size() )
177 		throw uno::RuntimeException();
178 
179 	::rtl::OUString aNextName = *(aListPath.begin());
180 	aListPath.erase( aListPath.begin() );
181 
182 	uno::Reference< embed::XExtendedStorageStream > xResult;
183 
184 	uno::Reference< embed::XStorage > xOwnStor = m_xOwnStorage.is() ? m_xOwnStorage
185 				: uno::Reference< embed::XStorage >( m_xWeakOwnStorage.get(), uno::UNO_QUERY );
186 	if ( !xOwnStor.is() )
187 		throw uno::RuntimeException();
188 
189 	if ( !aListPath.size() )
190 	{
191 		xOwnStor->removeElement( aNextName );
192 	}
193 	else
194 	{
195 		sal_Bool bNewElement = sal_False;
196 		::rtl::Reference< OHierarchyElement_Impl > aElement;
197 		OHierarchyElementList_Impl::iterator aIter = m_aChildren.find( aNextName );
198 		if ( aIter != m_aChildren.end() )
199 			aElement = aIter->second;
200 
201 		if ( !aElement.is() )
202 		{
203 			bNewElement = sal_True;
204 			uno::Reference< embed::XStorage > xChildStorage = xOwnStor->openStorageElement( aNextName,
205 																							embed::ElementModes::READWRITE );
206 			if ( !xChildStorage.is() )
207 				throw uno::RuntimeException();
208 
209 			aElement = new OHierarchyElement_Impl( NULL, xChildStorage );
210 		}
211 
212 		aElement->RemoveStreamHierarchically( aListPath );
213 	}
214 
215 	uno::Reference< embed::XTransactedObject > xTransact( xOwnStor, uno::UNO_QUERY );
216 	if ( xTransact.is() )
217 		xTransact->commit();
218 
219 	TestForClosing();
220 }
221 
222 //-----------------------------------------------
Commit()223 void OHierarchyElement_Impl::Commit()
224 {
225 	::rtl::Reference< OHierarchyElement_Impl > aLocker( this );
226 	::rtl::Reference< OHierarchyElement_Impl > aParent;
227 	uno::Reference< embed::XStorage > xOwnStor;
228 
229 	{
230 		::osl::MutexGuard aGuard( m_aMutex );
231 		aParent = m_rParent;
232 		xOwnStor = m_xOwnStorage;
233 	}
234 
235 	if ( xOwnStor.is() )
236 	{
237 		uno::Reference< embed::XTransactedObject > xTransact( xOwnStor, uno::UNO_QUERY_THROW );
238 		xTransact->commit();
239 		if ( aParent.is() )
240 			aParent->Commit();
241 	}
242 }
243 
244 //-----------------------------------------------
TestForClosing()245 void OHierarchyElement_Impl::TestForClosing()
246 {
247 	::rtl::Reference< OHierarchyElement_Impl > aLocker( this );
248 	{
249 		::osl::MutexGuard aGuard( m_aMutex );
250 
251 		if ( !m_aOpenStreams.size() && !m_aChildren.size() )
252 		{
253 			if ( m_rParent.is() )
254 			{
255 				// only the root storage should not be disposed, other storages can be disposed
256 				if ( m_xOwnStorage.is() )
257 				{
258 					try
259 					{
260 						m_xOwnStorage->dispose();
261 					}
262 					catch( uno::Exception& )
263 					{}
264 				}
265 
266 				m_rParent->RemoveElement( this );
267 			}
268 
269 			m_xOwnStorage = uno::Reference< embed::XStorage >();
270 		}
271 	}
272 }
273 
274 //-----------------------------------------------
disposing(const lang::EventObject & Source)275 void SAL_CALL OHierarchyElement_Impl::disposing( const lang::EventObject& Source )
276 		throw ( uno::RuntimeException )
277 {
278 	uno::Sequence< embed::XStorage > aStoragesToCommit;
279 
280 	try
281 	{
282 		::osl::ClearableMutexGuard aGuard( m_aMutex );
283 		uno::Reference< embed::XExtendedStorageStream > xStream( Source.Source, uno::UNO_QUERY );
284 
285 		for ( OWeakStorRefList_Impl::iterator pStorageIter = m_aOpenStreams.begin();
286 			  pStorageIter != m_aOpenStreams.end(); )
287 		{
288 			OWeakStorRefList_Impl::iterator pTmp = pStorageIter++;
289 			if ( !pTmp->get().is() || pTmp->get() == xStream )
290 				m_aOpenStreams.erase( pTmp );
291 		}
292 
293 		aGuard.clear();
294 
295 		TestForClosing();
296 	}
297 	catch( uno::Exception& )
298 	{
299 		throw uno::RuntimeException(); // no exception must happen here, usually an exception means disaster
300 	}
301 }
302 
303 //-----------------------------------------------
RemoveElement(const::rtl::Reference<OHierarchyElement_Impl> & aRef)304 void OHierarchyElement_Impl::RemoveElement( const ::rtl::Reference< OHierarchyElement_Impl >& aRef )
305 {
306 	{
307 		::osl::MutexGuard aGuard( m_aMutex );
308 		for ( OHierarchyElementList_Impl::iterator aIter = m_aChildren.begin();
309 			  aIter != m_aChildren.end(); /* increment is done in body */)
310 		{
311 			OHierarchyElementList_Impl::iterator aTmpIter = aIter;
312 			aIter++;
313 
314 			if ( aTmpIter->second == aRef )
315 				m_aChildren.erase( aTmpIter );
316 		}
317 	}
318 
319 	TestForClosing();
320 }
321 
322 // XTransactionListener
323 //-----------------------------------------------
preCommit(const::com::sun::star::lang::EventObject &)324 void SAL_CALL OHierarchyElement_Impl::preCommit( const ::com::sun::star::lang::EventObject& /*aEvent*/ )
325 	throw (::com::sun::star::uno::Exception, ::com::sun::star::uno::RuntimeException)
326 {
327 }
328 
329 //-----------------------------------------------
commited(const::com::sun::star::lang::EventObject &)330 void SAL_CALL OHierarchyElement_Impl::commited( const ::com::sun::star::lang::EventObject& /*aEvent*/ )
331 	throw (::com::sun::star::uno::RuntimeException)
332 {
333 	try
334 	{
335 		Commit();
336 	}
337 	catch( uno::Exception& e )
338 	{
339 		throw lang::WrappedTargetRuntimeException(
340 							::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Can not commit storage sequence!" ) ),
341 							uno::Reference< uno::XInterface >(),
342 							uno::makeAny( e ) );
343 	}
344 }
345 
346 //-----------------------------------------------
preRevert(const::com::sun::star::lang::EventObject &)347 void SAL_CALL OHierarchyElement_Impl::preRevert( const ::com::sun::star::lang::EventObject& /*aEvent*/ )
348 	throw (::com::sun::star::uno::Exception, ::com::sun::star::uno::RuntimeException)
349 {
350 }
351 
352 //-----------------------------------------------
reverted(const::com::sun::star::lang::EventObject &)353 void SAL_CALL OHierarchyElement_Impl::reverted( const ::com::sun::star::lang::EventObject& /*aEvent*/ )
354 	throw (::com::sun::star::uno::RuntimeException)
355 {
356 }
357 
358