LCOV - code coverage report
Current view: top level - sal/rtl - bootstrap.cxx (source / functions) Hit Total Coverage
Test: commit e02a6cb2c3e2b23b203b422e4e0680877f232636 Lines: 316 418 75.6 %
Date: 2014-04-14 Functions: 33 42 78.6 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.10