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