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