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