/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* * This file is part of the LibreOffice project. * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * This file incorporates work covered by the following license notice: * * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed * with this work for additional information regarding copyright * ownership. The ASF licenses this file to you under the Apache * License, Version 2.0 (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of * the License at http://www.apache.org/licenses/LICENSE-2.0 .
*/
/** a struct describing one content in one of the template dirs (or at least it's relevant aspects)
*/ struct TemplateContent : public ::salhelper::SimpleReferenceObject
{ public:
private:
INetURLObject m_aURL;
util::DateTime m_aLastModified; // date of last modification as reported by UCP
TemplateFolderContent m_aSubContents; // sorted (by name) list of the children
/// sorts the sib contents of a TemplateFolderContent struct SubContentSort
{ voidoperator() ( TemplateFolderContent& _rFolder ) const
{ // sort the directory by name
::std::sort(
_rFolder.begin(),
_rFolder.end(),
TemplateContentURLLess()
);
// sort the sub directories by name
::std::for_each(
_rFolder.begin(),
_rFolder.end(),
*this
);
}
/** does a deep compare of two template contents
*/ struct TemplateContentEqual
{
booloperator() (const ::rtl::Reference< TemplateContent >& _rLHS, const ::rtl::Reference< TemplateContent >& _rRHS )
{ if ( !_rLHS.is() || !_rRHS.is() )
{
OSL_FAIL( "TemplateContentEqual::operator(): invalid contents!" ); returntrue; // this is not strictly true, in case only one is invalid - but this is a heavy error anyway
}
if ( _rLHS->getURL() != _rRHS->getURL() ) returnfalse;
if ( _rLHS->getModDate() != _rRHS->getModDate() ) returnfalse;
if ( _rLHS->getSubContents().size() != _rRHS->getSubContents().size() ) returnfalse;
if ( !_rLHS->getSubContents().empty() )
{ // there are children // -> compare them
::std::pair< FolderIterator, FolderIterator > aFirstDifferent = ::std::mismatch(
_rLHS->getSubContents().begin(),
_rLHS->getSubContents().end(),
_rRHS->getSubContents().begin(),
*this
); if ( aFirstDifferent.first != _rLHS->getSubContents().end() ) returnfalse;// the sub contents differ
}
returntrue;
}
};
/// base class for functors which act on a SvStream struct StorageHelper
{ protected:
SvStream& m_rStorage; explicit StorageHelper( SvStream& _rStorage ) : m_rStorage( _rStorage ) { }
};
struct StoreContentURL : public StorageHelper
{
uno::Reference< util::XOfficeInstallationDirectories > m_xOfficeInstDirs;
voidoperator() ( const ::rtl::Reference< TemplateContent >& _rxContent ) const
{ // use the base class operator with the local name of the content
OUString sURL = _rxContent->getURL(); // #116281# Keep office installation relocatable. Never store // any direct references to office installation directory.
sURL = m_xOfficeInstDirs->makeRelocatableURL( sURL );
m_rStorage.WriteUniOrByteString( sURL, m_rStorage.GetStreamCharSet() );
}
};
/// functor which stores the complete content of a TemplateContent struct StoreFolderContent : public StorageHelper
{
uno::Reference< util::XOfficeInstallationDirectories > m_xOfficeInstDirs;
voidoperator() ( const TemplateContent& _rContent ) const
{ // store the info about this content
WriteDateTime( m_rStorage, _rContent.getModDate() );
// store the info about the children // the number
m_rStorage.WriteInt32( _rContent.size() ); // their URLs ( the local name is not enough, since URL might be not a hierarchical one, "expand:" for example )
::std::for_each(
_rContent.getSubContents().begin(),
_rContent.getSubContents().end(),
StoreContentURL( m_rStorage, m_xOfficeInstDirs )
); // their content
::std::for_each(
_rContent.getSubContents().begin(),
_rContent.getSubContents().end(),
*this
);
}
voidoperator() ( TemplateContent& _rContent ) const
{ // store the info about this content
util::DateTime aModDate;
m_rStorage >> aModDate;
_rContent.setModDate( aModDate );
// store the info about the children // the number
sal_Int32 nChildren = 0;
m_rStorage.ReadInt32( nChildren );
TemplateFolderContent& rChildren = _rContent.getSubContents();
rChildren.resize( 0 );
rChildren.reserve( nChildren ); // initialize them with their (local) names while ( nChildren-- )
{
OUString sURL = m_rStorage.ReadUniOrByteString(m_rStorage.GetStreamCharSet());
sURL = m_xOfficeInstDirs->makeAbsoluteURL( sURL );
rChildren.push_back( new TemplateContent( INetURLObject( sURL ) ) );
}
// their content
::std::for_each(
_rContent.getSubContents().begin(),
_rContent.getSubContents().end(),
*this
);
}
class TemplateFolderCacheImpl
{ private:
TemplateFolderContent m_aPreviousState; // the current state of the template dirs (as found on the HD)
TemplateFolderContent m_aCurrentState; // the previous state of the template dirs (as found in the cache file)
std::mutex m_aMutex; // will be lazy inited; never access directly; use getOfficeInstDirs().
uno::Reference< util::XOfficeInstallationDirectories > m_xOfficeInstDirs;
TemplateFolderCacheImpl::~TemplateFolderCacheImpl( )
{ // store the current state if possible and required if ( m_bValidCurrentState && m_bAutoStoreState )
storeState();
// as both arrays are sorted (by definition - this is a precondition of this method) // we can simply go from the front to the back and compare the single elements
// collect the infos about the sub contents if ( xResultSet.is() )
{
Reference< XRow > xRow( xResultSet, UNO_QUERY_THROW );
Reference< XContentAccess > xContentAccess( xResultSet, UNO_QUERY_THROW );
while ( xResultSet->next() )
{
INetURLObject aSubContentURL( xContentAccess->queryContentIdentifierString() );
// a new content instance
::rtl::Reference< TemplateContent > xChild = new TemplateContent( std::move(aSubContentURL) );
// the modified date
xChild->setModDateNormalized( xRow->getTimestamp( 2 ) ); // date modified if ( xRow->wasNull() )
xChild->setModDateNormalized( xRow->getTimestamp( 3 ) ); // fallback: date created
// push back this content
_rxRoot->push_back( xChild );
// is it a folder? if ( xRow->getBoolean( 4 ) && !xRow->wasNull() )
{ // yes -> step down
ConstFolderIterator aNextLevelRoot = _rxRoot->end();
--aNextLevelRoot;
implReadFolder( *aNextLevelRoot );
}
}
}
} catch( const Exception& )
{
TOOLS_WARN_EXCEPTION( "svtools", "TemplateFolderCacheImpl::implReadFolder" ); returnfalse;
} returntrue;
}
// the template directories from the config const SvtPathOptions aPathOptions; const OUString& aDirs = aPathOptions.GetTemplatePath();
// loop through all the root-level template folders
sal_Int32 nIndex = 0; do
{
OUString sTemplatePath( aDirs.getToken(0, ';', nIndex) );
sTemplatePath = aPathOptions.ExpandMacros( sTemplatePath );
// Make sure excess ".." path segments (from expanding bootstrap // variables in paths) are normalized in the same way they are // normalized for paths read from the .templdir.cache file (where // paths have gone through makeRelocatable URL on writing out and // then through makeAbsoluteURL when reading back in), as otherwise // equalStates() in needsUpdate() could erroneously consider // m_aCurrentState and m_aPreviousState as different:
sTemplatePath = getOfficeInstDirs()->makeAbsoluteURL(
getOfficeInstDirs()->makeRelocatableURL(sTemplatePath));
// create a new entry
m_aCurrentState.push_back( new TemplateContent( INetURLObject( sTemplatePath ) ) );
TemplateFolderContent::iterator aCurrentRoot = m_aCurrentState.end();
--aCurrentRoot;
if ( !implReadFolder( *aCurrentRoot ) ) returnfalse;
} while ( nIndex >= 0 );
// normalize the array (which basically means "sort it")
normalize( m_aCurrentState );
bool TemplateFolderCacheImpl::readPreviousState()
{
DBG_ASSERT( m_pCacheStream, "TemplateFolderCacheImpl::readPreviousState: not to be called without stream!" );
// check the magic number
sal_Int32 nMagic = 0;
m_pCacheStream->ReadInt32( nMagic );
DBG_ASSERT( getMagicNumber() == nMagic, "TemplateFolderCacheImpl::readPreviousState: invalid cache file!" ); if ( getMagicNumber() != nMagic ) returnfalse;
// the root directories // their number
sal_Int32 nRootDirectories = 0;
m_pCacheStream->ReadInt32( nRootDirectories ); // init empty TemplateContents with the URLs
m_aPreviousState.reserve( nRootDirectories ); while ( nRootDirectories-- )
{
OUString sURL = m_pCacheStream->ReadUniOrByteString(m_pCacheStream->GetStreamCharSet()); // #116281# Keep office installation relocatable. Never store // any direct references to office installation directory.
sURL = getOfficeInstDirs()->makeAbsoluteURL( sURL );
m_aPreviousState.push_back( new TemplateContent( INetURLObject(sURL) ) );
}
// read the contents of the root folders
::std::for_each(
m_aPreviousState.begin(),
m_aPreviousState.end(),
ReadFolderContent( *m_pCacheStream, getOfficeInstDirs() )
);
DBG_ASSERT( !m_pCacheStream->GetErrorCode(), "TemplateFolderCacheImpl::readPreviousState: unknown error during reading the state cache!" );
// normalize the array (which basically means "sort it")
normalize( m_aPreviousState );
returntrue;
}
bool TemplateFolderCacheImpl::openCacheStream( bool _bForRead )
{ // close any old stream instance
closeCacheStream( );
// get the storage directory
OUString sStorageURL = implParseSmart( SvtPathOptions().GetStoragePath() );
INetURLObject aStorageURL( sStorageURL ); if ( INetProtocol::NotValid == aStorageURL.GetProtocol() )
{
OSL_FAIL( "TemplateFolderCacheImpl::openCacheStream: invalid storage path!" ); returnfalse;
}
// append our name
aStorageURL.Append( u".templdir.cache" );
// open the stream
m_pCacheStream = UcbStreamHelper::CreateStream( aStorageURL.GetMainURL( INetURLObject::DecodeMechanism::ToIUri ),
_bForRead ? StreamMode::READ | StreamMode::NOCREATE : StreamMode::WRITE | StreamMode::TRUNC );
DBG_ASSERT( m_pCacheStream, "TemplateFolderCacheImpl::openCacheStream: could not open/create the cache stream!" ); if ( m_pCacheStream && m_pCacheStream->GetErrorCode() )
{
m_pCacheStream.reset();
}
if ( m_pCacheStream )
m_pCacheStream->SetStreamCharSet( RTL_TEXTENCODING_UTF8 );
return nullptr != m_pCacheStream;
}
bool TemplateFolderCacheImpl::needsUpdate()
{ if ( m_bKnowState ) return m_bNeedsUpdate;
m_bNeedsUpdate = true;
m_bKnowState = true;
if ( readCurrentState() )
{ // open the stream which contains the cached state of the directories if ( openCacheStream( true ) )
{ // opening the stream succeeded if ( readPreviousState() )
{
m_bNeedsUpdate = !equalStates( m_aPreviousState, m_aCurrentState );
} else
{
closeCacheStream();
}
}
} return m_bNeedsUpdate;
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.