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