716 lines
26 KiB
C++
716 lines
26 KiB
C++
/* -*- 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 .
|
|
*/
|
|
|
|
#include <config_folders.h>
|
|
|
|
#include <comphelper/lok.hxx>
|
|
#include <comphelper/compbase.hxx>
|
|
#include <cppuhelper/supportsservice.hxx>
|
|
|
|
#include <unotools/bootstrap.hxx>
|
|
#include <unotools/configmgr.hxx>
|
|
#include <osl/file.hxx>
|
|
#include <osl/security.hxx>
|
|
#include <osl/thread.hxx>
|
|
#include <i18nlangtag/languagetag.hxx>
|
|
#include <tools/urlobj.hxx>
|
|
#include <rtl/ustrbuf.hxx>
|
|
#include <rtl/bootstrap.hxx>
|
|
|
|
#include <officecfg/Office/Paths.hxx>
|
|
|
|
#include <com/sun/star/lang/XInitialization.hpp>
|
|
#include <com/sun/star/lang/XServiceInfo.hpp>
|
|
#include <com/sun/star/container/NoSuchElementException.hpp>
|
|
#include <com/sun/star/container/XHierarchicalNameAccess.hpp>
|
|
#include <com/sun/star/container/XNameAccess.hpp>
|
|
#include <com/sun/star/util/XStringSubstitution.hpp>
|
|
|
|
#include <unordered_map>
|
|
|
|
using namespace com::sun::star::uno;
|
|
using namespace com::sun::star::container;
|
|
|
|
namespace {
|
|
|
|
enum PreDefVariable
|
|
{
|
|
PREDEFVAR_INST,
|
|
PREDEFVAR_PROG,
|
|
PREDEFVAR_USER,
|
|
PREDEFVAR_WORK,
|
|
PREDEFVAR_HOME,
|
|
PREDEFVAR_TEMP,
|
|
PREDEFVAR_PATH,
|
|
PREDEFVAR_USERNAME,
|
|
PREDEFVAR_LANGID,
|
|
PREDEFVAR_VLANG,
|
|
PREDEFVAR_INSTPATH,
|
|
PREDEFVAR_PROGPATH,
|
|
PREDEFVAR_USERPATH,
|
|
PREDEFVAR_INSTURL,
|
|
PREDEFVAR_PROGURL,
|
|
PREDEFVAR_USERURL,
|
|
PREDEFVAR_WORKDIRURL,
|
|
// New variable of hierarchy service (#i32656#)
|
|
PREDEFVAR_BASEINSTURL,
|
|
PREDEFVAR_USERDATAURL,
|
|
PREDEFVAR_BRANDBASEURL,
|
|
PREDEFVAR_COUNT
|
|
};
|
|
|
|
struct FixedVariable
|
|
{
|
|
OUString pVarName;
|
|
bool bAbsPath;
|
|
};
|
|
|
|
// Table with all fixed/predefined variables supported.
|
|
constexpr FixedVariable aFixedVarTable[PREDEFVAR_COUNT] =
|
|
{
|
|
{ u"$(inst)"_ustr, true }, // PREDEFVAR_INST
|
|
{ u"$(prog)"_ustr, true }, // PREDEFVAR_PROG
|
|
{ u"$(user)"_ustr, true }, // PREDEFVAR_USER
|
|
{ u"$(work)"_ustr, true }, // PREDEFVAR_WORK, special variable
|
|
// (transient)
|
|
{ u"$(home)"_ustr, true }, // PREDEFVAR_HOME
|
|
{ u"$(temp)"_ustr, true }, // PREDEFVAR_TEMP
|
|
{ u"$(path)"_ustr, true }, // PREDEFVAR_PATH
|
|
{ u"$(username)"_ustr, false }, // PREDEFVAR_USERNAME
|
|
{ u"$(langid)"_ustr, false }, // PREDEFVAR_LANGID
|
|
{ u"$(vlang)"_ustr, false }, // PREDEFVAR_VLANG
|
|
{ u"$(instpath)"_ustr, true }, // PREDEFVAR_INSTPATH
|
|
{ u"$(progpath)"_ustr, true }, // PREDEFVAR_PROGPATH
|
|
{ u"$(userpath)"_ustr, true }, // PREDEFVAR_USERPATH
|
|
{ u"$(insturl)"_ustr, true }, // PREDEFVAR_INSTURL
|
|
{ u"$(progurl)"_ustr, true }, // PREDEFVAR_PROGURL
|
|
{ u"$(userurl)"_ustr, true }, // PREDEFVAR_USERURL
|
|
{ u"$(workdirurl)"_ustr, true }, // PREDEFVAR_WORKDIRURL, special variable
|
|
// (transient) and don't use for
|
|
// resubstitution
|
|
{ u"$(baseinsturl)"_ustr, true }, // PREDEFVAR_BASEINSTURL
|
|
{ u"$(userdataurl)"_ustr, true }, // PREDEFVAR_USERDATAURL
|
|
{ u"$(brandbaseurl)"_ustr, true } // PREDEFVAR_BRANDBASEURL
|
|
};
|
|
|
|
struct PredefinedPathVariables
|
|
{
|
|
// Predefined variables supported by substitute variables
|
|
LanguageType m_eLanguageType; // Language type of Office
|
|
OUString m_FixedVar[ PREDEFVAR_COUNT ]; // Variable value access by PreDefVariable
|
|
OUString m_FixedVarNames[ PREDEFVAR_COUNT ]; // Variable name access by PreDefVariable
|
|
};
|
|
|
|
struct ReSubstFixedVarOrder
|
|
{
|
|
sal_Int32 nVarValueLength;
|
|
PreDefVariable eVariable;
|
|
|
|
bool operator< ( const ReSubstFixedVarOrder& aFixedVarOrder ) const
|
|
{
|
|
// Reverse operator< to have high to low ordering
|
|
return ( nVarValueLength > aFixedVarOrder.nVarValueLength );
|
|
}
|
|
};
|
|
|
|
typedef comphelper::WeakComponentImplHelper<
|
|
css::util::XStringSubstitution,
|
|
css::lang::XServiceInfo,
|
|
css::lang::XInitialization > SubstitutePathVariables_BASE;
|
|
|
|
class SubstitutePathVariables : public SubstitutePathVariables_BASE
|
|
{
|
|
public:
|
|
explicit SubstitutePathVariables();
|
|
|
|
virtual OUString SAL_CALL getImplementationName() override
|
|
{
|
|
return u"com.sun.star.comp.framework.PathSubstitution"_ustr;
|
|
}
|
|
|
|
virtual sal_Bool SAL_CALL supportsService(OUString const & ServiceName) override
|
|
{
|
|
return cppu::supportsService(this, ServiceName);
|
|
}
|
|
|
|
virtual css::uno::Sequence<OUString> SAL_CALL getSupportedServiceNames() override
|
|
{
|
|
return {u"com.sun.star.util.PathSubstitution"_ustr};
|
|
}
|
|
|
|
// XStringSubstitution
|
|
virtual OUString SAL_CALL substituteVariables( const OUString& aText, sal_Bool bSubstRequired ) override;
|
|
virtual OUString SAL_CALL reSubstituteVariables( const OUString& aText ) override;
|
|
virtual OUString SAL_CALL getSubstituteVariableValue( const OUString& variable ) override;
|
|
|
|
// XInitialization
|
|
virtual void SAL_CALL initialize(const css::uno::Sequence<css::uno::Any>& /*rArguments*/) override;
|
|
|
|
private:
|
|
void impl_initialize();
|
|
|
|
void SetPredefinedPathVariables();
|
|
|
|
// Special case (transient) values can change during runtime!
|
|
// Don't store them in the pre defined struct
|
|
static OUString GetWorkPath();
|
|
static OUString GetWorkVariableValue();
|
|
static OUString GetPathVariableValue();
|
|
|
|
static OUString GetHomeVariableValue();
|
|
|
|
// XStringSubstitution implementation methods
|
|
/// @throws css::container::NoSuchElementException
|
|
/// @throws css::uno::RuntimeException
|
|
OUString impl_substituteVariable( const OUString& aText, bool bSustRequired );
|
|
/// @throws css::uno::RuntimeException
|
|
OUString impl_reSubstituteVariables( const OUString& aText );
|
|
/// @throws css::container::NoSuchElementException
|
|
/// @throws css::uno::RuntimeException
|
|
OUString const & impl_getSubstituteVariableValue( const OUString& variable );
|
|
|
|
private:
|
|
typedef std::unordered_map<OUString, PreDefVariable>
|
|
VarNameToIndexMap;
|
|
|
|
VarNameToIndexMap m_aPreDefVarMap; // Mapping from pre-def variable names to enum for array access
|
|
PredefinedPathVariables m_aPreDefVars; // All predefined variables
|
|
std::vector<ReSubstFixedVarOrder> m_aReSubstFixedVarOrder; // To speed up resubstitution fixed variables (order for lookup)
|
|
};
|
|
|
|
SubstitutePathVariables::SubstitutePathVariables()
|
|
{
|
|
impl_initialize();
|
|
}
|
|
|
|
void SubstitutePathVariables::impl_initialize()
|
|
{
|
|
SetPredefinedPathVariables();
|
|
|
|
// Init the predefined/fixed variable to index hash map
|
|
for ( int i = 0; i < PREDEFVAR_COUNT; i++ )
|
|
{
|
|
// Store variable name into struct of predefined/fixed variables
|
|
m_aPreDefVars.m_FixedVarNames[i] = aFixedVarTable[i].pVarName;
|
|
|
|
// Create hash map entry
|
|
m_aPreDefVarMap.emplace( m_aPreDefVars.m_FixedVarNames[i], PreDefVariable(i) );
|
|
}
|
|
|
|
// Sort predefined/fixed variable to path length
|
|
for ( int i = 0; i < PREDEFVAR_COUNT; i++ )
|
|
{
|
|
if (( i != PREDEFVAR_WORKDIRURL ) && ( i != PREDEFVAR_PATH ))
|
|
{
|
|
// Special path variables, don't include into automatic resubstitution search!
|
|
// $(workdirurl) is not allowed to resubstitute! This variable is the value of path settings entry
|
|
// and it could be possible that it will be resubstituted by itself!!
|
|
// Example: WORK_PATH=c:\test, $(workdirurl)=WORK_PATH => WORK_PATH=$(workdirurl) and this cannot be substituted!
|
|
ReSubstFixedVarOrder aFixedVar;
|
|
aFixedVar.eVariable = PreDefVariable(i);
|
|
aFixedVar.nVarValueLength = m_aPreDefVars.m_FixedVar[static_cast<sal_Int32>(aFixedVar.eVariable)].getLength();
|
|
m_aReSubstFixedVarOrder.push_back( aFixedVar );
|
|
}
|
|
}
|
|
sort(m_aReSubstFixedVarOrder.begin(),m_aReSubstFixedVarOrder.end());
|
|
}
|
|
|
|
void SAL_CALL SubstitutePathVariables::initialize(const css::uno::Sequence<css::uno::Any>& /*rArguments*/)
|
|
{
|
|
std::unique_lock g(m_aMutex);
|
|
impl_initialize();
|
|
}
|
|
|
|
// XStringSubstitution
|
|
OUString SAL_CALL SubstitutePathVariables::substituteVariables( const OUString& aText, sal_Bool bSubstRequired )
|
|
{
|
|
std::unique_lock g(m_aMutex);
|
|
return impl_substituteVariable( aText, bSubstRequired );
|
|
}
|
|
|
|
OUString SAL_CALL SubstitutePathVariables::reSubstituteVariables( const OUString& aText )
|
|
{
|
|
std::unique_lock g(m_aMutex);
|
|
return impl_reSubstituteVariables( aText );
|
|
}
|
|
|
|
OUString SAL_CALL SubstitutePathVariables::getSubstituteVariableValue( const OUString& aVariable )
|
|
{
|
|
std::unique_lock g(m_aMutex);
|
|
return impl_getSubstituteVariableValue( aVariable );
|
|
}
|
|
|
|
// static
|
|
OUString SubstitutePathVariables::GetWorkPath()
|
|
{
|
|
OUString aWorkPath;
|
|
css::uno::Reference< css::container::XHierarchicalNameAccess > xPaths(officecfg::Office::Paths::Paths::get(), css::uno::UNO_QUERY_THROW);
|
|
if (!(xPaths->getByHierarchicalName(u"['Work']/WritePath"_ustr) >>= aWorkPath))
|
|
// fallback in case config layer does not return a usable work dir value.
|
|
aWorkPath = GetWorkVariableValue();
|
|
|
|
return aWorkPath;
|
|
}
|
|
|
|
// static
|
|
OUString SubstitutePathVariables::GetWorkVariableValue()
|
|
{
|
|
OUString aWorkPath;
|
|
std::optional<OUString> x(officecfg::Office::Paths::Variables::Work::get());
|
|
if (!x)
|
|
{
|
|
// fallback to $HOME in case platform dependent config layer does not return
|
|
// a usable work dir value.
|
|
osl::Security aSecurity;
|
|
aSecurity.getHomeDir( aWorkPath );
|
|
}
|
|
else
|
|
aWorkPath = *x;
|
|
return aWorkPath;
|
|
}
|
|
|
|
// static
|
|
OUString SubstitutePathVariables::GetHomeVariableValue()
|
|
{
|
|
osl::Security aSecurity;
|
|
OUString aHomePath;
|
|
|
|
aSecurity.getHomeDir( aHomePath );
|
|
return aHomePath;
|
|
}
|
|
|
|
// static
|
|
OUString SubstitutePathVariables::GetPathVariableValue()
|
|
{
|
|
OUString aRetStr;
|
|
const char* pEnv = getenv( "PATH" );
|
|
|
|
if ( pEnv )
|
|
{
|
|
const int PATH_EXTEND_FACTOR = 200;
|
|
OUString aTmp;
|
|
OUString aPathList( pEnv, strlen( pEnv ), osl_getThreadTextEncoding() );
|
|
OUStringBuffer aPathStrBuffer( aPathList.getLength() * PATH_EXTEND_FACTOR / 100 );
|
|
|
|
bool bAppendSep = false;
|
|
sal_Int32 nToken = 0;
|
|
do
|
|
{
|
|
OUString sToken = aPathList.getToken(0, SAL_PATHSEPARATOR, nToken);
|
|
if (!sToken.isEmpty() &&
|
|
osl::FileBase::getFileURLFromSystemPath( sToken, aTmp ) ==
|
|
osl::FileBase::RC::E_None )
|
|
{
|
|
if ( bAppendSep )
|
|
aPathStrBuffer.append( ";" ); // Office uses ';' as path separator
|
|
aPathStrBuffer.append( aTmp );
|
|
bAppendSep = true;
|
|
}
|
|
}
|
|
while(nToken>=0);
|
|
|
|
aRetStr = aPathStrBuffer.makeStringAndClear();
|
|
}
|
|
|
|
return aRetStr;
|
|
}
|
|
|
|
OUString SubstitutePathVariables::impl_substituteVariable( const OUString& rText, bool bSubstRequired )
|
|
{
|
|
// This is maximal recursive depth supported!
|
|
const sal_Int32 nMaxRecursiveDepth = 8;
|
|
|
|
OUString aWorkText = rText;
|
|
OUString aResult;
|
|
|
|
// Use vector with strings to detect endless recursions!
|
|
std::vector< OUString > aEndlessRecursiveDetector;
|
|
|
|
// Search for first occurrence of "$(...".
|
|
sal_Int32 nDepth = 0;
|
|
bool bSubstitutionCompleted = false;
|
|
sal_Int32 nPosition = aWorkText.indexOf( "$(" );
|
|
sal_Int32 nLength = 0; // = count of letters from "$(" to ")" in string
|
|
bool bVarNotSubstituted = false;
|
|
|
|
// Have we found any variable like "$(...)"?
|
|
if ( nPosition != -1 )
|
|
{
|
|
// Yes; Get length of found variable.
|
|
// If no ")" was found - nLength is set to 0 by default! see before.
|
|
sal_Int32 nEndPosition = aWorkText.indexOf( ')', nPosition );
|
|
if ( nEndPosition != -1 )
|
|
nLength = nEndPosition - nPosition + 1;
|
|
}
|
|
|
|
// Is there something to replace ?
|
|
bool bWorkRetrieved = false;
|
|
bool bWorkDirURLRetrieved = false;
|
|
while (nDepth < nMaxRecursiveDepth)
|
|
{
|
|
while ( ( nPosition != -1 ) && ( nLength > 3 ) ) // "$(" ")"
|
|
{
|
|
// YES; Get the next variable for replace.
|
|
sal_Int32 nReplaceLength = 0;
|
|
OUString aReplacement;
|
|
OUString aSubString = aWorkText.copy( nPosition, nLength );
|
|
|
|
// Path variables are not case sensitive!
|
|
OUString aSubVarString = aSubString.toAsciiLowerCase();
|
|
VarNameToIndexMap::const_iterator pNTOIIter = m_aPreDefVarMap.find( aSubVarString );
|
|
if ( pNTOIIter != m_aPreDefVarMap.end() )
|
|
{
|
|
// Fixed/Predefined variable found
|
|
PreDefVariable nIndex = pNTOIIter->second;
|
|
|
|
// Determine variable value and length from array/table
|
|
if ( nIndex == PREDEFVAR_WORK && !bWorkRetrieved )
|
|
{
|
|
// Transient value, retrieve it again
|
|
m_aPreDefVars.m_FixedVar[ nIndex ] = GetWorkVariableValue();
|
|
bWorkRetrieved = true;
|
|
}
|
|
else if ( nIndex == PREDEFVAR_WORKDIRURL && !bWorkDirURLRetrieved )
|
|
{
|
|
// Transient value, retrieve it again
|
|
m_aPreDefVars.m_FixedVar[ nIndex ] = GetWorkPath();
|
|
bWorkDirURLRetrieved = true;
|
|
}
|
|
|
|
// Check preconditions to substitute path variables.
|
|
// 1. A path variable can only be substituted if it follows a ';'!
|
|
// 2. It's located exactly at the start of the string being substituted!
|
|
if (( aFixedVarTable[ int( nIndex ) ].bAbsPath && (( nPosition == 0 ) || (( nPosition > 0 ) && ( aWorkText[nPosition-1] == ';')))) ||
|
|
( !aFixedVarTable[ int( nIndex ) ].bAbsPath ))
|
|
{
|
|
aReplacement = m_aPreDefVars.m_FixedVar[ nIndex ];
|
|
nReplaceLength = nLength;
|
|
}
|
|
}
|
|
|
|
// Have we found something to replace?
|
|
if ( nReplaceLength > 0 )
|
|
{
|
|
// Yes ... then do it.
|
|
aWorkText = aWorkText.replaceAt( nPosition, nReplaceLength, aReplacement );
|
|
}
|
|
else
|
|
{
|
|
// Variable not known
|
|
bVarNotSubstituted = true;
|
|
nPosition += nLength;
|
|
}
|
|
|
|
// Step after replaced text! If no text was replaced (unknown variable!),
|
|
// length of aReplacement is 0 ... and we don't step then.
|
|
nPosition += aReplacement.getLength();
|
|
|
|
// We must control index in string before call something at OUString!
|
|
// The OUString-implementation don't do it for us :-( but the result is not defined otherwise.
|
|
if ( nPosition + 1 > aWorkText.getLength() )
|
|
{
|
|
// Position is out of range. Break loop!
|
|
nPosition = -1;
|
|
nLength = 0;
|
|
}
|
|
else
|
|
{
|
|
// Else; Position is valid. Search for next variable to replace.
|
|
nPosition = aWorkText.indexOf( "$(", nPosition );
|
|
// Have we found any variable like "$(...)"?
|
|
if ( nPosition != -1 )
|
|
{
|
|
// Yes; Get length of found variable. If no ")" was found - nLength must set to 0!
|
|
nLength = 0;
|
|
sal_Int32 nEndPosition = aWorkText.indexOf( ')', nPosition );
|
|
if ( nEndPosition != -1 )
|
|
nLength = nEndPosition - nPosition + 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
nPosition = aWorkText.indexOf( "$(" );
|
|
if ( nPosition == -1 )
|
|
{
|
|
bSubstitutionCompleted = true;
|
|
break; // All variables are substituted
|
|
}
|
|
else
|
|
{
|
|
// Check for recursion
|
|
const sal_uInt32 nCount = aEndlessRecursiveDetector.size();
|
|
for ( sal_uInt32 i=0; i < nCount; i++ )
|
|
{
|
|
if ( aEndlessRecursiveDetector[i] == aWorkText )
|
|
{
|
|
if ( bVarNotSubstituted )
|
|
break; // Not all variables could be substituted!
|
|
else
|
|
{
|
|
nDepth = nMaxRecursiveDepth;
|
|
break; // Recursion detected!
|
|
}
|
|
}
|
|
}
|
|
|
|
aEndlessRecursiveDetector.push_back( aWorkText );
|
|
|
|
// Initialize values for next
|
|
sal_Int32 nEndPosition = aWorkText.indexOf( ')', nPosition );
|
|
if ( nEndPosition != -1 )
|
|
nLength = nEndPosition - nPosition + 1;
|
|
bVarNotSubstituted = false;
|
|
++nDepth;
|
|
}
|
|
}
|
|
|
|
// Fill return value with result
|
|
if ( bSubstitutionCompleted )
|
|
{
|
|
// Substitution successful!
|
|
aResult = aWorkText;
|
|
}
|
|
else
|
|
{
|
|
// Substitution not successful!
|
|
if ( nDepth == nMaxRecursiveDepth )
|
|
{
|
|
// recursion depth reached!
|
|
if ( bSubstRequired )
|
|
{
|
|
throw NoSuchElementException( u"Endless recursion detected. Cannot substitute variables!"_ustr, static_cast<cppu::OWeakObject *>(this) );
|
|
}
|
|
aResult = rText;
|
|
}
|
|
else
|
|
{
|
|
// variable in text but unknown!
|
|
if ( bSubstRequired )
|
|
{
|
|
throw NoSuchElementException( u"Unknown variable found!"_ustr, static_cast<cppu::OWeakObject *>(this) );
|
|
}
|
|
aResult = aWorkText;
|
|
}
|
|
}
|
|
|
|
return aResult;
|
|
}
|
|
|
|
OUString SubstitutePathVariables::impl_reSubstituteVariables( const OUString& rURL )
|
|
{
|
|
OUString aURL;
|
|
|
|
INetURLObject aUrl( rURL );
|
|
if ( !aUrl.HasError() )
|
|
aURL = aUrl.GetMainURL( INetURLObject::DecodeMechanism::NONE );
|
|
else
|
|
{
|
|
// Convert a system path to a UCB compliant URL before resubstitution
|
|
OUString aTemp;
|
|
if ( osl::FileBase::getFileURLFromSystemPath( rURL, aTemp ) == osl::FileBase::E_None )
|
|
{
|
|
aURL = INetURLObject( aTemp ).GetMainURL( INetURLObject::DecodeMechanism::NONE );
|
|
if( aURL.isEmpty() )
|
|
return rURL;
|
|
}
|
|
else
|
|
{
|
|
// rURL is not a valid URL nor a osl system path. Give up and return error!
|
|
return rURL;
|
|
}
|
|
}
|
|
|
|
// Get transient predefined path variable $(work) value before starting resubstitution
|
|
m_aPreDefVars.m_FixedVar[ PREDEFVAR_WORK ] = GetWorkVariableValue();
|
|
|
|
for (;;)
|
|
{
|
|
bool bVariableFound = false;
|
|
|
|
for (auto const & i: m_aReSubstFixedVarOrder)
|
|
{
|
|
OUString aValue = m_aPreDefVars.m_FixedVar[i.eVariable];
|
|
sal_Int32 nPos = aURL.indexOf( aValue );
|
|
if ( nPos >= 0 )
|
|
{
|
|
bool bMatch = true;
|
|
if ( !aFixedVarTable[i.eVariable].bAbsPath )
|
|
{
|
|
// Special path variables as they can occur in the middle of a path. Only match if they
|
|
// describe a whole directory and not only a substring of a directory!
|
|
// (Ideally, all substitutions should stick to syntactical
|
|
// boundaries within the given URL, like not covering only
|
|
// part of a URL path segment; however, at least when saving
|
|
// an Impress document, one URL that is passed in is of the
|
|
// form <file:///.../share/palette%3Bfile:///.../user/
|
|
// config/standard.sob>, re-substituted to
|
|
// <$(inst)/share/palette%3B$(user)/config/standard.sob>.)
|
|
const sal_Unicode* pStr = aURL.getStr();
|
|
|
|
if ( nPos > 0 )
|
|
bMatch = ( aURL[ nPos-1 ] == '/' );
|
|
|
|
if ( bMatch )
|
|
{
|
|
if ( nPos + aValue.getLength() < aURL.getLength() )
|
|
bMatch = ( pStr[ nPos + aValue.getLength() ] == '/' );
|
|
}
|
|
}
|
|
|
|
if ( bMatch )
|
|
{
|
|
aURL = aURL.replaceAt(
|
|
nPos, aValue.getLength(),
|
|
m_aPreDefVars.m_FixedVarNames[i.eVariable]);
|
|
bVariableFound = true; // Resubstitution not finished yet!
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if ( !bVariableFound )
|
|
{
|
|
return aURL;
|
|
}
|
|
}
|
|
}
|
|
|
|
// This method support both request schemes "$("<varname>")" or "<varname>".
|
|
OUString const & SubstitutePathVariables::impl_getSubstituteVariableValue( const OUString& rVariable )
|
|
{
|
|
OUString aVariable;
|
|
|
|
sal_Int32 nPos = rVariable.indexOf( "$(" );
|
|
if ( nPos == -1 )
|
|
{
|
|
// Prepare variable name before hash map access
|
|
aVariable = "$(" + rVariable + ")";
|
|
}
|
|
|
|
VarNameToIndexMap::const_iterator pNTOIIter = m_aPreDefVarMap.find( ( nPos == -1 ) ? aVariable : rVariable );
|
|
|
|
// Fixed/Predefined variable
|
|
if ( pNTOIIter == m_aPreDefVarMap.end() )
|
|
{
|
|
throw NoSuchElementException(u"Unknown variable!"_ustr, static_cast<cppu::OWeakObject *>(this));
|
|
}
|
|
PreDefVariable nIndex = pNTOIIter->second;
|
|
return m_aPreDefVars.m_FixedVar[static_cast<sal_Int32>(nIndex)];
|
|
}
|
|
|
|
void SubstitutePathVariables::SetPredefinedPathVariables()
|
|
{
|
|
m_aPreDefVars.m_FixedVar[PREDEFVAR_BRANDBASEURL] = "$BRAND_BASE_DIR";
|
|
rtl::Bootstrap::expandMacros(
|
|
m_aPreDefVars.m_FixedVar[PREDEFVAR_BRANDBASEURL]);
|
|
|
|
// Get inspath and userpath from bootstrap mechanism in every case as file URL
|
|
::utl::Bootstrap::PathStatus aState;
|
|
OUString sVal;
|
|
|
|
aState = utl::Bootstrap::locateUserData( sVal );
|
|
//There can be the valid case that there is no user installation.
|
|
//TODO: Is that still the case? (With OOo 3.4, "unopkg sync" was run as part
|
|
// of the setup. Then no user installation was required.)
|
|
//Therefore we do not assert here.
|
|
// It's not possible to detect when an empty value would actually be used.
|
|
// (note: getenv is a hack to detect if we're running in a unit test)
|
|
// Also, it's okay to have an empty user installation path in case of LOK
|
|
if (aState == ::utl::Bootstrap::PATH_EXISTS || getenv("SRC_ROOT") ||
|
|
(comphelper::LibreOfficeKit::isActive() && aState == ::utl::Bootstrap::PATH_VALID))
|
|
{
|
|
m_aPreDefVars.m_FixedVar[ PREDEFVAR_USERPATH ] = sVal;
|
|
}
|
|
|
|
// Set $(inst), $(instpath), $(insturl)
|
|
m_aPreDefVars.m_FixedVar[ PREDEFVAR_INSTPATH ] = m_aPreDefVars.m_FixedVar[PREDEFVAR_BRANDBASEURL];
|
|
m_aPreDefVars.m_FixedVar[ PREDEFVAR_INSTURL ] = m_aPreDefVars.m_FixedVar[ PREDEFVAR_INSTPATH ];
|
|
m_aPreDefVars.m_FixedVar[ PREDEFVAR_INST ] = m_aPreDefVars.m_FixedVar[ PREDEFVAR_INSTPATH ];
|
|
// New variable of hierarchy service (#i32656#)
|
|
m_aPreDefVars.m_FixedVar[ PREDEFVAR_BASEINSTURL ]= m_aPreDefVars.m_FixedVar[ PREDEFVAR_INSTPATH ];
|
|
|
|
// Set $(user), $(userpath), $(userurl)
|
|
m_aPreDefVars.m_FixedVar[ PREDEFVAR_USERURL ] = m_aPreDefVars.m_FixedVar[ PREDEFVAR_USERPATH ];
|
|
m_aPreDefVars.m_FixedVar[ PREDEFVAR_USER ] = m_aPreDefVars.m_FixedVar[ PREDEFVAR_USERPATH ];
|
|
// New variable of hierarchy service (#i32656#)
|
|
m_aPreDefVars.m_FixedVar[ PREDEFVAR_USERDATAURL ]= m_aPreDefVars.m_FixedVar[ PREDEFVAR_USERPATH ];
|
|
|
|
// Detect the program directory
|
|
// Set $(prog), $(progpath), $(progurl)
|
|
INetURLObject aProgObj(
|
|
m_aPreDefVars.m_FixedVar[PREDEFVAR_BRANDBASEURL] );
|
|
if ( !aProgObj.HasError() && aProgObj.insertName( u"" LIBO_BIN_FOLDER ) )
|
|
{
|
|
m_aPreDefVars.m_FixedVar[ PREDEFVAR_PROGPATH ] = aProgObj.GetMainURL(INetURLObject::DecodeMechanism::NONE);
|
|
m_aPreDefVars.m_FixedVar[ PREDEFVAR_PROGURL ] = m_aPreDefVars.m_FixedVar[ PREDEFVAR_PROGPATH ];
|
|
m_aPreDefVars.m_FixedVar[ PREDEFVAR_PROG ] = m_aPreDefVars.m_FixedVar[ PREDEFVAR_PROGPATH ];
|
|
}
|
|
|
|
// Set $(username)
|
|
OUString aSystemUser;
|
|
::osl::Security aSecurity;
|
|
aSecurity.getUserName( aSystemUser, false );
|
|
m_aPreDefVars.m_FixedVar[ PREDEFVAR_USERNAME ] = aSystemUser;
|
|
|
|
// Detect the language type of the current office
|
|
m_aPreDefVars.m_eLanguageType = LANGUAGE_ENGLISH_US;
|
|
OUString aLocaleStr( utl::ConfigManager::getUILocale() );
|
|
m_aPreDefVars.m_eLanguageType = LanguageTag::convertToLanguageTypeWithFallback( aLocaleStr );
|
|
// We used to have an else branch here with a SAL_WARN, but that
|
|
// always fired in some unit tests when this code was built with
|
|
// debug=t, so it seems fairly pointless, especially as
|
|
// m_aPreDefVars.m_eLanguageType has been initialized to a
|
|
// default value above anyway.
|
|
|
|
// Set $(vlang)
|
|
m_aPreDefVars.m_FixedVar[ PREDEFVAR_VLANG ] = aLocaleStr;
|
|
|
|
// Set $(langid)
|
|
m_aPreDefVars.m_FixedVar[ PREDEFVAR_LANGID ] = OUString::number( static_cast<sal_uInt16>(m_aPreDefVars.m_eLanguageType) );
|
|
|
|
// Set the other pre defined path variables
|
|
// Set $(work)
|
|
m_aPreDefVars.m_FixedVar[ PREDEFVAR_WORK ] = GetWorkVariableValue();
|
|
m_aPreDefVars.m_FixedVar[ PREDEFVAR_HOME ] = GetHomeVariableValue();
|
|
|
|
// Set $(workdirurl) this is the value of the path PATH_WORK which doesn't make sense
|
|
// anymore because the path settings service has this value! It can deliver this value more
|
|
// quickly than the substitution service!
|
|
m_aPreDefVars.m_FixedVar[ PREDEFVAR_WORKDIRURL ] = GetWorkPath();
|
|
|
|
// Set $(path) variable
|
|
m_aPreDefVars.m_FixedVar[ PREDEFVAR_PATH ] = GetPathVariableValue();
|
|
|
|
// Set $(temp)
|
|
OUString aTmp;
|
|
osl::FileBase::getTempDirURL( aTmp );
|
|
m_aPreDefVars.m_FixedVar[ PREDEFVAR_TEMP ] = aTmp;
|
|
}
|
|
|
|
}
|
|
|
|
extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface *
|
|
com_sun_star_comp_framework_PathSubstitution_get_implementation(
|
|
css::uno::XComponentContext *,
|
|
css::uno::Sequence<css::uno::Any> const &)
|
|
{
|
|
return cppu::acquire(new SubstitutePathVariables());
|
|
}
|
|
|
|
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|