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