1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
19 #include <config_features.h>
20 #include <config_folders.h>
22 #include <rtl/bootstrap.h>
23 #include <rtl/bootstrap.hxx>
24 #include <osl/diagnose.h>
25 #include <osl/module.h>
26 #include <osl/process.h>
27 #include <osl/file.hxx>
28 #include <osl/mutex.hxx>
29 #include <osl/profile.hxx>
30 #include <osl/security.hxx>
31 #include <rtl/alloc.h>
32 #include <rtl/string.hxx>
33 #include <rtl/ustrbuf.hxx>
34 #include <rtl/ustring.hxx>
35 #include <rtl/byteseq.hxx>
36 #include <rtl/instance.hxx>
37 #include <rtl/malformeduriexception.hxx>
38 #include <rtl/uri.hxx>
39 #include <sal/log.hxx>
43 #include <unordered_map>
46 #include <osl/detail/android-bootstrap.h>
51 #import <Foundation/Foundation.h>
55 using osl::DirectoryItem
;
56 using osl::FileStatus
;
58 struct Bootstrap_Impl
;
63 static char const VND_SUN_STAR_PATHNAME
[] = "vnd.sun.star.pathname:";
65 bool isPathnameUrl(OUString
const & url
)
67 return url
.matchIgnoreAsciiCase(VND_SUN_STAR_PATHNAME
);
70 bool resolvePathnameUrl(OUString
* url
)
73 if (!isPathnameUrl(*url
) ||
74 (osl::FileBase::getFileURLFromSystemPath(
75 url
->copy(RTL_CONSTASCII_LENGTH(VND_SUN_STAR_PATHNAME
)), *url
) ==
76 osl::FileBase::E_None
))
85 LOOKUP_MODE_NORMAL
, LOOKUP_MODE_URE_BOOTSTRAP
,
86 LOOKUP_MODE_URE_BOOTSTRAP_EXPANSION
};
88 struct ExpandRequestLink
{
89 ExpandRequestLink
const * next
;
90 Bootstrap_Impl
const * file
;
94 OUString
expandMacros(
95 Bootstrap_Impl
const * file
, OUString
const & text
, LookupMode mode
,
96 ExpandRequestLink
const * requestStack
);
98 OUString
recursivelyExpandMacros(
99 Bootstrap_Impl
const * file
, OUString
const & text
, LookupMode mode
,
100 Bootstrap_Impl
const * requestFile
, OUString
const & requestKey
,
101 ExpandRequestLink
const * requestStack
)
103 for (; requestStack
; requestStack
= requestStack
->next
) {
104 if (requestStack
->file
== requestFile
&&
105 requestStack
->key
== requestKey
)
107 return OUString("***RECURSION DETECTED***");
110 ExpandRequestLink link
= { requestStack
, requestFile
, requestKey
};
111 return expandMacros(file
, text
, mode
, &link
);
116 struct rtl_bootstrap_NameValue
121 rtl_bootstrap_NameValue()
123 rtl_bootstrap_NameValue(OUString
const & name
, OUString
const & value
)
129 typedef std::vector
<rtl_bootstrap_NameValue
> NameValueVector
;
132 NameValueVector
const & vector
, OUString
const & key
,
136 for (NameValueVector::const_iterator
i(vector
.begin()); i
!= vector
.end(); ++i
)
149 struct rtl_bootstrap_set_vector
:
150 public rtl::Static
< NameValueVector
, rtl_bootstrap_set_vector
> {};
153 static bool getFromCommandLineArgs(
154 OUString
const & key
, OUString
* value
)
158 static NameValueVector
*pNameValueVector
= nullptr;
159 if (!pNameValueVector
)
161 static NameValueVector nameValueVector
;
163 sal_Int32 nArgCount
= osl_getCommandArgCount();
164 for(sal_Int32 i
= 0; i
< nArgCount
; ++ i
)
166 rtl_uString
*pArg
= nullptr;
167 osl_getCommandArg( i
, &pArg
);
168 if( (pArg
->buffer
[0] == '-' || pArg
->buffer
[0] == '/' ) &&
169 pArg
->buffer
[1] == 'e' &&
170 pArg
->buffer
[2] == 'n' &&
171 pArg
->buffer
[3] == 'v' &&
172 pArg
->buffer
[4] == ':' )
174 sal_Int32 nIndex
= rtl_ustr_indexOfChar( pArg
->buffer
, '=' );
178 rtl_bootstrap_NameValue nameValue
;
179 nameValue
.sName
= OUString( &(pArg
->buffer
[5]), nIndex
- 5 );
180 nameValue
.sValue
= OUString( &(pArg
->buffer
[nIndex
+1]) );
182 if( i
== nArgCount
-1 &&
183 nameValue
.sValue
.getLength() &&
184 nameValue
.sValue
[nameValue
.sValue
.getLength()-1] == 13 )
186 // avoid the 13 linefeed for the last argument,
187 // when the executable is started from a script,
188 // that was edited on windows
189 nameValue
.sValue
= nameValue
.sValue
.copy(0,nameValue
.sValue
.getLength()-1);
192 nameValueVector
.push_back( nameValue
);
195 rtl_uString_release( pArg
);
197 pNameValueVector
= &nameValueVector
;
202 for(NameValueVector::iterator ii
= pNameValueVector
->begin();
203 ii
!= pNameValueVector
->end();
206 if ((*ii
).sName
== key
)
208 *value
= (*ii
).sValue
;
217 static void getExecutableDirectory_Impl(rtl_uString
** ppDirURL
)
220 osl_getExecutableFile(&(fileName
.pData
));
222 sal_Int32 nDirEnd
= fileName
.lastIndexOf('/');
223 OSL_ENSURE(nDirEnd
>= 0, "Cannot locate executable directory");
225 rtl_uString_newFromStr_WithLength(ppDirURL
,fileName
.getStr(),nDirEnd
);
228 static OUString
& getIniFileName_Impl()
230 static OUString aStaticName
= []() {
234 // On iOS hardcode the inifile as "rc" in the .app
235 // directory. Apps are self-contained anyway, there is no
236 // possibility to have several "applications" in the same
237 // installation location with different inifiles.
238 const char *inifile
= [[@
"vnd.sun.star.pathname:" stringByAppendingString
: [[[NSBundle mainBundle
] bundlePath
] stringByAppendingPathComponent
: @
"rc"]] UTF8String
];
239 fileName
= OUString(inifile
, strlen(inifile
), RTL_TEXTENCODING_UTF8
);
240 resolvePathnameUrl(&fileName
);
241 #elif defined ANDROID
242 // Apps are self-contained on Android, too, can as well hardcode
243 // it as "rc" in the "/assets" directory, i.e. inside the app's
244 // .apk (zip) archive as the /assets/rc file.
245 fileName
= OUString("vnd.sun.star.pathname:/assets/rc");
246 resolvePathnameUrl(&fileName
);
248 if (getFromCommandLineArgs("INIFILENAME", &fileName
))
250 resolvePathnameUrl(&fileName
);
254 osl_getExecutableFile(&(fileName
.pData
));
256 // get rid of a potential executable extension
257 OUString progExt
= ".bin";
258 if (fileName
.getLength() > progExt
.getLength()
259 && fileName
.copy(fileName
.getLength() - progExt
.getLength()).equalsIgnoreAsciiCase(progExt
))
261 fileName
= fileName
.copy(0, fileName
.getLength() - progExt
.getLength());
265 if (fileName
.getLength() > progExt
.getLength()
266 && fileName
.copy(fileName
.getLength() - progExt
.getLength()).equalsIgnoreAsciiCase(progExt
))
268 fileName
= fileName
.copy(0, fileName
.getLength() - progExt
.getLength());
271 // append config file suffix
272 fileName
+= SAL_CONFIGFILE("");
275 // We keep only executables in the MacOS folder, and all
276 // rc files in LIBO_ETC_FOLDER (typically "Resources").
277 sal_Int32 off
= fileName
.lastIndexOf( "/MacOS/" );
279 fileName
= fileName
.replaceAt(off
+ 1, strlen("MacOS"), LIBO_ETC_FOLDER
);
290 // ensure the given file url has no final slash
292 static void EnsureNoFinalSlash (OUString
& url
)
294 sal_Int32 i
= url
.getLength();
296 if (i
> 0 && url
[i
- 1] == '/')
297 url
= url
.copy(0, i
- 1);
300 struct Bootstrap_Impl
302 sal_Int32 _nRefCount
;
303 Bootstrap_Impl
* _base_ini
;
305 NameValueVector _nameValueVector
;
306 OUString
const _iniName
;
308 explicit Bootstrap_Impl (OUString
const & rIniName
);
311 static void * operator new (std::size_t n
)
312 { return malloc (sal_uInt32(n
)); }
313 static void operator delete (void * p
, std::size_t)
317 OUString
const & key
, rtl_uString
** value
,
318 rtl_uString
* defaultValue
, LookupMode mode
, bool override
,
319 ExpandRequestLink
const * requestStack
) const;
321 OUString
const & key
, rtl_uString
** value
, LookupMode mode
,
322 ExpandRequestLink
const * requestStack
) const;
323 bool getAmbienceValue(
324 OUString
const & key
, rtl_uString
** value
, LookupMode mode
,
325 ExpandRequestLink
const * requestStack
) const;
327 rtl_uString
** value
, OUString
const & text
, LookupMode mode
,
328 Bootstrap_Impl
const * requestFile
, OUString
const & requestKey
,
329 ExpandRequestLink
const * requestStack
) const;
332 Bootstrap_Impl::Bootstrap_Impl( OUString
const & rIniName
)
334 _base_ini( nullptr ),
337 OUString
base_ini(getIniFileName_Impl());
339 FileStatus
status( osl_FileStatus_Mask_FileURL
);
340 DirectoryItem dirItem
;
341 if (DirectoryItem::get(base_ini
, dirItem
) == DirectoryItem::E_None
&&
342 dirItem
.getFileStatus(status
) == DirectoryItem::E_None
)
344 base_ini
= status
.getFileURL();
345 if (rIniName
!= base_ini
)
347 _base_ini
= static_cast< Bootstrap_Impl
* >(
348 rtl_bootstrap_args_open(base_ini
.pData
));
351 SAL_INFO("sal.bootstrap", "Bootstrap_Impl(): sFile=" << _iniName
);
352 oslFileHandle handle
;
353 if (!_iniName
.isEmpty() &&
354 osl_openFile(_iniName
.pData
, &handle
, osl_File_OpenFlag_Read
) == osl_File_E_None
)
356 rtl::ByteSequence seq
;
358 while (osl_readLine(handle
, reinterpret_cast<sal_Sequence
**>(&seq
)) == osl_File_E_None
)
360 OString
line(reinterpret_cast<const char *>(seq
.getConstArray()), seq
.getLength());
361 sal_Int32 nIndex
= line
.indexOf('=');
364 struct rtl_bootstrap_NameValue nameValue
;
365 nameValue
.sName
= OStringToOUString(line
.copy(0,nIndex
).trim(), RTL_TEXTENCODING_ASCII_US
);
366 nameValue
.sValue
= OStringToOUString(line
.copy(nIndex
+1).trim(), RTL_TEXTENCODING_UTF8
);
368 SAL_INFO("sal.bootstrap", "pushing: name=" << nameValue
.sName
<< " value=" << nameValue
.sValue
);
370 _nameValueVector
.push_back(nameValue
);
373 osl_closeFile(handle
);
377 SAL_INFO( "sal.bootstrap", "couldn't open file: " << _iniName
);
381 Bootstrap_Impl::~Bootstrap_Impl()
384 rtl_bootstrap_args_close( _base_ini
);
389 Bootstrap_Impl
* get_static_bootstrap_handle()
391 static Bootstrap_Impl
* s_handle
= []() {
392 OUString
iniName(getIniFileName_Impl());
393 Bootstrap_Impl
* that
= static_cast<Bootstrap_Impl
*>(rtl_bootstrap_args_open(iniName
.pData
));
396 that
= new Bootstrap_Impl(iniName
);
405 struct FundamentalIniData
407 rtlBootstrapHandle ini
;
413 (get_static_bootstrap_handle()->getValue(
414 "URE_BOOTSTRAP", &uri
.pData
, nullptr, LOOKUP_MODE_NORMAL
, false,
416 && resolvePathnameUrl(&uri
))
417 ? rtl_bootstrap_args_open(uri
.pData
) : nullptr;
420 ~FundamentalIniData() { rtl_bootstrap_args_close(ini
); }
422 FundamentalIniData(const FundamentalIniData
&) = delete;
423 FundamentalIniData
& operator=(const FundamentalIniData
&) = delete;
426 struct FundamentalIni
: public rtl::Static
< FundamentalIniData
, FundamentalIni
>
431 bool Bootstrap_Impl::getValue(
432 OUString
const & key
, rtl_uString
** value
, rtl_uString
* defaultValue
,
433 LookupMode mode
, bool override
, ExpandRequestLink
const * requestStack
)
436 if (mode
== LOOKUP_MODE_NORMAL
&& key
== "URE_BOOTSTRAP")
437 mode
= LOOKUP_MODE_URE_BOOTSTRAP
;
439 if (override
&& getDirectValue(key
, value
, mode
, requestStack
))
445 value
, OUString(RTL_OS
).pData
);
452 value
, OUString(RTL_ARCH
).pData
);
456 if (key
== "_CPPU_ENV")
461 SAL_STRINGIFY(CPPU_ENV
)).
467 if (key
== "APP_DATA_DIR")
469 const char *app_data_dir
= lo_get_app_data_dir();
471 value
, OUString(app_data_dir
, strlen(app_data_dir
), RTL_TEXTENCODING_UTF8
).pData
);
477 if (key
== "APP_DATA_DIR")
479 const char *app_data_dir
= [[[[NSBundle mainBundle
] bundlePath
] stringByAddingPercentEncodingWithAllowedCharacters
: [NSCharacterSet URLPathAllowedCharacterSet
]] UTF8String
];
481 value
, OUString(app_data_dir
, strlen(app_data_dir
), RTL_TEXTENCODING_UTF8
).pData
);
491 0, std::max
<sal_Int32
>(0, _iniName
.lastIndexOf('/'))).pData
);
495 if (getAmbienceValue(key
, value
, mode
, requestStack
))
498 if (key
== "SYSUSERCONFIG")
501 bool b
= osl::Security().getConfigDir(v
);
502 EnsureNoFinalSlash(v
);
503 rtl_uString_assign(value
, v
.pData
);
507 if (key
== "SYSUSERHOME")
510 bool b
= osl::Security().getHomeDir(v
);
511 EnsureNoFinalSlash(v
);
512 rtl_uString_assign(value
, v
.pData
);
516 if (key
== "SYSBINDIR")
518 getExecutableDirectory_Impl(value
);
522 if (_base_ini
!= nullptr && _base_ini
->getDirectValue(key
, value
, mode
, requestStack
))
525 if (!override
&& getDirectValue(key
, value
, mode
, requestStack
))
528 if (mode
== LOOKUP_MODE_NORMAL
)
530 FundamentalIniData
const & d
= FundamentalIni::get();
531 Bootstrap_Impl
const * b
= static_cast<Bootstrap_Impl
const *>(d
.ini
);
532 if (b
!= nullptr && b
!= this && b
->getDirectValue(key
, value
, mode
, requestStack
))
536 if (defaultValue
!= nullptr)
538 rtl_uString_assign(value
, defaultValue
);
542 rtl_uString_new(value
);
546 bool Bootstrap_Impl::getDirectValue(
547 OUString
const & key
, rtl_uString
** value
, LookupMode mode
,
548 ExpandRequestLink
const * requestStack
) const
551 if (find(_nameValueVector
, key
, &v
))
553 expandValue(value
, v
, mode
, this, key
, requestStack
);
560 bool Bootstrap_Impl::getAmbienceValue(
561 OUString
const & key
, rtl_uString
** value
, LookupMode mode
,
562 ExpandRequestLink
const * requestStack
) const
568 osl::MutexGuard
g(osl::Mutex::getGlobalMutex());
569 f
= find(rtl_bootstrap_set_vector::get(), key
, &v
);
572 if (f
|| getFromCommandLineArgs(key
, &v
) ||
573 osl_getEnvironment(key
.pData
, &v
.pData
) == osl_Process_E_None
)
575 expandValue(value
, v
, mode
, nullptr, key
, requestStack
);
582 void Bootstrap_Impl::expandValue(
583 rtl_uString
** value
, OUString
const & text
, LookupMode mode
,
584 Bootstrap_Impl
const * requestFile
, OUString
const & requestKey
,
585 ExpandRequestLink
const * requestStack
) const
589 (mode
== LOOKUP_MODE_URE_BOOTSTRAP
&& isPathnameUrl(text
) ?
591 recursivelyExpandMacros(
593 (mode
== LOOKUP_MODE_URE_BOOTSTRAP
?
594 LOOKUP_MODE_URE_BOOTSTRAP_EXPANSION
: mode
),
595 requestFile
, requestKey
, requestStack
)).pData
);
600 struct bootstrap_map
{
601 typedef std::unordered_map
<
602 OUString
, Bootstrap_Impl
* > t
;
604 bootstrap_map(const bootstrap_map
&) = delete;
605 bootstrap_map
& operator=(const bootstrap_map
&) = delete;
607 // get and release must only be called properly synchronized via some mutex
608 // (e.g., osl::Mutex::getGlobalMutex()):
618 static void release()
620 if (m_map
!= nullptr && m_map
->empty())
631 bootstrap_map::t
* bootstrap_map::m_map
= nullptr;
635 rtlBootstrapHandle SAL_CALL
rtl_bootstrap_args_open(rtl_uString
* pIniName
)
637 OUString
iniName( pIniName
);
640 FileStatus
status(osl_FileStatus_Mask_FileURL
);
641 DirectoryItem dirItem
;
642 if (DirectoryItem::get(iniName
, dirItem
) != DirectoryItem::E_None
||
643 dirItem
.getFileStatus(status
) != DirectoryItem::E_None
)
648 iniName
= status
.getFileURL();
650 Bootstrap_Impl
* that
;
651 osl::ResettableMutexGuard
guard(osl::Mutex::getGlobalMutex());
652 bootstrap_map::t
* p_bootstrap_map
= bootstrap_map::get();
653 bootstrap_map::t::const_iterator
iFind(p_bootstrap_map
->find(iniName
));
654 if (iFind
== p_bootstrap_map
->end())
656 bootstrap_map::release();
658 that
= new Bootstrap_Impl(iniName
);
660 p_bootstrap_map
= bootstrap_map::get();
661 iFind
= p_bootstrap_map
->find(iniName
);
662 if (iFind
== p_bootstrap_map
->end())
665 ::std::pair
< bootstrap_map::t::iterator
, bool > insertion(
666 p_bootstrap_map
->emplace(iniName
, that
));
667 OSL_ASSERT(insertion
.second
);
671 Bootstrap_Impl
* obsolete
= that
;
672 that
= iFind
->second
;
680 that
= iFind
->second
;
683 return static_cast< rtlBootstrapHandle
>( that
);
686 void SAL_CALL
rtl_bootstrap_args_close(rtlBootstrapHandle handle
) SAL_THROW_EXTERN_C()
691 Bootstrap_Impl
* that
= static_cast< Bootstrap_Impl
* >( handle
);
693 osl::MutexGuard
guard(osl::Mutex::getGlobalMutex());
694 bootstrap_map::t
* p_bootstrap_map
= bootstrap_map::get();
695 OSL_ASSERT(p_bootstrap_map
->find(that
->_iniName
)->second
== that
);
698 if (that
->_nRefCount
== 0)
700 std::size_t const nLeaking
= 8; // only hold up to 8 files statically
701 if (p_bootstrap_map
->size() > nLeaking
)
703 ::std::size_t erased
= p_bootstrap_map
->erase( that
->_iniName
);
709 bootstrap_map::release();
713 sal_Bool SAL_CALL
rtl_bootstrap_get_from_handle(
714 rtlBootstrapHandle handle
,
716 rtl_uString
** ppValue
,
717 rtl_uString
* pDefault
720 osl::MutexGuard
guard(osl::Mutex::getGlobalMutex());
726 handle
= get_static_bootstrap_handle();
728 found
= static_cast< Bootstrap_Impl
* >(handle
)->getValue(
729 pName
, ppValue
, pDefault
, LOOKUP_MODE_NORMAL
, false, nullptr );
735 void SAL_CALL
rtl_bootstrap_get_iniName_from_handle (
736 rtlBootstrapHandle handle
,
737 rtl_uString
** ppIniName
744 Bootstrap_Impl
* pImpl
= static_cast<Bootstrap_Impl
*>(handle
);
745 rtl_uString_assign(ppIniName
, pImpl
->_iniName
.pData
);
749 const OUString
& iniName
= getIniFileName_Impl();
750 rtl_uString_assign(ppIniName
, iniName
.pData
);
755 void SAL_CALL
rtl_bootstrap_setIniFileName (
759 osl::MutexGuard
guard(osl::Mutex::getGlobalMutex());
760 OUString
& file
= getIniFileName_Impl();
764 sal_Bool SAL_CALL
rtl_bootstrap_get (
766 rtl_uString
** ppValue
,
767 rtl_uString
* pDefault
770 return rtl_bootstrap_get_from_handle(nullptr, pName
, ppValue
, pDefault
);
773 void SAL_CALL
rtl_bootstrap_set (
778 const OUString
name(pName
);
779 const OUString
value(pValue
);
781 osl::MutexGuard
guard(osl::Mutex::getGlobalMutex());
783 NameValueVector
& r_rtl_bootstrap_set_vector
= rtl_bootstrap_set_vector::get();
784 for (auto & item
: r_rtl_bootstrap_set_vector
)
786 if (item
.sName
== name
)
793 SAL_INFO("sal.bootstrap", "explicitly getting: name=" << name
<< " value=" <<value
);
795 r_rtl_bootstrap_set_vector
.emplace_back(name
, value
);
798 void SAL_CALL
rtl_bootstrap_expandMacros_from_handle(
799 rtlBootstrapHandle handle
,
800 rtl_uString
** macro
)
803 handle
= get_static_bootstrap_handle();
805 OUString
expanded(expandMacros(static_cast< Bootstrap_Impl
* >(handle
),
806 OUString::unacquired(macro
),
807 LOOKUP_MODE_NORMAL
, nullptr));
808 rtl_uString_assign(macro
, expanded
.pData
);
811 void SAL_CALL
rtl_bootstrap_expandMacros(rtl_uString
** macro
)
813 rtl_bootstrap_expandMacros_from_handle(nullptr, macro
);
816 void rtl_bootstrap_encode(rtl_uString
const * value
, rtl_uString
** encoded
)
820 for (sal_Int32 i
= 0; i
< value
->length
; ++i
)
822 sal_Unicode c
= value
->buffer
[i
];
823 if (c
== '$' || c
== '\\')
829 rtl_uString_assign(encoded
, b
.makeStringAndClear().pData
);
834 int hex(sal_Unicode c
)
837 c
>= '0' && c
<= '9' ? c
- '0' :
838 c
>= 'A' && c
<= 'F' ? c
- 'A' + 10 :
839 c
>= 'a' && c
<= 'f' ? c
- 'a' + 10 : -1;
842 sal_Unicode
read(OUString
const & text
, sal_Int32
* pos
, bool * escaped
)
844 OSL_ASSERT(pos
&& *pos
>= 0 && *pos
< text
.getLength() && escaped
);
845 sal_Unicode c
= text
[(*pos
)++];
849 if (*pos
< text
.getLength() - 4 && text
[*pos
] == 'u' &&
850 ((n1
= hex(text
[*pos
+ 1])) >= 0) &&
851 ((n2
= hex(text
[*pos
+ 2])) >= 0) &&
852 ((n3
= hex(text
[*pos
+ 3])) >= 0) &&
853 ((n4
= hex(text
[*pos
+ 4])) >= 0))
857 return static_cast< sal_Unicode
>(
858 (n1
<< 12) | (n2
<< 8) | (n3
<< 4) | n4
);
861 if (*pos
< text
.getLength())
864 return text
[(*pos
)++];
873 Bootstrap_Impl
const * file
, LookupMode mode
, bool override
,
874 OUString
const & key
, ExpandRequestLink
const * requestStack
)
877 (file
== nullptr ? get_static_bootstrap_handle() : file
)->getValue(
878 key
, &v
.pData
, nullptr, mode
, override
, requestStack
);
882 OUString
expandMacros(
883 Bootstrap_Impl
const * file
, OUString
const & text
, LookupMode mode
,
884 ExpandRequestLink
const * requestStack
)
886 SAL_INFO("sal.bootstrap", "expandMacros called with: " << text
);
889 for (sal_Int32 i
= 0; i
< text
.getLength();)
892 sal_Unicode c
= read(text
, &i
, &escaped
);
893 if (escaped
|| c
!= '$')
899 if (i
< text
.getLength() && text
[i
] == '{')
903 sal_Int32 nesting
= 0;
907 while (i
< text
.getLength())
910 c
= read(text
, &i
, &escaped
);
922 seg
[n
++] = text
.copy(p
, j
- p
);
931 if (nesting
== 0 && n
< 2)
933 seg
[n
++] = text
.copy(p
, j
- p
);
941 for (int j
= 0; j
< n
; ++j
)
943 seg
[j
] = expandMacros(file
, seg
[j
], mode
, requestStack
);
948 buf
.append(lookup(file
, mode
, false, seg
[0], requestStack
));
950 else if (n
== 3 && seg
[0] == ".override")
952 rtl::Bootstrap
b(seg
[1]);
953 Bootstrap_Impl
* f
= static_cast< Bootstrap_Impl
* >(b
.getHandle());
954 buf
.append(lookup(f
, mode
, f
!= nullptr, seg
[2], requestStack
));
958 if (n
== 3 && seg
[1].isEmpty())
960 // For backward compatibility, treat ${file::key} the
961 // same as just ${file:key}:
970 static_cast< Bootstrap_Impl
* >(
971 rtl::Bootstrap(seg
[0]).getHandle()),
972 mode
, false, seg
[1], requestStack
));
976 // Going through osl::Profile, this code erroneously
977 // does not recursively expand macros in the resulting
978 // replacement text (and if it did, it would fail to
979 // detect cycles that pass through here):
982 osl::Profile(seg
[0]).readString(
984 seg
[1], RTL_TEXTENCODING_UTF8
),
986 seg
[2], RTL_TEXTENCODING_UTF8
),
988 RTL_TEXTENCODING_UTF8
));
995 for (; i
< text
.getLength();)
998 c
= read(text
, &j
, &escaped
);
1000 (c
== ' ' || c
== '$' || c
== '-' || c
== '/' ||
1001 c
== ';' || c
== '\\'))
1012 file
, mode
, false, kbuf
.makeStringAndClear(),
1018 OUString
result(buf
.makeStringAndClear());
1019 SAL_INFO("sal.bootstrap", "expandMacros result: " << result
);
1026 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */