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_svtools.hxx"
30 #include <svtools/templatefoldercache.hxx>
31 #include <unotools/ucbstreamhelper.hxx>
32 #include <unotools/localfilehelper.hxx>
33 #include <com/sun/star/beans/XPropertySet.hpp>
34 #include <com/sun/star/sdbc/XResultSet.hpp>
35 #include <com/sun/star/ucb/XDynamicResultSet.hpp>
36 #include <com/sun/star/sdbc/XRow.hpp>
37 #include <com/sun/star/ucb/XContentAccess.hpp>
38 #include <com/sun/star/uno/XComponentContext.hpp>
39 #include <com/sun/star/util/XOfficeInstallationDirectories.hpp>
40 #include <ucbhelper/content.hxx>
41 #include <vos/ref.hxx>
42 #include <vos/refernce.hxx>
43 #include <tools/urlobj.hxx>
44 #include <tools/debug.hxx>
45 #include <unotools/pathoptions.hxx>
46 
47 #include "comphelper/processfactory.hxx"
48 
49 #include <vector>
50 #include <list>
51 #include <functional>
52 #include <algorithm>
53 
54 //.........................................................................
55 namespace svt
56 {
57 //.........................................................................
58 
59 	using namespace ::utl;
60 	using namespace ::com::sun::star;
61 	using namespace ::com::sun::star::sdbc;
62 	using namespace ::com::sun::star::ucb;
63 	using namespace ::com::sun::star::uno;
64 
65 	//=====================================================================
66 	//= helpers
67 	//=====================================================================
68 	//---------------------------------------------------------------------
69 	SvStream& operator << ( SvStream& _rStorage, const util::DateTime& _rDate )
70 	{
71 		_rStorage << _rDate.HundredthSeconds;
72 		_rStorage << _rDate.Seconds;
73 		_rStorage << _rDate.Minutes;
74 		_rStorage << _rDate.Hours;
75 		_rStorage << _rDate.Day;
76 		_rStorage << _rDate.Month;
77 		_rStorage << _rDate.Year;
78 
79 		return _rStorage;
80 	}
81 
82 	//---------------------------------------------------------------------
83 	SvStream& operator >> ( SvStream& _rStorage, util::DateTime& _rDate )
84 	{
85 		_rStorage >> _rDate.HundredthSeconds;
86 		_rStorage >> _rDate.Seconds;
87 		_rStorage >> _rDate.Minutes;
88 		_rStorage >> _rDate.Hours;
89 		_rStorage >> _rDate.Day;
90 		_rStorage >> _rDate.Month;
91 		_rStorage >> _rDate.Year;
92 
93 		return _rStorage;
94 	}
95 
96 	//---------------------------------------------------------------------
97 	sal_Bool operator == ( const util::DateTime& _rLHS, const util::DateTime& _rRHS )
98 	{
99 		return	_rLHS.HundredthSeconds == _rRHS.HundredthSeconds
100 			&&	_rLHS.Seconds	== _rRHS.Seconds
101 			&&	_rLHS.Minutes	== _rRHS.Minutes
102 			&&	_rLHS.Hours		== _rRHS.Hours
103 			&&	_rLHS.Day		== _rRHS.Day
104 			&&	_rLHS.Month		== _rRHS.Month
105 			&&	_rLHS.Year		== _rRHS.Year;
106 	}
107 
108 	//---------------------------------------------------------------------
109 	sal_Bool operator != ( const util::DateTime& _rLHS, const util::DateTime& _rRHS )
110 	{
111 		return !( _rLHS == _rRHS );
112 	}
113 
114 	//=====================================================================
115 	//= TemplateContent
116 	//=====================================================================
117 	struct TemplateContent;
118 	typedef	::std::vector< ::vos::ORef< TemplateContent > >	TemplateFolderContent;
119     typedef TemplateFolderContent::const_iterator           ConstFolderIterator;
120     typedef TemplateFolderContent::iterator                 FolderIterator;
121 
122 	/** a struct describing one content in one of the template dirs (or at least it's relevant aspects)
123 	*/
124 	struct TemplateContent : public ::vos::OReference
125 	{
126 	public:
127 
128 	private:
129 		INetURLObject			m_aURL;
130 		String					m_sLocalName;		// redundant - last segment of m_aURL
131 		util::DateTime			m_aLastModified;	// date of last modification as reported by UCP
132 		TemplateFolderContent	m_aSubContents;		// sorted (by name) list of the children
133 
134 	private:
135 		inline	void	implResetDate( )
136 		{
137 			m_aLastModified.HundredthSeconds = m_aLastModified.Seconds = m_aLastModified.Minutes = m_aLastModified.Hours = 0;
138 			m_aLastModified.Day = m_aLastModified.Month = m_aLastModified.Year = 0;
139 		}
140 
141 	private:
142 		~TemplateContent();
143 
144 	public:
145 		TemplateContent();
146 		TemplateContent( const INetURLObject& _rURL );
147 		TemplateContent( const INetURLObject& _rURL, const util::DateTime& _rLastModified );
148 
149 		// attribute access
150 		inline String					getName( ) const							{ return m_sLocalName; }
151 		inline String					getURL( ) const								{ return m_aURL.GetMainURL( INetURLObject::DECODE_TO_IURI ); }
152 		inline void						setModDate( const util::DateTime& _rDate )	{ m_aLastModified = _rDate; }
153 		inline const util::DateTime&	getModDate( ) const							{ return m_aLastModified; }
154 
155 		inline TemplateFolderContent&	getSubContents()			{ return m_aSubContents; }
156 		inline const TemplateFolderContent&	getSubContents() const	{ return m_aSubContents; }
157 
158                 inline ConstFolderIterator              begin() const   { return m_aSubContents.begin(); }
159                 inline ConstFolderIterator              end() const             { return m_aSubContents.end(); }
160 		inline TemplateFolderContent::size_type
161 										size() const	{ return m_aSubContents.size(); }
162 
163 		inline void						push_back( const ::vos::ORef< TemplateContent >& _rxNewElement )
164 														{ m_aSubContents.push_back( _rxNewElement ); }
165 	};
166 
167 	//---------------------------------------------------------------------
168 	DBG_NAME( TemplateContent )
169 
170 	//---------------------------------------------------------------------
171 	TemplateContent::TemplateContent()
172 	{
173 		DBG_CTOR( TemplateContent, NULL );
174 		implResetDate();
175 	}
176 
177 	//---------------------------------------------------------------------
178 	TemplateContent::TemplateContent( const INetURLObject& _rURL )
179 		:m_aURL( _rURL )
180 	{
181 		DBG_CTOR( TemplateContent, NULL );
182 		DBG_ASSERT( INET_PROT_NOT_VALID != m_aURL.GetProtocol(), "TemplateContent::TemplateContent: invalid URL!" );
183 		m_sLocalName = m_aURL.getName();
184 		implResetDate();
185 	}
186 
187 	//---------------------------------------------------------------------
188 	TemplateContent::TemplateContent( const INetURLObject& _rURL, const util::DateTime& _rLastModified )
189 		:m_aURL( _rURL )
190 		,m_aLastModified( _rLastModified )
191 	{
192 		DBG_CTOR( TemplateContent, NULL );
193 		DBG_ASSERT( INET_PROT_NOT_VALID != m_aURL.GetProtocol(), "TemplateContent::TemplateContent: invalid URL!" );
194 		m_sLocalName = m_aURL.getName();
195 	}
196 
197 	//---------------------------------------------------------------------
198 	TemplateContent::~TemplateContent()
199 	{
200 		DBG_DTOR( TemplateContent, NULL );
201 	}
202 
203 	//=====================================================================
204 	//= stl helpers
205 	//=====================================================================
206 	//---------------------------------------------------------------------
207 	/// compares two TemplateContent by URL
208 	struct TemplateContentURLLess
209 		:public ::std::binary_function	<	::vos::ORef< TemplateContent >
210 										,	::vos::ORef< TemplateContent >
211 										,	bool
212 										>
213 	{
214 		bool operator() ( const ::vos::ORef< TemplateContent >& _rxLHS, const ::vos::ORef< TemplateContent >& _rxRHS ) const
215 		{
216 			return	_rxLHS->getURL() < _rxRHS->getURL()
217 				?	true
218 				:	false;
219 		}
220 	};
221 
222 	//---------------------------------------------------------------------
223 	/// sorts the sib contents of a TemplateFolderContent
224 	struct SubContentSort : public ::std::unary_function< ::vos::ORef< TemplateContent >, void >
225 	{
226 		void operator() ( TemplateFolderContent& _rFolder ) const
227 		{
228 			// sort the directory by name
229 			::std::sort(
230 				_rFolder.begin(),
231 				_rFolder.end(),
232 				TemplateContentURLLess()
233 			);
234 
235 			// sort the sub directories by name
236 			::std::for_each(
237 				_rFolder.begin(),
238 				_rFolder.end(),
239 				*this
240 			);
241 		}
242 
243 		void operator() ( const ::vos::ORef< TemplateContent >& _rxContent ) const
244 		{
245 			if ( _rxContent.isValid() && _rxContent->size() )
246 			{
247 				operator()( _rxContent->getSubContents() );
248 			}
249 		}
250 	};
251 	//---------------------------------------------------------------------
252 	/** does a deep compare of two template contents
253 	*/
254 	struct TemplateContentEqual
255 		:public ::std::binary_function	<	::vos::ORef< TemplateContent >
256 										,	::vos::ORef< TemplateContent >
257 										,	bool
258 										>
259 	{
260 		//.................................................................
261 		bool operator() (const ::vos::ORef< TemplateContent >& _rLHS, const ::vos::ORef< TemplateContent >& _rRHS )
262 		{
263 			if ( !_rLHS.isValid() || !_rRHS.isValid() )
264 			{
265 				DBG_ERROR( "TemplateContentEqual::operator(): invalid contents!" );
266 				return true;
267 					// this is not strictly true, in case only one is invalid - but this is a heavy error anyway
268 			}
269 
270 			if ( _rLHS->getURL() != _rRHS->getURL() )
271 				return false;
272 
273 			if ( _rLHS->getModDate() != _rRHS->getModDate() )
274 				return false;
275 
276 			if ( _rLHS->getSubContents().size() != _rRHS->getSubContents().size() )
277 				return false;
278 
279 			if ( _rLHS->getSubContents().size() )
280 			{	// there are children
281 				// -> compare them
282 				::std::pair< FolderIterator, FolderIterator > aFirstDifferent = ::std::mismatch(
283 					_rLHS->getSubContents().begin(),
284 					_rLHS->getSubContents().end(),
285 					_rRHS->getSubContents().begin(),
286 					*this
287 				);
288 				if ( aFirstDifferent.first != _rLHS->getSubContents().end() )
289 					return false;// the sub contents differ
290 			}
291 
292 			return true;
293 		}
294 	};
295 
296 	//---------------------------------------------------------------------
297 	/// base class for functors which act an an SvStream
298 	struct StorageHelper
299 	{
300 	protected:
301 		SvStream&	m_rStorage;
302 		StorageHelper( SvStream& _rStorage ) : m_rStorage( _rStorage ) { }
303 	};
304 
305 	//---------------------------------------------------------------------
306 	/// functor which allows storing a string
307 	struct StoreString
308 			:public ::std::unary_function< String, void >
309 			,public StorageHelper
310 	{
311 		StoreString( SvStream& _rStorage ) : StorageHelper( _rStorage ) { }
312 
313 		void operator() ( const String& _rString ) const
314 		{
315 			m_rStorage.WriteByteString( _rString );
316 		}
317 	};
318 
319 	//---------------------------------------------------------------------
320 	/// functor which stores the local name of a TemplateContent
321 	struct StoreLocalContentName
322 			:public ::std::unary_function< ::vos::ORef< TemplateContent >, void >
323 			,public StoreString
324 	{
325 		StoreLocalContentName( SvStream& _rStorage ) : StoreString( _rStorage ) { }
326 
327 		void operator() ( const ::vos::ORef< TemplateContent >& _rxContent ) const
328 		{
329 			DBG_ERRORFILE( "This method must not be used, the whole URL must be stored!" );
330 
331 			// use the base class operator with the local name of the content
332 			StoreString::operator() ( _rxContent->getName() );
333 		}
334 	};
335 
336 	//---------------------------------------------------------------------
337 	struct StoreContentURL
338 			:public ::std::unary_function< ::vos::ORef< TemplateContent >, void >
339 			,public StoreString
340 	{
341         uno::Reference< util::XOfficeInstallationDirectories > m_xOfficeInstDirs;
342 
343         StoreContentURL( SvStream& _rStorage,
344                          const uno::Reference<
345                             util::XOfficeInstallationDirectories > &
346                                 xOfficeInstDirs )
347         : StoreString( _rStorage ), m_xOfficeInstDirs( xOfficeInstDirs ) { }
348 
349 		void operator() ( const ::vos::ORef< TemplateContent >& _rxContent ) const
350 		{
351 			// use the base class operator with the local name of the content
352             String sURL = _rxContent->getURL();
353             // #116281# Keep office installtion relocatable. Never store
354             // any direct references to office installation directory.
355             sURL = m_xOfficeInstDirs->makeRelocatableURL( sURL );
356             StoreString::operator() ( sURL );
357 		}
358 	};
359 
360 	//---------------------------------------------------------------------
361 	/// functor which stores the complete content of a TemplateContent
362 	struct StoreFolderContent
363 			:public ::std::unary_function< ::vos::ORef< TemplateContent >, void >
364 			,public StorageHelper
365 	{
366         uno::Reference< util::XOfficeInstallationDirectories > m_xOfficeInstDirs;
367 
368 	public:
369 		StoreFolderContent( SvStream& _rStorage,
370                          const uno::Reference<
371                             util::XOfficeInstallationDirectories > &
372                                 xOfficeInstDirs )
373         : StorageHelper( _rStorage ), m_xOfficeInstDirs( xOfficeInstDirs ) { }
374 
375 		//.................................................................
376 		void operator() ( const TemplateContent& _rContent ) const
377 		{
378 			// store the info about this content
379 			m_rStorage << _rContent.getModDate();
380 
381 			// store the info about the children
382 			// the number
383 			m_rStorage << (sal_Int32)_rContent.size();
384 			// their URLs ( the local name is not enough, since URL might be not a hierarchical one, "expand:" for example )
385 			::std::for_each(
386 				_rContent.getSubContents().begin(),
387 				_rContent.getSubContents().end(),
388 				StoreContentURL( m_rStorage, m_xOfficeInstDirs )
389 			);
390 			// their content
391 			::std::for_each(
392 				_rContent.getSubContents().begin(),
393 				_rContent.getSubContents().end(),
394 				*this
395 			);
396 		}
397 
398 		//.................................................................
399 		void operator() ( const ::vos::ORef< TemplateContent >& _rxContent ) const
400 		{
401 			if ( _rxContent.isValid() )
402 			{
403 				operator()( *_rxContent );
404 			}
405 		}
406 	};
407 
408 	//---------------------------------------------------------------------
409 	/// functor which reads a complete TemplateContent instance
410 	struct ReadFolderContent
411 			:public ::std::unary_function< ::vos::ORef< TemplateContent >, void >
412 			,public StorageHelper
413 	{
414         uno::Reference< util::XOfficeInstallationDirectories > m_xOfficeInstDirs;
415 
416 		ReadFolderContent( SvStream& _rStorage,
417                          const uno::Reference<
418                             util::XOfficeInstallationDirectories > &
419                                 xOfficeInstDirs )
420         : StorageHelper( _rStorage ), m_xOfficeInstDirs( xOfficeInstDirs ) { }
421 
422 		//.................................................................
423 		void operator() ( TemplateContent& _rContent ) const
424 		{
425 			// store the info about this content
426 			util::DateTime aModDate;
427 			m_rStorage >> aModDate;
428 			_rContent.setModDate( aModDate );
429 
430 			// store the info about the children
431 			// the number
432 			sal_Int32 nChildren = 0;
433 			m_rStorage >> nChildren;
434 			TemplateFolderContent& rChildren = _rContent.getSubContents();
435 			rChildren.resize( 0 );
436 			rChildren.reserve( nChildren );
437 			// initialize them with their (local) names
438 			while ( nChildren-- )
439 			{
440 				String sURL;
441 				m_rStorage.ReadByteString( sURL );
442                 sURL = m_xOfficeInstDirs->makeAbsoluteURL( sURL );
443 				INetURLObject aChildURL( sURL );
444 				rChildren.push_back( new TemplateContent( aChildURL ) );
445 			}
446 
447 			// their content
448 			::std::for_each(
449 				_rContent.getSubContents().begin(),
450 				_rContent.getSubContents().end(),
451 				*this
452 			);
453 		}
454 
455 		//.................................................................
456 		void operator() ( const ::vos::ORef< TemplateContent >& _rxContent ) const
457 		{
458 			if ( _rxContent.isValid() )
459 			{
460 				operator()( *_rxContent );
461 			}
462 		}
463 	};
464 
465 	//=====================================================================
466 	//= TemplateFolderCacheImpl
467 	//=====================================================================
468     class TemplateFolderCacheImpl
469 	{
470 	private:
471 		TemplateFolderContent			m_aPreviousState;	// the current state of the template dirs (as found on the HD)
472 		TemplateFolderContent			m_aCurrentState;	// the previous state of the template dirs (as found in the cache file)
473 
474         osl::Mutex                      m_aMutex;
475         // will be lazy inited; never access directly; use getOfficeInstDirs().
476         uno::Reference< util::XOfficeInstallationDirectories > m_xOfficeInstDirs;
477 
478 		SvStream*						m_pCacheStream;
479 		sal_Bool						m_bNeedsUpdate : 1;
480 		sal_Bool						m_bKnowState : 1;
481 		sal_Bool						m_bValidCurrentState : 1;
482 		sal_Bool						m_bAutoStoreState : 1;
483 
484 	public:
485 		TemplateFolderCacheImpl( sal_Bool _bAutoStoreState );
486 		~TemplateFolderCacheImpl( );
487 
488 		sal_Bool	needsUpdate( sal_Bool _bForceCheck );
489 		void		storeState( sal_Bool _bForceRetrieval );
490 
491 	private:
492 		void		initTemplDirs( ::std::vector< String >& _rRootDirs );
493 		sal_Bool	openCacheStream( sal_Bool _bForRead );
494 		void		closeCacheStream( );
495 
496 		/// read the state of the dirs from the cache file
497 		sal_Bool	readPreviousState();
498 		/// read the current state of the dirs
499 		sal_Bool	readCurrentState();
500 
501 		String		implParseSmart( const String& _rPath );
502 
503 		sal_Bool	implReadFolder( const ::vos::ORef< TemplateContent >& _rxRoot );
504 
505 		static	String		getCacheFileName();
506 		static	sal_Int32	getMagicNumber();
507 		static	void		normalize( TemplateFolderContent& _rState );
508 
509 		// @return <TRUE/> if the states equal
510 		static	sal_Bool	equalStates( const TemplateFolderContent& _rLHS, const TemplateFolderContent& _rRHS );
511 
512         // late initialize m_xOfficeInstDirs
513         uno::Reference< util::XOfficeInstallationDirectories > getOfficeInstDirs();
514 	};
515 
516 	//---------------------------------------------------------------------
517 	TemplateFolderCacheImpl::TemplateFolderCacheImpl( sal_Bool _bAutoStoreState )
518 		:m_pCacheStream			( NULL )
519 		,m_bNeedsUpdate			( sal_True )
520 		,m_bKnowState			( sal_False )
521 		,m_bValidCurrentState	( sal_False )
522 		,m_bAutoStoreState		( _bAutoStoreState )
523 	{
524 	}
525 
526 	//---------------------------------------------------------------------
527 	TemplateFolderCacheImpl::~TemplateFolderCacheImpl( )
528 	{
529 		// store the current state if possible and required
530 		if ( m_bValidCurrentState && m_bAutoStoreState )
531 			storeState( sal_False );
532 
533 		closeCacheStream( );
534 	}
535 
536 	//---------------------------------------------------------------------
537 	sal_Int32 TemplateFolderCacheImpl::getMagicNumber()
538 	{
539 		sal_Int32 nMagic = 0;
540 		( nMagic += (sal_Int8)'T' ) <<= 4;
541 		( nMagic += (sal_Int8)'D' ) <<= 4;
542 		( nMagic += (sal_Int8)'S' ) <<= 4;
543 		( nMagic += (sal_Int8)'C' ) <<= 0;
544 		return nMagic;
545 	}
546 
547 	//---------------------------------------------------------------------
548 	String TemplateFolderCacheImpl::getCacheFileName()
549 	{
550 		return String::CreateFromAscii( ".templdir.cache" );
551 	}
552 
553 
554 	//---------------------------------------------------------------------
555 	void TemplateFolderCacheImpl::normalize( TemplateFolderContent& _rState )
556 	{
557 		SubContentSort()( _rState );
558 	}
559 
560 	//---------------------------------------------------------------------
561 	sal_Bool TemplateFolderCacheImpl::equalStates( const TemplateFolderContent& _rLHS, const TemplateFolderContent& _rRHS )
562 	{
563 		if ( _rLHS.size() != _rRHS.size() )
564 			return sal_False;
565 
566 		// as both arrays are sorted (by definition - this is a precondition of this method)
567 		// we can simply go from the front to the back and compare the single elements
568 
569 		::std::pair< ConstFolderIterator, ConstFolderIterator > aFirstDifferent = ::std::mismatch(
570 			_rLHS.begin(),
571 			_rLHS.end(),
572 			_rRHS.begin(),
573 			TemplateContentEqual()
574 		);
575 
576 		return aFirstDifferent.first == _rLHS.end();
577 	}
578 
579 	//---------------------------------------------------------------------
580 	void TemplateFolderCacheImpl::storeState( sal_Bool _bForceRetrieval )
581 	{
582 		if ( !m_bValidCurrentState || _bForceRetrieval )
583 			readCurrentState( );
584 
585 		if ( m_bValidCurrentState && openCacheStream( sal_False ) )
586 		{
587 			*m_pCacheStream	<< getMagicNumber();
588 
589 			// store the template root folders
590 			// the size
591 			*m_pCacheStream << (sal_Int32)m_aCurrentState.size();
592 			// the complete URLs
593 			::std::for_each(
594 				m_aCurrentState.begin(),
595 				m_aCurrentState.end(),
596                 StoreContentURL( *m_pCacheStream, getOfficeInstDirs() )
597 			);
598 
599 			// the contents
600 			::std::for_each(
601 				m_aCurrentState.begin(),
602 				m_aCurrentState.end(),
603 				StoreFolderContent( *m_pCacheStream, getOfficeInstDirs() )
604 			);
605 		}
606 	}
607 
608 	//---------------------------------------------------------------------
609 	String TemplateFolderCacheImpl::implParseSmart( const String& _rPath )
610 	{
611 		INetURLObject aParser;
612 		aParser.SetSmartProtocol( INET_PROT_FILE );
613 		aParser.SetURL( _rPath, INetURLObject::WAS_ENCODED );
614 		if ( INET_PROT_NOT_VALID == aParser.GetProtocol() )
615 		{
616 			String sURL;
617 			LocalFileHelper::ConvertPhysicalNameToURL( _rPath, sURL );
618 			aParser.SetURL( sURL, INetURLObject::WAS_ENCODED );
619 		}
620 		return aParser.GetMainURL( INetURLObject::DECODE_TO_IURI );
621 	}
622 
623 	//---------------------------------------------------------------------
624 	void TemplateFolderCacheImpl::closeCacheStream( )
625 	{
626 		DELETEZ( m_pCacheStream );
627 	}
628 
629 	//---------------------------------------------------------------------
630 	sal_Bool TemplateFolderCacheImpl::implReadFolder( const ::vos::ORef< TemplateContent >& _rxRoot )
631 	{
632 		try
633 		{
634 			// create a content for the current folder root
635 			Reference< XResultSet > xResultSet;
636 			Sequence< ::rtl::OUString > aContentProperties( 4);
637 			aContentProperties[0] = ::rtl::OUString::createFromAscii( "Title" );
638 			aContentProperties[1] = ::rtl::OUString::createFromAscii( "DateModified" );
639 			aContentProperties[2] = ::rtl::OUString::createFromAscii( "DateCreated" );
640 			aContentProperties[3] = ::rtl::OUString::createFromAscii( "IsFolder" );
641 
642 			// get the set of sub contents in the folder
643     		try
644 			{
645 				Reference< XDynamicResultSet > xDynResultSet;
646 
647 				::ucbhelper::Content aTemplateRoot( _rxRoot->getURL(), Reference< XCommandEnvironment >() );
648 				xDynResultSet = aTemplateRoot.createDynamicCursor( aContentProperties, ::ucbhelper::INCLUDE_FOLDERS_AND_DOCUMENTS );
649 				if ( xDynResultSet.is() )
650 					xResultSet = xDynResultSet->getStaticResultSet();
651 			}
652 			catch( CommandAbortedException& )
653 			{
654 				DBG_ERRORFILE( "TemplateFolderCacheImpl::implReadFolder: caught a CommandAbortedException!" );
655 				return sal_False;
656 			}
657 			catch( ::com::sun::star::uno::Exception& )
658 			{
659 			}
660 
661 			// collect the infos about the sub contents
662 			if ( xResultSet.is() )
663 			{
664 				Reference< XRow > xRow( xResultSet, UNO_QUERY_THROW );
665 				Reference< XContentAccess > xContentAccess( xResultSet, UNO_QUERY_THROW );
666 
667 				while ( xResultSet->next() )
668 				{
669 					INetURLObject aSubContentURL( xContentAccess->queryContentIdentifierString() );
670 
671 					// a new content instance
672 					::vos::ORef< TemplateContent > xChild = new TemplateContent( aSubContentURL );
673 
674 					// the modified date
675 					xChild->setModDate( xRow->getTimestamp( 2 ) );	// date modified
676 					if ( xRow->wasNull() )
677 						xChild->setModDate( xRow->getTimestamp( 3 ) );	// fallback: date created
678 
679 					// push back this content
680 					_rxRoot->push_back( xChild );
681 
682 					// is it a folder?
683 					if ( xRow->getBoolean( 4 ) && !xRow->wasNull() )
684 					{	// yes -> step down
685                                                 ConstFolderIterator aNextLevelRoot = _rxRoot->end();
686 						--aNextLevelRoot;
687 						implReadFolder( *aNextLevelRoot );
688 					}
689 				}
690 			}
691 		}
692 		catch( const Exception& )
693 		{
694 			DBG_ERROR( "TemplateFolderCacheImpl::implReadFolder: caught an exception!" );
695 			return sal_False;
696 		}
697 		return sal_True;
698 	}
699 
700 	//---------------------------------------------------------------------
701 	sal_Bool TemplateFolderCacheImpl::readCurrentState()
702 	{
703 		// reset
704 		m_bValidCurrentState = sal_False;
705         TemplateFolderContent aTemplateFolderContent;
706 		m_aCurrentState.swap( aTemplateFolderContent );
707 
708 		// the template directories from the config
709         const SvtPathOptions aPathOptions;
710 	    String		aDirs = aPathOptions.GetTemplatePath();
711 		sal_uInt16	nDirs = aDirs.GetTokenCount( ';' );
712 
713 		m_aCurrentState.reserve( nDirs );
714 		// loop through all the root-level template folders
715 		for ( sal_uInt16 i=0; i<nDirs; ++i)
716 		{
717             String sTemplatePath( aDirs.GetToken( i, ';' ) );
718             sTemplatePath = aPathOptions.ExpandMacros( sTemplatePath );
719 			// create a new entry
720 			m_aCurrentState.push_back( new TemplateContent( INetURLObject( sTemplatePath ) ) );
721 			TemplateFolderContent::iterator aCurrentRoot = m_aCurrentState.end();
722 			--aCurrentRoot;
723 
724 			if ( !implReadFolder( *aCurrentRoot ) )
725 				return sal_False;
726 		}
727 
728 		// normalize the array (which basically means "sort it")
729 		normalize( m_aCurrentState );
730 
731 		m_bValidCurrentState = sal_True;
732 		return m_bValidCurrentState;
733 	}
734 
735 	//---------------------------------------------------------------------
736 	sal_Bool TemplateFolderCacheImpl::readPreviousState()
737 	{
738 		DBG_ASSERT( m_pCacheStream, "TemplateFolderCacheImpl::readPreviousState: not to be called without stream!" );
739 
740 		// reset
741         TemplateFolderContent aTemplateFolderContent;
742 		m_aPreviousState.swap( aTemplateFolderContent );
743 
744 		// check the magic number
745 		sal_Int32 nMagic = 0;
746 		*m_pCacheStream >> nMagic;
747 		DBG_ASSERT( getMagicNumber() == nMagic, "TemplateFolderCacheImpl::readPreviousState: invalid cache file!" );
748 		if ( getMagicNumber() != nMagic )
749 			return sal_False;
750 
751 		// the root directories
752 		// their number
753 		sal_Int32 nRootDirectories = 0;
754 		*m_pCacheStream >> nRootDirectories;
755 		// init empty TemplateContens with the URLs
756 		m_aPreviousState.reserve( nRootDirectories );
757 		while ( nRootDirectories-- )
758 		{
759 			String sURL;
760 			m_pCacheStream->ReadByteString( sURL );
761             // #116281# Keep office installtion relocatable. Never store
762             // any direct references to office installation directory.
763             sURL = getOfficeInstDirs()->makeAbsoluteURL( sURL );
764 			m_aPreviousState.push_back(
765 				new TemplateContent( INetURLObject(sURL) ) );
766 		}
767 
768 		// read the contents of the root folders
769 		::std::for_each(
770 			m_aPreviousState.begin(),
771 			m_aPreviousState.end(),
772 			ReadFolderContent( *m_pCacheStream, getOfficeInstDirs() )
773 		);
774 
775 		DBG_ASSERT( !m_pCacheStream->GetErrorCode(), "TemplateFolderCacheImpl::readPreviousState: unknown error during reading the state cache!" );
776 
777 		// normalize the array (which basically means "sort it")
778 		normalize( m_aPreviousState );
779 
780 		return sal_True;
781 	}
782 
783 	//---------------------------------------------------------------------
784 	sal_Bool TemplateFolderCacheImpl::openCacheStream( sal_Bool _bForRead )
785 	{
786 		// close any old stream instance
787 		closeCacheStream( );
788 
789 		// get the storage directory
790 		String sStorageURL = implParseSmart( SvtPathOptions().GetStoragePath() );
791 		INetURLObject aStorageURL( sStorageURL );
792 		if ( INET_PROT_NOT_VALID == aStorageURL.GetProtocol() )
793 		{
794 			DBG_ERROR( "TemplateFolderCacheImpl::openCacheStream: invalid storage path!" );
795 			return sal_False;
796 		}
797 
798 		// append our name
799 		aStorageURL.Append( getCacheFileName() );
800 
801 		// open the stream
802 		m_pCacheStream = UcbStreamHelper::CreateStream( aStorageURL.GetMainURL( INetURLObject::DECODE_TO_IURI ),
803 			_bForRead ?	STREAM_READ | STREAM_NOCREATE : STREAM_WRITE | STREAM_TRUNC );
804 		DBG_ASSERT( m_pCacheStream, "TemplateFolderCacheImpl::openCacheStream: could not open/create the cache stream!" );
805 		if ( m_pCacheStream && m_pCacheStream->GetErrorCode() )
806 		{
807 			DELETEZ( m_pCacheStream );
808 		}
809 
810 		if ( m_pCacheStream )
811 			m_pCacheStream->SetStreamCharSet( RTL_TEXTENCODING_UTF8 );
812 
813 		return NULL != m_pCacheStream;
814 	}
815 
816 	//---------------------------------------------------------------------
817 	sal_Bool TemplateFolderCacheImpl::needsUpdate( sal_Bool _bForceCheck )
818 	{
819 		if ( m_bKnowState && !_bForceCheck )
820 			return m_bNeedsUpdate;
821 
822 		m_bNeedsUpdate = sal_True;
823 		m_bKnowState = sal_True;
824 
825 		if ( readCurrentState() )
826 		{
827 			// open the stream which contains the cached state of the directories
828 			if ( openCacheStream( sal_True ) )
829 			{	// opening the stream succeeded
830 				if ( readPreviousState() )
831 				{
832 					m_bNeedsUpdate = !equalStates( m_aPreviousState, m_aCurrentState );
833 				}
834 				else
835 				{
836 					closeCacheStream();
837 				}
838 			}
839 		}
840 		return m_bNeedsUpdate;
841 	}
842 
843 	//---------------------------------------------------------------------
844 	void TemplateFolderCacheImpl::initTemplDirs( ::std::vector< String >& )
845 	{
846 	}
847 
848     //---------------------------------------------------------------------
849     uno::Reference< util::XOfficeInstallationDirectories >
850     TemplateFolderCacheImpl::getOfficeInstDirs()
851     {
852         if ( !m_xOfficeInstDirs.is() )
853         {
854             osl::MutexGuard aGuard( m_aMutex );
855             if ( !m_xOfficeInstDirs.is() )
856             {
857                 // @@@ This is bad!
858                 uno::Reference< lang::XMultiServiceFactory > xSMgr
859                     = comphelper::getProcessServiceFactory();
860                 OSL_ENSURE( xSMgr.is(), "No service manager!" );
861 
862                 uno::Reference< beans::XPropertySet > xPropSet(
863                     xSMgr, uno::UNO_QUERY );
864                 if ( xPropSet.is() )
865                 {
866                     uno::Reference< uno::XComponentContext > xCtx;
867                     xPropSet->getPropertyValue(
868                         rtl::OUString(
869                             RTL_CONSTASCII_USTRINGPARAM( "DefaultContext" ) ) )
870                     >>= xCtx;
871 
872                     OSL_ENSURE( xCtx.is(),
873                                 "Unable to obtain component context from service manager!" );
874 
875                     if ( xCtx.is() )
876                     {
877                         xCtx->getValueByName(
878                             rtl::OUString( RTL_CONSTASCII_USTRINGPARAM(
879                                 "/singletons/com.sun.star.util.theOfficeInstallationDirectories" ) ) )
880                         >>= m_xOfficeInstDirs;
881                     }
882 
883                     OSL_ENSURE( m_xOfficeInstDirs.is(),
884                                 "Unable to obtain office directories singleton!" );
885 
886                 }
887             }
888         }
889         return m_xOfficeInstDirs;
890     }
891 
892 	//=====================================================================
893 	//= TemplateFolderCache
894 	//=====================================================================
895 	//---------------------------------------------------------------------
896 	TemplateFolderCache::TemplateFolderCache( sal_Bool _bAutoStoreState )
897 		:m_pImpl( new TemplateFolderCacheImpl( _bAutoStoreState ) )
898 	{
899 	}
900 
901 	//---------------------------------------------------------------------
902 	TemplateFolderCache::~TemplateFolderCache( )
903 	{
904 		DELETEZ( m_pImpl );
905 	}
906 
907 	//---------------------------------------------------------------------
908 	sal_Bool TemplateFolderCache::needsUpdate( sal_Bool _bForceCheck )
909 	{
910 		return m_pImpl->needsUpdate( _bForceCheck );
911 	}
912 
913 	//---------------------------------------------------------------------
914 	void TemplateFolderCache::storeState( sal_Bool _bForceRetrieval )
915 	{
916 		m_pImpl->storeState( _bForceRetrieval );
917 	}
918 
919 //.........................................................................
920 }	// namespace sfx2
921 //.........................................................................
922 
923