xref: /trunk/main/svtools/source/misc/templatefoldercache.cxx (revision cdf0e10c4e3984b49a9502b011690b615761d4a3)
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