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 .
21 #include "rtl/bootstrap.h"
22 #include "rtl/bootstrap.hxx"
23 #include <osl/diagnose.h>
24 #include <osl/module.h>
25 #include <osl/process.h>
26 #include <osl/file.hxx>
27 #include <osl/mutex.hxx>
28 #include <osl/profile.hxx>
29 #include <osl/security.hxx>
30 #include <rtl/alloc.h>
31 #include <rtl/string.hxx>
32 #include <rtl/ustrbuf.hxx>
33 #include <rtl/ustring.hxx>
34 #include <rtl/byteseq.hxx>
35 #include <rtl/instance.hxx>
36 #include <rtl/malformeduriexception.hxx>
37 #include <rtl/uri.hxx>
38 #include "rtl/allocator.hxx"
40 #include <boost/unordered_map.hpp>
44 #include <osl/detail/android-bootstrap.h>
49 #import <Foundation/Foundation.h>
53 using osl::DirectoryItem
;
54 using osl::FileStatus
;
58 using rtl::OUStringToOString
;
60 struct Bootstrap_Impl
;
64 static char const VND_SUN_STAR_PATHNAME
[] = "vnd.sun.star.pathname:";
66 bool isPathnameUrl(rtl::OUString
const & url
) {
67 return url
.matchIgnoreAsciiCaseAsciiL(
68 RTL_CONSTASCII_STRINGPARAM(VND_SUN_STAR_PATHNAME
));
71 bool resolvePathnameUrl(rtl::OUString
* url
) {
72 OSL_ASSERT(url
!= NULL
);
73 if (!isPathnameUrl(*url
) ||
74 (osl::FileBase::getFileURLFromSystemPath(
75 url
->copy(RTL_CONSTASCII_LENGTH(VND_SUN_STAR_PATHNAME
)), *url
) ==
76 osl::FileBase::E_None
))
80 *url
= rtl::OUString();
86 LOOKUP_MODE_NORMAL
, LOOKUP_MODE_URE_BOOTSTRAP
,
87 LOOKUP_MODE_URE_BOOTSTRAP_EXPANSION
};
89 struct ExpandRequestLink
{
90 ExpandRequestLink
const * next
;
91 Bootstrap_Impl
const * file
;
95 rtl::OUString
expandMacros(
96 Bootstrap_Impl
const * file
, rtl::OUString
const & text
, LookupMode mode
,
97 ExpandRequestLink
const * requestStack
);
99 rtl::OUString
recursivelyExpandMacros(
100 Bootstrap_Impl
const * file
, rtl::OUString
const & text
, LookupMode mode
,
101 Bootstrap_Impl
const * requestFile
, rtl::OUString
const & requestKey
,
102 ExpandRequestLink
const * requestStack
)
104 for (; requestStack
!= NULL
; requestStack
= requestStack
->next
) {
105 if (requestStack
->file
== requestFile
&&
106 requestStack
->key
== requestKey
)
108 return rtl::OUString("***RECURSION DETECTED***");
111 ExpandRequestLink link
= { requestStack
, requestFile
, requestKey
};
112 return expandMacros(file
, text
, mode
, &link
);
117 //----------------------------------------------------------------------------
119 struct rtl_bootstrap_NameValue
124 inline rtl_bootstrap_NameValue() SAL_THROW( () )
126 inline rtl_bootstrap_NameValue(
127 OUString
const & name
, OUString
const & value
) SAL_THROW( () )
134 rtl_bootstrap_NameValue
,
135 rtl::Allocator
< rtl_bootstrap_NameValue
>
139 NameValueList
const & list
, rtl::OUString
const & key
,
140 rtl::OUString
* value
)
142 OSL_ASSERT(value
!= NULL
);
143 for (NameValueList::const_iterator
i(list
.begin()); i
!= list
.end(); ++i
) {
144 if (i
->sName
== key
) {
153 struct rtl_bootstrap_set_list
:
154 public rtl::Static
< NameValueList
, rtl_bootstrap_set_list
> {};
157 //----------------------------------------------------------------------------
159 static sal_Bool
getFromCommandLineArgs(
160 rtl::OUString
const & key
, rtl::OUString
* value
)
162 OSL_ASSERT(value
!= NULL
);
163 static NameValueList
*pNameValueList
= 0;
164 if( ! pNameValueList
)
166 static NameValueList nameValueList
;
168 sal_Int32 nArgCount
= osl_getCommandArgCount();
169 for(sal_Int32 i
= 0; i
< nArgCount
; ++ i
)
171 rtl_uString
*pArg
= 0;
172 osl_getCommandArg( i
, &pArg
);
173 if( ('-' == pArg
->buffer
[0] || '/' == pArg
->buffer
[0] ) &&
174 'e' == pArg
->buffer
[1] &&
175 'n' == pArg
->buffer
[2] &&
176 'v' == pArg
->buffer
[3] &&
177 ':' == pArg
->buffer
[4] )
179 sal_Int32 nIndex
= rtl_ustr_indexOfChar( pArg
->buffer
, '=' );
183 rtl_bootstrap_NameValue nameValue
;
184 nameValue
.sName
= OUString( &(pArg
->buffer
[5]), nIndex
- 5 );
185 nameValue
.sValue
= OUString( &(pArg
->buffer
[nIndex
+1]) );
186 if( i
== nArgCount
-1 &&
187 nameValue
.sValue
.getLength() &&
188 nameValue
.sValue
[nameValue
.sValue
.getLength()-1] == 13 )
190 // avoid the 13 linefeed for the last argument,
191 // when the executable is started from a script,
192 // that was edited on windows
193 nameValue
.sValue
= nameValue
.sValue
.copy(0,nameValue
.sValue
.getLength()-1);
195 nameValueList
.push_back( nameValue
);
198 rtl_uString_release( pArg
);
200 pNameValueList
= &nameValueList
;
203 sal_Bool found
= sal_False
;
205 for( NameValueList::iterator ii
= pNameValueList
->begin() ;
206 ii
!= pNameValueList
->end() ;
209 if( (*ii
).sName
.equals(key
) )
211 *value
= (*ii
).sValue
;
220 //----------------------------------------------------------------------------
222 extern "C" oslProcessError SAL_CALL
osl_bootstrap_getExecutableFile_Impl (
223 rtl_uString
** ppFileURL
) SAL_THROW_EXTERN_C();
225 inline void getExecutableFile_Impl (rtl_uString
** ppFileURL
)
227 osl_bootstrap_getExecutableFile_Impl (ppFileURL
);
230 //----------------------------------------------------------------------------
232 static void getExecutableDirectory_Impl (rtl_uString
** ppDirURL
)
235 getExecutableFile_Impl (&(fileName
.pData
));
237 sal_Int32 nDirEnd
= fileName
.lastIndexOf('/');
238 OSL_ENSURE(nDirEnd
>= 0, "Cannot locate executable directory");
240 rtl_uString_newFromStr_WithLength(ppDirURL
,fileName
.getStr(),nDirEnd
);
243 //----------------------------------------------------------------------------
245 static OUString
& getIniFileName_Impl()
247 osl::MutexGuard
guard( osl::Mutex::getGlobalMutex() );
248 static OUString
*pStaticName
= 0;
254 // On iOS hardcode the inifile as "rc" in the .app
255 // directory. Apps are self-contained anyway, there is no
256 // possibility to have several "applications" in the same
257 // installation location with different inifiles.
258 const char *inifile
= [[@
"vnd.sun.star.pathname:" stringByAppendingString
: [[[NSBundle mainBundle
] bundlePath
] stringByAppendingPathComponent
: @
"rc"]] UTF8String
];
259 fileName
= rtl::OUString(inifile
, strlen(inifile
), RTL_TEXTENCODING_UTF8
);
260 resolvePathnameUrl(&fileName
);
261 #elif defined ANDROID
262 // Apps are self-contained on Android, too, can as well hardcode
263 // it as "rc" in the "/assets" directory, i.e. inside the app's
264 // .apk (zip) archive as the /assets/rc file.
265 fileName
= rtl::OUString("vnd.sun.star.pathname:/assets/rc");
266 resolvePathnameUrl(&fileName
);
268 if(getFromCommandLineArgs(
269 OUString("INIFILENAME"), &fileName
))
271 resolvePathnameUrl(&fileName
);
275 getExecutableFile_Impl (&(fileName
.pData
));
277 // get rid of a potential executable extension
278 OUString progExt
= ".bin";
279 if(fileName
.getLength() > progExt
.getLength()
280 && fileName
.copy(fileName
.getLength() - progExt
.getLength()).equalsIgnoreAsciiCase(progExt
))
281 fileName
= fileName
.copy(0, fileName
.getLength() - progExt
.getLength());
284 if(fileName
.getLength() > progExt
.getLength()
285 && fileName
.copy(fileName
.getLength() - progExt
.getLength()).equalsIgnoreAsciiCase(progExt
))
286 fileName
= fileName
.copy(0, fileName
.getLength() - progExt
.getLength());
288 // append config file suffix
289 fileName
+= OUString(SAL_CONFIGFILE(""));
293 static OUString theFileName
;
294 if(fileName
.getLength())
295 theFileName
= fileName
;
297 pStaticName
= &theFileName
;
303 //----------------------------------------------------------------------------
305 static inline bool path_exists( OUString
const & path
)
307 DirectoryItem dirItem
;
308 return (DirectoryItem::E_None
== DirectoryItem::get( path
, dirItem
));
311 //----------------------------------------------------------------------------
313 // ensure the given file url has no final slash
315 inline void EnsureNoFinalSlash (rtl::OUString
& url
)
317 sal_Int32 i
= url
.getLength();
318 if (i
> 0 && url
[i
- 1] == '/') {
319 url
= url
.copy(0, i
- 1);
323 struct Bootstrap_Impl
325 sal_Int32 _nRefCount
;
326 Bootstrap_Impl
* _base_ini
;
328 NameValueList _nameValueList
;
331 explicit Bootstrap_Impl (OUString
const & rIniName
);
334 static void * operator new (std::size_t n
) SAL_THROW(())
335 { return rtl_allocateMemory (sal_uInt32(n
)); }
336 static void operator delete (void * p
, std::size_t) SAL_THROW(())
337 { rtl_freeMemory (p
); }
340 rtl::OUString
const & key
, rtl_uString
** value
,
341 rtl_uString
* defaultValue
, LookupMode mode
, bool override
,
342 ExpandRequestLink
const * requestStack
) const;
344 rtl::OUString
const & key
, rtl_uString
** value
, LookupMode mode
,
345 ExpandRequestLink
const * requestStack
) const;
346 bool getAmbienceValue(
347 rtl::OUString
const & key
, rtl_uString
** value
, LookupMode mode
,
348 ExpandRequestLink
const * requestStack
) const;
350 rtl_uString
** value
, rtl::OUString
const & text
, LookupMode mode
,
351 Bootstrap_Impl
const * requestFile
, rtl::OUString
const & requestKey
,
352 ExpandRequestLink
const * requestStack
) const;
355 //----------------------------------------------------------------------------
357 Bootstrap_Impl::Bootstrap_Impl( OUString
const & rIniName
)
362 OUString
base_ini( getIniFileName_Impl() );
364 FileStatus
status( osl_FileStatus_Mask_FileURL
);
365 DirectoryItem dirItem
;
366 if (DirectoryItem::E_None
== DirectoryItem::get( base_ini
, dirItem
) &&
367 DirectoryItem::E_None
== dirItem
.getFileStatus( status
))
369 base_ini
= status
.getFileURL();
370 if (! rIniName
.equals( base_ini
))
372 _base_ini
= static_cast< Bootstrap_Impl
* >(
373 rtl_bootstrap_args_open( base_ini
.pData
) );
377 #if OSL_DEBUG_LEVEL > 1
378 OString sFile
= OUStringToOString(_iniName
, RTL_TEXTENCODING_ASCII_US
);
379 OSL_TRACE("Bootstrap_Impl(): sFile=%s", sFile
.getStr());
380 #endif /* OSL_DEBUG_LEVEL > 1 */
382 oslFileHandle handle
;
383 if (!_iniName
.isEmpty() &&
384 osl_File_E_None
== osl_openFile(_iniName
.pData
, &handle
, osl_File_OpenFlag_Read
))
386 rtl::ByteSequence seq
;
388 while (osl_File_E_None
== osl_readLine(handle
, (sal_Sequence
**)&seq
))
390 OString
line( (const sal_Char
*) seq
.getConstArray(), seq
.getLength() );
391 sal_Int32 nIndex
= line
.indexOf('=');
394 struct rtl_bootstrap_NameValue nameValue
;
395 nameValue
.sName
= OStringToOUString(
396 line
.copy(0,nIndex
).trim(), RTL_TEXTENCODING_ASCII_US
);
397 nameValue
.sValue
= OStringToOUString(
398 line
.copy(nIndex
+1).trim(), RTL_TEXTENCODING_UTF8
);
400 #if OSL_DEBUG_LEVEL > 1
401 OString name_tmp
= OUStringToOString(nameValue
.sName
, RTL_TEXTENCODING_ASCII_US
);
402 OString value_tmp
= OUStringToOString(nameValue
.sValue
, RTL_TEXTENCODING_UTF8
);
404 "pushing: name=%s value=%s",
405 name_tmp
.getStr(), value_tmp
.getStr() );
406 #endif /* OSL_DEBUG_LEVEL > 1 */
408 _nameValueList
.push_back(nameValue
);
411 osl_closeFile(handle
);
413 #if OSL_DEBUG_LEVEL > 1
416 OString file_tmp
= OUStringToOString(_iniName
, RTL_TEXTENCODING_ASCII_US
);
417 OSL_TRACE( "couldn't open file: %s", file_tmp
.getStr() );
419 #endif /* OSL_DEBUG_LEVEL > 1 */
422 //----------------------------------------------------------------------------
424 Bootstrap_Impl::~Bootstrap_Impl()
427 rtl_bootstrap_args_close( _base_ini
);
430 //----------------------------------------------------------------------------
434 Bootstrap_Impl
* get_static_bootstrap_handle() SAL_THROW(())
436 osl::MutexGuard
guard( osl::Mutex::getGlobalMutex() );
437 static Bootstrap_Impl
* s_handle
= 0;
440 OUString
iniName (getIniFileName_Impl());
441 s_handle
= static_cast< Bootstrap_Impl
* >(
442 rtl_bootstrap_args_open( iniName
.pData
) );
445 Bootstrap_Impl
* that
= new Bootstrap_Impl( iniName
);
453 struct FundamentalIniData
{
454 rtlBootstrapHandle ini
;
456 FundamentalIniData() {
459 ((static_cast< Bootstrap_Impl
* >(get_static_bootstrap_handle())->
461 rtl::OUString("URE_BOOTSTRAP"),
462 &uri
.pData
, 0, LOOKUP_MODE_NORMAL
, false, 0)) &&
463 resolvePathnameUrl(&uri
))
464 ? rtl_bootstrap_args_open(uri
.pData
) : NULL
;
467 ~FundamentalIniData() { rtl_bootstrap_args_close(ini
); }
470 FundamentalIniData(FundamentalIniData
&); // not defined
471 void operator =(FundamentalIniData
&); // not defined
474 struct FundamentalIni
: public rtl::Static
< FundamentalIniData
, FundamentalIni
>
479 bool Bootstrap_Impl::getValue(
480 rtl::OUString
const & key
, rtl_uString
** value
, rtl_uString
* defaultValue
,
481 LookupMode mode
, bool override
, ExpandRequestLink
const * requestStack
)
484 if (mode
== LOOKUP_MODE_NORMAL
&&
485 key
.equalsAsciiL(RTL_CONSTASCII_STRINGPARAM("URE_BOOTSTRAP")))
487 mode
= LOOKUP_MODE_URE_BOOTSTRAP
;
489 if (override
&& getDirectValue(key
, value
, mode
, requestStack
)) {
494 value
, rtl::OUString(RTL_OS
).pData
);
497 if (key
== "_ARCH") {
499 value
, rtl::OUString(RTL_ARCH
).pData
);
502 if (key
== "_CPPU_ENV") {
506 SAL_STRINGIFY(CPPU_ENV
)).
511 if (key
== "APP_DATA_DIR") {
512 const char *app_data_dir
= lo_get_app_data_dir();
514 value
, rtl::OUString(app_data_dir
, strlen(app_data_dir
), RTL_TEXTENCODING_UTF8
).pData
);
519 if (key
== "APP_DATA_DIR") {
520 const char *app_data_dir
= [[[[NSBundle mainBundle
] bundlePath
] stringByAddingPercentEscapesUsingEncoding
: NSUTF8StringEncoding
] UTF8String
];
522 value
, rtl::OUString(app_data_dir
, strlen(app_data_dir
), RTL_TEXTENCODING_UTF8
).pData
);
526 if (key
== "ORIGIN") {
530 0, std::max
<sal_Int32
>(0, _iniName
.lastIndexOf('/'))).pData
);
533 if (getAmbienceValue(key
, value
, mode
, requestStack
)) {
536 if (key
== "SYSUSERCONFIG") {
538 bool b
= osl::Security().getConfigDir(v
);
539 EnsureNoFinalSlash(v
);
540 rtl_uString_assign(value
, v
.pData
);
543 if (key
== "SYSUSERHOME") {
545 bool b
= osl::Security().getHomeDir(v
);
546 EnsureNoFinalSlash(v
);
547 rtl_uString_assign(value
, v
.pData
);
550 if (key
== "SYSBINDIR") {
551 getExecutableDirectory_Impl(value
);
554 if (_base_ini
!= NULL
&&
555 _base_ini
->getDirectValue(key
, value
, mode
, requestStack
))
559 if (!override
&& getDirectValue(key
, value
, mode
, requestStack
)) {
562 if (mode
== LOOKUP_MODE_NORMAL
) {
563 FundamentalIniData
const & d
= FundamentalIni::get();
564 Bootstrap_Impl
const * b
= static_cast<Bootstrap_Impl
const *>(d
.ini
);
565 if (b
!= NULL
&& b
!= this &&
566 b
->getDirectValue(key
, value
, mode
, requestStack
))
571 if (defaultValue
!= NULL
) {
572 rtl_uString_assign(value
, defaultValue
);
575 rtl_uString_new(value
);
579 bool Bootstrap_Impl::getDirectValue(
580 rtl::OUString
const & key
, rtl_uString
** value
, LookupMode mode
,
581 ExpandRequestLink
const * requestStack
) const
584 if (find(_nameValueList
, key
, &v
)) {
585 expandValue(value
, v
, mode
, this, key
, requestStack
);
592 bool Bootstrap_Impl::getAmbienceValue(
593 rtl::OUString
const & key
, rtl_uString
** value
, LookupMode mode
,
594 ExpandRequestLink
const * requestStack
) const
599 osl::MutexGuard
g(osl::Mutex::getGlobalMutex());
600 f
= find(rtl_bootstrap_set_list::get(), key
, &v
);
602 if (f
|| getFromCommandLineArgs(key
, &v
) ||
603 osl_getEnvironment(key
.pData
, &v
.pData
) == osl_Process_E_None
)
605 expandValue(value
, v
, mode
, NULL
, key
, requestStack
);
612 void Bootstrap_Impl::expandValue(
613 rtl_uString
** value
, rtl::OUString
const & text
, LookupMode mode
,
614 Bootstrap_Impl
const * requestFile
, rtl::OUString
const & requestKey
,
615 ExpandRequestLink
const * requestStack
) const
619 (mode
== LOOKUP_MODE_URE_BOOTSTRAP
&& isPathnameUrl(text
) ?
621 recursivelyExpandMacros(
623 (mode
== LOOKUP_MODE_URE_BOOTSTRAP
?
624 LOOKUP_MODE_URE_BOOTSTRAP_EXPANSION
: mode
),
625 requestFile
, requestKey
, requestStack
)).pData
);
630 struct bootstrap_map
{
631 typedef boost::unordered_map
<
632 rtl::OUString
, Bootstrap_Impl
*,
633 rtl::OUStringHash
, std::equal_to
< rtl::OUString
>,
634 rtl::Allocator
< OUString
> > t
;
636 // get and release must only be called properly synchronized via some mutex
637 // (e.g., osl::Mutex::getGlobalMutex()):
646 static void release() {
647 if (m_map
!= NULL
&& m_map
->empty()) {
654 bootstrap_map(); // not defined
659 bootstrap_map::t
* bootstrap_map::m_map
= NULL
;
663 //----------------------------------------------------------------------------
665 rtlBootstrapHandle SAL_CALL
rtl_bootstrap_args_open (
666 rtl_uString
* pIniName
667 ) SAL_THROW_EXTERN_C()
669 OUString
iniName( pIniName
);
672 FileStatus
status( osl_FileStatus_Mask_FileURL
);
673 DirectoryItem dirItem
;
674 if (DirectoryItem::E_None
!= DirectoryItem::get( iniName
, dirItem
) ||
675 DirectoryItem::E_None
!= dirItem
.getFileStatus( status
))
679 iniName
= status
.getFileURL();
681 Bootstrap_Impl
* that
;
682 osl::ResettableMutexGuard
guard( osl::Mutex::getGlobalMutex() );
683 bootstrap_map::t
* p_bootstrap_map
= bootstrap_map::get();
684 bootstrap_map::t::const_iterator
iFind( p_bootstrap_map
->find( iniName
) );
685 if (iFind
== p_bootstrap_map
->end())
687 bootstrap_map::release();
689 that
= new Bootstrap_Impl( iniName
);
691 p_bootstrap_map
= bootstrap_map::get();
692 iFind
= p_bootstrap_map
->find( iniName
);
693 if (iFind
== p_bootstrap_map
->end())
696 ::std::pair
< bootstrap_map::t::iterator
, bool > insertion(
697 p_bootstrap_map
->insert(
698 bootstrap_map::t::value_type( iniName
, that
) ) );
699 (void) insertion
; // WaE: unused variable
700 OSL_ASSERT( insertion
.second
);
704 Bootstrap_Impl
* obsolete
= that
;
705 that
= iFind
->second
;
713 that
= iFind
->second
;
716 return static_cast< rtlBootstrapHandle
>( that
);
719 //----------------------------------------------------------------------------
721 void SAL_CALL
rtl_bootstrap_args_close (
722 rtlBootstrapHandle handle
723 ) SAL_THROW_EXTERN_C()
727 Bootstrap_Impl
* that
= static_cast< Bootstrap_Impl
* >( handle
);
729 osl::MutexGuard
guard( osl::Mutex::getGlobalMutex() );
730 bootstrap_map::t
* p_bootstrap_map
= bootstrap_map::get();
732 p_bootstrap_map
->find( that
->_iniName
)->second
== that
);
734 if (that
->_nRefCount
== 0)
736 ::std::size_t nLeaking
= 8; // only hold up to 8 files statically
738 #if OSL_DEBUG_LEVEL == 1 // nonpro
740 #elif OSL_DEBUG_LEVEL > 1 // debug
742 #endif /* OSL_DEBUG_LEVEL */
744 if (p_bootstrap_map
->size() > nLeaking
)
746 ::std::size_t erased
= p_bootstrap_map
->erase( that
->_iniName
);
752 bootstrap_map::release();
756 //----------------------------------------------------------------------------
758 sal_Bool SAL_CALL
rtl_bootstrap_get_from_handle(
759 rtlBootstrapHandle handle
,
761 rtl_uString
** ppValue
,
762 rtl_uString
* pDefault
763 ) SAL_THROW_EXTERN_C()
765 osl::MutexGuard
guard( osl::Mutex::getGlobalMutex() );
767 sal_Bool found
= sal_False
;
771 handle
= get_static_bootstrap_handle();
772 found
= static_cast< Bootstrap_Impl
* >( handle
)->getValue(
773 pName
, ppValue
, pDefault
, LOOKUP_MODE_NORMAL
, false, NULL
);
779 //----------------------------------------------------------------------------
781 void SAL_CALL
rtl_bootstrap_get_iniName_from_handle (
782 rtlBootstrapHandle handle
,
783 rtl_uString
** ppIniName
784 ) SAL_THROW_EXTERN_C()
790 Bootstrap_Impl
* pImpl
= static_cast<Bootstrap_Impl
*>(handle
);
791 rtl_uString_assign(ppIniName
, pImpl
->_iniName
.pData
);
795 const OUString
& iniName
= getIniFileName_Impl();
796 rtl_uString_assign(ppIniName
, iniName
.pData
);
801 //----------------------------------------------------------------------------
803 void SAL_CALL
rtl_bootstrap_setIniFileName (
805 ) SAL_THROW_EXTERN_C()
807 osl::MutexGuard
guard( osl::Mutex::getGlobalMutex() );
808 OUString
& file
= getIniFileName_Impl();
812 //----------------------------------------------------------------------------
814 sal_Bool SAL_CALL
rtl_bootstrap_get (
816 rtl_uString
** ppValue
,
817 rtl_uString
* pDefault
818 ) SAL_THROW_EXTERN_C()
820 return rtl_bootstrap_get_from_handle(0, pName
, ppValue
, pDefault
);
823 //----------------------------------------------------------------------------
825 void SAL_CALL
rtl_bootstrap_set (
828 ) SAL_THROW_EXTERN_C()
830 const OUString
name( pName
);
831 const OUString
value( pValue
);
833 osl::MutexGuard
guard( osl::Mutex::getGlobalMutex() );
835 NameValueList
& r_rtl_bootstrap_set_list
= rtl_bootstrap_set_list::get();
836 NameValueList::iterator
iPos( r_rtl_bootstrap_set_list
.begin() );
837 NameValueList::iterator
iEnd( r_rtl_bootstrap_set_list
.end() );
838 for ( ; iPos
!= iEnd
; ++iPos
)
840 if (iPos
->sName
.equals( name
))
842 iPos
->sValue
= value
;
847 #if OSL_DEBUG_LEVEL > 1
848 OString
cstr_name( OUStringToOString( name
, RTL_TEXTENCODING_ASCII_US
) );
849 OString
cstr_value( OUStringToOString( value
, RTL_TEXTENCODING_ASCII_US
) );
851 "bootstrap.cxx: explicitly setting: name=%s value=%s\n",
852 cstr_name
.getStr(), cstr_value
.getStr() );
853 #endif /* OSL_DEBUG_LEVEL > 1 */
855 r_rtl_bootstrap_set_list
.push_back( rtl_bootstrap_NameValue( name
, value
) );
858 //----------------------------------------------------------------------------
860 void SAL_CALL
rtl_bootstrap_expandMacros_from_handle (
861 rtlBootstrapHandle handle
,
863 ) SAL_THROW_EXTERN_C()
865 if (handle
== NULL
) {
866 handle
= get_static_bootstrap_handle();
868 OUString
expanded( expandMacros( static_cast< Bootstrap_Impl
* >( handle
),
869 * reinterpret_cast< OUString
const * >( macro
),
870 LOOKUP_MODE_NORMAL
, NULL
) );
871 rtl_uString_assign( macro
, expanded
.pData
);
874 //----------------------------------------------------------------------------
876 void SAL_CALL
rtl_bootstrap_expandMacros(
877 rtl_uString
** macro
)
880 rtl_bootstrap_expandMacros_from_handle(NULL
, macro
);
883 void rtl_bootstrap_encode( rtl_uString
const * value
, rtl_uString
** encoded
)
886 OSL_ASSERT(value
!= NULL
);
887 rtl::OUStringBuffer b
;
888 for (sal_Int32 i
= 0; i
< value
->length
; ++i
) {
889 sal_Unicode c
= value
->buffer
[i
];
890 if (c
== '$' || c
== '\\') {
891 b
.append(sal_Unicode('\\'));
895 rtl_uString_assign(encoded
, b
.makeStringAndClear().pData
);
900 int hex(sal_Unicode c
) {
902 c
>= '0' && c
<= '9' ? c
- '0' :
903 c
>= 'A' && c
<= 'F' ? c
- 'A' + 10 :
904 c
>= 'a' && c
<= 'f' ? c
- 'a' + 10 : -1;
907 sal_Unicode
read(rtl::OUString
const & text
, sal_Int32
* pos
, bool * escaped
) {
909 pos
!= NULL
&& *pos
>= 0 && *pos
< text
.getLength() && escaped
!= NULL
);
910 sal_Unicode c
= text
[(*pos
)++];
913 if (*pos
< text
.getLength() - 4 && text
[*pos
] == 'u' &&
914 ((n1
= hex(text
[*pos
+ 1])) >= 0) &&
915 ((n2
= hex(text
[*pos
+ 2])) >= 0) &&
916 ((n3
= hex(text
[*pos
+ 3])) >= 0) &&
917 ((n4
= hex(text
[*pos
+ 4])) >= 0))
921 return static_cast< sal_Unicode
>(
922 (n1
<< 12) | (n2
<< 8) | (n3
<< 4) | n4
);
923 } else if (*pos
< text
.getLength()) {
925 return text
[(*pos
)++];
932 rtl::OUString
lookup(
933 Bootstrap_Impl
const * file
, LookupMode mode
, bool override
,
934 rtl::OUString
const & key
, ExpandRequestLink
const * requestStack
)
937 (file
== NULL
? get_static_bootstrap_handle() : file
)->getValue(
938 key
, &v
.pData
, NULL
, mode
, override
, requestStack
);
942 rtl::OUString
expandMacros(
943 Bootstrap_Impl
const * file
, rtl::OUString
const & text
, LookupMode mode
,
944 ExpandRequestLink
const * requestStack
)
946 rtl::OUStringBuffer buf
;
947 for (sal_Int32 i
= 0; i
< text
.getLength();) {
949 sal_Unicode c
= read(text
, &i
, &escaped
);
950 if (escaped
|| c
!= '$') {
953 if (i
< text
.getLength() && text
[i
] == '{') {
956 sal_Int32 nesting
= 0;
957 rtl::OUString seg
[3];
959 while (i
< text
.getLength()) {
961 c
= read(text
, &i
, &escaped
);
969 seg
[n
++] = text
.copy(p
, j
- p
);
976 if (nesting
== 0 && n
< 2) {
977 seg
[n
++] = text
.copy(p
, j
- p
);
985 for (int j
= 0; j
< n
; ++j
) {
986 seg
[j
] = expandMacros(file
, seg
[j
], mode
, requestStack
);
989 buf
.append(lookup(file
, mode
, false, seg
[0], requestStack
));
990 } else if (n
== 2 && seg
[0] == ".link") {
992 rtl::ByteSequence seq
;
995 // Silently ignore any errors (is that good?):
996 if ((f
.open(osl_File_OpenFlag_Read
) ==
997 osl::FileBase::E_None
) &&
998 f
.readLine(seq
) == osl::FileBase::E_None
&&
999 rtl_convertStringToUString(
1001 reinterpret_cast< char const * >(
1002 seq
.getConstArray()),
1003 seq
.getLength(), RTL_TEXTENCODING_UTF8
,
1004 (RTL_TEXTTOUNICODE_FLAGS_UNDEFINED_ERROR
|
1005 RTL_TEXTTOUNICODE_FLAGS_MBUNDEFINED_ERROR
|
1006 RTL_TEXTTOUNICODE_FLAGS_INVALID_ERROR
)) &&
1007 (osl::File::getFileURLFromSystemPath(line
, url
) ==
1008 osl::FileBase::E_None
))
1012 rtl::Uri::convertRelToAbs(seg
[1], url
));
1013 } catch (const rtl::MalformedUriException
&) {}
1015 } else if (n
== 3 && seg
[0] == ".override") {
1016 rtl::Bootstrap
b(seg
[1]);
1017 Bootstrap_Impl
* f
= static_cast< Bootstrap_Impl
* >(
1020 lookup(f
, mode
, f
!= NULL
, seg
[2], requestStack
));
1022 if (n
== 3 && seg
[1].isEmpty()) {
1023 // For backward compatibility, treat ${file::key} the
1024 // same as just ${file:key}:
1031 static_cast< Bootstrap_Impl
* >(
1032 rtl::Bootstrap(seg
[0]).getHandle()),
1033 mode
, false, seg
[1], requestStack
));
1035 // Going through osl::Profile, this code erroneously
1036 // does not recursively expand macros in the resulting
1037 // replacement text (and if it did, it would fail to
1038 // detect cycles that pass through here):
1040 rtl::OStringToOUString(
1041 osl::Profile(seg
[0]).readString(
1042 rtl::OUStringToOString(
1043 seg
[1], RTL_TEXTENCODING_UTF8
),
1044 rtl::OUStringToOString(
1045 seg
[2], RTL_TEXTENCODING_UTF8
),
1047 RTL_TEXTENCODING_UTF8
));
1051 rtl::OUStringBuffer kbuf
;
1052 for (; i
< text
.getLength();) {
1054 c
= read(text
, &j
, &escaped
);
1056 (c
== ' ' || c
== '$' || c
== '-' || c
== '/' ||
1057 c
== ';' || c
== '\\'))
1066 file
, mode
, false, kbuf
.makeStringAndClear(),
1071 return buf
.makeStringAndClear();
1076 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */