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_folders.h>
21 #include <rtl/bootstrap.h>
22 #include <rtl/bootstrap.hxx>
23 #include <osl/diagnose.h>
24 #include <osl/process.h>
25 #include <osl/file.hxx>
26 #include <osl/mutex.hxx>
27 #include <osl/profile.hxx>
28 #include <osl/security.hxx>
29 #include <rtl/string.hxx>
30 #include <rtl/ustrbuf.hxx>
31 #include <rtl/ustring.hxx>
32 #include <rtl/byteseq.hxx>
33 #include <sal/log.hxx>
34 #include <o3tl/lru_map.hxx>
35 #include <o3tl/string_view.hxx>
41 #include <string_view>
42 #include <unordered_map>
45 #include <osl/detail/android-bootstrap.h>
49 #include <osl/detail/emscripten-bootstrap.h>
54 #import <Foundation/Foundation.h>
58 using osl::DirectoryItem
;
59 using osl::FileStatus
;
64 struct Bootstrap_Impl
;
66 constexpr std::u16string_view VND_SUN_STAR_PATHNAME
= u
"vnd.sun.star.pathname:";
68 bool isPathnameUrl(std::u16string_view url
)
70 return o3tl::matchIgnoreAsciiCase(url
, VND_SUN_STAR_PATHNAME
);
73 bool resolvePathnameUrl(OUString
* url
)
76 if (!isPathnameUrl(*url
) ||
77 (osl::FileBase::getFileURLFromSystemPath(
78 url
->copy(VND_SUN_STAR_PATHNAME
.size()), *url
) ==
79 osl::FileBase::E_None
))
87 enum class LookupMode
{
88 NORMAL
, URE_BOOTSTRAP
,
89 URE_BOOTSTRAP_EXPANSION
};
91 struct ExpandRequestLink
{
92 ExpandRequestLink
const * next
;
93 Bootstrap_Impl
const * file
;
97 OUString
expandMacros(
98 Bootstrap_Impl
const * file
, std::u16string_view text
, LookupMode mode
,
99 ExpandRequestLink
const * requestStack
);
101 OUString
recursivelyExpandMacros(
102 Bootstrap_Impl
const * file
, std::u16string_view text
, LookupMode mode
,
103 Bootstrap_Impl
const * requestFile
, OUString
const & requestKey
,
104 ExpandRequestLink
const * requestStack
)
106 for (; requestStack
; requestStack
= requestStack
->next
) {
107 if (requestStack
->file
== requestFile
&&
108 requestStack
->key
== requestKey
)
110 return u
"***RECURSION DETECTED***"_ustr
;
113 ExpandRequestLink link
= { requestStack
, requestFile
, requestKey
};
114 return expandMacros(file
, text
, mode
, &link
);
117 struct rtl_bootstrap_NameValue
122 rtl_bootstrap_NameValue()
124 rtl_bootstrap_NameValue(OUString name
, OUString value
)
125 : sName(std::move( name
)),
126 sValue(std::move( value
))
132 typedef std::vector
<rtl_bootstrap_NameValue
> NameValueVector
;
135 NameValueVector
const & vector
, OUString
const & key
,
139 auto i
= std::find_if(vector
.begin(), vector
.end(),
140 [&key
](const rtl_bootstrap_NameValue
& rNameValue
) { return rNameValue
.sName
== key
; });
141 if (i
!= vector
.end())
151 NameValueVector rtl_bootstrap_set_vector
;
154 static bool getFromCommandLineArgs(
155 OUString
const & key
, OUString
* value
)
159 static NameValueVector nameValueVector
= []()
163 sal_Int32 nArgCount
= osl_getCommandArgCount();
164 for(sal_Int32 i
= 0; i
< nArgCount
; ++ i
)
167 osl_getCommandArg( i
, &pArg
.pData
);
168 if( (pArg
.startsWith("-") || pArg
.startsWith("/") ) &&
169 pArg
.match("env:", 1) )
171 sal_Int32 nIndex
= pArg
.indexOf( '=' );
175 rtl_bootstrap_NameValue nameValue
;
176 nameValue
.sName
= pArg
.copy( 5, nIndex
- 5 );
177 nameValue
.sValue
= pArg
.copy( nIndex
+1 );
179 if( i
== nArgCount
-1 &&
180 nameValue
.sValue
.getLength() &&
181 nameValue
.sValue
[nameValue
.sValue
.getLength()-1] == 13 )
183 // avoid the 13 linefeed for the last argument,
184 // when the executable is started from a script,
185 // that was edited on windows
186 nameValue
.sValue
= nameValue
.sValue
.copy(0,nameValue
.sValue
.getLength()-1);
189 tmp
.push_back( nameValue
);
196 return find(nameValueVector
, key
, value
);
199 static void getExecutableDirectory_Impl(rtl_uString
** ppDirURL
)
202 osl_getExecutableFile(&(fileName
.pData
));
204 sal_Int32 nDirEnd
= fileName
.lastIndexOf('/');
205 OSL_ENSURE(nDirEnd
>= 0, "Cannot locate executable directory");
207 rtl_uString_newFromStr_WithLength(ppDirURL
,fileName
.getStr(),nDirEnd
);
210 static OUString
getIniFileName(bool overriding
) {
214 // On iOS hardcode the inifile as "rc" in the .app
215 // directory. Apps are self-contained anyway, there is no
216 // possibility to have several "applications" in the same
217 // installation location with different inifiles.
218 const char *inifile
= [[@
"vnd.sun.star.pathname:" stringByAppendingString
: [[[NSBundle mainBundle
] bundlePath
] stringByAppendingPathComponent
: (overriding
? @
"fundamental.override.ini" : @
"rc")]] UTF8String
];
219 fileName
= OUString(inifile
, strlen(inifile
), RTL_TEXTENCODING_UTF8
);
220 resolvePathnameUrl(&fileName
);
221 #elif defined ANDROID
222 // Apps are self-contained on Android, too, can as well hardcode
223 // it as "rc" in the "/assets" directory, i.e. inside the app's
224 // .apk (zip) archive as the /assets/rc file.
225 fileName
= overriding
226 ? OUString("vnd.sun.star.pathname:/assets/fundamental.override.ini")
227 : OUString("vnd.sun.star.pathname:/assets/rc");
228 resolvePathnameUrl(&fileName
);
229 #elif defined(EMSCRIPTEN)
230 fileName
= overriding
231 ? OUString("vnd.sun.star.pathname:/instdir/program/fundamental.override.ini")
232 : OUString("vnd.sun.star.pathname:/instdir/program/sofficerc");
233 resolvePathnameUrl(&fileName
);
235 if (!overriding
&& getFromCommandLineArgs(u
"INIFILENAME"_ustr
, &fileName
))
237 resolvePathnameUrl(&fileName
);
241 osl_getExecutableFile(&(fileName
.pData
));
244 auto const i
= fileName
.lastIndexOf('/') + 1;
245 fileName
= fileName
.replaceAt(i
, fileName
.getLength() - i
, u
"fundamental.override.ini");
247 // get rid of a potential executable extension
248 OUString progExt
= u
".bin"_ustr
;
249 if (fileName
.getLength() > progExt
.getLength()
250 && o3tl::equalsIgnoreAsciiCase(fileName
.subView(fileName
.getLength() - progExt
.getLength()), progExt
))
252 fileName
= fileName
.copy(0, fileName
.getLength() - progExt
.getLength());
256 if (fileName
.getLength() > progExt
.getLength()
257 && o3tl::equalsIgnoreAsciiCase(fileName
.subView(fileName
.getLength() - progExt
.getLength()), progExt
))
259 fileName
= fileName
.copy(0, fileName
.getLength() - progExt
.getLength());
262 // append config file suffix
263 fileName
+= SAL_CONFIGFILE("");
267 // We keep only executables in the MacOS folder, and all
268 // rc files in LIBO_ETC_FOLDER (typically "Resources").
269 sal_Int32 off
= fileName
.lastIndexOf( "/MacOS/" );
271 fileName
= fileName
.replaceAt(off
+ 1, strlen("MacOS"), u
"" LIBO_ETC_FOLDER
);
279 static OUString
const & getOverrideIniFileName_Impl()
281 static OUString aStaticName
= getIniFileName(true);
286 static OUString
& getIniFileName_Impl()
288 static OUString aStaticName
= getIniFileName(false);
293 // ensure the given file url has no final slash
295 static void EnsureNoFinalSlash (OUString
& url
)
297 sal_Int32 i
= url
.getLength();
299 if (i
> 0 && url
[i
- 1] == '/')
300 url
= url
.copy(0, i
- 1);
305 struct Bootstrap_Impl
307 sal_Int32 _nRefCount
;
308 Bootstrap_Impl
* _override_base_ini
;
309 Bootstrap_Impl
* _base_ini
;
311 NameValueVector _nameValueVector
;
314 explicit Bootstrap_Impl (OUString
const & rIniName
);
317 static void * operator new (std::size_t n
)
318 { return malloc (sal_uInt32(n
)); }
319 static void operator delete (void * p
, std::size_t)
323 OUString
const & key
, rtl_uString
** value
,
324 rtl_uString
* defaultValue
, LookupMode mode
, bool override
,
325 ExpandRequestLink
const * requestStack
) const;
327 OUString
const & key
, rtl_uString
** value
, LookupMode mode
,
328 ExpandRequestLink
const * requestStack
) const;
329 bool getAmbienceValue(
330 OUString
const & key
, rtl_uString
** value
, LookupMode mode
,
331 ExpandRequestLink
const * requestStack
) const;
333 rtl_uString
** value
, OUString
const & text
, LookupMode mode
,
334 Bootstrap_Impl
const * requestFile
, OUString
const & requestKey
,
335 ExpandRequestLink
const * requestStack
) const;
340 Bootstrap_Impl::Bootstrap_Impl( OUString
const & rIniName
)
342 _override_base_ini( nullptr ),
343 _base_ini( nullptr ),
346 OUString
override_base_ini(getOverrideIniFileName_Impl());
348 FileStatus
override_status( osl_FileStatus_Mask_FileURL
);
349 DirectoryItem override_dirItem
;
350 bool skip_base_ini
= false;
351 if (DirectoryItem::get(override_base_ini
, override_dirItem
) == DirectoryItem::E_None
&&
352 override_dirItem
.getFileStatus(override_status
) == DirectoryItem::E_None
)
354 override_base_ini
= override_status
.getFileURL();
355 if (rIniName
!= override_base_ini
)
357 _override_base_ini
= static_cast< Bootstrap_Impl
* >(
358 rtl_bootstrap_args_open(override_base_ini
.pData
));
362 skip_base_ini
= true;
366 if (!skip_base_ini
) {
367 OUString
base_ini(getIniFileName_Impl());
369 FileStatus
status( osl_FileStatus_Mask_FileURL
);
370 DirectoryItem dirItem
;
371 if (DirectoryItem::get(base_ini
, dirItem
) == DirectoryItem::E_None
&&
372 dirItem
.getFileStatus(status
) == DirectoryItem::E_None
)
374 base_ini
= status
.getFileURL();
375 if (rIniName
!= base_ini
)
377 _base_ini
= static_cast< Bootstrap_Impl
* >(
378 rtl_bootstrap_args_open(base_ini
.pData
));
383 SAL_INFO("sal.bootstrap", "Bootstrap_Impl(): sFile=" << _iniName
);
384 oslFileHandle handle
;
385 if (!_iniName
.isEmpty() &&
386 osl_openFile(_iniName
.pData
, &handle
, osl_File_OpenFlag_Read
) == osl_File_E_None
)
388 rtl::ByteSequence seq
;
390 while (osl_readLine(handle
, reinterpret_cast<sal_Sequence
**>(&seq
)) == osl_File_E_None
)
392 OString
line(reinterpret_cast<const char *>(seq
.getConstArray()), seq
.getLength());
393 sal_Int32 nIndex
= line
.indexOf('=');
396 struct rtl_bootstrap_NameValue nameValue
;
397 nameValue
.sName
= OStringToOUString(o3tl::trim(line
.subView(0,nIndex
)), RTL_TEXTENCODING_ASCII_US
);
398 nameValue
.sValue
= OStringToOUString(o3tl::trim(line
.subView(nIndex
+1)), RTL_TEXTENCODING_UTF8
);
400 SAL_INFO("sal.bootstrap", "pushing: name=" << nameValue
.sName
<< " value=" << nameValue
.sValue
);
402 _nameValueVector
.push_back(nameValue
);
405 osl_closeFile(handle
);
409 SAL_INFO( "sal.bootstrap", "couldn't open file: " << _iniName
);
413 Bootstrap_Impl::~Bootstrap_Impl()
416 rtl_bootstrap_args_close( _base_ini
);
417 if (_override_base_ini
)
418 rtl_bootstrap_args_close( _override_base_ini
);
423 Bootstrap_Impl
* get_static_bootstrap_handle()
425 static Bootstrap_Impl
* s_handle
= []() {
426 OUString
iniName(getIniFileName_Impl());
427 Bootstrap_Impl
* that
= static_cast<Bootstrap_Impl
*>(rtl_bootstrap_args_open(iniName
.pData
));
430 that
= new Bootstrap_Impl(iniName
);
439 struct FundamentalIniData
441 rtlBootstrapHandle ini
;
447 (get_static_bootstrap_handle()->getValue(
448 u
"URE_BOOTSTRAP"_ustr
, &uri
.pData
, nullptr, LookupMode::NORMAL
, false,
450 && resolvePathnameUrl(&uri
))
451 ? rtl_bootstrap_args_open(uri
.pData
) : nullptr;
454 ~FundamentalIniData() { rtl_bootstrap_args_close(ini
); }
456 FundamentalIniData(const FundamentalIniData
&) = delete;
457 FundamentalIniData
& operator=(const FundamentalIniData
&) = delete;
460 FundamentalIniData
& FundamentalIni()
462 static FundamentalIniData SINGLETON
;
468 bool Bootstrap_Impl::getValue(
469 OUString
const & key
, rtl_uString
** value
, rtl_uString
* defaultValue
,
470 LookupMode mode
, bool override
, ExpandRequestLink
const * requestStack
)
473 if (mode
== LookupMode::NORMAL
&& key
== "URE_BOOTSTRAP")
474 mode
= LookupMode::URE_BOOTSTRAP
;
476 if (override
&& getDirectValue(key
, value
, mode
, requestStack
))
479 if (_override_base_ini
!= nullptr
480 && _override_base_ini
->getDirectValue(key
, value
, mode
, requestStack
))
482 SAL_INFO("sal.bootstrap", "getValue(" << key
<< ") from fundamental.override.ini");
489 value
, (u
"" RTL_OS
""_ustr
).pData
);
496 value
, (u
"" RTL_ARCH
""_ustr
).pData
);
500 if (key
== "_CPPU_ENV")
504 (u
"" SAL_STRINGIFY(CPPU_ENV
) ""_ustr
).pData
);
508 #if defined ANDROID || defined EMSCRIPTEN
509 if (key
== "APP_DATA_DIR")
511 const char *app_data_dir
= lo_get_app_data_dir();
513 value
, OUString(app_data_dir
, strlen(app_data_dir
), RTL_TEXTENCODING_UTF8
).pData
);
519 if (key
== "APP_DATA_DIR")
521 const char *app_data_dir
= [[[[NSBundle mainBundle
] bundlePath
] stringByAddingPercentEncodingWithAllowedCharacters
: [NSCharacterSet URLPathAllowedCharacterSet
]] UTF8String
];
523 value
, OUString(app_data_dir
, strlen(app_data_dir
), RTL_TEXTENCODING_UTF8
).pData
);
533 0, std::max
<sal_Int32
>(0, _iniName
.lastIndexOf('/'))).pData
);
537 if (getAmbienceValue(key
, value
, mode
, requestStack
))
540 if (key
== "SYSUSERCONFIG")
543 bool b
= osl::Security().getConfigDir(v
);
544 EnsureNoFinalSlash(v
);
545 rtl_uString_assign(value
, v
.pData
);
549 if (key
== "SYSUSERHOME")
552 bool b
= osl::Security().getHomeDir(v
);
553 EnsureNoFinalSlash(v
);
554 rtl_uString_assign(value
, v
.pData
);
558 if (key
== "SYSBINDIR")
560 getExecutableDirectory_Impl(value
);
564 if (_base_ini
!= nullptr && _base_ini
->getDirectValue(key
, value
, mode
, requestStack
))
567 if (!override
&& getDirectValue(key
, value
, mode
, requestStack
))
570 if (mode
== LookupMode::NORMAL
)
572 FundamentalIniData
const & d
= FundamentalIni();
573 Bootstrap_Impl
const * b
= static_cast<Bootstrap_Impl
const *>(d
.ini
);
574 if (b
!= nullptr && b
!= this && b
->getDirectValue(key
, value
, mode
, requestStack
))
578 if (defaultValue
!= nullptr)
580 rtl_uString_assign(value
, defaultValue
);
584 rtl_uString_new(value
);
588 bool Bootstrap_Impl::getDirectValue(
589 OUString
const & key
, rtl_uString
** value
, LookupMode mode
,
590 ExpandRequestLink
const * requestStack
) const
593 if (find(_nameValueVector
, key
, &v
))
595 expandValue(value
, v
, mode
, this, key
, requestStack
);
602 bool Bootstrap_Impl::getAmbienceValue(
603 OUString
const & key
, rtl_uString
** value
, LookupMode mode
,
604 ExpandRequestLink
const * requestStack
) const
610 osl::MutexGuard
g(osl::Mutex::getGlobalMutex());
611 f
= find(rtl_bootstrap_set_vector
, key
, &v
);
614 if (f
|| getFromCommandLineArgs(key
, &v
) ||
615 osl_getEnvironment(key
.pData
, &v
.pData
) == osl_Process_E_None
)
617 expandValue(value
, v
, mode
, nullptr, key
, requestStack
);
624 void Bootstrap_Impl::expandValue(
625 rtl_uString
** value
, OUString
const & text
, LookupMode mode
,
626 Bootstrap_Impl
const * requestFile
, OUString
const & requestKey
,
627 ExpandRequestLink
const * requestStack
) const
631 (mode
== LookupMode::URE_BOOTSTRAP
&& isPathnameUrl(text
) ?
633 recursivelyExpandMacros(
635 (mode
== LookupMode::URE_BOOTSTRAP
?
636 LookupMode::URE_BOOTSTRAP_EXPANSION
: mode
),
637 requestFile
, requestKey
, requestStack
)).pData
);
642 typedef std::unordered_map
< OUString
, Bootstrap_Impl
* > bootstrap_map_t
;
643 bootstrap_map_t bootstrap_map
;
647 rtlBootstrapHandle SAL_CALL
rtl_bootstrap_args_open(rtl_uString
* pIniName
)
649 static o3tl::lru_map
<OUString
,OUString
> fileUrlLookupCache(16);
651 OUString
originalIniName( pIniName
);
654 osl::ResettableMutexGuard
guard(osl::Mutex::getGlobalMutex());
655 auto cacheIt
= fileUrlLookupCache
.find(originalIniName
);
656 bool foundInCache
= cacheIt
!= fileUrlLookupCache
.end();
658 iniName
= cacheIt
->second
;
664 FileStatus
status(osl_FileStatus_Mask_FileURL
);
665 DirectoryItem dirItem
;
666 if (DirectoryItem::get(originalIniName
, dirItem
) != DirectoryItem::E_None
||
667 dirItem
.getFileStatus(status
) != DirectoryItem::E_None
)
671 iniName
= status
.getFileURL();
676 fileUrlLookupCache
.insert({originalIniName
, iniName
});
677 Bootstrap_Impl
* that
;
678 auto iFind(bootstrap_map
.find(iniName
));
679 if (iFind
== bootstrap_map
.end())
682 that
= new Bootstrap_Impl(iniName
);
684 iFind
= bootstrap_map
.find(iniName
);
685 if (iFind
== bootstrap_map
.end())
688 ::std::pair
< bootstrap_map_t::iterator
, bool > insertion(
689 bootstrap_map
.emplace(iniName
, that
));
690 OSL_ASSERT(insertion
.second
);
694 Bootstrap_Impl
* obsolete
= that
;
695 that
= iFind
->second
;
703 that
= iFind
->second
;
706 return static_cast< rtlBootstrapHandle
>( that
);
709 void SAL_CALL
rtl_bootstrap_args_close(rtlBootstrapHandle handle
) noexcept
714 Bootstrap_Impl
* that
= static_cast< Bootstrap_Impl
* >( handle
);
716 osl::MutexGuard
guard(osl::Mutex::getGlobalMutex());
717 OSL_ASSERT(bootstrap_map
.find(that
->_iniName
)->second
== that
);
720 if (that
->_nRefCount
!= 0)
723 std::size_t const nLeaking
= 8; // only hold up to 8 files statically
724 if (bootstrap_map
.size() > nLeaking
)
726 ::std::size_t erased
= bootstrap_map
.erase( that
->_iniName
);
734 sal_Bool SAL_CALL
rtl_bootstrap_get_from_handle(
735 rtlBootstrapHandle handle
,
737 rtl_uString
** ppValue
,
738 rtl_uString
* pDefault
741 osl::MutexGuard
guard(osl::Mutex::getGlobalMutex());
747 handle
= get_static_bootstrap_handle();
749 found
= static_cast< Bootstrap_Impl
* >(handle
)->getValue(
750 pName
, ppValue
, pDefault
, LookupMode::NORMAL
, false, nullptr );
756 void SAL_CALL
rtl_bootstrap_get_iniName_from_handle (
757 rtlBootstrapHandle handle
,
758 rtl_uString
** ppIniName
766 Bootstrap_Impl
* pImpl
= static_cast<Bootstrap_Impl
*>(handle
);
767 rtl_uString_assign(ppIniName
, pImpl
->_iniName
.pData
);
771 const OUString
& iniName
= getIniFileName_Impl();
772 rtl_uString_assign(ppIniName
, iniName
.pData
);
776 void SAL_CALL
rtl_bootstrap_setIniFileName (
780 osl::MutexGuard
guard(osl::Mutex::getGlobalMutex());
781 OUString
& file
= getIniFileName_Impl();
785 sal_Bool SAL_CALL
rtl_bootstrap_get (
787 rtl_uString
** ppValue
,
788 rtl_uString
* pDefault
791 return rtl_bootstrap_get_from_handle(nullptr, pName
, ppValue
, pDefault
);
794 void SAL_CALL
rtl_bootstrap_set (
799 const OUString
name(pName
);
800 const OUString
value(pValue
);
802 osl::MutexGuard
guard(osl::Mutex::getGlobalMutex());
804 for (auto & item
: rtl_bootstrap_set_vector
)
806 if (item
.sName
== name
)
813 SAL_INFO("sal.bootstrap", "explicitly setting: name=" << name
<< " value=" <<value
);
815 rtl_bootstrap_set_vector
.emplace_back(name
, value
);
818 void SAL_CALL
rtl_bootstrap_expandMacros_from_handle(
819 rtlBootstrapHandle handle
,
820 rtl_uString
** macro
)
823 handle
= get_static_bootstrap_handle();
825 OUString
expanded(expandMacros(static_cast< Bootstrap_Impl
* >(handle
),
826 OUString::unacquired(macro
),
827 LookupMode::NORMAL
, nullptr));
828 rtl_uString_assign(macro
, expanded
.pData
);
831 void SAL_CALL
rtl_bootstrap_expandMacros(rtl_uString
** macro
)
833 rtl_bootstrap_expandMacros_from_handle(nullptr, macro
);
836 void rtl_bootstrap_encode(rtl_uString
const * value
, rtl_uString
** encoded
)
839 OUStringBuffer
b(value
->length
+5);
840 for (sal_Int32 i
= 0; i
< value
->length
; ++i
)
842 sal_Unicode c
= value
->buffer
[i
];
843 if (c
== '$' || c
== '\\')
849 rtl_uString_assign(encoded
, b
.makeStringAndClear().pData
);
854 int hex(sal_Unicode c
)
857 c
>= '0' && c
<= '9' ? c
- '0' :
858 c
>= 'A' && c
<= 'F' ? c
- 'A' + 10 :
859 c
>= 'a' && c
<= 'f' ? c
- 'a' + 10 : -1;
862 sal_Unicode
read(std::u16string_view text
, std::size_t * pos
, bool * escaped
)
864 assert(pos
&& *pos
< text
.length() && escaped
);
865 sal_Unicode c
= text
[(*pos
)++];
869 if (*pos
< text
.length() - 4 && text
[*pos
] == 'u' &&
870 ((n1
= hex(text
[*pos
+ 1])) >= 0) &&
871 ((n2
= hex(text
[*pos
+ 2])) >= 0) &&
872 ((n3
= hex(text
[*pos
+ 3])) >= 0) &&
873 ((n4
= hex(text
[*pos
+ 4])) >= 0))
877 return static_cast< sal_Unicode
>(
878 (n1
<< 12) | (n2
<< 8) | (n3
<< 4) | n4
);
881 if (*pos
< text
.length())
884 return text
[(*pos
)++];
893 Bootstrap_Impl
const * file
, LookupMode mode
, bool override
,
894 OUString
const & key
, ExpandRequestLink
const * requestStack
)
897 (file
== nullptr ? get_static_bootstrap_handle() : file
)->getValue(
898 key
, &v
.pData
, nullptr, mode
, override
, requestStack
);
902 OUString
expandMacros(
903 Bootstrap_Impl
const * file
, std::u16string_view text
, LookupMode mode
,
904 ExpandRequestLink
const * requestStack
)
906 SAL_INFO("sal.bootstrap", "expandMacros called with: " << OUString(text
));
907 OUStringBuffer
buf(2048);
909 for (std::size_t i
= 0; i
< text
.length();)
912 sal_Unicode c
= read(text
, &i
, &escaped
);
913 if (escaped
|| c
!= '$')
919 if (i
< text
.length() && text
[i
] == '{')
923 sal_Int32 nesting
= 0;
927 while (i
< text
.length())
930 c
= read(text
, &i
, &escaped
);
942 seg
[n
++] = text
.substr(p
, j
- p
);
951 if (nesting
== 0 && n
< 2)
953 seg
[n
++] = text
.substr(p
, j
- p
);
961 for (int j
= 0; j
< n
; ++j
)
963 seg
[j
] = expandMacros(file
, seg
[j
], mode
, requestStack
);
966 if (n
== 3 && seg
[0] != ".override" && seg
[1].isEmpty())
968 // For backward compatibility, treat ${file::key} the
969 // same as just ${file:key}:
976 buf
.append(lookup(file
, mode
, false, seg
[0], requestStack
));
980 rtl::Bootstrap
b(seg
[0]);
981 Bootstrap_Impl
* f
= static_cast< Bootstrap_Impl
* >(b
.getHandle());
982 buf
.append(lookup(f
, mode
, false, seg
[1], requestStack
));
984 else if (n
== 3 && seg
[0] == ".override")
986 rtl::Bootstrap
b(seg
[1]);
987 Bootstrap_Impl
* f
= static_cast< Bootstrap_Impl
* >(b
.getHandle());
988 buf
.append(lookup(f
, mode
, f
!= nullptr, seg
[2], requestStack
));
992 // Going through osl::Profile, this code erroneously
993 // does not recursively expand macros in the resulting
994 // replacement text (and if it did, it would fail to
995 // detect cycles that pass through here):
998 osl::Profile(seg
[0]).readString(
1000 seg
[1], RTL_TEXTENCODING_UTF8
),
1002 seg
[2], RTL_TEXTENCODING_UTF8
),
1004 RTL_TEXTENCODING_UTF8
));
1009 OUStringBuffer
kbuf(sal_Int32(text
.length()));
1010 for (; i
< text
.length();)
1013 c
= read(text
, &j
, &escaped
);
1015 (c
== ' ' || c
== '$' || c
== '-' || c
== '/' ||
1016 c
== ';' || c
== '\\'))
1027 file
, mode
, false, kbuf
.makeStringAndClear(),
1033 OUString
result(buf
.makeStringAndClear());
1034 SAL_INFO("sal.bootstrap", "expandMacros result: " << result
);
1041 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */