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

Generated by: LCOV version 1.10