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