1 /**************************************************************
2 *
3 * Licensed to the Apache Software Foundation (ASF) under one
4 * or more contributor license agreements. See the NOTICE file
5 * distributed with this work for additional information
6 * regarding copyright ownership. The ASF licenses this file
7 * to you under the Apache License, Version 2.0 (the
8 * "License"); you may not use this file except in compliance
9 * with the License. You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing,
14 * software distributed under the License is distributed on an
15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16 * KIND, either express or implied. See the License for the
17 * specific language governing permissions and limitations
18 * under the License.
19 *
20 *************************************************************/
21
22
23
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_sal.hxx"
26
27 #include "rtl/bootstrap.h"
28 #include "rtl/bootstrap.hxx"
29 #include <osl/diagnose.h>
30 #include <osl/module.h>
31 #include <osl/process.h>
32 #include <osl/file.hxx>
33 #include <osl/mutex.hxx>
34 #include <osl/profile.hxx>
35 #include <osl/security.hxx>
36 #include <rtl/alloc.h>
37 #include <rtl/string.hxx>
38 #include <rtl/ustrbuf.hxx>
39 #include <rtl/ustring.hxx>
40 #include <rtl/byteseq.hxx>
41 #include <rtl/instance.hxx>
42 #include <rtl/malformeduriexception.hxx>
43 #include <rtl/uri.hxx>
44
45 #include "macro.hxx"
46
47 #include <hash_map>
48 #include <list>
49
50 #define MY_STRING_(x) # x
51 #define MY_STRING(x) MY_STRING_(x)
52
53 //----------------------------------------------------------------------------
54
55 using osl::DirectoryItem;
56 using osl::FileStatus;
57
58 using rtl::OString;
59 using rtl::OUString;
60 using rtl::OUStringToOString;
61
62 struct Bootstrap_Impl;
63
64 namespace {
65
66 static char const VND_SUN_STAR_PATHNAME[] = "vnd.sun.star.pathname:";
67
isPathnameUrl(rtl::OUString const & url)68 bool isPathnameUrl(rtl::OUString const & url) {
69 return url.matchIgnoreAsciiCaseAsciiL(
70 RTL_CONSTASCII_STRINGPARAM(VND_SUN_STAR_PATHNAME));
71 }
72
resolvePathnameUrl(rtl::OUString * url)73 bool resolvePathnameUrl(rtl::OUString * url) {
74 OSL_ASSERT(url != NULL);
75 if (!isPathnameUrl(*url) ||
76 (osl::FileBase::getFileURLFromSystemPath(
77 url->copy(RTL_CONSTASCII_LENGTH(VND_SUN_STAR_PATHNAME)), *url) ==
78 osl::FileBase::E_None))
79 {
80 return true;
81 } else {
82 *url = rtl::OUString();
83 return false;
84 }
85 }
86
87 enum LookupMode {
88 LOOKUP_MODE_NORMAL, LOOKUP_MODE_URE_BOOTSTRAP,
89 LOOKUP_MODE_URE_BOOTSTRAP_EXPANSION };
90
91 struct ExpandRequestLink {
92 ExpandRequestLink const * next;
93 Bootstrap_Impl const * file;
94 rtl::OUString key;
95 };
96
97 rtl::OUString expandMacros(
98 Bootstrap_Impl const * file, rtl::OUString const & text, LookupMode mode,
99 ExpandRequestLink const * requestStack);
100
recursivelyExpandMacros(Bootstrap_Impl const * file,rtl::OUString const & text,LookupMode mode,Bootstrap_Impl const * requestFile,rtl::OUString const & requestKey,ExpandRequestLink const * requestStack)101 rtl::OUString recursivelyExpandMacros(
102 Bootstrap_Impl const * file, rtl::OUString const & text, LookupMode mode,
103 Bootstrap_Impl const * requestFile, rtl::OUString const & requestKey,
104 ExpandRequestLink const * requestStack)
105 {
106 for (; requestStack != NULL; requestStack = requestStack->next) {
107 if (requestStack->file == requestFile &&
108 requestStack->key == requestKey)
109 {
110 return rtl::OUString(
111 RTL_CONSTASCII_USTRINGPARAM("***RECURSION DETECTED***"));
112 }
113 }
114 ExpandRequestLink link = { requestStack, requestFile, requestKey };
115 return expandMacros(file, text, mode, &link);
116 }
117
118 }
119
120 //----------------------------------------------------------------------------
121
122 struct rtl_bootstrap_NameValue
123 {
124 OUString sName;
125 OUString sValue;
126
127 inline rtl_bootstrap_NameValue() SAL_THROW( () )
128 {}
rtl_bootstrap_NameValuertl_bootstrap_NameValue129 inline rtl_bootstrap_NameValue(
130 OUString const & name, OUString const & value ) SAL_THROW( () )
131 : sName( name ),
132 sValue( value )
133 {}
134 };
135
136 typedef std::list<rtl_bootstrap_NameValue> NameValueList;
137
find(NameValueList const & list,rtl::OUString const & key,rtl::OUString * value)138 bool find(
139 NameValueList const & list, rtl::OUString const & key,
140 rtl::OUString * value)
141 {
142 OSL_ASSERT(value != NULL);
143 for (NameValueList::const_iterator i(list.begin()); i != list.end(); ++i) {
144 if (i->sName == key) {
145 *value = i->sValue;
146 return true;
147 }
148 }
149 return false;
150 }
151
152 namespace {
153 struct rtl_bootstrap_set_list :
154 public rtl::Static< NameValueList, rtl_bootstrap_set_list > {};
155 }
156
157 //----------------------------------------------------------------------------
158
getFromCommandLineArgs(rtl::OUString const & key,rtl::OUString * value)159 static sal_Bool getFromCommandLineArgs(
160 rtl::OUString const & key, rtl::OUString * value )
161 {
162 OSL_ASSERT(value != NULL);
163 static NameValueList *pNameValueList = 0;
164 if( ! pNameValueList )
165 {
166 static NameValueList nameValueList;
167
168 sal_Int32 nArgCount = osl_getCommandArgCount();
169 for(sal_Int32 i = 0; i < nArgCount; ++ i)
170 {
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] )
178 {
179 sal_Int32 nIndex = rtl_ustr_indexOfChar( pArg->buffer, '=' );
180 if( nIndex >= 0 )
181 {
182
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 )
189 {
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);
194 }
195 nameValueList.push_back( nameValue );
196 }
197 }
198 rtl_uString_release( pArg );
199 }
200 pNameValueList = &nameValueList;
201 }
202
203 sal_Bool found = sal_False;
204
205 for( NameValueList::iterator ii = pNameValueList->begin() ;
206 ii != pNameValueList->end() ;
207 ++ii )
208 {
209 if( (*ii).sName.equals(key) )
210 {
211 *value = (*ii).sValue;
212 found = sal_True;
213 break;
214 }
215 }
216
217 return found;
218 }
219
220 //----------------------------------------------------------------------------
221
222 extern "C" oslProcessError SAL_CALL osl_bootstrap_getExecutableFile_Impl (
223 rtl_uString ** ppFileURL) SAL_THROW_EXTERN_C();
224
getExecutableFile_Impl(rtl_uString ** ppFileURL)225 inline void getExecutableFile_Impl (rtl_uString ** ppFileURL)
226 {
227 osl_bootstrap_getExecutableFile_Impl (ppFileURL);
228 }
229
230 //----------------------------------------------------------------------------
231
getExecutableDirectory_Impl(rtl_uString ** ppDirURL)232 static void getExecutableDirectory_Impl (rtl_uString ** ppDirURL)
233 {
234 OUString fileName;
235 getExecutableFile_Impl (&(fileName.pData));
236
237 sal_Int32 nDirEnd = fileName.lastIndexOf('/');
238 OSL_ENSURE(nDirEnd >= 0, "Cannot locate executable directory");
239
240 rtl_uString_newFromStr_WithLength(ppDirURL,fileName.getStr(),nDirEnd);
241 }
242
243 //----------------------------------------------------------------------------
244
getIniFileName_Impl()245 static OUString & getIniFileName_Impl()
246 {
247 static OUString *pStaticName = 0;
248 if( ! pStaticName )
249 {
250 OUString fileName;
251
252 if(getFromCommandLineArgs(
253 OUString(RTL_CONSTASCII_USTRINGPARAM("INIFILENAME")), &fileName))
254 {
255 resolvePathnameUrl(&fileName);
256 }
257 else
258 {
259 getExecutableFile_Impl (&(fileName.pData));
260
261 // get rid of a potential executable extension
262 OUString progExt (RTL_CONSTASCII_USTRINGPARAM(".bin"));
263 if(fileName.getLength() > progExt.getLength()
264 && fileName.copy(fileName.getLength() - progExt.getLength()).equalsIgnoreAsciiCase(progExt))
265 fileName = fileName.copy(0, fileName.getLength() - progExt.getLength());
266
267 progExt = OUString::createFromAscii(".exe");
268 if(fileName.getLength() > progExt.getLength()
269 && fileName.copy(fileName.getLength() - progExt.getLength()).equalsIgnoreAsciiCase(progExt))
270 fileName = fileName.copy(0, fileName.getLength() - progExt.getLength());
271
272 // append config file suffix
273 fileName += OUString(RTL_CONSTASCII_USTRINGPARAM(SAL_CONFIGFILE("")));
274 }
275
276 static OUString theFileName;
277 if(fileName.getLength())
278 theFileName = fileName;
279
280 pStaticName = &theFileName;
281 }
282
283 return *pStaticName;
284 }
285
286 //----------------------------------------------------------------------------
287
path_exists(OUString const & path)288 static inline bool path_exists( OUString const & path )
289 {
290 DirectoryItem dirItem;
291 return (DirectoryItem::E_None == DirectoryItem::get( path, dirItem ));
292 }
293
294 //----------------------------------------------------------------------------
295 // #111772#
296 // ensure the given file url has no final slash
297
EnsureNoFinalSlash(rtl::OUString & url)298 inline void EnsureNoFinalSlash (rtl::OUString & url)
299 {
300 sal_Int32 i = url.getLength();
301 if (i > 0 && url[i - 1] == '/') {
302 url = url.copy(0, i - 1);
303 }
304 }
305
306 //----------------------------------------------------------------------------
307 //----------------------------------------------------------------------------
308
309 struct Bootstrap_Impl
310 {
311 sal_Int32 _nRefCount;
312 Bootstrap_Impl * _base_ini;
313
314 NameValueList _nameValueList;
315 OUString _iniName;
316
317 explicit Bootstrap_Impl (OUString const & rIniName);
318 ~Bootstrap_Impl();
319
operator newBootstrap_Impl320 static void * operator new (std::size_t n) SAL_THROW(())
321 { return rtl_allocateMemory (sal_uInt32(n)); }
operator deleteBootstrap_Impl322 static void operator delete (void * p , std::size_t) SAL_THROW(())
323 { rtl_freeMemory (p); }
324
325 bool getValue(
326 rtl::OUString const & key, rtl_uString ** value,
327 rtl_uString * defaultValue, LookupMode mode, bool override,
328 ExpandRequestLink const * requestStack) const;
329 bool getDirectValue(
330 rtl::OUString const & key, rtl_uString ** value, LookupMode mode,
331 ExpandRequestLink const * requestStack) const;
332 bool getAmbienceValue(
333 rtl::OUString const & key, rtl_uString ** value, LookupMode mode,
334 ExpandRequestLink const * requestStack) const;
335 void expandValue(
336 rtl_uString ** value, rtl::OUString const & text, LookupMode mode,
337 Bootstrap_Impl const * requestFile, rtl::OUString const & requestKey,
338 ExpandRequestLink const * requestStack) const;
339 };
340
341 //----------------------------------------------------------------------------
342
Bootstrap_Impl(OUString const & rIniName)343 Bootstrap_Impl::Bootstrap_Impl( OUString const & rIniName )
344 : _nRefCount( 0 ),
345 _base_ini( 0 ),
346 _iniName (rIniName)
347 {
348 OUString base_ini( getIniFileName_Impl() );
349 // normalize path
350 FileStatus status( FileStatusMask_FileURL );
351 DirectoryItem dirItem;
352 if (DirectoryItem::E_None == DirectoryItem::get( base_ini, dirItem ) &&
353 DirectoryItem::E_None == dirItem.getFileStatus( status ))
354 {
355 base_ini = status.getFileURL();
356 if (! rIniName.equals( base_ini ))
357 {
358 _base_ini = static_cast< Bootstrap_Impl * >(
359 rtl_bootstrap_args_open( base_ini.pData ) );
360 }
361 }
362
363 #if OSL_DEBUG_LEVEL > 1
364 OString sFile = OUStringToOString(_iniName, RTL_TEXTENCODING_ASCII_US);
365 OSL_TRACE(__FILE__" -- Bootstrap_Impl() - %s\n", sFile.getStr());
366 #endif /* OSL_DEBUG_LEVEL > 1 */
367
368 oslFileHandle handle;
369 if (_iniName.getLength() &&
370 osl_File_E_None == osl_openFile(_iniName.pData, &handle, osl_File_OpenFlag_Read))
371 {
372 rtl::ByteSequence seq;
373
374 while (osl_File_E_None == osl_readLine(handle , (sal_Sequence **)&seq))
375 {
376 OString line( (const sal_Char *) seq.getConstArray(), seq.getLength() );
377 sal_Int32 nIndex = line.indexOf('=');
378 if (nIndex >= 1)
379 {
380 struct rtl_bootstrap_NameValue nameValue;
381 nameValue.sName = OStringToOUString(
382 line.copy(0,nIndex).trim(), RTL_TEXTENCODING_ASCII_US );
383 nameValue.sValue = OStringToOUString(
384 line.copy(nIndex+1).trim(), RTL_TEXTENCODING_UTF8 );
385
386 #if OSL_DEBUG_LEVEL > 1
387 OString name_tmp = OUStringToOString(nameValue.sName, RTL_TEXTENCODING_ASCII_US);
388 OString value_tmp = OUStringToOString(nameValue.sValue, RTL_TEXTENCODING_UTF8);
389 OSL_TRACE(
390 __FILE__" -- pushing: name=%s value=%s\n",
391 name_tmp.getStr(), value_tmp.getStr() );
392 #endif /* OSL_DEBUG_LEVEL > 1 */
393
394 _nameValueList.push_back(nameValue);
395 }
396 }
397 osl_closeFile(handle);
398 }
399 #if OSL_DEBUG_LEVEL > 1
400 else
401 {
402 OString file_tmp = OUStringToOString(_iniName, RTL_TEXTENCODING_ASCII_US);
403 OSL_TRACE( __FILE__" -- couldn't open file: %s", file_tmp.getStr() );
404 }
405 #endif /* OSL_DEBUG_LEVEL > 1 */
406 }
407
408 //----------------------------------------------------------------------------
409
~Bootstrap_Impl()410 Bootstrap_Impl::~Bootstrap_Impl()
411 {
412 if (_base_ini != 0)
413 rtl_bootstrap_args_close( _base_ini );
414 }
415
416 //----------------------------------------------------------------------------
417
418 namespace {
419
get_static_bootstrap_handle()420 Bootstrap_Impl * get_static_bootstrap_handle() SAL_THROW(())
421 {
422 osl::MutexGuard guard( osl::Mutex::getGlobalMutex() );
423 static Bootstrap_Impl * s_handle = 0;
424 if (s_handle == 0)
425 {
426 OUString iniName (getIniFileName_Impl());
427 s_handle = static_cast< Bootstrap_Impl * >(
428 rtl_bootstrap_args_open( iniName.pData ) );
429 if (s_handle == 0)
430 {
431 Bootstrap_Impl * that = new Bootstrap_Impl( iniName );
432 ++that->_nRefCount;
433 s_handle = that;
434 }
435 }
436 return s_handle;
437 }
438
439 struct FundamentalIniData {
440 rtlBootstrapHandle ini;
441
FundamentalIniData__anon903ad04e0311::FundamentalIniData442 FundamentalIniData() {
443 OUString uri;
444 ini =
445 ((static_cast< Bootstrap_Impl * >(get_static_bootstrap_handle())->
446 getValue(
447 rtl::OUString(
448 RTL_CONSTASCII_USTRINGPARAM("URE_BOOTSTRAP")),
449 &uri.pData, 0, LOOKUP_MODE_NORMAL, false, 0)) &&
450 resolvePathnameUrl(&uri))
451 ? rtl_bootstrap_args_open(uri.pData) : NULL;
452 }
453
~FundamentalIniData__anon903ad04e0311::FundamentalIniData454 ~FundamentalIniData() { rtl_bootstrap_args_close(ini); }
455
456 private:
457 FundamentalIniData(FundamentalIniData &); // not defined
458 void operator =(FundamentalIniData &); // not defined
459 };
460
461 struct FundamentalIni: public rtl::Static< FundamentalIniData, FundamentalIni >
462 {};
463
464 }
465
getValue(rtl::OUString const & key,rtl_uString ** value,rtl_uString * defaultValue,LookupMode mode,bool override,ExpandRequestLink const * requestStack) const466 bool Bootstrap_Impl::getValue(
467 rtl::OUString const & key, rtl_uString ** value, rtl_uString * defaultValue,
468 LookupMode mode, bool override, ExpandRequestLink const * requestStack)
469 const
470 {
471 if (mode == LOOKUP_MODE_NORMAL &&
472 key.equalsAsciiL(RTL_CONSTASCII_STRINGPARAM("URE_BOOTSTRAP")))
473 {
474 mode = LOOKUP_MODE_URE_BOOTSTRAP;
475 }
476 if (override && getDirectValue(key, value, mode, requestStack)) {
477 return true;
478 }
479 if (key.equalsAsciiL(RTL_CONSTASCII_STRINGPARAM("_OS"))) {
480 rtl_uString_assign(
481 value, rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(THIS_OS)).pData);
482 return true;
483 }
484 if (key.equalsAsciiL(RTL_CONSTASCII_STRINGPARAM("_ARCH"))) {
485 rtl_uString_assign(
486 value, rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(THIS_ARCH)).pData);
487 return true;
488 }
489 if (key.equalsAsciiL(RTL_CONSTASCII_STRINGPARAM("_CPPU_ENV"))) {
490 rtl_uString_assign(
491 value,
492 (rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(MY_STRING(CPPU_ENV))).
493 pData));
494 return true;
495 }
496 if (key.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM("ORIGIN"))) {
497 rtl_uString_assign(
498 value,
499 _iniName.copy(
500 0, std::max<sal_Int32>(0, _iniName.lastIndexOf('/'))).pData);
501 return true;
502 }
503 if (getAmbienceValue(key, value, mode, requestStack)) {
504 return true;
505 }
506 if (key.equalsAsciiL(RTL_CONSTASCII_STRINGPARAM("SYSUSERCONFIG"))) {
507 rtl::OUString v;
508 bool b = osl::Security().getConfigDir(v);
509 EnsureNoFinalSlash(v);
510 rtl_uString_assign(value, v.pData);
511 return b;
512 }
513 if (key.equalsAsciiL(RTL_CONSTASCII_STRINGPARAM("SYSUSERHOME"))) {
514 rtl::OUString v;
515 bool b = osl::Security().getHomeDir(v);
516 EnsureNoFinalSlash(v);
517 rtl_uString_assign(value, v.pData);
518 return b;
519 }
520 if (key.equalsAsciiL(RTL_CONSTASCII_STRINGPARAM("SYSBINDIR"))) {
521 getExecutableDirectory_Impl(value);
522 return true;
523 }
524 if (_base_ini != NULL &&
525 _base_ini->getDirectValue(key, value, mode, requestStack))
526 {
527 return true;
528 }
529 if (!override && getDirectValue(key, value, mode, requestStack)) {
530 return true;
531 }
532 if (mode == LOOKUP_MODE_NORMAL) {
533 FundamentalIniData const & d = FundamentalIni::get();
534 Bootstrap_Impl const * b = static_cast<Bootstrap_Impl const *>(d.ini);
535 if (b != NULL && b != this &&
536 b->getDirectValue(key, value, mode, requestStack))
537 {
538 return true;
539 }
540 }
541 if (defaultValue != NULL) {
542 rtl_uString_assign(value, defaultValue);
543 return true;
544 }
545 rtl_uString_new(value);
546 return false;
547 }
548
getDirectValue(rtl::OUString const & key,rtl_uString ** value,LookupMode mode,ExpandRequestLink const * requestStack) const549 bool Bootstrap_Impl::getDirectValue(
550 rtl::OUString const & key, rtl_uString ** value, LookupMode mode,
551 ExpandRequestLink const * requestStack) const
552 {
553 rtl::OUString v;
554 if (find(_nameValueList, key, &v)) {
555 expandValue(value, v, mode, this, key, requestStack);
556 return true;
557 } else {
558 return false;
559 }
560 }
561
getAmbienceValue(rtl::OUString const & key,rtl_uString ** value,LookupMode mode,ExpandRequestLink const * requestStack) const562 bool Bootstrap_Impl::getAmbienceValue(
563 rtl::OUString const & key, rtl_uString ** value, LookupMode mode,
564 ExpandRequestLink const * requestStack) const
565 {
566 rtl::OUString v;
567 bool f;
568 {
569 osl::MutexGuard g(osl::Mutex::getGlobalMutex());
570 f = find(rtl_bootstrap_set_list::get(), key, &v);
571 }
572 if (f || getFromCommandLineArgs(key, &v) ||
573 osl_getEnvironment(key.pData, &v.pData) == osl_Process_E_None)
574 {
575 expandValue(value, v, mode, NULL, key, requestStack);
576 return true;
577 } else {
578 return false;
579 }
580 }
581
expandValue(rtl_uString ** value,rtl::OUString const & text,LookupMode mode,Bootstrap_Impl const * requestFile,rtl::OUString const & requestKey,ExpandRequestLink const * requestStack) const582 void Bootstrap_Impl::expandValue(
583 rtl_uString ** value, rtl::OUString const & text, LookupMode mode,
584 Bootstrap_Impl const * requestFile, rtl::OUString const & requestKey,
585 ExpandRequestLink const * requestStack) const
586 {
587 rtl_uString_assign(
588 value,
589 (mode == LOOKUP_MODE_URE_BOOTSTRAP && isPathnameUrl(text) ?
590 text :
591 recursivelyExpandMacros(
592 this, text,
593 (mode == LOOKUP_MODE_URE_BOOTSTRAP ?
594 LOOKUP_MODE_URE_BOOTSTRAP_EXPANSION : mode),
595 requestFile, requestKey, requestStack)).pData);
596 }
597
598 //----------------------------------------------------------------------------
599 //----------------------------------------------------------------------------
600
601 namespace {
602
603 struct bootstrap_map {
604 typedef std::hash_map< const rtl::OUString, Bootstrap_Impl*, rtl::OUStringHash > t;
605
606 // get and release must only be called properly synchronized via some mutex
607 // (e.g., osl::Mutex::getGlobalMutex()):
608
get__anon903ad04e0411::bootstrap_map609 static t * get() {
610 if (m_map == NULL) {
611 m_map = new t;
612 }
613 return m_map;
614 }
615
release__anon903ad04e0411::bootstrap_map616 static void release() {
617 if (m_map != NULL && m_map->empty()) {
618 delete m_map;
619 m_map = NULL;
620 }
621 }
622
623 private:
624 bootstrap_map(); // not defined
625
626 static t * m_map;
627 };
628
629 bootstrap_map::t * bootstrap_map::m_map = NULL;
630
631 }
632
633 //----------------------------------------------------------------------------
634
rtl_bootstrap_args_open(rtl_uString * pIniName)635 rtlBootstrapHandle SAL_CALL rtl_bootstrap_args_open (
636 rtl_uString * pIniName
637 ) SAL_THROW_EXTERN_C()
638 {
639 OUString iniName( pIniName );
640
641 // normalize path
642 FileStatus status( FileStatusMask_FileURL );
643 DirectoryItem dirItem;
644 if (DirectoryItem::E_None != DirectoryItem::get( iniName, dirItem ) ||
645 DirectoryItem::E_None != dirItem.getFileStatus( status ))
646 {
647 return 0;
648 }
649 iniName = status.getFileURL();
650
651 Bootstrap_Impl * that;
652 osl::ResettableMutexGuard guard( osl::Mutex::getGlobalMutex() );
653 bootstrap_map::t* p_bootstrap_map = bootstrap_map::get();
654 bootstrap_map::t::const_iterator iFind( p_bootstrap_map->find( iniName ) );
655 if (iFind == p_bootstrap_map->end())
656 {
657 bootstrap_map::release();
658 guard.clear();
659 that = new Bootstrap_Impl( iniName );
660 guard.reset();
661 p_bootstrap_map = bootstrap_map::get();
662 iFind = p_bootstrap_map->find( iniName );
663 if (iFind == p_bootstrap_map->end())
664 {
665 ++that->_nRefCount;
666 ::std::pair< bootstrap_map::t::iterator, bool > insertion(
667 p_bootstrap_map->insert(
668 bootstrap_map::t::value_type( iniName, that ) ) );
669 OSL_ASSERT( insertion.second );
670 }
671 else
672 {
673 Bootstrap_Impl * obsolete = that;
674 that = iFind->second;
675 ++that->_nRefCount;
676 guard.clear();
677 delete obsolete;
678 }
679 }
680 else
681 {
682 that = iFind->second;
683 ++that->_nRefCount;
684 }
685 return static_cast< rtlBootstrapHandle >( that );
686 }
687
688 //----------------------------------------------------------------------------
689
rtl_bootstrap_args_close(rtlBootstrapHandle handle)690 void SAL_CALL rtl_bootstrap_args_close (
691 rtlBootstrapHandle handle
692 ) SAL_THROW_EXTERN_C()
693 {
694 if (handle == 0)
695 return;
696 Bootstrap_Impl * that = static_cast< Bootstrap_Impl * >( handle );
697
698 osl::MutexGuard guard( osl::Mutex::getGlobalMutex() );
699 bootstrap_map::t* p_bootstrap_map = bootstrap_map::get();
700 OSL_ASSERT(
701 p_bootstrap_map->find( that->_iniName )->second == that );
702 --that->_nRefCount;
703 if (that->_nRefCount == 0)
704 {
705 ::std::size_t nLeaking = 8; // only hold up to 8 files statically
706
707 #if OSL_DEBUG_LEVEL == 1 // nonpro
708 nLeaking = 0;
709 #elif OSL_DEBUG_LEVEL > 1 // debug
710 nLeaking = 1;
711 #endif /* OSL_DEBUG_LEVEL */
712
713 if (p_bootstrap_map->size() > nLeaking)
714 {
715 ::std::size_t erased = p_bootstrap_map->erase( that->_iniName );
716 if (erased != 1) {
717 OSL_ASSERT( false );
718 }
719 delete that;
720 }
721 bootstrap_map::release();
722 }
723 }
724
725 //----------------------------------------------------------------------------
726
rtl_bootstrap_get_from_handle(rtlBootstrapHandle handle,rtl_uString * pName,rtl_uString ** ppValue,rtl_uString * pDefault)727 sal_Bool SAL_CALL rtl_bootstrap_get_from_handle(
728 rtlBootstrapHandle handle,
729 rtl_uString * pName,
730 rtl_uString ** ppValue,
731 rtl_uString * pDefault
732 ) SAL_THROW_EXTERN_C()
733 {
734 osl::MutexGuard guard( osl::Mutex::getGlobalMutex() );
735
736 sal_Bool found = sal_False;
737 if(ppValue && pName)
738 {
739 if (handle == 0)
740 handle = get_static_bootstrap_handle();
741 found = static_cast< Bootstrap_Impl * >( handle )->getValue(
742 pName, ppValue, pDefault, LOOKUP_MODE_NORMAL, false, NULL );
743 }
744
745 return found;
746 }
747
748 //----------------------------------------------------------------------------
749
rtl_bootstrap_get_iniName_from_handle(rtlBootstrapHandle handle,rtl_uString ** ppIniName)750 void SAL_CALL rtl_bootstrap_get_iniName_from_handle (
751 rtlBootstrapHandle handle,
752 rtl_uString ** ppIniName
753 ) SAL_THROW_EXTERN_C()
754 {
755 if(ppIniName)
756 {
757 if(handle)
758 {
759 Bootstrap_Impl * pImpl = static_cast<Bootstrap_Impl*>(handle);
760 rtl_uString_assign(ppIniName, pImpl->_iniName.pData);
761 }
762 else
763 {
764 const OUString & iniName = getIniFileName_Impl();
765 rtl_uString_assign(ppIniName, iniName.pData);
766 }
767 }
768 }
769
770 //----------------------------------------------------------------------------
771
rtl_bootstrap_setIniFileName(rtl_uString * pName)772 void SAL_CALL rtl_bootstrap_setIniFileName (
773 rtl_uString * pName
774 ) SAL_THROW_EXTERN_C()
775 {
776 osl::MutexGuard guard( osl::Mutex::getGlobalMutex() );
777 OUString & file = getIniFileName_Impl();
778 file = pName;
779 }
780
781 //----------------------------------------------------------------------------
782
rtl_bootstrap_get(rtl_uString * pName,rtl_uString ** ppValue,rtl_uString * pDefault)783 sal_Bool SAL_CALL rtl_bootstrap_get (
784 rtl_uString * pName,
785 rtl_uString ** ppValue,
786 rtl_uString * pDefault
787 ) SAL_THROW_EXTERN_C()
788 {
789 return rtl_bootstrap_get_from_handle(0, pName, ppValue, pDefault);
790 }
791
792 //----------------------------------------------------------------------------
793
rtl_bootstrap_set(rtl_uString * pName,rtl_uString * pValue)794 void SAL_CALL rtl_bootstrap_set (
795 rtl_uString * pName,
796 rtl_uString * pValue
797 ) SAL_THROW_EXTERN_C()
798 {
799 const OUString name( pName );
800 const OUString value( pValue );
801
802 osl::MutexGuard guard( osl::Mutex::getGlobalMutex() );
803
804 NameValueList& r_rtl_bootstrap_set_list = rtl_bootstrap_set_list::get();
805 NameValueList::iterator iPos( r_rtl_bootstrap_set_list.begin() );
806 NameValueList::iterator iEnd( r_rtl_bootstrap_set_list.end() );
807 for ( ; iPos != iEnd; ++iPos )
808 {
809 if (iPos->sName.equals( name ))
810 {
811 iPos->sValue = value;
812 return;
813 }
814 }
815
816 #if OSL_DEBUG_LEVEL > 1
817 OString cstr_name( OUStringToOString( name, RTL_TEXTENCODING_ASCII_US ) );
818 OString cstr_value( OUStringToOString( value, RTL_TEXTENCODING_ASCII_US ) );
819 OSL_TRACE(
820 "bootstrap.cxx: explicitly setting: name=%s value=%s\n",
821 cstr_name.getStr(), cstr_value.getStr() );
822 #endif /* OSL_DEBUG_LEVEL > 1 */
823
824 r_rtl_bootstrap_set_list.push_back( rtl_bootstrap_NameValue( name, value ) );
825 }
826
827 //----------------------------------------------------------------------------
828
rtl_bootstrap_expandMacros_from_handle(rtlBootstrapHandle handle,rtl_uString ** macro)829 void SAL_CALL rtl_bootstrap_expandMacros_from_handle (
830 rtlBootstrapHandle handle,
831 rtl_uString ** macro
832 ) SAL_THROW_EXTERN_C()
833 {
834 if (handle == NULL) {
835 handle = get_static_bootstrap_handle();
836 }
837 OUString expanded( expandMacros( static_cast< Bootstrap_Impl * >( handle ),
838 * reinterpret_cast< OUString const * >( macro ),
839 LOOKUP_MODE_NORMAL, NULL ) );
840 rtl_uString_assign( macro, expanded.pData );
841 }
842
843 //----------------------------------------------------------------------------
844
rtl_bootstrap_expandMacros(rtl_uString ** macro)845 void SAL_CALL rtl_bootstrap_expandMacros(
846 rtl_uString ** macro )
847 SAL_THROW_EXTERN_C()
848 {
849 rtl_bootstrap_expandMacros_from_handle(NULL, macro);
850 }
851
rtl_bootstrap_encode(rtl_uString const * value,rtl_uString ** encoded)852 void rtl_bootstrap_encode( rtl_uString const * value, rtl_uString ** encoded )
853 SAL_THROW_EXTERN_C()
854 {
855 OSL_ASSERT(value != NULL);
856 rtl::OUStringBuffer b;
857 for (sal_Int32 i = 0; i < value->length; ++i) {
858 sal_Unicode c = value->buffer[i];
859 if (c == '$' || c == '\\') {
860 b.append(sal_Unicode('\\'));
861 }
862 b.append(c);
863 }
864 rtl_uString_assign(encoded, b.makeStringAndClear().pData);
865 }
866
867 namespace {
868
hex(sal_Unicode c)869 int hex(sal_Unicode c) {
870 return
871 c >= '0' && c <= '9' ? c - '0' :
872 c >= 'A' && c <= 'F' ? c - 'A' + 10 :
873 c >= 'a' && c <= 'f' ? c - 'a' + 10 : -1;
874 }
875
read(rtl::OUString const & text,sal_Int32 * pos,bool * escaped)876 sal_Unicode read(rtl::OUString const & text, sal_Int32 * pos, bool * escaped) {
877 OSL_ASSERT(
878 pos != NULL && *pos >= 0 && *pos < text.getLength() && escaped != NULL);
879 sal_Unicode c = text[(*pos)++];
880 if (c == '\\') {
881 int n1, n2, n3, n4;
882 if (*pos < text.getLength() - 4 && text[*pos] == 'u' &&
883 ((n1 = hex(text[*pos + 1])) >= 0) &&
884 ((n2 = hex(text[*pos + 2])) >= 0) &&
885 ((n3 = hex(text[*pos + 3])) >= 0) &&
886 ((n4 = hex(text[*pos + 4])) >= 0))
887 {
888 *pos += 5;
889 *escaped = true;
890 return static_cast< sal_Unicode >(
891 (n1 << 12) | (n2 << 8) | (n3 << 4) | n4);
892 } else if (*pos < text.getLength()) {
893 *escaped = true;
894 return text[(*pos)++];
895 }
896 }
897 *escaped = false;
898 return c;
899 }
900
lookup(Bootstrap_Impl const * file,LookupMode mode,bool override,rtl::OUString const & key,ExpandRequestLink const * requestStack)901 rtl::OUString lookup(
902 Bootstrap_Impl const * file, LookupMode mode, bool override,
903 rtl::OUString const & key, ExpandRequestLink const * requestStack)
904 {
905 rtl::OUString v;
906 (file == NULL ? get_static_bootstrap_handle() : file)->getValue(
907 key, &v.pData, NULL, mode, override, requestStack);
908 return v;
909 }
910
expandMacros(Bootstrap_Impl const * file,rtl::OUString const & text,LookupMode mode,ExpandRequestLink const * requestStack)911 rtl::OUString expandMacros(
912 Bootstrap_Impl const * file, rtl::OUString const & text, LookupMode mode,
913 ExpandRequestLink const * requestStack)
914 {
915 rtl::OUStringBuffer buf;
916 for (sal_Int32 i = 0; i < text.getLength();) {
917 bool escaped;
918 sal_Unicode c = read(text, &i, &escaped);
919 if (escaped || c != '$') {
920 buf.append(c);
921 } else {
922 if (i < text.getLength() && text[i] == '{') {
923 ++i;
924 sal_Int32 p = i;
925 sal_Int32 nesting = 0;
926 rtl::OUString seg[3];
927 int n = 0;
928 while (i < text.getLength()) {
929 sal_Int32 j = i;
930 c = read(text, &i, &escaped);
931 if (!escaped) {
932 switch (c) {
933 case '{':
934 ++nesting;
935 break;
936 case '}':
937 if (nesting == 0) {
938 seg[n++] = text.copy(p, j - p);
939 goto done;
940 } else {
941 --nesting;
942 }
943 break;
944 case ':':
945 if (nesting == 0 && n < 2) {
946 seg[n++] = text.copy(p, j - p);
947 p = i;
948 }
949 break;
950 }
951 }
952 }
953 done:
954 for (int j = 0; j < n; ++j) {
955 seg[j] = expandMacros(file, seg[j], mode, requestStack);
956 }
957 if (n == 3 && seg[1].getLength() == 0) {
958 // For backward compatibility, treat ${file::key} the same
959 // as just ${file:key}:
960 seg[1] = seg[2];
961 n = 2;
962 }
963 if (n == 1) {
964 buf.append(lookup(file, mode, false, seg[0], requestStack));
965 } else if (n == 2) {
966 if (seg[0].equalsAsciiL(
967 RTL_CONSTASCII_STRINGPARAM(".link")))
968 {
969 osl::File f(seg[1]);
970 rtl::ByteSequence seq;
971 rtl::OUString line;
972 rtl::OUString url;
973 // Silently ignore any errors (is that good?):
974 if (f.open(OpenFlag_Read) == osl::FileBase::E_None &&
975 f.readLine(seq) == osl::FileBase::E_None &&
976 rtl_convertStringToUString(
977 &line.pData,
978 reinterpret_cast< char const * >(
979 seq.getConstArray()),
980 seq.getLength(), RTL_TEXTENCODING_UTF8,
981 (RTL_TEXTTOUNICODE_FLAGS_UNDEFINED_ERROR |
982 RTL_TEXTTOUNICODE_FLAGS_MBUNDEFINED_ERROR |
983 RTL_TEXTTOUNICODE_FLAGS_INVALID_ERROR)) &&
984 (osl::File::getFileURLFromSystemPath(line, url) ==
985 osl::FileBase::E_None))
986 {
987 try {
988 buf.append(
989 rtl::Uri::convertRelToAbs(seg[1], url));
990 } catch (rtl::MalformedUriException &) {}
991 }
992 } else {
993 buf.append(
994 lookup(
995 static_cast< Bootstrap_Impl * >(
996 rtl::Bootstrap(seg[0]).getHandle()),
997 mode, false, seg[1], requestStack));
998 }
999 } else if (seg[0].equalsAsciiL(
1000 RTL_CONSTASCII_STRINGPARAM(".override")))
1001 {
1002 rtl::Bootstrap b(seg[1]);
1003 Bootstrap_Impl * f = static_cast< Bootstrap_Impl * >(
1004 b.getHandle());
1005 buf.append(
1006 lookup(f, mode, f != NULL, seg[2], requestStack));
1007 } else {
1008 // Going through osl::Profile, this code erroneously does
1009 // not recursively expand macros in the resulting
1010 // replacement text (and if it did, it would fail to detect
1011 // cycles that pass through here):
1012 buf.append(
1013 rtl::OStringToOUString(
1014 osl::Profile(seg[0]).readString(
1015 rtl::OUStringToOString(
1016 seg[1], RTL_TEXTENCODING_UTF8),
1017 rtl::OUStringToOString(
1018 seg[2], RTL_TEXTENCODING_UTF8),
1019 rtl::OString()),
1020 RTL_TEXTENCODING_UTF8));
1021 }
1022 } else {
1023 rtl::OUStringBuffer kbuf;
1024 for (; i < text.getLength();) {
1025 sal_Int32 j = i;
1026 c = read(text, &j, &escaped);
1027 if (!escaped &&
1028 (c == ' ' || c == '$' || c == '-' || c == '/' ||
1029 c == ';' || c == '\\'))
1030 {
1031 break;
1032 }
1033 kbuf.append(c);
1034 i = j;
1035 }
1036 buf.append(
1037 lookup(
1038 file, mode, false, kbuf.makeStringAndClear(),
1039 requestStack));
1040 }
1041 }
1042 }
1043 return buf.makeStringAndClear();
1044 }
1045
1046 }
1047