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