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_ucbhelper.hxx"
26 
27 /**************************************************************************
28 								TODO
29  **************************************************************************
30 
31  *************************************************************************/
32 
33 #include <hash_map>
34 #include <com/sun/star/beans/XPropertyAccess.hpp>
35 #include <com/sun/star/container/XNameAccess.hpp>
36 #include <com/sun/star/container/XNamed.hpp>
37 #include <com/sun/star/ucb/XPropertySetRegistryFactory.hpp>
38 #include <com/sun/star/ucb/XPropertySetRegistry.hpp>
39 
40 #include "osl/diagnose.h"
41 #include "osl/mutex.hxx"
42 #include "cppuhelper/weakref.hxx"
43 #include <ucbhelper/contentidentifier.hxx>
44 #include <ucbhelper/providerhelper.hxx>
45 #include <ucbhelper/contenthelper.hxx>
46 
47 using namespace com::sun::star;
48 
49 namespace ucbhelper_impl
50 {
51 
52 //=========================================================================
53 //
54 // Contents.
55 //
56 //=========================================================================
57 
58 struct equalString
59 {
operator ()ucbhelper_impl::equalString60 	bool operator()(
61         const rtl::OUString& rKey11, const rtl::OUString& rKey22 ) const
62   	{
63   		return !!( rKey11 == rKey22 );
64   	}
65 };
66 
67 struct hashString
68 {
operator ()ucbhelper_impl::hashString69 	size_t operator()( const rtl::OUString & rName ) const
70 	{
71 		return rName.hashCode();
72 	}
73 };
74 
75 typedef std::hash_map
76 <
77 	rtl::OUString,
78     uno::WeakReference< ucb::XContent >,
79 	hashString,
80 	equalString
81 >
82 Contents;
83 
84 //=========================================================================
85 //
86 // struct ContentProviderImplHelper_Impl.
87 //
88 //=========================================================================
89 
90 struct ContentProviderImplHelper_Impl
91 {
92 	uno::Reference< com::sun::star::ucb::XPropertySetRegistry >
93         m_xPropertySetRegistry;
94 	Contents
95         m_aContents;
96 };
97 
98 } // namespace ucbhelper_impl
99 
100 //=========================================================================
101 //=========================================================================
102 //
103 // ContentProviderImplHelper Implementation.
104 //
105 //=========================================================================
106 //=========================================================================
107 
108 namespace ucbhelper {
109 
ContentProviderImplHelper(const uno::Reference<lang::XMultiServiceFactory> & rXSMgr)110 ContentProviderImplHelper::ContentProviderImplHelper(
111     const uno::Reference< lang::XMultiServiceFactory >& rXSMgr )
112 : m_pImpl( new ucbhelper_impl::ContentProviderImplHelper_Impl ),
113   m_xSMgr( rXSMgr )
114 {
115 }
116 
117 //=========================================================================
118 // virtual
~ContentProviderImplHelper()119 ContentProviderImplHelper::~ContentProviderImplHelper()
120 {
121 	delete m_pImpl;
122 }
123 
124 //=========================================================================
125 //
126 // XInterface methods.
127 //
128 //=========================================================================
129 
130 XINTERFACE_IMPL_3( ContentProviderImplHelper,
131 				   lang::XTypeProvider,
132 				   lang::XServiceInfo,
133 				   com::sun::star::ucb::XContentProvider );
134 
135 //=========================================================================
136 //
137 // XTypeProvider methods.
138 //
139 //=========================================================================
140 
141 XTYPEPROVIDER_IMPL_3( ContentProviderImplHelper,
142 				   	  lang::XTypeProvider,
143 				   	  lang::XServiceInfo,
144 				   	  com::sun::star::ucb::XContentProvider );
145 
146 //=========================================================================
147 //
148 // XServiceInfo methods.
149 //
150 //=========================================================================
151 
152 // virtual
supportsService(const rtl::OUString & ServiceName)153 sal_Bool SAL_CALL ContentProviderImplHelper::supportsService(
154 											const rtl::OUString& ServiceName )
155 	throw( uno::RuntimeException )
156 {
157 	uno::Sequence< rtl::OUString > aSNL = getSupportedServiceNames();
158 	const rtl::OUString* pArray = aSNL.getConstArray();
159 	for ( sal_Int32 i = 0; i < aSNL.getLength(); i++ )
160 	{
161 		if ( pArray[ i ] == ServiceName )
162 			return sal_True;
163 	}
164 
165 	return sal_False;
166 }
167 
168 //=========================================================================
169 //
170 // XContentProvider methods.
171 //
172 //=========================================================================
173 
174 // virtual
compareContentIds(const uno::Reference<com::sun::star::ucb::XContentIdentifier> & Id1,const uno::Reference<com::sun::star::ucb::XContentIdentifier> & Id2)175 sal_Int32 SAL_CALL ContentProviderImplHelper::compareContentIds(
176         const uno::Reference< com::sun::star::ucb::XContentIdentifier >& Id1,
177         const uno::Reference< com::sun::star::ucb::XContentIdentifier >& Id2 )
178 	throw( uno::RuntimeException )
179 {
180 	// Simply do a string compare.
181 
182 	rtl::OUString aURL1( Id1->getContentIdentifier() );
183 	rtl::OUString aURL2( Id2->getContentIdentifier() );
184 
185 	return aURL1.compareTo( aURL2 );;
186 }
187 
188 //=========================================================================
189 //
190 // Non-interface methods
191 //
192 //=========================================================================
193 
cleanupRegisteredContents()194 void ContentProviderImplHelper::cleanupRegisteredContents()
195 {
196 	osl::MutexGuard aGuard( m_aMutex );
197 
198     ucbhelper_impl::Contents::iterator it
199         = m_pImpl->m_aContents.begin();
200     while( it != m_pImpl->m_aContents.end() )
201     {
202         uno::Reference< ucb::XContent > xContent( (*it).second );
203         if ( !xContent.is() )
204         {
205             ucbhelper_impl::Contents::iterator tmp = it;
206             ++it;
207             m_pImpl->m_aContents.erase( tmp );
208         }
209         else
210         {
211             ++it;
212         }
213     }
214 }
215 
216 //=========================================================================
217 
removeContent(ContentImplHelper * pContent)218 void ContentProviderImplHelper::removeContent( ContentImplHelper* pContent )
219 {
220 	osl::MutexGuard aGuard( m_aMutex );
221 
222     cleanupRegisteredContents();
223 
224 	const rtl::OUString aURL(
225         pContent->getIdentifier()->getContentIdentifier() );
226 
227 	ucbhelper_impl::Contents::iterator it = m_pImpl->m_aContents.find( aURL );
228 
229 	if ( it != m_pImpl->m_aContents.end() )
230 		m_pImpl->m_aContents.erase( it );
231 }
232 
233 //=========================================================================
234 rtl::Reference< ContentImplHelper >
queryExistingContent(const uno::Reference<com::sun::star::ucb::XContentIdentifier> & Identifier)235 ContentProviderImplHelper::queryExistingContent(
236     const uno::Reference< com::sun::star::ucb::XContentIdentifier >&
237         Identifier )
238 {
239 	return queryExistingContent( Identifier->getContentIdentifier() );
240 }
241 
242 //=========================================================================
243 rtl::Reference< ContentImplHelper >
queryExistingContent(const rtl::OUString & rURL)244 ContentProviderImplHelper::queryExistingContent( const rtl::OUString& rURL )
245 {
246 	osl::MutexGuard aGuard( m_aMutex );
247 
248     cleanupRegisteredContents();
249 
250 	// Check, if a content with given id already exists...
251 
252 	ucbhelper_impl::Contents::const_iterator it
253         = m_pImpl->m_aContents.find( rURL );
254 	if ( it != m_pImpl->m_aContents.end() )
255 	{
256         uno::Reference< ucb::XContent > xContent( (*it).second );
257         if ( xContent.is() )
258         {
259             return rtl::Reference< ContentImplHelper >(
260                 static_cast< ContentImplHelper * >( xContent.get() ) );
261         }
262 	}
263 	return rtl::Reference< ContentImplHelper >();
264 }
265 
266 //=========================================================================
queryExistingContents(ContentRefList & rContents)267 void ContentProviderImplHelper::queryExistingContents(
268 		ContentRefList& rContents )
269 {
270 	osl::MutexGuard aGuard( m_aMutex );
271 
272     cleanupRegisteredContents();
273 
274 	ucbhelper_impl::Contents::const_iterator it
275         = m_pImpl->m_aContents.begin();
276 	ucbhelper_impl::Contents::const_iterator end
277         = m_pImpl->m_aContents.end();
278 
279 	while ( it != end )
280 	{
281         uno::Reference< ucb::XContent > xContent( (*it).second );
282         if ( xContent.is() )
283         {
284             rContents.push_back(
285                 rtl::Reference< ContentImplHelper >(
286                     static_cast< ContentImplHelper * >( xContent.get() ) ) );
287         }
288 		++it;
289 	}
290 }
291 
292 //=========================================================================
registerNewContent(const uno::Reference<ucb::XContent> & xContent)293 void ContentProviderImplHelper::registerNewContent(
294     const uno::Reference< ucb::XContent > & xContent )
295 {
296     if ( xContent.is() )
297     {
298         osl::MutexGuard aGuard( m_aMutex );
299 
300         cleanupRegisteredContents();
301 
302         const rtl::OUString aURL(
303             xContent->getIdentifier()->getContentIdentifier() );
304         ucbhelper_impl::Contents::const_iterator it
305             = m_pImpl->m_aContents.find( aURL );
306         if ( it == m_pImpl->m_aContents.end() )
307             m_pImpl->m_aContents[ aURL ] = xContent;
308     }
309 }
310 
311 //=========================================================================
312 uno::Reference< com::sun::star::ucb::XPropertySetRegistry >
getAdditionalPropertySetRegistry()313 ContentProviderImplHelper::getAdditionalPropertySetRegistry()
314 {
315 	// Get propertyset registry.
316 
317 	osl::MutexGuard aGuard( m_aMutex );
318 
319 	if ( !m_pImpl->m_xPropertySetRegistry.is() )
320 	{
321 		uno::Reference< com::sun::star::ucb::XPropertySetRegistryFactory >
322             xRegFac(
323 				m_xSMgr->createInstance(
324 					rtl::OUString::createFromAscii(
325                         "com.sun.star.ucb.Store" ) ),
326 				uno::UNO_QUERY );
327 
328         OSL_ENSURE( xRegFac.is(),
329 					"ContentProviderImplHelper::getAdditionalPropertySet - "
330 					"No UCB-Store service!" );
331 
332 		if ( xRegFac.is() )
333 		{
334 			// Open/create a registry.
335 			m_pImpl->m_xPropertySetRegistry
336                 = xRegFac->createPropertySetRegistry( rtl::OUString() );
337 
338             OSL_ENSURE( m_pImpl->m_xPropertySetRegistry.is(),
339 					"ContentProviderImplHelper::getAdditionalPropertySet - "
340 					"Error opening registry!" );
341 		}
342 	}
343 
344 	return m_pImpl->m_xPropertySetRegistry;
345 }
346 
347 
348 //=========================================================================
349 uno::Reference< com::sun::star::ucb::XPersistentPropertySet >
getAdditionalPropertySet(const rtl::OUString & rKey,sal_Bool bCreate)350 ContentProviderImplHelper::getAdditionalPropertySet(
351     const rtl::OUString& rKey, sal_Bool bCreate )
352 {
353 	// Get propertyset registry.
354 	getAdditionalPropertySetRegistry();
355 
356 	if ( m_pImpl->m_xPropertySetRegistry.is() )
357 	{
358 		// Open/create persistent property set.
359 	    return uno::Reference< com::sun::star::ucb::XPersistentPropertySet >(
360             m_pImpl->m_xPropertySetRegistry->openPropertySet(
361                 rKey, bCreate ) );
362 	}
363 
364 	return uno::Reference< com::sun::star::ucb::XPersistentPropertySet >();
365 }
366 
367 //=========================================================================
renameAdditionalPropertySet(const rtl::OUString & rOldKey,const rtl::OUString & rNewKey,sal_Bool bRecursive)368 sal_Bool ContentProviderImplHelper::renameAdditionalPropertySet(
369     const rtl::OUString& rOldKey,
370     const rtl::OUString& rNewKey,
371     sal_Bool bRecursive )
372 {
373 	if ( rOldKey == rNewKey )
374 		return sal_True;
375 
376 	osl::MutexGuard aGuard( m_aMutex );
377 
378 	if ( bRecursive )
379 	{
380 		// Get propertyset registry.
381 		getAdditionalPropertySetRegistry();
382 
383 		if ( m_pImpl->m_xPropertySetRegistry.is() )
384 		{
385 			uno::Reference< container::XNameAccess > xNameAccess(
386                 m_pImpl->m_xPropertySetRegistry, uno::UNO_QUERY );
387 			if ( xNameAccess.is() )
388 			{
389 				uno::Sequence< rtl::OUString > aKeys
390                     = xNameAccess->getElementNames();
391 				sal_Int32 nCount = aKeys.getLength();
392 				if ( nCount > 0 )
393 				{
394 					rtl::OUString aOldKeyWithSlash = rOldKey;
395 					rtl::OUString aOldKeyWithoutSlash;
396 					if ( aOldKeyWithSlash.lastIndexOf(
397                              sal_Unicode('/')
398                                  != aOldKeyWithSlash.getLength() - 1 ) )
399 					{
400 						aOldKeyWithSlash += rtl::OUString( sal_Unicode('/') );
401 						aOldKeyWithoutSlash = rOldKey;
402 					}
403 					else if ( rOldKey.getLength() )
404 						aOldKeyWithoutSlash
405                             = rOldKey.copy( 0, rOldKey.getLength() - 1 );
406 
407 					const rtl::OUString* pKeys = aKeys.getConstArray();
408 					for ( sal_Int32 n = 0; n < nCount; ++n )
409 					{
410 						const rtl::OUString& rKey = pKeys[ n ];
411 						if ( rKey.compareTo(
412                                  aOldKeyWithSlash,
413                                  aOldKeyWithSlash.getLength() ) == 0
414                              || rKey.equals( aOldKeyWithoutSlash ) )
415 						{
416 							rtl::OUString aNewKey
417 								= rKey.replaceAt(
418 									0, rOldKey.getLength(), rNewKey );
419 							if ( !renameAdditionalPropertySet(
420 									rKey, aNewKey, sal_False ) )
421 								return sal_False;
422 						}
423 					}
424 				}
425 			}
426 			else
427 				return sal_False;
428 		}
429 		else
430 			return sal_False;
431 	}
432 	else
433 	{
434 		// Get old property set, if exists.
435 		uno::Reference< com::sun::star::ucb::XPersistentPropertySet > xOldSet
436             = getAdditionalPropertySet( rOldKey, sal_False );
437 		if ( xOldSet.is() )
438 		{
439 			// Rename property set.
440 			uno::Reference< container::XNamed > xNamed(
441                 xOldSet, uno::UNO_QUERY );
442 			if ( xNamed.is() )
443 			{
444 				// ??? throws no exceptions and has no return value ???
445 				xNamed->setName( rNewKey );
446 			}
447 			else
448 				return sal_False;
449 		}
450 	}
451 	return sal_True;
452 }
453 
454 //=========================================================================
copyAdditionalPropertySet(const rtl::OUString & rSourceKey,const rtl::OUString & rTargetKey,sal_Bool bRecursive)455 sal_Bool ContentProviderImplHelper::copyAdditionalPropertySet(
456     const rtl::OUString& rSourceKey,
457     const rtl::OUString& rTargetKey,
458     sal_Bool bRecursive )
459 {
460 	if ( rSourceKey == rTargetKey )
461 		return sal_True;
462 
463 	osl::MutexGuard aGuard( m_aMutex );
464 
465 	if ( bRecursive )
466 	{
467 		// Get propertyset registry.
468 		getAdditionalPropertySetRegistry();
469 
470 		if ( m_pImpl->m_xPropertySetRegistry.is() )
471 		{
472 			uno::Reference< container::XNameAccess > xNameAccess(
473                 m_pImpl->m_xPropertySetRegistry, uno::UNO_QUERY );
474 			if ( xNameAccess.is() )
475 			{
476 				uno::Sequence< rtl::OUString > aKeys
477                     = xNameAccess->getElementNames();
478 				sal_Int32 nCount = aKeys.getLength();
479 				if ( nCount > 0 )
480 				{
481 					rtl::OUString aSrcKeyWithSlash = rSourceKey;
482 					rtl::OUString aSrcKeyWithoutSlash;
483 					if ( aSrcKeyWithSlash.lastIndexOf(
484                              sal_Unicode('/')
485                              != aSrcKeyWithSlash.getLength() - 1 ) )
486 					{
487 						aSrcKeyWithSlash += rtl::OUString( sal_Unicode('/') );
488 						aSrcKeyWithoutSlash = rSourceKey;
489 					}
490 					else if ( rSourceKey.getLength() )
491 						aSrcKeyWithoutSlash = rSourceKey.copy(
492                             0, rSourceKey.getLength() - 1 );
493 
494 					const rtl::OUString* pKeys = aKeys.getConstArray();
495 					for ( sal_Int32 n = 0; n < nCount; ++n )
496 					{
497 						const rtl::OUString& rKey = pKeys[ n ];
498 						if ( rKey.compareTo(
499                                  aSrcKeyWithSlash,
500                                  aSrcKeyWithSlash.getLength() ) == 0
501                              || rKey.equals( aSrcKeyWithoutSlash ) )
502 						{
503 							rtl::OUString aNewKey
504 								= rKey.replaceAt(
505 									0, rSourceKey.getLength(), rTargetKey );
506 							if ( !copyAdditionalPropertySet(
507 									rKey, aNewKey, sal_False ) )
508 								return sal_False;
509 						}
510 					}
511 				}
512 			}
513 			else
514 				return sal_False;
515 		}
516 		else
517 			return sal_False;
518 	}
519 	else
520 	{
521 		// Get old property set, if exists.
522 		uno::Reference< com::sun::star::ucb::XPersistentPropertySet >
523             xOldPropSet = getAdditionalPropertySet( rSourceKey, sal_False );
524 		if ( !xOldPropSet.is() )
525 			return sal_False;
526 
527 		uno::Reference< beans::XPropertySetInfo > xPropSetInfo
528             = xOldPropSet->getPropertySetInfo();
529 		if ( !xPropSetInfo.is() )
530 			return sal_False;
531 
532 		uno::Reference< beans::XPropertyAccess > xOldPropAccess(
533             xOldPropSet, uno::UNO_QUERY );
534 		if ( !xOldPropAccess.is() )
535 			return sal_False;
536 
537 		// Obtain all values from old set.
538 	    uno::Sequence< beans::PropertyValue > aValues
539             = xOldPropAccess->getPropertyValues();
540 		sal_Int32 nCount = aValues.getLength();
541 
542 		uno::Sequence< beans::Property > aProps
543             = xPropSetInfo->getProperties();
544 
545 		if ( nCount )
546 		{
547 			// Fail, if property set with new key already exists.
548 			uno::Reference< com::sun::star::ucb::XPersistentPropertySet >
549                 xNewPropSet
550                     = getAdditionalPropertySet( rTargetKey, sal_False );
551 			if ( xNewPropSet.is() )
552 				return sal_False;
553 
554 			// Create new, empty set.
555 			xNewPropSet = getAdditionalPropertySet( rTargetKey, sal_True );
556 			if ( !xNewPropSet.is() )
557 				return sal_False;
558 
559 			uno::Reference< beans::XPropertyContainer > xNewPropContainer(
560                 xNewPropSet, uno::UNO_QUERY );
561 			if ( !xNewPropContainer.is() )
562 				return sal_False;
563 
564 			for ( sal_Int32 n = 0; n < nCount; ++n )
565 			{
566 				const beans::PropertyValue& rValue = aValues[ n ];
567 
568 				sal_Int16 nAttribs = 0;
569 				for ( sal_Int32 m = 0; m < aProps.getLength(); ++m )
570 				{
571 					if ( aProps[ m ].Name == rValue.Name )
572 					{
573 						nAttribs = aProps[ m ].Attributes;
574 						break;
575 					}
576 				}
577 
578 				try
579 				{
580 					xNewPropContainer->addProperty(
581                         rValue.Name, nAttribs, rValue.Value );
582 				}
583 				catch ( beans::PropertyExistException & )
584 				{
585 				}
586 			   	catch ( beans::IllegalTypeException & )
587 				{
588 				}
589 				catch ( lang::IllegalArgumentException & )
590 				{
591 				}
592 			}
593         }
594 	}
595 	return sal_True;
596 }
597 
598 //=========================================================================
removeAdditionalPropertySet(const rtl::OUString & rKey,sal_Bool bRecursive)599 sal_Bool ContentProviderImplHelper::removeAdditionalPropertySet(
600     const rtl::OUString& rKey, sal_Bool bRecursive )
601 {
602 	osl::MutexGuard aGuard( m_aMutex );
603 
604 	if ( bRecursive )
605 	{
606 		// Get propertyset registry.
607 		getAdditionalPropertySetRegistry();
608 
609 		if ( m_pImpl->m_xPropertySetRegistry.is() )
610 		{
611 			uno::Reference< container::XNameAccess > xNameAccess(
612                 m_pImpl->m_xPropertySetRegistry, uno::UNO_QUERY );
613 			if ( xNameAccess.is() )
614 			{
615 				uno::Sequence< rtl::OUString > aKeys
616                     = xNameAccess->getElementNames();
617 				sal_Int32 nCount = aKeys.getLength();
618 				if ( nCount > 0 )
619 				{
620 					rtl::OUString aKeyWithSlash = rKey;
621 					rtl::OUString aKeyWithoutSlash;
622 					if ( aKeyWithSlash.lastIndexOf(
623                              sal_Unicode('/')
624                              != aKeyWithSlash.getLength() - 1 ) )
625 					{
626 						aKeyWithSlash += rtl::OUString( (sal_Unicode)'/' );
627 						aKeyWithoutSlash = rKey;
628 					}
629 					else if ( rKey.getLength() )
630 						aKeyWithoutSlash
631                             = rKey.copy( 0, rKey.getLength() - 1 );
632 
633 					const rtl::OUString* pKeys = aKeys.getConstArray();
634 					for ( sal_Int32 n = 0; n < nCount; ++n )
635 					{
636 						const rtl::OUString& rCurrKey = pKeys[ n ];
637 						if ( rCurrKey.compareTo(
638                                  aKeyWithSlash,
639                                  aKeyWithSlash.getLength() ) == 0
640                              || rCurrKey.equals( aKeyWithoutSlash ) )
641 						{
642 							if ( !removeAdditionalPropertySet(
643                                      rCurrKey, sal_False ) )
644 								return sal_False;
645 						}
646 					}
647 				}
648 			}
649 			else
650 				return sal_False;
651 		}
652 		else
653 			return sal_False;
654 	}
655 	else
656 	{
657 		// Get propertyset registry.
658 		getAdditionalPropertySetRegistry();
659 
660 		if ( m_pImpl->m_xPropertySetRegistry.is() )
661 			m_pImpl->m_xPropertySetRegistry->removePropertySet( rKey );
662 		else
663 			return sal_False;
664 	}
665 	return sal_True;
666 }
667 
668 } // namespace ucbhelper
669