20#include <config_folders.h>
28#include <osl/file.hxx>
29#include <osl/security.hxx>
30#include <osl/thread.hxx>
33#include <rtl/ustrbuf.hxx>
34#include <rtl/bootstrap.hxx>
36#include <officecfg/Office/Paths.hxx>
38#include <com/sun/star/lang/XServiceInfo.hpp>
39#include <com/sun/star/container/NoSuchElementException.hpp>
40#include <com/sun/star/container/XHierarchicalNameAccess.hpp>
41#include <com/sun/star/container/XNameAccess.hpp>
42#include <com/sun/star/util/XStringSubstitution.hpp>
44#include <unordered_map>
71 PREDEFVAR_BASEINSTURL,
72 PREDEFVAR_USERDATAURL,
73 PREDEFVAR_BRANDBASEURL,
84const FixedVariable aFixedVarTable[PREDEFVAR_COUNT] =
94 {
"$(username)",
false },
95 {
"$(langid)",
false },
96 {
"$(vlang)",
false },
97 {
"$(instpath)",
true },
98 {
"$(progpath)",
true },
99 {
"$(userpath)",
true },
100 {
"$(insturl)",
true },
101 {
"$(progurl)",
true },
102 {
"$(userurl)",
true },
103 {
"$(workdirurl)",
true },
106 {
"$(baseinsturl)",
true },
107 {
"$(userdataurl)",
true },
108 {
"$(brandbaseurl)",
true }
111struct PredefinedPathVariables
115 OUString m_FixedVar[ PREDEFVAR_COUNT ];
116 OUString m_FixedVarNames[ PREDEFVAR_COUNT ];
119struct ReSubstFixedVarOrder
121 sal_Int32 nVarValueLength;
122 PreDefVariable eVariable;
124 bool operator< (
const ReSubstFixedVarOrder& aFixedVarOrder )
const
127 return ( nVarValueLength > aFixedVarOrder.nVarValueLength );
132 css::util::XStringSubstitution,
133 css::lang::XServiceInfo > SubstitutePathVariables_BASE;
135class SubstitutePathVariables :
public SubstitutePathVariables_BASE
138 explicit SubstitutePathVariables();
142 return "com.sun.star.comp.framework.PathSubstitution";
152 return {
"com.sun.star.util.PathSubstitution"};
156 virtual OUString SAL_CALL substituteVariables(
const OUString& aText,
sal_Bool bSubstRequired )
override;
157 virtual OUString SAL_CALL reSubstituteVariables(
const OUString& aText )
override;
158 virtual OUString SAL_CALL getSubstituteVariableValue(
const OUString& variable )
override;
161 void SetPredefinedPathVariables();
165 OUString GetWorkPath()
const;
166 OUString GetWorkVariableValue()
const;
167 OUString GetPathVariableValue()
const;
169 OUString GetHomeVariableValue()
const;
174 OUString impl_substituteVariable(
const OUString& aText,
bool bSustRequired );
176 OUString impl_reSubstituteVariables(
const OUString& aText );
179 OUString
const & impl_getSubstituteVariableValue(
const OUString& variable );
182 typedef std::unordered_map<OUString, PreDefVariable>
185 VarNameToIndexMap m_aPreDefVarMap;
186 PredefinedPathVariables m_aPreDefVars;
187 std::vector<ReSubstFixedVarOrder> m_aReSubstFixedVarOrder;
190SubstitutePathVariables::SubstitutePathVariables()
192 SetPredefinedPathVariables();
195 for (
int i = 0;
i < PREDEFVAR_COUNT;
i++ )
198 m_aPreDefVars.m_FixedVarNames[
i] = OUString::createFromAscii( aFixedVarTable[i].pVarName );
201 m_aPreDefVarMap.emplace( m_aPreDefVars.m_FixedVarNames[i], PreDefVariable(i) );
205 for (
int i = 0;
i < PREDEFVAR_COUNT;
i++ )
207 if (( i != PREDEFVAR_WORKDIRURL ) && ( i != PREDEFVAR_PATH ))
213 ReSubstFixedVarOrder aFixedVar;
214 aFixedVar.eVariable = PreDefVariable(i);
215 aFixedVar.nVarValueLength = m_aPreDefVars.m_FixedVar[
static_cast<sal_Int32
>(aFixedVar.eVariable)].
getLength();
216 m_aReSubstFixedVarOrder.push_back( aFixedVar );
219 sort(m_aReSubstFixedVarOrder.begin(),m_aReSubstFixedVarOrder.end());
223OUString SAL_CALL SubstitutePathVariables::substituteVariables(
const OUString& aText,
sal_Bool bSubstRequired )
226 return impl_substituteVariable( aText, bSubstRequired );
229OUString SAL_CALL SubstitutePathVariables::reSubstituteVariables(
const OUString& aText )
232 return impl_reSubstituteVariables( aText );
235OUString SAL_CALL SubstitutePathVariables::getSubstituteVariableValue(
const OUString& aVariable )
238 return impl_getSubstituteVariableValue( aVariable );
241OUString SubstitutePathVariables::GetWorkPath()
const
244 css::uno::Reference< css::container::XHierarchicalNameAccess > xPaths(officecfg::Office::Paths::Paths::get(), css::uno::UNO_QUERY_THROW);
245 if (!(xPaths->getByHierarchicalName(
"['Work']/WritePath") >>= aWorkPath))
247 aWorkPath = GetWorkVariableValue();
252OUString SubstitutePathVariables::GetWorkVariableValue()
const
255 std::optional<OUString>
x(officecfg::Office::Paths::Variables::Work::get());
260 osl::Security aSecurity;
261 aSecurity.getHomeDir( aWorkPath );
268OUString SubstitutePathVariables::GetHomeVariableValue()
const
270 osl::Security aSecurity;
273 aSecurity.getHomeDir( aHomePath );
277OUString SubstitutePathVariables::GetPathVariableValue()
const
280 const char* pEnv = getenv(
"PATH" );
284 const int PATH_EXTEND_FACTOR = 200;
286 OUString aPathList( pEnv, strlen( pEnv ), osl_getThreadTextEncoding() );
287 OUStringBuffer aPathStrBuffer( aPathList.getLength() * PATH_EXTEND_FACTOR / 100 );
289 bool bAppendSep =
false;
293 OUString sToken = aPathList.getToken(0, SAL_PATHSEPARATOR, nToken);
294 if (!sToken.isEmpty() &&
295 osl::FileBase::getFileURLFromSystemPath( sToken, aTmp ) ==
296 osl::FileBase::RC::E_None )
299 aPathStrBuffer.append(
";" );
300 aPathStrBuffer.append( aTmp );
306 aRetStr = aPathStrBuffer.makeStringAndClear();
312OUString SubstitutePathVariables::impl_substituteVariable(
const OUString& rText,
bool bSubstRequired )
315 const sal_Int32 nMaxRecursiveDepth = 8;
317 OUString aWorkText = rText;
321 std::vector< OUString > aEndlessRecursiveDetector;
324 sal_Int32 nDepth = 0;
325 bool bSubstitutionCompleted =
false;
326 sal_Int32 nPosition = aWorkText.indexOf(
"$(" );
328 bool bVarNotSubstituted =
false;
331 if ( nPosition != -1 )
335 sal_Int32 nEndPosition = aWorkText.indexOf(
')', nPosition );
336 if ( nEndPosition != -1 )
337 nLength = nEndPosition - nPosition + 1;
341 bool bWorkRetrieved =
false;
342 bool bWorkDirURLRetrieved =
false;
343 while (nDepth < nMaxRecursiveDepth)
345 while ( ( nPosition != -1 ) && ( nLength > 3 ) )
348 sal_Int32 nReplaceLength = 0;
349 OUString aReplacement;
350 OUString aSubString = aWorkText.copy( nPosition, nLength );
353 OUString aSubVarString = aSubString.toAsciiLowerCase();
354 VarNameToIndexMap::const_iterator pNTOIIter = m_aPreDefVarMap.find( aSubVarString );
355 if ( pNTOIIter != m_aPreDefVarMap.end() )
358 PreDefVariable
nIndex = pNTOIIter->second;
361 if ( nIndex == PREDEFVAR_WORK && !bWorkRetrieved )
364 m_aPreDefVars.m_FixedVar[
nIndex ] = GetWorkVariableValue();
365 bWorkRetrieved =
true;
367 else if ( nIndex == PREDEFVAR_WORKDIRURL && !bWorkDirURLRetrieved )
370 m_aPreDefVars.m_FixedVar[
nIndex ] = GetWorkPath();
371 bWorkDirURLRetrieved =
true;
377 if (( aFixedVarTable[
int( nIndex ) ].bAbsPath && (( nPosition == 0 ) || (( nPosition > 0 ) && ( aWorkText[nPosition-1] ==
';')))) ||
378 ( !aFixedVarTable[
int( nIndex ) ].bAbsPath ))
380 aReplacement = m_aPreDefVars.m_FixedVar[
nIndex ];
386 if ( nReplaceLength > 0 )
389 aWorkText = aWorkText.replaceAt( nPosition, nReplaceLength, aReplacement );
394 bVarNotSubstituted =
true;
400 nPosition += aReplacement.getLength();
404 if ( nPosition + 1 > aWorkText.getLength() )
413 nPosition = aWorkText.indexOf(
"$(", nPosition );
415 if ( nPosition != -1 )
419 sal_Int32 nEndPosition = aWorkText.indexOf(
')', nPosition );
420 if ( nEndPosition != -1 )
421 nLength = nEndPosition - nPosition + 1;
426 nPosition = aWorkText.indexOf(
"$(" );
427 if ( nPosition == -1 )
429 bSubstitutionCompleted =
true;
435 const sal_uInt32
nCount = aEndlessRecursiveDetector.size();
436 for ( sal_uInt32 i=0;
i <
nCount;
i++ )
438 if ( aEndlessRecursiveDetector[i] == aWorkText )
440 if ( bVarNotSubstituted )
444 nDepth = nMaxRecursiveDepth;
450 aEndlessRecursiveDetector.push_back( aWorkText );
453 sal_Int32 nEndPosition = aWorkText.indexOf(
')', nPosition );
454 if ( nEndPosition != -1 )
455 nLength = nEndPosition - nPosition + 1;
456 bVarNotSubstituted =
false;
462 if ( bSubstitutionCompleted )
470 if ( nDepth == nMaxRecursiveDepth )
473 if ( bSubstRequired )
475 throw NoSuchElementException(
"Endless recursion detected. Cannot substitute variables!",
static_cast<cppu::OWeakObject *
>(
this) );
482 if ( bSubstRequired )
484 throw NoSuchElementException(
"Unknown variable found!",
static_cast<cppu::OWeakObject *
>(
this) );
493OUString SubstitutePathVariables::impl_reSubstituteVariables(
const OUString& rURL )
498 if ( !aUrl.HasError() )
504 if ( osl::FileBase::getFileURLFromSystemPath( rURL, aTemp ) == osl::FileBase::E_None )
518 m_aPreDefVars.m_FixedVar[ PREDEFVAR_WORK ] = GetWorkVariableValue();
522 bool bVariableFound =
false;
524 for (
auto const & i: m_aReSubstFixedVarOrder)
526 OUString aValue = m_aPreDefVars.m_FixedVar[
i.eVariable];
527 sal_Int32
nPos =
aURL.indexOf( aValue );
531 if ( !aFixedVarTable[
i.eVariable].bAbsPath )
549 if ( nPos + aValue.getLength() <
aURL.getLength() )
550 bMatch = ( pStr[ nPos + aValue.getLength() ] ==
'/' );
557 nPos, aValue.getLength(),
558 m_aPreDefVars.m_FixedVarNames[
i.eVariable]);
559 bVariableFound =
true;
565 if ( !bVariableFound )
573OUString
const & SubstitutePathVariables::impl_getSubstituteVariableValue(
const OUString& rVariable )
577 sal_Int32
nPos = rVariable.indexOf(
"$(" );
581 aVariable =
"$(" + rVariable +
")";
584 VarNameToIndexMap::const_iterator pNTOIIter = m_aPreDefVarMap.find( ( nPos == -1 ) ? aVariable : rVariable );
587 if ( pNTOIIter == m_aPreDefVarMap.end() )
589 throw NoSuchElementException(
"Unknown variable!",
static_cast<cppu::OWeakObject *
>(
this));
591 PreDefVariable
nIndex = pNTOIIter->second;
592 return m_aPreDefVars.m_FixedVar[
static_cast<sal_Int32
>(
nIndex)];
595void SubstitutePathVariables::SetPredefinedPathVariables()
598 m_aPreDefVars.m_FixedVar[PREDEFVAR_BRANDBASEURL] =
"$BRAND_BASE_DIR";
599 rtl::Bootstrap::expandMacros(
600 m_aPreDefVars.m_FixedVar[PREDEFVAR_BRANDBASEURL]);
617 m_aPreDefVars.m_FixedVar[ PREDEFVAR_USERPATH ] = sVal;
621 m_aPreDefVars.m_FixedVar[ PREDEFVAR_INSTPATH ] = m_aPreDefVars.m_FixedVar[PREDEFVAR_BRANDBASEURL];
622 m_aPreDefVars.m_FixedVar[ PREDEFVAR_INSTURL ] = m_aPreDefVars.m_FixedVar[ PREDEFVAR_INSTPATH ];
623 m_aPreDefVars.m_FixedVar[ PREDEFVAR_INST ] = m_aPreDefVars.m_FixedVar[ PREDEFVAR_INSTPATH ];
625 m_aPreDefVars.m_FixedVar[ PREDEFVAR_BASEINSTURL ]= m_aPreDefVars.m_FixedVar[ PREDEFVAR_INSTPATH ];
628 m_aPreDefVars.m_FixedVar[ PREDEFVAR_USERURL ] = m_aPreDefVars.m_FixedVar[ PREDEFVAR_USERPATH ];
629 m_aPreDefVars.m_FixedVar[ PREDEFVAR_USER ] = m_aPreDefVars.m_FixedVar[ PREDEFVAR_USERPATH ];
631 m_aPreDefVars.m_FixedVar[ PREDEFVAR_USERDATAURL ]= m_aPreDefVars.m_FixedVar[ PREDEFVAR_USERPATH ];
636 m_aPreDefVars.m_FixedVar[PREDEFVAR_BRANDBASEURL] );
637 if ( !aProgObj.HasError() && aProgObj.insertName( u
"" LIBO_BIN_FOLDER ) )
640 m_aPreDefVars.m_FixedVar[ PREDEFVAR_PROGURL ] = m_aPreDefVars.m_FixedVar[ PREDEFVAR_PROGPATH ];
641 m_aPreDefVars.m_FixedVar[ PREDEFVAR_PROG ] = m_aPreDefVars.m_FixedVar[ PREDEFVAR_PROGPATH ];
645 OUString aSystemUser;
646 ::osl::Security aSecurity;
647 aSecurity.getUserName( aSystemUser,
false );
648 m_aPreDefVars.m_FixedVar[ PREDEFVAR_USERNAME ] = aSystemUser;
661 m_aPreDefVars.m_FixedVar[ PREDEFVAR_VLANG ] = aLocaleStr;
664 m_aPreDefVars.m_FixedVar[ PREDEFVAR_LANGID ] = OUString::number(
static_cast<sal_uInt16
>(m_aPreDefVars.m_eLanguageType) );
668 m_aPreDefVars.m_FixedVar[ PREDEFVAR_WORK ] = GetWorkVariableValue();
669 m_aPreDefVars.m_FixedVar[ PREDEFVAR_HOME ] = GetHomeVariableValue();
674 m_aPreDefVars.m_FixedVar[ PREDEFVAR_WORKDIRURL ] = GetWorkPath();
677 m_aPreDefVars.m_FixedVar[ PREDEFVAR_PATH ] = GetPathVariableValue();
681 osl::FileBase::getTempDirURL( aTmp );
682 m_aPreDefVars.m_FixedVar[ PREDEFVAR_TEMP ] = aTmp;
687extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface *
689 css::uno::XComponentContext *,
690 css::uno::Sequence<css::uno::Any>
const &)
692 return cppu::acquire(
new SubstitutePathVariables());
OUString GetMainURL(DecodeMechanism eMechanism, rtl_TextEncoding eCharset=RTL_TEXTENCODING_UTF8) const
static LanguageType convertToLanguageTypeWithFallback(const OUString &rBcp47)
static PathStatus locateUserData(OUString &_rURL)
static OUString getUILocale()
#define LANGUAGE_ENGLISH_US
double getLength(const B2DPolygon &rCandidate)
css::uno::Sequence< OUString > getSupportedServiceNames()
OUString getImplementationName()
bool CPPUHELPER_DLLPUBLIC supportsService(css::lang::XServiceInfo *implementation, rtl::OUString const &name)
SAL_DLLPUBLIC_EXPORT css::uno::XInterface * com_sun_star_comp_framework_PathSubstitution_get_implementation(css::uno::XComponentContext *, css::uno::Sequence< css::uno::Any > const &)