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 <config_folders.h> 21 22 #include <comphelper/lok.hxx> 23 #include <cppuhelper/basemutex.hxx> 24 #include <cppuhelper/compbase.hxx> 25 #include <cppuhelper/supportsservice.hxx> 26 27 #include <unotools/bootstrap.hxx> 28 #include <unotools/configmgr.hxx> 29 #include <osl/file.hxx> 30 #include <osl/security.hxx> 31 #include <osl/thread.hxx> 32 #include <i18nlangtag/languagetag.hxx> 33 #include <tools/urlobj.hxx> 34 #include <rtl/ustrbuf.hxx> 35 #include <rtl/bootstrap.hxx> 36 #include <sal/log.hxx> 37 38 #include <officecfg/Office/Paths.hxx> 39 40 #include <com/sun/star/lang/XServiceInfo.hpp> 41 #include <com/sun/star/container/NoSuchElementException.hpp> 42 #include <com/sun/star/container/XHierarchicalNameAccess.hpp> 43 #include <com/sun/star/util/XStringSubstitution.hpp> 44 45 #include <unordered_map> 46 47 using namespace com::sun::star::uno; 48 using namespace com::sun::star::container; 49 50 namespace { 51 52 enum PreDefVariable 53 { 54 PREDEFVAR_INST, 55 PREDEFVAR_PROG, 56 PREDEFVAR_USER, 57 PREDEFVAR_WORK, 58 PREDEFVAR_HOME, 59 PREDEFVAR_TEMP, 60 PREDEFVAR_PATH, 61 PREDEFVAR_USERNAME, 62 PREDEFVAR_LANGID, 63 PREDEFVAR_VLANG, 64 PREDEFVAR_INSTPATH, 65 PREDEFVAR_PROGPATH, 66 PREDEFVAR_USERPATH, 67 PREDEFVAR_INSTURL, 68 PREDEFVAR_PROGURL, 69 PREDEFVAR_USERURL, 70 PREDEFVAR_WORKDIRURL, 71 // New variable of hierarchy service (#i32656#) 72 PREDEFVAR_BASEINSTURL, 73 PREDEFVAR_USERDATAURL, 74 PREDEFVAR_BRANDBASEURL, 75 PREDEFVAR_COUNT 76 }; 77 78 struct FixedVariable 79 { 80 const char* pVarName; 81 bool bAbsPath; 82 }; 83 84 // Table with all fixed/predefined variables supported. 85 static const FixedVariable aFixedVarTable[PREDEFVAR_COUNT] = 86 { 87 { "$(inst)", true }, // PREDEFVAR_INST 88 { "$(prog)", true }, // PREDEFVAR_PROG 89 { "$(user)", true }, // PREDEFVAR_USER 90 { "$(work)", true }, // PREDEFVAR_WORK, special variable 91 // (transient) 92 { "$(home)", true }, // PREDEFVAR_HOME 93 { "$(temp)", true }, // PREDEFVAR_TEMP 94 { "$(path)", true }, // PREDEFVAR_PATH 95 { "$(username)", false }, // PREDEFVAR_USERNAME 96 { "$(langid)", false }, // PREDEFVAR_LANGID 97 { "$(vlang)", false }, // PREDEFVAR_VLANG 98 { "$(instpath)", true }, // PREDEFVAR_INSTPATH 99 { "$(progpath)", true }, // PREDEFVAR_PROGPATH 100 { "$(userpath)", true }, // PREDEFVAR_USERPATH 101 { "$(insturl)", true }, // PREDEFVAR_INSTURL 102 { "$(progurl)", true }, // PREDEFVAR_PROGURL 103 { "$(userurl)", true }, // PREDEFVAR_USERURL 104 { "$(workdirurl)", true }, // PREDEFVAR_WORKDIRURL, special variable 105 // (transient) and don't use for 106 // resubstitution 107 { "$(baseinsturl)", true }, // PREDEFVAR_BASEINSTURL 108 { "$(userdataurl)", true }, // PREDEFVAR_USERDATAURL 109 { "$(brandbaseurl)", true } // PREDEFVAR_BRANDBASEURL 110 }; 111 112 struct PredefinedPathVariables 113 { 114 // Predefined variables supported by substitute variables 115 LanguageType m_eLanguageType; // Language type of Office 116 OUString m_FixedVar[ PREDEFVAR_COUNT ]; // Variable value access by PreDefVariable 117 OUString m_FixedVarNames[ PREDEFVAR_COUNT ]; // Variable name access by PreDefVariable 118 }; 119 120 struct ReSubstFixedVarOrder 121 { 122 sal_Int32 nVarValueLength; 123 PreDefVariable eVariable; 124 125 bool operator< ( const ReSubstFixedVarOrder& aFixedVarOrder ) const 126 { 127 // Reverse operator< to have high to low ordering 128 return ( nVarValueLength > aFixedVarOrder.nVarValueLength ); 129 } 130 }; 131 132 typedef ::cppu::WeakComponentImplHelper< 133 css::util::XStringSubstitution, 134 css::lang::XServiceInfo > SubstitutePathVariables_BASE; 135 136 class SubstitutePathVariables : private cppu::BaseMutex, 137 public SubstitutePathVariables_BASE 138 { 139 public: 140 explicit SubstitutePathVariables(const css::uno::Reference< css::uno::XComponentContext >& xContext); 141 142 virtual OUString SAL_CALL getImplementationName() override 143 { 144 return OUString("com.sun.star.comp.framework.PathSubstitution"); 145 } 146 147 virtual sal_Bool SAL_CALL supportsService(OUString const & ServiceName) override 148 { 149 return cppu::supportsService(this, ServiceName); 150 } 151 152 virtual css::uno::Sequence<OUString> SAL_CALL getSupportedServiceNames() override 153 { 154 return {"com.sun.star.util.PathSubstitution"}; 155 } 156 157 // XStringSubstitution 158 virtual OUString SAL_CALL substituteVariables( const OUString& aText, sal_Bool bSubstRequired ) override; 159 virtual OUString SAL_CALL reSubstituteVariables( const OUString& aText ) override; 160 virtual OUString SAL_CALL getSubstituteVariableValue( const OUString& variable ) override; 161 162 protected: 163 void SetPredefinedPathVariables(); 164 165 // Special case (transient) values can change during runtime! 166 // Don't store them in the pre defined struct 167 OUString GetWorkPath() const; 168 OUString GetWorkVariableValue() const; 169 OUString GetPathVariableValue() const; 170 171 OUString GetHomeVariableValue() const; 172 173 // XStringSubstitution implementation methods 174 /// @throws css::container::NoSuchElementException 175 /// @throws css::uno::RuntimeException 176 OUString impl_substituteVariable( const OUString& aText, bool bSustRequired ); 177 /// @throws css::uno::RuntimeException 178 OUString impl_reSubstituteVariables( const OUString& aText ); 179 /// @throws css::container::NoSuchElementException 180 /// @throws css::uno::RuntimeException 181 OUString const & impl_getSubstituteVariableValue( const OUString& variable ); 182 183 private: 184 typedef std::unordered_map<OUString, PreDefVariable> 185 VarNameToIndexMap; 186 187 VarNameToIndexMap m_aPreDefVarMap; // Mapping from pre-def variable names to enum for array access 188 PredefinedPathVariables m_aPreDefVars; // All predefined variables 189 std::vector<ReSubstFixedVarOrder> m_aReSubstFixedVarOrder; // To speed up resubstitution fixed variables (order for lookup) 190 css::uno::Reference< css::uno::XComponentContext > m_xContext; 191 }; 192 193 SubstitutePathVariables::SubstitutePathVariables( const Reference< XComponentContext >& xContext ) : 194 SubstitutePathVariables_BASE(m_aMutex), 195 m_xContext( xContext ) 196 { 197 SetPredefinedPathVariables(); 198 199 // Init the predefined/fixed variable to index hash map 200 for ( int i = 0; i < PREDEFVAR_COUNT; i++ ) 201 { 202 // Store variable name into struct of predefined/fixed variables 203 m_aPreDefVars.m_FixedVarNames[i] = OUString::createFromAscii( aFixedVarTable[i].pVarName ); 204 205 // Create hash map entry 206 m_aPreDefVarMap.emplace( m_aPreDefVars.m_FixedVarNames[i], PreDefVariable(i) ); 207 } 208 209 // Sort predefined/fixed variable to path length 210 for ( int i = 0; i < PREDEFVAR_COUNT; i++ ) 211 { 212 if (( i != PREDEFVAR_WORKDIRURL ) && ( i != PREDEFVAR_PATH )) 213 { 214 // Special path variables, don't include into automatic resubstitution search! 215 // $(workdirurl) is not allowed to resubstitute! This variable is the value of path settings entry 216 // and it could be possible that it will be resubstituted by itself!! 217 // Example: WORK_PATH=c:\test, $(workdirurl)=WORK_PATH => WORK_PATH=$(workdirurl) and this cannot be substituted! 218 ReSubstFixedVarOrder aFixedVar; 219 aFixedVar.eVariable = PreDefVariable(i); 220 aFixedVar.nVarValueLength = m_aPreDefVars.m_FixedVar[static_cast<sal_Int32>(aFixedVar.eVariable)].getLength(); 221 m_aReSubstFixedVarOrder.push_back( aFixedVar ); 222 } 223 } 224 sort(m_aReSubstFixedVarOrder.begin(),m_aReSubstFixedVarOrder.end()); 225 } 226 227 // XStringSubstitution 228 OUString SAL_CALL SubstitutePathVariables::substituteVariables( const OUString& aText, sal_Bool bSubstRequired ) 229 { 230 osl::MutexGuard g(rBHelper.rMutex); 231 return impl_substituteVariable( aText, bSubstRequired ); 232 } 233 234 OUString SAL_CALL SubstitutePathVariables::reSubstituteVariables( const OUString& aText ) 235 { 236 osl::MutexGuard g(rBHelper.rMutex); 237 return impl_reSubstituteVariables( aText ); 238 } 239 240 OUString SAL_CALL SubstitutePathVariables::getSubstituteVariableValue( const OUString& aVariable ) 241 { 242 osl::MutexGuard g(rBHelper.rMutex); 243 return impl_getSubstituteVariableValue( aVariable ); 244 } 245 246 OUString SubstitutePathVariables::GetWorkPath() const 247 { 248 OUString aWorkPath; 249 css::uno::Reference< css::container::XHierarchicalNameAccess > xPaths(officecfg::Office::Paths::Paths::get(m_xContext), css::uno::UNO_QUERY_THROW); 250 if (!(xPaths->getByHierarchicalName("['Work']/WritePath") >>= aWorkPath)) 251 // fallback in case config layer does not return an usable work dir value. 252 aWorkPath = GetWorkVariableValue(); 253 254 return aWorkPath; 255 } 256 257 OUString SubstitutePathVariables::GetWorkVariableValue() const 258 { 259 OUString aWorkPath; 260 boost::optional<OUString> x(officecfg::Office::Paths::Variables::Work::get(m_xContext)); 261 if (!x) 262 { 263 // fallback to $HOME in case platform dependent config layer does not return 264 // an usable work dir value. 265 osl::Security aSecurity; 266 aSecurity.getHomeDir( aWorkPath ); 267 } 268 else 269 aWorkPath = x.get(); 270 return aWorkPath; 271 } 272 273 OUString SubstitutePathVariables::GetHomeVariableValue() const 274 { 275 osl::Security aSecurity; 276 OUString aHomePath; 277 278 aSecurity.getHomeDir( aHomePath ); 279 return aHomePath; 280 } 281 282 OUString SubstitutePathVariables::GetPathVariableValue() const 283 { 284 OUString aRetStr; 285 const char* pEnv = getenv( "PATH" ); 286 287 if ( pEnv ) 288 { 289 const int PATH_EXTEND_FACTOR = 120; 290 OUString aTmp; 291 OUString aPathList( pEnv, strlen( pEnv ), osl_getThreadTextEncoding() ); 292 OUStringBuffer aPathStrBuffer( aPathList.getLength() * PATH_EXTEND_FACTOR / 100 ); 293 294 bool bAppendSep = false; 295 sal_Int32 nToken = 0; 296 do 297 { 298 OUString sToken = aPathList.getToken(0, SAL_PATHSEPARATOR, nToken); 299 if (!sToken.isEmpty() && 300 osl::FileBase::getFileURLFromSystemPath( sToken, aTmp ) == 301 osl::FileBase::RC::E_None ) 302 { 303 if ( bAppendSep ) 304 aPathStrBuffer.append( ";" ); // Office uses ';' as path separator 305 aPathStrBuffer.append( aTmp ); 306 bAppendSep = true; 307 } 308 } 309 while(nToken>=0); 310 311 aRetStr = aPathStrBuffer.makeStringAndClear(); 312 } 313 314 return aRetStr; 315 } 316 317 OUString SubstitutePathVariables::impl_substituteVariable( const OUString& rText, bool bSubstRequired ) 318 { 319 // This is maximal recursive depth supported! 320 const sal_Int32 nMaxRecursiveDepth = 8; 321 322 OUString aWorkText = rText; 323 OUString aResult; 324 325 // Use vector with strings to detect endless recursions! 326 std::vector< OUString > aEndlessRecursiveDetector; 327 328 // Search for first occurrence of "$(...". 329 sal_Int32 nDepth = 0; 330 bool bSubstitutionCompleted = false; 331 sal_Int32 nPosition = aWorkText.indexOf( "$(" ); 332 sal_Int32 nLength = 0; // = count of letters from "$(" to ")" in string 333 bool bVarNotSubstituted = false; 334 335 // Have we found any variable like "$(...)"? 336 if ( nPosition != -1 ) 337 { 338 // Yes; Get length of found variable. 339 // If no ")" was found - nLength is set to 0 by default! see before. 340 sal_Int32 nEndPosition = aWorkText.indexOf( ')', nPosition ); 341 if ( nEndPosition != -1 ) 342 nLength = nEndPosition - nPosition + 1; 343 } 344 345 // Is there something to replace ? 346 bool bWorkRetrieved = false; 347 bool bWorkDirURLRetrieved = false; 348 while ( !bSubstitutionCompleted && nDepth < nMaxRecursiveDepth ) 349 { 350 while ( ( nPosition != -1 ) && ( nLength > 3 ) ) // "$(" ")" 351 { 352 // YES; Get the next variable for replace. 353 sal_Int32 nReplaceLength = 0; 354 OUString aReplacement; 355 OUString aSubString = aWorkText.copy( nPosition, nLength ); 356 OUString aSubVarString; 357 358 // Path variables are not case sensitive! 359 aSubVarString = aSubString.toAsciiLowerCase(); 360 VarNameToIndexMap::const_iterator pNTOIIter = m_aPreDefVarMap.find( aSubVarString ); 361 if ( pNTOIIter != m_aPreDefVarMap.end() ) 362 { 363 // Fixed/Predefined variable found 364 PreDefVariable nIndex = pNTOIIter->second; 365 366 // Determine variable value and length from array/table 367 if ( nIndex == PREDEFVAR_WORK && !bWorkRetrieved ) 368 { 369 // Transient value, retrieve it again 370 m_aPreDefVars.m_FixedVar[ nIndex ] = GetWorkVariableValue(); 371 bWorkRetrieved = true; 372 } 373 else if ( nIndex == PREDEFVAR_WORKDIRURL && !bWorkDirURLRetrieved ) 374 { 375 // Transient value, retrieve it again 376 m_aPreDefVars.m_FixedVar[ nIndex ] = GetWorkPath(); 377 bWorkDirURLRetrieved = true; 378 } 379 380 // Check preconditions to substitute path variables. 381 // 1. A path variable can only be substituted if it follows a ';'! 382 // 2. It's located exactly at the start of the string being substituted! 383 if (( aFixedVarTable[ int( nIndex ) ].bAbsPath && (( nPosition == 0 ) || (( nPosition > 0 ) && ( aWorkText[nPosition-1] == ';')))) || 384 ( !aFixedVarTable[ int( nIndex ) ].bAbsPath )) 385 { 386 aReplacement = m_aPreDefVars.m_FixedVar[ nIndex ]; 387 nReplaceLength = nLength; 388 } 389 } 390 391 // Have we found something to replace? 392 if ( nReplaceLength > 0 ) 393 { 394 // Yes ... then do it. 395 aWorkText = aWorkText.replaceAt( nPosition, nReplaceLength, aReplacement ); 396 } 397 else 398 { 399 // Variable not known 400 bVarNotSubstituted = true; 401 nPosition += nLength; 402 } 403 404 // Step after replaced text! If no text was replaced (unknown variable!), 405 // length of aReplacement is 0 ... and we don't step then. 406 nPosition += aReplacement.getLength(); 407 408 // We must control index in string before call something at OUString! 409 // The OUString-implementation don't do it for us :-( but the result is not defined otherwise. 410 if ( nPosition + 1 > aWorkText.getLength() ) 411 { 412 // Position is out of range. Break loop! 413 nPosition = -1; 414 nLength = 0; 415 } 416 else 417 { 418 // Else; Position is valid. Search for next variable to replace. 419 nPosition = aWorkText.indexOf( "$(", nPosition ); 420 // Have we found any variable like "$(...)"? 421 if ( nPosition != -1 ) 422 { 423 // Yes; Get length of found variable. If no ")" was found - nLength must set to 0! 424 nLength = 0; 425 sal_Int32 nEndPosition = aWorkText.indexOf( ')', nPosition ); 426 if ( nEndPosition != -1 ) 427 nLength = nEndPosition - nPosition + 1; 428 } 429 } 430 } 431 432 nPosition = aWorkText.indexOf( "$(" ); 433 if ( nPosition == -1 ) 434 { 435 bSubstitutionCompleted = true; 436 break; // All variables are substituted 437 } 438 else 439 { 440 // Check for recursion 441 const sal_uInt32 nCount = aEndlessRecursiveDetector.size(); 442 for ( sal_uInt32 i=0; i < nCount; i++ ) 443 { 444 if ( aEndlessRecursiveDetector[i] == aWorkText ) 445 { 446 if ( bVarNotSubstituted ) 447 break; // Not all variables could be substituted! 448 else 449 { 450 nDepth = nMaxRecursiveDepth; 451 break; // Recursion detected! 452 } 453 } 454 } 455 456 aEndlessRecursiveDetector.push_back( aWorkText ); 457 458 // Initialize values for next 459 sal_Int32 nEndPosition = aWorkText.indexOf( ')', nPosition ); 460 if ( nEndPosition != -1 ) 461 nLength = nEndPosition - nPosition + 1; 462 bVarNotSubstituted = false; 463 ++nDepth; 464 } 465 } 466 467 // Fill return value with result 468 if ( bSubstitutionCompleted ) 469 { 470 // Substitution successful! 471 aResult = aWorkText; 472 } 473 else 474 { 475 // Substitution not successful! 476 if ( nDepth == nMaxRecursiveDepth ) 477 { 478 // recursion depth reached! 479 if ( bSubstRequired ) 480 { 481 throw NoSuchElementException( "Endless recursion detected. Cannot substitute variables!", static_cast<cppu::OWeakObject *>(this) ); 482 } 483 aResult = rText; 484 } 485 else 486 { 487 // variable in text but unknown! 488 if ( bSubstRequired ) 489 { 490 throw NoSuchElementException( "Unknown variable found!", static_cast<cppu::OWeakObject *>(this) ); 491 } 492 aResult = aWorkText; 493 } 494 } 495 496 return aResult; 497 } 498 499 OUString SubstitutePathVariables::impl_reSubstituteVariables( const OUString& rURL ) 500 { 501 OUString aURL; 502 503 INetURLObject aUrl( rURL ); 504 if ( !aUrl.HasError() ) 505 aURL = aUrl.GetMainURL( INetURLObject::DecodeMechanism::NONE ); 506 else 507 { 508 // Convert a system path to a UCB compliant URL before resubstitution 509 OUString aTemp; 510 if ( osl::FileBase::getFileURLFromSystemPath( rURL, aTemp ) == osl::FileBase::E_None ) 511 { 512 aURL = INetURLObject( aTemp ).GetMainURL( INetURLObject::DecodeMechanism::NONE ); 513 if( aURL.isEmpty() ) 514 return rURL; 515 } 516 else 517 { 518 // rURL is not a valid URL nor a osl system path. Give up and return error! 519 return rURL; 520 } 521 } 522 523 // Get transient predefined path variable $(work) value before starting resubstitution 524 m_aPreDefVars.m_FixedVar[ PREDEFVAR_WORK ] = GetWorkVariableValue(); 525 526 for (;;) 527 { 528 bool bVariableFound = false; 529 530 for (auto const & i: m_aReSubstFixedVarOrder) 531 { 532 OUString aValue = m_aPreDefVars.m_FixedVar[i.eVariable]; 533 sal_Int32 nPos = aURL.indexOf( aValue ); 534 if ( nPos >= 0 ) 535 { 536 bool bMatch = true; 537 if ( !aFixedVarTable[i.eVariable].bAbsPath ) 538 { 539 // Special path variables as they can occur in the middle of a path. Only match if they 540 // describe a whole directory and not only a substring of a directory! 541 // (Ideally, all substitutions should stick to syntactical 542 // boundaries within the given URL, like not covering only 543 // part of a URL path segment; however, at least when saving 544 // an Impress document, one URL that is passed in is of the 545 // form <file:///.../share/palette%3Bfile:///.../user/ 546 // config/standard.sob>, re-substituted to 547 // <$(inst)/share/palette%3B$(user)/config/standard.sob>.) 548 const sal_Unicode* pStr = aURL.getStr(); 549 550 if ( nPos > 0 ) 551 bMatch = ( aURL[ nPos-1 ] == '/' ); 552 553 if ( bMatch ) 554 { 555 if ( nPos + aValue.getLength() < aURL.getLength() ) 556 bMatch = ( pStr[ nPos + aValue.getLength() ] == '/' ); 557 } 558 } 559 560 if ( bMatch ) 561 { 562 aURL = aURL.replaceAt( 563 nPos, aValue.getLength(), 564 m_aPreDefVars.m_FixedVarNames[i.eVariable]); 565 bVariableFound = true; // Resubstitution not finished yet! 566 break; 567 } 568 } 569 } 570 571 if ( !bVariableFound ) 572 { 573 return aURL; 574 } 575 } 576 } 577 578 // This method support both request schemes "$("<varname>")" or "<varname>". 579 OUString const & SubstitutePathVariables::impl_getSubstituteVariableValue( const OUString& rVariable ) 580 { 581 OUString aVariable; 582 583 sal_Int32 nPos = rVariable.indexOf( "$(" ); 584 if ( nPos == -1 ) 585 { 586 // Prepare variable name before hash map access 587 aVariable = "$(" + rVariable + ")"; 588 } 589 590 VarNameToIndexMap::const_iterator pNTOIIter = m_aPreDefVarMap.find( ( nPos == -1 ) ? aVariable : rVariable ); 591 592 // Fixed/Predefined variable 593 if ( pNTOIIter == m_aPreDefVarMap.end() ) 594 { 595 throw NoSuchElementException("Unknown variable!", static_cast<cppu::OWeakObject *>(this)); 596 } 597 PreDefVariable nIndex = pNTOIIter->second; 598 return m_aPreDefVars.m_FixedVar[static_cast<sal_Int32>(nIndex)]; 599 } 600 601 void SubstitutePathVariables::SetPredefinedPathVariables() 602 { 603 604 m_aPreDefVars.m_FixedVar[PREDEFVAR_BRANDBASEURL] = "$BRAND_BASE_DIR"; 605 rtl::Bootstrap::expandMacros( 606 m_aPreDefVars.m_FixedVar[PREDEFVAR_BRANDBASEURL]); 607 608 // Get inspath and userpath from bootstrap mechanism in every case as file URL 609 ::utl::Bootstrap::PathStatus aState; 610 OUString sVal; 611 612 aState = utl::Bootstrap::locateUserData( sVal ); 613 //There can be the valid case that there is no user installation. 614 //TODO: Is that still the case? (With OOo 3.4, "unopkg sync" was run as part 615 // of the setup. Then no user installation was required.) 616 //Therefore we do not assert here. 617 // It's not possible to detect when an empty value would actually be used. 618 // (note: getenv is a hack to detect if we're running in a unit test) 619 // Also, it's okay to have an empty user installation path in case of LOK 620 if (aState == ::utl::Bootstrap::PATH_EXISTS || getenv("SRC_ROOT") || 621 (comphelper::LibreOfficeKit::isActive() && aState == ::utl::Bootstrap::PATH_VALID)) 622 { 623 m_aPreDefVars.m_FixedVar[ PREDEFVAR_USERPATH ] = sVal; 624 } 625 626 // Set $(inst), $(instpath), $(insturl) 627 m_aPreDefVars.m_FixedVar[ PREDEFVAR_INSTPATH ] = m_aPreDefVars.m_FixedVar[PREDEFVAR_BRANDBASEURL]; 628 m_aPreDefVars.m_FixedVar[ PREDEFVAR_INSTURL ] = m_aPreDefVars.m_FixedVar[ PREDEFVAR_INSTPATH ]; 629 m_aPreDefVars.m_FixedVar[ PREDEFVAR_INST ] = m_aPreDefVars.m_FixedVar[ PREDEFVAR_INSTPATH ]; 630 // New variable of hierarchy service (#i32656#) 631 m_aPreDefVars.m_FixedVar[ PREDEFVAR_BASEINSTURL ]= m_aPreDefVars.m_FixedVar[ PREDEFVAR_INSTPATH ]; 632 633 // Set $(user), $(userpath), $(userurl) 634 m_aPreDefVars.m_FixedVar[ PREDEFVAR_USERURL ] = m_aPreDefVars.m_FixedVar[ PREDEFVAR_USERPATH ]; 635 m_aPreDefVars.m_FixedVar[ PREDEFVAR_USER ] = m_aPreDefVars.m_FixedVar[ PREDEFVAR_USERPATH ]; 636 // New variable of hierarchy service (#i32656#) 637 m_aPreDefVars.m_FixedVar[ PREDEFVAR_USERDATAURL ]= m_aPreDefVars.m_FixedVar[ PREDEFVAR_USERPATH ]; 638 639 // Detect the program directory 640 // Set $(prog), $(progpath), $(progurl) 641 INetURLObject aProgObj( 642 m_aPreDefVars.m_FixedVar[PREDEFVAR_BRANDBASEURL] ); 643 if ( !aProgObj.HasError() && aProgObj.insertName( LIBO_BIN_FOLDER ) ) 644 { 645 m_aPreDefVars.m_FixedVar[ PREDEFVAR_PROGPATH ] = aProgObj.GetMainURL(INetURLObject::DecodeMechanism::NONE); 646 m_aPreDefVars.m_FixedVar[ PREDEFVAR_PROGURL ] = m_aPreDefVars.m_FixedVar[ PREDEFVAR_PROGPATH ]; 647 m_aPreDefVars.m_FixedVar[ PREDEFVAR_PROG ] = m_aPreDefVars.m_FixedVar[ PREDEFVAR_PROGPATH ]; 648 } 649 650 // Set $(username) 651 OUString aSystemUser; 652 ::osl::Security aSecurity; 653 aSecurity.getUserName( aSystemUser, false ); 654 m_aPreDefVars.m_FixedVar[ PREDEFVAR_USERNAME ] = aSystemUser; 655 656 // Detect the language type of the current office 657 m_aPreDefVars.m_eLanguageType = LANGUAGE_ENGLISH_US; 658 OUString aLocaleStr( utl::ConfigManager::getUILocale() ); 659 m_aPreDefVars.m_eLanguageType = LanguageTag::convertToLanguageTypeWithFallback( aLocaleStr ); 660 // We used to have an else branch here with a SAL_WARN, but that 661 // always fired in some unit tests when this code was built with 662 // debug=t, so it seems fairly pointless, especially as 663 // m_aPreDefVars.m_eLanguageType has been initialized to a 664 // default value above anyway. 665 666 // Set $(vlang) 667 m_aPreDefVars.m_FixedVar[ PREDEFVAR_VLANG ] = aLocaleStr; 668 669 // Set $(langid) 670 m_aPreDefVars.m_FixedVar[ PREDEFVAR_LANGID ] = OUString::number( static_cast<sal_uInt16>(m_aPreDefVars.m_eLanguageType) ); 671 672 // Set the other pre defined path variables 673 // Set $(work) 674 m_aPreDefVars.m_FixedVar[ PREDEFVAR_WORK ] = GetWorkVariableValue(); 675 m_aPreDefVars.m_FixedVar[ PREDEFVAR_HOME ] = GetHomeVariableValue(); 676 677 // Set $(workdirurl) this is the value of the path PATH_WORK which doesn't make sense 678 // anymore because the path settings service has this value! It can deliver this value more 679 // quickly than the substitution service! 680 m_aPreDefVars.m_FixedVar[ PREDEFVAR_WORKDIRURL ] = GetWorkPath(); 681 682 // Set $(path) variable 683 m_aPreDefVars.m_FixedVar[ PREDEFVAR_PATH ] = GetPathVariableValue(); 684 685 // Set $(temp) 686 OUString aTmp; 687 osl::FileBase::getTempDirURL( aTmp ); 688 m_aPreDefVars.m_FixedVar[ PREDEFVAR_TEMP ] = aTmp; 689 } 690 691 struct Instance { 692 explicit Instance( 693 css::uno::Reference<css::uno::XComponentContext> const & context): 694 instance( 695 static_cast<cppu::OWeakObject *>(new SubstitutePathVariables(context))) 696 { 697 } 698 699 css::uno::Reference<css::uno::XInterface> instance; 700 }; 701 702 struct Singleton: 703 public rtl::StaticWithArg< 704 Instance, css::uno::Reference<css::uno::XComponentContext>, Singleton> 705 {}; 706 707 } 708 709 extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface * 710 com_sun_star_comp_framework_PathSubstitution_get_implementation( 711 css::uno::XComponentContext *context, 712 css::uno::Sequence<css::uno::Any> const &) 713 { 714 return cppu::acquire(static_cast<cppu::OWeakObject *>( 715 Singleton::get(context).instance.get())); 716 } 717 718 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ 719
