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 68 bool isPathnameUrl(rtl::OUString const & url) { 69 return url.matchIgnoreAsciiCaseAsciiL( 70 RTL_CONSTASCII_STRINGPARAM(VND_SUN_STAR_PATHNAME)); 71 } 72 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 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 {} 129 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 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 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 225 inline void getExecutableFile_Impl (rtl_uString ** ppFileURL) 226 { 227 osl_bootstrap_getExecutableFile_Impl (ppFileURL); 228 } 229 230 //---------------------------------------------------------------------------- 231 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 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 #ifdef MACOSX 276 // In an application bundle only Mach-O binaries may live in 277 // Contents/MacOS -- code signing rejects the bundle otherwise -- 278 // so the installation itself (rc files, rdbs, the libraries) sits 279 // in Contents/program, exactly as on the other UNX platforms. 280 // Look the ini file up there; $ORIGIN is derived from it below, 281 // which anchors the whole bootstrap chain in the program dir. 282 OUString macOSDir (RTL_CONSTASCII_USTRINGPARAM("/Contents/MacOS/")); 283 sal_Int32 nMacOSDir = fileName.lastIndexOf(macOSDir); 284 if (nMacOSDir >= 0) 285 { 286 OUString programName = 287 fileName.replaceAt(nMacOSDir, macOSDir.getLength(), 288 OUString(RTL_CONSTASCII_USTRINGPARAM("/Contents/program/"))); 289 // Fall back to the old location for anything that is not laid 290 // out this way (a plain bundle, an mdimporter, ...). 291 ::osl::DirectoryItem item; 292 if (::osl::DirectoryItem::get(programName, item) == ::osl::DirectoryItem::E_None) 293 fileName = programName; 294 } 295 #endif 296 } 297 298 static OUString theFileName; 299 if(fileName.getLength()) 300 theFileName = fileName; 301 302 pStaticName = &theFileName; 303 } 304 305 return *pStaticName; 306 } 307 308 //---------------------------------------------------------------------------- 309 310 static inline bool path_exists( OUString const & path ) 311 { 312 DirectoryItem dirItem; 313 return (DirectoryItem::E_None == DirectoryItem::get( path, dirItem )); 314 } 315 316 //---------------------------------------------------------------------------- 317 // #111772# 318 // ensure the given file url has no final slash 319 320 inline void EnsureNoFinalSlash (rtl::OUString & url) 321 { 322 sal_Int32 i = url.getLength(); 323 if (i > 0 && url[i - 1] == '/') { 324 url = url.copy(0, i - 1); 325 } 326 } 327 328 //---------------------------------------------------------------------------- 329 //---------------------------------------------------------------------------- 330 331 struct Bootstrap_Impl 332 { 333 sal_Int32 _nRefCount; 334 Bootstrap_Impl * _base_ini; 335 336 NameValueList _nameValueList; 337 OUString _iniName; 338 339 explicit Bootstrap_Impl (OUString const & rIniName); 340 ~Bootstrap_Impl(); 341 342 static void * operator new (std::size_t n) SAL_THROW(()) 343 { return rtl_allocateMemory (sal_uInt32(n)); } 344 static void operator delete (void * p , std::size_t) SAL_THROW(()) 345 { rtl_freeMemory (p); } 346 347 bool getValue( 348 rtl::OUString const & key, rtl_uString ** value, 349 rtl_uString * defaultValue, LookupMode mode, bool override, 350 ExpandRequestLink const * requestStack) const; 351 bool getDirectValue( 352 rtl::OUString const & key, rtl_uString ** value, LookupMode mode, 353 ExpandRequestLink const * requestStack) const; 354 bool getAmbienceValue( 355 rtl::OUString const & key, rtl_uString ** value, LookupMode mode, 356 ExpandRequestLink const * requestStack) const; 357 void expandValue( 358 rtl_uString ** value, rtl::OUString const & text, LookupMode mode, 359 Bootstrap_Impl const * requestFile, rtl::OUString const & requestKey, 360 ExpandRequestLink const * requestStack) const; 361 }; 362 363 //---------------------------------------------------------------------------- 364 365 Bootstrap_Impl::Bootstrap_Impl( OUString const & rIniName ) 366 : _nRefCount( 0 ), 367 _base_ini( 0 ), 368 _iniName (rIniName) 369 { 370 OUString base_ini( getIniFileName_Impl() ); 371 // normalize path 372 FileStatus status( FileStatusMask_FileURL ); 373 DirectoryItem dirItem; 374 if (DirectoryItem::E_None == DirectoryItem::get( base_ini, dirItem ) && 375 DirectoryItem::E_None == dirItem.getFileStatus( status )) 376 { 377 base_ini = status.getFileURL(); 378 if (! rIniName.equals( base_ini )) 379 { 380 _base_ini = static_cast< Bootstrap_Impl * >( 381 rtl_bootstrap_args_open( base_ini.pData ) ); 382 } 383 } 384 385 #if OSL_DEBUG_LEVEL > 1 386 OString sFile = OUStringToOString(_iniName, RTL_TEXTENCODING_ASCII_US); 387 OSL_TRACE(__FILE__" -- Bootstrap_Impl() - %s\n", sFile.getStr()); 388 #endif /* OSL_DEBUG_LEVEL > 1 */ 389 390 oslFileHandle handle; 391 if (_iniName.getLength() && 392 osl_File_E_None == osl_openFile(_iniName.pData, &handle, osl_File_OpenFlag_Read)) 393 { 394 rtl::ByteSequence seq; 395 396 while (osl_File_E_None == osl_readLine(handle , (sal_Sequence **)&seq)) 397 { 398 OString line( (const sal_Char *) seq.getConstArray(), seq.getLength() ); 399 sal_Int32 nIndex = line.indexOf('='); 400 if (nIndex >= 1) 401 { 402 struct rtl_bootstrap_NameValue nameValue; 403 nameValue.sName = OStringToOUString( 404 line.copy(0,nIndex).trim(), RTL_TEXTENCODING_ASCII_US ); 405 nameValue.sValue = OStringToOUString( 406 line.copy(nIndex+1).trim(), RTL_TEXTENCODING_UTF8 ); 407 408 #if OSL_DEBUG_LEVEL > 1 409 OString name_tmp = OUStringToOString(nameValue.sName, RTL_TEXTENCODING_ASCII_US); 410 OString value_tmp = OUStringToOString(nameValue.sValue, RTL_TEXTENCODING_UTF8); 411 OSL_TRACE( 412 __FILE__" -- pushing: name=%s value=%s\n", 413 name_tmp.getStr(), value_tmp.getStr() ); 414 #endif /* OSL_DEBUG_LEVEL > 1 */ 415 416 _nameValueList.push_back(nameValue); 417 } 418 } 419 osl_closeFile(handle); 420 } 421 #if OSL_DEBUG_LEVEL > 1 422 else 423 { 424 OString file_tmp = OUStringToOString(_iniName, RTL_TEXTENCODING_ASCII_US); 425 OSL_TRACE( __FILE__" -- couldn't open file: %s", file_tmp.getStr() ); 426 } 427 #endif /* OSL_DEBUG_LEVEL > 1 */ 428 } 429 430 //---------------------------------------------------------------------------- 431 432 Bootstrap_Impl::~Bootstrap_Impl() 433 { 434 if (_base_ini != 0) 435 rtl_bootstrap_args_close( _base_ini ); 436 } 437 438 //---------------------------------------------------------------------------- 439 440 namespace { 441 442 Bootstrap_Impl * get_static_bootstrap_handle() SAL_THROW(()) 443 { 444 osl::MutexGuard guard( osl::Mutex::getGlobalMutex() ); 445 static Bootstrap_Impl * s_handle = 0; 446 if (s_handle == 0) 447 { 448 OUString iniName (getIniFileName_Impl()); 449 s_handle = static_cast< Bootstrap_Impl * >( 450 rtl_bootstrap_args_open( iniName.pData ) ); 451 if (s_handle == 0) 452 { 453 Bootstrap_Impl * that = new Bootstrap_Impl( iniName ); 454 ++that->_nRefCount; 455 s_handle = that; 456 } 457 } 458 return s_handle; 459 } 460 461 struct FundamentalIniData { 462 rtlBootstrapHandle ini; 463 464 FundamentalIniData() { 465 OUString uri; 466 ini = 467 ((static_cast< Bootstrap_Impl * >(get_static_bootstrap_handle())-> 468 getValue( 469 rtl::OUString( 470 RTL_CONSTASCII_USTRINGPARAM("URE_BOOTSTRAP")), 471 &uri.pData, 0, LOOKUP_MODE_NORMAL, false, 0)) && 472 resolvePathnameUrl(&uri)) 473 ? rtl_bootstrap_args_open(uri.pData) : NULL; 474 } 475 476 ~FundamentalIniData() { rtl_bootstrap_args_close(ini); } 477 478 private: 479 FundamentalIniData(FundamentalIniData &); // not defined 480 void operator =(FundamentalIniData &); // not defined 481 }; 482 483 struct FundamentalIni: public rtl::Static< FundamentalIniData, FundamentalIni > 484 {}; 485 486 } 487 488 bool Bootstrap_Impl::getValue( 489 rtl::OUString const & key, rtl_uString ** value, rtl_uString * defaultValue, 490 LookupMode mode, bool override, ExpandRequestLink const * requestStack) 491 const 492 { 493 if (mode == LOOKUP_MODE_NORMAL && 494 key.equalsAsciiL(RTL_CONSTASCII_STRINGPARAM("URE_BOOTSTRAP"))) 495 { 496 mode = LOOKUP_MODE_URE_BOOTSTRAP; 497 } 498 if (override && getDirectValue(key, value, mode, requestStack)) { 499 return true; 500 } 501 if (key.equalsAsciiL(RTL_CONSTASCII_STRINGPARAM("_OS"))) { 502 rtl_uString_assign( 503 value, rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(THIS_OS)).pData); 504 return true; 505 } 506 if (key.equalsAsciiL(RTL_CONSTASCII_STRINGPARAM("_ARCH"))) { 507 rtl_uString_assign( 508 value, rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(THIS_ARCH)).pData); 509 return true; 510 } 511 if (key.equalsAsciiL(RTL_CONSTASCII_STRINGPARAM("_CPPU_ENV"))) { 512 rtl_uString_assign( 513 value, 514 (rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(MY_STRING(CPPU_ENV))). 515 pData)); 516 return true; 517 } 518 if (key.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM("ORIGIN"))) { 519 rtl_uString_assign( 520 value, 521 _iniName.copy( 522 0, std::max<sal_Int32>(0, _iniName.lastIndexOf('/'))).pData); 523 return true; 524 } 525 if (getAmbienceValue(key, value, mode, requestStack)) { 526 return true; 527 } 528 if (key.equalsAsciiL(RTL_CONSTASCII_STRINGPARAM("SYSUSERCONFIG"))) { 529 rtl::OUString v; 530 bool b = osl::Security().getConfigDir(v); 531 EnsureNoFinalSlash(v); 532 rtl_uString_assign(value, v.pData); 533 return b; 534 } 535 if (key.equalsAsciiL(RTL_CONSTASCII_STRINGPARAM("SYSUSERHOME"))) { 536 rtl::OUString v; 537 bool b = osl::Security().getHomeDir(v); 538 EnsureNoFinalSlash(v); 539 rtl_uString_assign(value, v.pData); 540 return b; 541 } 542 if (key.equalsAsciiL(RTL_CONSTASCII_STRINGPARAM("SYSBINDIR"))) { 543 getExecutableDirectory_Impl(value); 544 return true; 545 } 546 if (_base_ini != NULL && 547 _base_ini->getDirectValue(key, value, mode, requestStack)) 548 { 549 return true; 550 } 551 if (!override && getDirectValue(key, value, mode, requestStack)) { 552 return true; 553 } 554 if (mode == LOOKUP_MODE_NORMAL) { 555 FundamentalIniData const & d = FundamentalIni::get(); 556 Bootstrap_Impl const * b = static_cast<Bootstrap_Impl const *>(d.ini); 557 if (b != NULL && b != this && 558 b->getDirectValue(key, value, mode, requestStack)) 559 { 560 return true; 561 } 562 } 563 if (defaultValue != NULL) { 564 rtl_uString_assign(value, defaultValue); 565 return true; 566 } 567 rtl_uString_new(value); 568 return false; 569 } 570 571 bool Bootstrap_Impl::getDirectValue( 572 rtl::OUString const & key, rtl_uString ** value, LookupMode mode, 573 ExpandRequestLink const * requestStack) const 574 { 575 rtl::OUString v; 576 if (find(_nameValueList, key, &v)) { 577 expandValue(value, v, mode, this, key, requestStack); 578 return true; 579 } else { 580 return false; 581 } 582 } 583 584 bool Bootstrap_Impl::getAmbienceValue( 585 rtl::OUString const & key, rtl_uString ** value, LookupMode mode, 586 ExpandRequestLink const * requestStack) const 587 { 588 rtl::OUString v; 589 bool f; 590 { 591 osl::MutexGuard g(osl::Mutex::getGlobalMutex()); 592 f = find(rtl_bootstrap_set_list::get(), key, &v); 593 } 594 if (f || getFromCommandLineArgs(key, &v) || 595 osl_getEnvironment(key.pData, &v.pData) == osl_Process_E_None) 596 { 597 expandValue(value, v, mode, NULL, key, requestStack); 598 return true; 599 } else { 600 return false; 601 } 602 } 603 604 void Bootstrap_Impl::expandValue( 605 rtl_uString ** value, rtl::OUString const & text, LookupMode mode, 606 Bootstrap_Impl const * requestFile, rtl::OUString const & requestKey, 607 ExpandRequestLink const * requestStack) const 608 { 609 rtl_uString_assign( 610 value, 611 (mode == LOOKUP_MODE_URE_BOOTSTRAP && isPathnameUrl(text) ? 612 text : 613 recursivelyExpandMacros( 614 this, text, 615 (mode == LOOKUP_MODE_URE_BOOTSTRAP ? 616 LOOKUP_MODE_URE_BOOTSTRAP_EXPANSION : mode), 617 requestFile, requestKey, requestStack)).pData); 618 } 619 620 //---------------------------------------------------------------------------- 621 //---------------------------------------------------------------------------- 622 623 namespace { 624 625 struct bootstrap_map { 626 typedef std::hash_map< const rtl::OUString, Bootstrap_Impl*, rtl::OUStringHash > t; 627 628 // get and release must only be called properly synchronized via some mutex 629 // (e.g., osl::Mutex::getGlobalMutex()): 630 631 static t * get() { 632 if (m_map == NULL) { 633 m_map = new t; 634 } 635 return m_map; 636 } 637 638 static void release() { 639 if (m_map != NULL && m_map->empty()) { 640 delete m_map; 641 m_map = NULL; 642 } 643 } 644 645 private: 646 bootstrap_map(); // not defined 647 648 static t * m_map; 649 }; 650 651 bootstrap_map::t * bootstrap_map::m_map = NULL; 652 653 } 654 655 //---------------------------------------------------------------------------- 656 657 rtlBootstrapHandle SAL_CALL rtl_bootstrap_args_open ( 658 rtl_uString * pIniName 659 ) SAL_THROW_EXTERN_C() 660 { 661 OUString iniName( pIniName ); 662 663 // normalize path 664 FileStatus status( FileStatusMask_FileURL ); 665 DirectoryItem dirItem; 666 if (DirectoryItem::E_None != DirectoryItem::get( iniName, dirItem ) || 667 DirectoryItem::E_None != dirItem.getFileStatus( status )) 668 { 669 return 0; 670 } 671 iniName = status.getFileURL(); 672 673 Bootstrap_Impl * that; 674 osl::ResettableMutexGuard guard( osl::Mutex::getGlobalMutex() ); 675 bootstrap_map::t* p_bootstrap_map = bootstrap_map::get(); 676 bootstrap_map::t::const_iterator iFind( p_bootstrap_map->find( iniName ) ); 677 if (iFind == p_bootstrap_map->end()) 678 { 679 bootstrap_map::release(); 680 guard.clear(); 681 that = new Bootstrap_Impl( iniName ); 682 guard.reset(); 683 p_bootstrap_map = bootstrap_map::get(); 684 iFind = p_bootstrap_map->find( iniName ); 685 if (iFind == p_bootstrap_map->end()) 686 { 687 ++that->_nRefCount; 688 ::std::pair< bootstrap_map::t::iterator, bool > insertion( 689 p_bootstrap_map->insert( 690 bootstrap_map::t::value_type( iniName, that ) ) ); 691 OSL_ASSERT( insertion.second ); 692 } 693 else 694 { 695 Bootstrap_Impl * obsolete = that; 696 that = iFind->second; 697 ++that->_nRefCount; 698 guard.clear(); 699 delete obsolete; 700 } 701 } 702 else 703 { 704 that = iFind->second; 705 ++that->_nRefCount; 706 } 707 return static_cast< rtlBootstrapHandle >( that ); 708 } 709 710 //---------------------------------------------------------------------------- 711 712 void SAL_CALL rtl_bootstrap_args_close ( 713 rtlBootstrapHandle handle 714 ) SAL_THROW_EXTERN_C() 715 { 716 if (handle == 0) 717 return; 718 Bootstrap_Impl * that = static_cast< Bootstrap_Impl * >( handle ); 719 720 osl::MutexGuard guard( osl::Mutex::getGlobalMutex() ); 721 bootstrap_map::t* p_bootstrap_map = bootstrap_map::get(); 722 OSL_ASSERT( 723 p_bootstrap_map->find( that->_iniName )->second == that ); 724 --that->_nRefCount; 725 if (that->_nRefCount == 0) 726 { 727 ::std::size_t nLeaking = 8; // only hold up to 8 files statically 728 729 #if OSL_DEBUG_LEVEL == 1 // nonpro 730 nLeaking = 0; 731 #elif OSL_DEBUG_LEVEL > 1 // debug 732 nLeaking = 1; 733 #endif /* OSL_DEBUG_LEVEL */ 734 735 if (p_bootstrap_map->size() > nLeaking) 736 { 737 ::std::size_t erased = p_bootstrap_map->erase( that->_iniName ); 738 if (erased != 1) { 739 OSL_ASSERT( false ); 740 } 741 delete that; 742 } 743 bootstrap_map::release(); 744 } 745 } 746 747 //---------------------------------------------------------------------------- 748 749 sal_Bool SAL_CALL rtl_bootstrap_get_from_handle( 750 rtlBootstrapHandle handle, 751 rtl_uString * pName, 752 rtl_uString ** ppValue, 753 rtl_uString * pDefault 754 ) SAL_THROW_EXTERN_C() 755 { 756 osl::MutexGuard guard( osl::Mutex::getGlobalMutex() ); 757 758 sal_Bool found = sal_False; 759 if(ppValue && pName) 760 { 761 if (handle == 0) 762 handle = get_static_bootstrap_handle(); 763 found = static_cast< Bootstrap_Impl * >( handle )->getValue( 764 pName, ppValue, pDefault, LOOKUP_MODE_NORMAL, false, NULL ); 765 } 766 767 return found; 768 } 769 770 //---------------------------------------------------------------------------- 771 772 void SAL_CALL rtl_bootstrap_get_iniName_from_handle ( 773 rtlBootstrapHandle handle, 774 rtl_uString ** ppIniName 775 ) SAL_THROW_EXTERN_C() 776 { 777 if(ppIniName) 778 { 779 if(handle) 780 { 781 Bootstrap_Impl * pImpl = static_cast<Bootstrap_Impl*>(handle); 782 rtl_uString_assign(ppIniName, pImpl->_iniName.pData); 783 } 784 else 785 { 786 const OUString & iniName = getIniFileName_Impl(); 787 rtl_uString_assign(ppIniName, iniName.pData); 788 } 789 } 790 } 791 792 //---------------------------------------------------------------------------- 793 794 void SAL_CALL rtl_bootstrap_setIniFileName ( 795 rtl_uString * pName 796 ) SAL_THROW_EXTERN_C() 797 { 798 osl::MutexGuard guard( osl::Mutex::getGlobalMutex() ); 799 OUString & file = getIniFileName_Impl(); 800 file = pName; 801 } 802 803 //---------------------------------------------------------------------------- 804 805 sal_Bool SAL_CALL rtl_bootstrap_get ( 806 rtl_uString * pName, 807 rtl_uString ** ppValue, 808 rtl_uString * pDefault 809 ) SAL_THROW_EXTERN_C() 810 { 811 return rtl_bootstrap_get_from_handle(0, pName, ppValue, pDefault); 812 } 813 814 //---------------------------------------------------------------------------- 815 816 void SAL_CALL rtl_bootstrap_set ( 817 rtl_uString * pName, 818 rtl_uString * pValue 819 ) SAL_THROW_EXTERN_C() 820 { 821 const OUString name( pName ); 822 const OUString value( pValue ); 823 824 osl::MutexGuard guard( osl::Mutex::getGlobalMutex() ); 825 826 NameValueList& r_rtl_bootstrap_set_list = rtl_bootstrap_set_list::get(); 827 NameValueList::iterator iPos( r_rtl_bootstrap_set_list.begin() ); 828 NameValueList::iterator iEnd( r_rtl_bootstrap_set_list.end() ); 829 for ( ; iPos != iEnd; ++iPos ) 830 { 831 if (iPos->sName.equals( name )) 832 { 833 iPos->sValue = value; 834 return; 835 } 836 } 837 838 #if OSL_DEBUG_LEVEL > 1 839 OString cstr_name( OUStringToOString( name, RTL_TEXTENCODING_ASCII_US ) ); 840 OString cstr_value( OUStringToOString( value, RTL_TEXTENCODING_ASCII_US ) ); 841 OSL_TRACE( 842 "bootstrap.cxx: explicitly setting: name=%s value=%s\n", 843 cstr_name.getStr(), cstr_value.getStr() ); 844 #endif /* OSL_DEBUG_LEVEL > 1 */ 845 846 r_rtl_bootstrap_set_list.push_back( rtl_bootstrap_NameValue( name, value ) ); 847 } 848 849 //---------------------------------------------------------------------------- 850 851 void SAL_CALL rtl_bootstrap_expandMacros_from_handle ( 852 rtlBootstrapHandle handle, 853 rtl_uString ** macro 854 ) SAL_THROW_EXTERN_C() 855 { 856 if (handle == NULL) { 857 handle = get_static_bootstrap_handle(); 858 } 859 OUString expanded( expandMacros( static_cast< Bootstrap_Impl * >( handle ), 860 * reinterpret_cast< OUString const * >( macro ), 861 LOOKUP_MODE_NORMAL, NULL ) ); 862 rtl_uString_assign( macro, expanded.pData ); 863 } 864 865 //---------------------------------------------------------------------------- 866 867 void SAL_CALL rtl_bootstrap_expandMacros( 868 rtl_uString ** macro ) 869 SAL_THROW_EXTERN_C() 870 { 871 rtl_bootstrap_expandMacros_from_handle(NULL, macro); 872 } 873 874 void rtl_bootstrap_encode( rtl_uString const * value, rtl_uString ** encoded ) 875 SAL_THROW_EXTERN_C() 876 { 877 OSL_ASSERT(value != NULL); 878 rtl::OUStringBuffer b; 879 for (sal_Int32 i = 0; i < value->length; ++i) { 880 sal_Unicode c = value->buffer[i]; 881 if (c == '$' || c == '\\') { 882 b.append(sal_Unicode('\\')); 883 } 884 b.append(c); 885 } 886 rtl_uString_assign(encoded, b.makeStringAndClear().pData); 887 } 888 889 namespace { 890 891 int hex(sal_Unicode c) { 892 return 893 c >= '0' && c <= '9' ? c - '0' : 894 c >= 'A' && c <= 'F' ? c - 'A' + 10 : 895 c >= 'a' && c <= 'f' ? c - 'a' + 10 : -1; 896 } 897 898 sal_Unicode read(rtl::OUString const & text, sal_Int32 * pos, bool * escaped) { 899 OSL_ASSERT( 900 pos != NULL && *pos >= 0 && *pos < text.getLength() && escaped != NULL); 901 sal_Unicode c = text[(*pos)++]; 902 if (c == '\\') { 903 int n1, n2, n3, n4; 904 if (*pos < text.getLength() - 4 && text[*pos] == 'u' && 905 ((n1 = hex(text[*pos + 1])) >= 0) && 906 ((n2 = hex(text[*pos + 2])) >= 0) && 907 ((n3 = hex(text[*pos + 3])) >= 0) && 908 ((n4 = hex(text[*pos + 4])) >= 0)) 909 { 910 *pos += 5; 911 *escaped = true; 912 return static_cast< sal_Unicode >( 913 (n1 << 12) | (n2 << 8) | (n3 << 4) | n4); 914 } else if (*pos < text.getLength()) { 915 *escaped = true; 916 return text[(*pos)++]; 917 } 918 } 919 *escaped = false; 920 return c; 921 } 922 923 rtl::OUString lookup( 924 Bootstrap_Impl const * file, LookupMode mode, bool override, 925 rtl::OUString const & key, ExpandRequestLink const * requestStack) 926 { 927 rtl::OUString v; 928 (file == NULL ? get_static_bootstrap_handle() : file)->getValue( 929 key, &v.pData, NULL, mode, override, requestStack); 930 return v; 931 } 932 933 rtl::OUString expandMacros( 934 Bootstrap_Impl const * file, rtl::OUString const & text, LookupMode mode, 935 ExpandRequestLink const * requestStack) 936 { 937 rtl::OUStringBuffer buf; 938 for (sal_Int32 i = 0; i < text.getLength();) { 939 bool escaped; 940 sal_Unicode c = read(text, &i, &escaped); 941 if (escaped || c != '$') { 942 buf.append(c); 943 } else { 944 if (i < text.getLength() && text[i] == '{') { 945 ++i; 946 sal_Int32 p = i; 947 sal_Int32 nesting = 0; 948 rtl::OUString seg[3]; 949 int n = 0; 950 while (i < text.getLength()) { 951 sal_Int32 j = i; 952 c = read(text, &i, &escaped); 953 if (!escaped) { 954 switch (c) { 955 case '{': 956 ++nesting; 957 break; 958 case '}': 959 if (nesting == 0) { 960 seg[n++] = text.copy(p, j - p); 961 goto done; 962 } else { 963 --nesting; 964 } 965 break; 966 case ':': 967 if (nesting == 0 && n < 2) { 968 seg[n++] = text.copy(p, j - p); 969 p = i; 970 } 971 break; 972 } 973 } 974 } 975 done: 976 for (int j = 0; j < n; ++j) { 977 seg[j] = expandMacros(file, seg[j], mode, requestStack); 978 } 979 if (n == 3 && seg[1].getLength() == 0) { 980 // For backward compatibility, treat ${file::key} the same 981 // as just ${file:key}: 982 seg[1] = seg[2]; 983 n = 2; 984 } 985 if (n == 1) { 986 buf.append(lookup(file, mode, false, seg[0], requestStack)); 987 } else if (n == 2) { 988 if (seg[0].equalsAsciiL( 989 RTL_CONSTASCII_STRINGPARAM(".link"))) 990 { 991 osl::File f(seg[1]); 992 rtl::ByteSequence seq; 993 rtl::OUString line; 994 rtl::OUString url; 995 // Silently ignore any errors (is that good?): 996 if (f.open(OpenFlag_Read) == osl::FileBase::E_None && 997 f.readLine(seq) == osl::FileBase::E_None && 998 rtl_convertStringToUString( 999 &line.pData, 1000 reinterpret_cast< char const * >( 1001 seq.getConstArray()), 1002 seq.getLength(), RTL_TEXTENCODING_UTF8, 1003 (RTL_TEXTTOUNICODE_FLAGS_UNDEFINED_ERROR | 1004 RTL_TEXTTOUNICODE_FLAGS_MBUNDEFINED_ERROR | 1005 RTL_TEXTTOUNICODE_FLAGS_INVALID_ERROR)) && 1006 (osl::File::getFileURLFromSystemPath(line, url) == 1007 osl::FileBase::E_None)) 1008 { 1009 try { 1010 buf.append( 1011 rtl::Uri::convertRelToAbs(seg[1], url)); 1012 } catch (rtl::MalformedUriException &) {} 1013 } 1014 } else { 1015 buf.append( 1016 lookup( 1017 static_cast< Bootstrap_Impl * >( 1018 rtl::Bootstrap(seg[0]).getHandle()), 1019 mode, false, seg[1], requestStack)); 1020 } 1021 } else if (seg[0].equalsAsciiL( 1022 RTL_CONSTASCII_STRINGPARAM(".override"))) 1023 { 1024 rtl::Bootstrap b(seg[1]); 1025 Bootstrap_Impl * f = static_cast< Bootstrap_Impl * >( 1026 b.getHandle()); 1027 buf.append( 1028 lookup(f, mode, f != NULL, seg[2], requestStack)); 1029 } else { 1030 // Going through osl::Profile, this code erroneously does 1031 // not recursively expand macros in the resulting 1032 // replacement text (and if it did, it would fail to detect 1033 // cycles that pass through here): 1034 buf.append( 1035 rtl::OStringToOUString( 1036 osl::Profile(seg[0]).readString( 1037 rtl::OUStringToOString( 1038 seg[1], RTL_TEXTENCODING_UTF8), 1039 rtl::OUStringToOString( 1040 seg[2], RTL_TEXTENCODING_UTF8), 1041 rtl::OString()), 1042 RTL_TEXTENCODING_UTF8)); 1043 } 1044 } else { 1045 rtl::OUStringBuffer kbuf; 1046 for (; i < text.getLength();) { 1047 sal_Int32 j = i; 1048 c = read(text, &j, &escaped); 1049 if (!escaped && 1050 (c == ' ' || c == '$' || c == '-' || c == '/' || 1051 c == ';' || c == '\\')) 1052 { 1053 break; 1054 } 1055 kbuf.append(c); 1056 i = j; 1057 } 1058 buf.append( 1059 lookup( 1060 file, mode, false, kbuf.makeStringAndClear(), 1061 requestStack)); 1062 } 1063 } 1064 } 1065 return buf.makeStringAndClear(); 1066 } 1067 1068 } 1069