LCOV - code coverage report
Current view: top level - sal/rtl - bootstrap.cxx (source / functions) Hit Total Coverage
Test: commit 0e63ca4fde4e446f346e35849c756a30ca294aab Lines: 339 418 81.1 %
Date: 2014-04-11 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             : #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         414 : bool isPathnameUrl(rtl::OUString const & url) {
      72         414 :     return url.matchIgnoreAsciiCase(VND_SUN_STAR_PATHNAME);
      73             : }
      74             : 
      75         192 : bool resolvePathnameUrl(rtl::OUString * url) {
      76             :     OSL_ASSERT(url !=  NULL);
      77         625 :     if (!isPathnameUrl(*url) ||
      78             :         (osl::FileBase::getFileURLFromSystemPath(
      79         339 :             url->copy(RTL_CONSTASCII_LENGTH(VND_SUN_STAR_PATHNAME)), *url) ==
      80             :          osl::FileBase::E_None))
      81             :     {
      82         192 :         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      126677 : 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      126677 : 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      157363 :     for (; requestStack != NULL; requestStack = requestStack->next) {
     109       39900 :         if (requestStack->file == requestFile &&
     110        9214 :             requestStack->key == requestKey)
     111             :         {
     112           0 :             return rtl::OUString("***RECURSION DETECTED***");
     113             :         }
     114             :     }
     115      126677 :     ExpandRequestLink link = { requestStack, requestFile, requestKey };
     116      126677 :     return expandMacros(file, text, mode, &link);
     117             : }
     118             : 
     119             : }
     120             : 
     121       26337 : struct rtl_bootstrap_NameValue
     122             : {
     123             :     OUString sName;
     124             :     OUString sValue;
     125             : 
     126       12192 :     inline rtl_bootstrap_NameValue() SAL_THROW( () )
     127       12192 :         {}
     128          83 :     inline rtl_bootstrap_NameValue(
     129             :         OUString const & name, OUString const & value ) SAL_THROW( () )
     130             :         : sName( name ),
     131          83 :           sValue( value )
     132          83 :         {}
     133             : };
     134             : 
     135             : typedef std::list<
     136             :     rtl_bootstrap_NameValue,
     137             :     rtl::Allocator< rtl_bootstrap_NameValue >
     138             : > NameValueList;
     139             : 
     140      291808 : bool find(
     141             :     NameValueList const & list, rtl::OUString const & key,
     142             :     rtl::OUString * value)
     143             : {
     144             :     OSL_ASSERT(value != NULL);
     145     1436294 :     for (NameValueList::const_iterator i(list.begin()); i != list.end(); ++i) {
     146     1205242 :         if (i->sName == key) {
     147       60756 :             *value = i->sValue;
     148       60756 :             return true;
     149             :         }
     150             :     }
     151      231052 :     return false;
     152             : }
     153             : 
     154             : namespace {
     155             :     struct rtl_bootstrap_set_list :
     156             :         public rtl::Static< NameValueList, rtl_bootstrap_set_list > {};
     157             : }
     158             : 
     159      130167 : static bool getFromCommandLineArgs(
     160             :     rtl::OUString const & key, rtl::OUString * value )
     161             : {
     162             :     OSL_ASSERT(value != NULL);
     163             :     static NameValueList *pNameValueList = 0;
     164      130167 :     if( ! pNameValueList )
     165             :     {
     166         509 :         static NameValueList nameValueList;
     167             : 
     168         509 :         sal_Int32 nArgCount = osl_getCommandArgCount();
     169        4939 :         for(sal_Int32 i = 0; i < nArgCount; ++ i)
     170             :         {
     171        4430 :             rtl_uString *pArg = 0;
     172        4430 :             osl_getCommandArg( i, &pArg );
     173        7933 :             if( ('-' == pArg->buffer[0] || '/' == pArg->buffer[0] ) &&
     174        5207 :                 'e' == pArg->buffer[1] &&
     175        3408 :                 'n' == pArg->buffer[2] &&
     176        3408 :                 'v' == pArg->buffer[3] &&
     177        1704 :                 ':' == pArg->buffer[4] )
     178             :             {
     179        1704 :                 sal_Int32 nIndex = rtl_ustr_indexOfChar( pArg->buffer, '=' );
     180        1704 :                 if( nIndex >= 0 )
     181             :                 {
     182             : 
     183        1704 :                     rtl_bootstrap_NameValue nameValue;
     184        1704 :                     nameValue.sName = OUString( &(pArg->buffer[5]), nIndex - 5  );
     185        1704 :                     nameValue.sValue = OUString( &(pArg->buffer[nIndex+1]) );
     186        3744 :                     if( i == nArgCount-1 &&
     187        2040 :                         nameValue.sValue.getLength() &&
     188         336 :                         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        1704 :                     nameValueList.push_back( nameValue );
     196             :                 }
     197             :             }
     198        4430 :             rtl_uString_release( pArg );
     199             :         }
     200         509 :         pNameValueList = &nameValueList;
     201             :     }
     202             : 
     203      130167 :     bool found = false;
     204             : 
     205      992067 :     for( NameValueList::iterator ii = pNameValueList->begin() ;
     206      661378 :          ii != pNameValueList->end() ;
     207             :          ++ii )
     208             :     {
     209      266371 :         if( (*ii).sName.equals(key) )
     210             :         {
     211       65849 :             *value = (*ii).sValue;
     212       65849 :             found = true;
     213       65849 :             break;
     214             :         }
     215             :     }
     216             : 
     217      130167 :     return found;
     218             : }
     219             : 
     220         459 : inline void getExecutableFile_Impl (rtl_uString ** ppFileURL)
     221             : {
     222         459 :     osl_bootstrap_getExecutableFile_Impl (ppFileURL);
     223         459 : }
     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        2042 : static OUString & getIniFileName_Impl()
     237             : {
     238        2042 :     osl::MutexGuard guard( osl::Mutex::getGlobalMutex() );
     239             :     static OUString *pStaticName = 0;
     240        2042 :     if( ! pStaticName )
     241             :     {
     242         509 :         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        1018 :         if(getFromCommandLineArgs(
     260        1018 :                OUString("INIFILENAME"), &fileName))
     261             :         {
     262          50 :             resolvePathnameUrl(&fileName);
     263             :         }
     264             :         else
     265             :         {
     266         459 :             getExecutableFile_Impl (&(fileName.pData));
     267             : 
     268             :             // get rid of a potential executable extension
     269         459 :             OUString progExt = ".bin";
     270        1377 :             if(fileName.getLength() > progExt.getLength()
     271        1836 :             && fileName.copy(fileName.getLength() - progExt.getLength()).equalsIgnoreAsciiCase(progExt))
     272          92 :                 fileName = fileName.copy(0, fileName.getLength() - progExt.getLength());
     273             : 
     274         459 :             progExt = ".exe";
     275        1377 :             if(fileName.getLength() > progExt.getLength()
     276        1836 :             && 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         459 :             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         509 :         static OUString theFileName;
     292         509 :         if(fileName.getLength())
     293         507 :             theFileName = fileName;
     294             : 
     295         509 :         pStaticName = &theFileName;
     296             :     }
     297             : 
     298        2042 :     return *pStaticName;
     299             : }
     300             : 
     301             : // #111772#
     302             : // ensure the given file url has no final slash
     303             : 
     304           0 : inline void EnsureNoFinalSlash (rtl::OUString & url)
     305             : {
     306           0 :     sal_Int32 i = url.getLength();
     307           0 :     if (i > 0 && url[i - 1] == '/') {
     308           0 :         url = url.copy(0, i - 1);
     309             :     }
     310           0 : }
     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        1589 :     static void * operator new (std::size_t n) SAL_THROW(())
     324        1589 :         { 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        1589 : Bootstrap_Impl::Bootstrap_Impl( OUString const & rIniName )
     345             :     : _nRefCount( 0 ),
     346             :       _base_ini( 0 ),
     347        1589 :       _iniName (rIniName)
     348             : {
     349        1589 :     OUString base_ini( getIniFileName_Impl() );
     350             :     // normalize path
     351        3178 :     FileStatus status( osl_FileStatus_Mask_FileURL );
     352        3178 :     DirectoryItem dirItem;
     353        2342 :     if (DirectoryItem::E_None == DirectoryItem::get( base_ini, dirItem ) &&
     354         753 :         DirectoryItem::E_None == dirItem.getFileStatus( status ))
     355             :     {
     356         753 :         base_ini = status.getFileURL();
     357         753 :         if (! rIniName.equals( base_ini ))
     358             :         {
     359             :             _base_ini = static_cast< Bootstrap_Impl * >(
     360         625 :                 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        3176 :     if (!_iniName.isEmpty() &&
     371        1587 :         osl_File_E_None == osl_openFile(_iniName.pData, &handle, osl_File_OpenFlag_Read))
     372             :     {
     373        1264 :         rtl::ByteSequence seq;
     374             : 
     375       23213 :         while (osl_File_E_None == osl_readLine(handle , (sal_Sequence **)&seq))
     376             :         {
     377       20685 :             OString line( (const sal_Char *) seq.getConstArray(), seq.getLength() );
     378       20685 :             sal_Int32 nIndex = line.indexOf('=');
     379       20685 :             if (nIndex >= 1)
     380             :             {
     381       10488 :                 struct rtl_bootstrap_NameValue nameValue;
     382       20976 :                 nameValue.sName = OStringToOUString(
     383       10488 :                     line.copy(0,nIndex).trim(), RTL_TEXTENCODING_ASCII_US );
     384       20976 :                 nameValue.sValue = OStringToOUString(
     385       10488 :                     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       10488 :                 _nameValueList.push_back(nameValue);
     396             :             }
     397       20685 :         }
     398        1264 :         osl_closeFile(handle);
     399        1589 :     }
     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        1589 : }
     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        8958 : Bootstrap_Impl * get_static_bootstrap_handle() SAL_THROW(())
     418             : {
     419        8958 :     osl::MutexGuard guard( osl::Mutex::getGlobalMutex() );
     420             :     static Bootstrap_Impl * s_handle = 0;
     421        8958 :     if (s_handle == 0)
     422             :     {
     423         453 :         OUString iniName (getIniFileName_Impl());
     424             :         s_handle = static_cast< Bootstrap_Impl * >(
     425         453 :             rtl_bootstrap_args_open( iniName.pData ) );
     426         453 :         if (s_handle == 0)
     427             :         {
     428         325 :             Bootstrap_Impl * that = new Bootstrap_Impl( iniName );
     429         325 :             ++that->_nRefCount;
     430         325 :             s_handle = that;
     431         453 :         }
     432             :     }
     433        8958 :     return s_handle;
     434             : }
     435             : 
     436             : struct FundamentalIniData: private boost::noncopyable {
     437             :     rtlBootstrapHandle ini;
     438             : 
     439         433 :     FundamentalIniData() {
     440         433 :         OUString uri;
     441             :         ini =
     442             :             ((static_cast< Bootstrap_Impl * >(get_static_bootstrap_handle())->
     443             :               getValue(
     444             :                   rtl::OUString("URE_BOOTSTRAP"),
     445        1874 :                   &uri.pData, 0, LOOKUP_MODE_NORMAL, false, 0)) &&
     446         142 :              resolvePathnameUrl(&uri))
     447        1874 :             ? rtl_bootstrap_args_open(uri.pData) : NULL;
     448         433 :     }
     449             : 
     450         433 :     ~FundamentalIniData() { rtl_bootstrap_args_close(ini); }
     451             : };
     452             : 
     453             : struct FundamentalIni: public rtl::Static< FundamentalIniData, FundamentalIni >
     454             : {};
     455             : 
     456             : }
     457             : 
     458      164480 : 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      164480 :     if (mode == LOOKUP_MODE_NORMAL && key == "URE_BOOTSTRAP") {
     464         524 :         mode = LOOKUP_MODE_URE_BOOTSTRAP;
     465             :     }
     466      164480 :     if (override && getDirectValue(key, value, mode, requestStack)) {
     467           0 :         return true;
     468             :     }
     469      164480 :     if (key == "_OS") {
     470             :         rtl_uString_assign(
     471         848 :             value, rtl::OUString(RTL_OS).pData);
     472         848 :         return true;
     473             :     }
     474      163632 :     if (key == "_ARCH") {
     475             :         rtl_uString_assign(
     476         843 :             value, rtl::OUString(RTL_ARCH).pData);
     477         843 :         return true;
     478             :     }
     479      162789 :     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      162789 :     if (key == "ORIGIN") {
     504             :         rtl_uString_assign(
     505             :             value,
     506             :             _iniName.copy(
     507       32891 :                 0, std::max<sal_Int32>(0, _iniName.lastIndexOf('/'))).pData);
     508       32891 :         return true;
     509             :     }
     510      129898 :     if (getAmbienceValue(key, value, mode, requestStack)) {
     511       66162 :         return true;
     512             :     }
     513       63736 :     if (key == "SYSUSERCONFIG") {
     514           0 :         rtl::OUString v;
     515           0 :         bool b = osl::Security().getConfigDir(v);
     516           0 :         EnsureNoFinalSlash(v);
     517           0 :         rtl_uString_assign(value, v.pData);
     518           0 :         return b;
     519             :     }
     520       63736 :     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       63736 :     if (key == "SYSBINDIR") {
     528           0 :         getExecutableDirectory_Impl(value);
     529           0 :         return true;
     530             :     }
     531      119721 :     if (_base_ini != NULL &&
     532       55985 :         _base_ini->getDirectValue(key, value, mode, requestStack))
     533             :     {
     534           0 :         return true;
     535             :     }
     536       63736 :     if (!override && getDirectValue(key, value, mode, requestStack)) {
     537       20449 :         return true;
     538             :     }
     539       43287 :     if (mode == LOOKUP_MODE_NORMAL) {
     540       42985 :         FundamentalIniData const & d = FundamentalIni::get();
     541       42985 :         Bootstrap_Impl const * b = static_cast<Bootstrap_Impl const *>(d.ini);
     542       85174 :         if (b != NULL && b != this &&
     543       42189 :             b->getDirectValue(key, value, mode, requestStack))
     544             :         {
     545       40067 :             return true;
     546             :         }
     547             :     }
     548        3220 :     if (defaultValue != NULL) {
     549         305 :         rtl_uString_assign(value, defaultValue);
     550         305 :         return true;
     551             :     }
     552        2915 :     rtl_uString_new(value);
     553        2915 :     return false;
     554             : }
     555             : 
     556      161910 : bool Bootstrap_Impl::getDirectValue(
     557             :     rtl::OUString const & key, rtl_uString ** value, LookupMode mode,
     558             :     ExpandRequestLink const * requestStack) const
     559             : {
     560      161910 :     rtl::OUString v;
     561      161910 :     if (find(_nameValueList, key, &v)) {
     562       60516 :         expandValue(value, v, mode, this, key, requestStack);
     563       60516 :         return true;
     564             :     } else {
     565      101394 :         return false;
     566      161910 :     }
     567             : }
     568             : 
     569      129898 : bool Bootstrap_Impl::getAmbienceValue(
     570             :     rtl::OUString const & key, rtl_uString ** value, LookupMode mode,
     571             :     ExpandRequestLink const * requestStack) const
     572             : {
     573      129898 :     rtl::OUString v;
     574             :     bool f;
     575             :     {
     576      129898 :         osl::MutexGuard g(osl::Mutex::getGlobalMutex());
     577      129898 :         f = find(rtl_bootstrap_set_list::get(), key, &v);
     578             :     }
     579      193757 :     if (f || getFromCommandLineArgs(key, &v) ||
     580       63859 :         osl_getEnvironment(key.pData, &v.pData) == osl_Process_E_None)
     581             :     {
     582       66162 :         expandValue(value, v, mode, NULL, key, requestStack);
     583       66162 :         return true;
     584             :     } else {
     585       63736 :         return false;
     586      129898 :     }
     587             : }
     588             : 
     589      126678 : 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         222 :         (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      126679 :              requestFile, requestKey, requestStack)).pData);
     603      126678 : }
     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       36708 :     static t * get() {
     617       36708 :         if (m_map == NULL) {
     618        1060 :             m_map = new t;
     619             :         }
     620       36708 :         return m_map;
     621             :     }
     622             : 
     623       18353 :     static void release() {
     624       18353 :         if (m_map != NULL && m_map->empty()) {
     625         554 :             delete m_map;
     626         554 :             m_map = NULL;
     627             :         }
     628       18353 :     }
     629             : 
     630             : private:
     631             :     static t * m_map;
     632             : };
     633             : 
     634             : bootstrap_map::t * bootstrap_map::m_map = NULL;
     635             : 
     636             : }
     637             : 
     638       19557 : rtlBootstrapHandle SAL_CALL rtl_bootstrap_args_open (
     639             :     rtl_uString * pIniName
     640             : ) SAL_THROW_EXTERN_C()
     641             : {
     642       19557 :     OUString iniName( pIniName );
     643             : 
     644             :     // normalize path
     645       39114 :     FileStatus status( osl_FileStatus_Mask_FileURL );
     646       39114 :     DirectoryItem dirItem;
     647       37911 :     if (DirectoryItem::E_None != DirectoryItem::get( iniName, dirItem ) ||
     648       18354 :         DirectoryItem::E_None != dirItem.getFileStatus( status ))
     649             :     {
     650        1203 :         return 0;
     651             :     }
     652       18354 :     iniName = status.getFileURL();
     653             : 
     654             :     Bootstrap_Impl * that;
     655       36708 :     osl::ResettableMutexGuard guard( osl::Mutex::getGlobalMutex() );
     656       18354 :     bootstrap_map::t* p_bootstrap_map = bootstrap_map::get();
     657       18354 :     bootstrap_map::t::const_iterator iFind( p_bootstrap_map->find( iniName ) );
     658       18354 :     if (iFind == p_bootstrap_map->end())
     659             :     {
     660        1264 :         bootstrap_map::release();
     661        1264 :         guard.clear();
     662        1264 :         that = new Bootstrap_Impl( iniName );
     663        1264 :         guard.reset();
     664        1264 :         p_bootstrap_map = bootstrap_map::get();
     665        1264 :         iFind = p_bootstrap_map->find( iniName );
     666        1264 :         if (iFind == p_bootstrap_map->end())
     667             :         {
     668        1264 :             ++that->_nRefCount;
     669             :             ::std::pair< bootstrap_map::t::iterator, bool > insertion(
     670             :                 p_bootstrap_map->insert(
     671        1264 :                     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       17090 :         that = iFind->second;
     687       17090 :         ++that->_nRefCount;
     688             :     }
     689       37911 :     return static_cast< rtlBootstrapHandle >( that );
     690             : }
     691             : 
     692       20008 : void SAL_CALL rtl_bootstrap_args_close (
     693             :     rtlBootstrapHandle handle
     694             : ) SAL_THROW_EXTERN_C()
     695             : {
     696       20008 :     if (handle == 0)
     697       22926 :         return;
     698       17090 :     Bootstrap_Impl * that = static_cast< Bootstrap_Impl * >( handle );
     699             : 
     700       17090 :     osl::MutexGuard guard( osl::Mutex::getGlobalMutex() );
     701       17090 :     bootstrap_map::t* p_bootstrap_map = bootstrap_map::get();
     702             :     OSL_ASSERT(
     703             :         p_bootstrap_map->find( that->_iniName )->second == that );
     704       17090 :     --that->_nRefCount;
     705       17090 :     if (that->_nRefCount == 0)
     706             :     {
     707       17089 :         ::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       17089 :         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       17089 :         bootstrap_map::release();
     724       17090 :     }
     725             : }
     726             : 
     727        6444 : 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        6444 :     osl::MutexGuard guard( osl::Mutex::getGlobalMutex() );
     735             : 
     736        6444 :     bool found = false;
     737        6444 :     if(ppValue && pName)
     738             :     {
     739        6444 :         if (handle == 0)
     740        2378 :             handle = get_static_bootstrap_handle();
     741             :         found = static_cast< Bootstrap_Impl * >( handle )->getValue(
     742        6444 :             pName, ppValue, pDefault, LOOKUP_MODE_NORMAL, false, NULL );
     743             :     }
     744             : 
     745        6444 :     return found;
     746             : }
     747             : 
     748         225 : void SAL_CALL rtl_bootstrap_get_iniName_from_handle (
     749             :     rtlBootstrapHandle handle,
     750             :     rtl_uString     ** ppIniName
     751             : ) SAL_THROW_EXTERN_C()
     752             : {
     753         225 :     if(ppIniName)
     754             :     {
     755         225 :         if(handle)
     756             :         {
     757         225 :             Bootstrap_Impl * pImpl = static_cast<Bootstrap_Impl*>(handle);
     758         225 :             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         225 : }
     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        2178 : 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        2178 :     return rtl_bootstrap_get_from_handle(0, pName, ppValue, pDefault);
     784             : }
     785             : 
     786        1757 : void SAL_CALL rtl_bootstrap_set (
     787             :     rtl_uString * pName,
     788             :     rtl_uString * pValue
     789             : ) SAL_THROW_EXTERN_C()
     790             : {
     791        1757 :     const OUString name( pName );
     792        1840 :     const OUString value( pValue );
     793             : 
     794        1840 :     osl::MutexGuard guard( osl::Mutex::getGlobalMutex() );
     795             : 
     796        1757 :     NameValueList& r_rtl_bootstrap_set_list = rtl_bootstrap_set_list::get();
     797        1757 :     NameValueList::iterator iPos( r_rtl_bootstrap_set_list.begin() );
     798        1757 :     NameValueList::iterator iEnd( r_rtl_bootstrap_set_list.end() );
     799        1764 :     for ( ; iPos != iEnd; ++iPos )
     800             :     {
     801        1681 :         if (iPos->sName.equals( name ))
     802             :         {
     803        1674 :             iPos->sValue = value;
     804        3431 :             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         166 :     r_rtl_bootstrap_set_list.push_back( rtl_bootstrap_NameValue( name, value ) );
     817             : }
     818             : 
     819       57470 : void SAL_CALL rtl_bootstrap_expandMacros_from_handle (
     820             :     rtlBootstrapHandle handle,
     821             :     rtl_uString     ** macro
     822             : ) SAL_THROW_EXTERN_C()
     823             : {
     824       57470 :     if (handle == NULL) {
     825        5652 :         handle = get_static_bootstrap_handle();
     826             :     }
     827             :     OUString expanded( expandMacros( static_cast< Bootstrap_Impl * >( handle ),
     828             :                                      * reinterpret_cast< OUString const * >( macro ),
     829       57470 :                                      LOOKUP_MODE_NORMAL, NULL ) );
     830       57470 :     rtl_uString_assign( macro, expanded.pData );
     831       57470 : }
     832             : 
     833        5652 : void SAL_CALL rtl_bootstrap_expandMacros(
     834             :     rtl_uString ** macro )
     835             :     SAL_THROW_EXTERN_C()
     836             : {
     837        5652 :     rtl_bootstrap_expandMacros_from_handle(NULL, macro);
     838        5652 : }
     839             : 
     840          91 : void rtl_bootstrap_encode( rtl_uString const * value, rtl_uString ** encoded )
     841             :     SAL_THROW_EXTERN_C()
     842             : {
     843             :     OSL_ASSERT(value != NULL);
     844          91 :     rtl::OUStringBuffer b;
     845        5681 :     for (sal_Int32 i = 0; i < value->length; ++i) {
     846        5590 :         sal_Unicode c = value->buffer[i];
     847        5590 :         if (c == '$' || c == '\\') {
     848           0 :             b.append('\\');
     849             :         }
     850        5590 :         b.append(c);
     851             :     }
     852          91 :     rtl_uString_assign(encoded, b.makeStringAndClear().pData);
     853          91 : }
     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     8889230 : 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     8889230 :     sal_Unicode c = text[(*pos)++];
     868     8889230 :     if (c == '\\') {
     869             :         int n1, n2, n3, n4;
     870           6 :         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           2 :             ((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           2 :         } else if (*pos < text.getLength()) {
     881           2 :             *escaped = true;
     882           2 :             return text[(*pos)++];
     883             :         }
     884             :     }
     885     8889228 :     *escaped = false;
     886     8889228 :     return c;
     887             : }
     888             : 
     889      157603 : rtl::OUString lookup(
     890             :     Bootstrap_Impl const * file, LookupMode mode, bool override,
     891             :     rtl::OUString const & key, ExpandRequestLink const * requestStack)
     892             : {
     893      157603 :     rtl::OUString v;
     894             :     (file == NULL ? get_static_bootstrap_handle() : file)->getValue(
     895      157603 :         key, &v.pData, NULL, mode, override, requestStack);
     896      157603 :     return v;
     897             : }
     898             : 
     899      248393 : rtl::OUString expandMacros(
     900             :     Bootstrap_Impl const * file, rtl::OUString const & text, LookupMode mode,
     901             :     ExpandRequestLink const * requestStack)
     902             : {
     903      248393 :     rtl::OUStringBuffer buf;
     904     6668110 :     for (sal_Int32 i = 0; i < text.getLength();) {
     905             :         bool escaped;
     906     6171324 :         sal_Unicode c = read(text, &i, &escaped);
     907     6171324 :         if (escaped || c != '$') {
     908     6013719 :             buf.append(c);
     909             :         } else {
     910      157605 :             if (i < text.getLength() && text[i] == '{') {
     911       48592 :                 ++i;
     912       48592 :                 sal_Int32 p = i;
     913       48592 :                 sal_Int32 nesting = 0;
     914      194368 :                 rtl::OUString seg[3];
     915       48592 :                 int n = 0;
     916     1030401 :                 while (i < text.getLength()) {
     917      981809 :                     sal_Int32 j = i;
     918      981809 :                     c = read(text, &i, &escaped);
     919      981809 :                     if (!escaped) {
     920      981809 :                         switch (c) {
     921             :                         case '{':
     922         746 :                             ++nesting;
     923         746 :                             break;
     924             :                         case '}':
     925       49338 :                             if (nesting == 0) {
     926       48592 :                                 seg[n++] = text.copy(p, j - p);
     927       48592 :                                 goto done;
     928             :                             } else {
     929         746 :                                 --nesting;
     930             :                             }
     931         746 :                             break;
     932             :                         case ':':
     933       16152 :                             if (nesting == 0 && n < 2) {
     934       15654 :                                 seg[n++] = text.copy(p, j - p);
     935       15654 :                                 p = i;
     936             :                             }
     937       16152 :                             break;
     938             :                         }
     939             :                     }
     940             :                 }
     941             :             done:
     942      112838 :                 for (int j = 0; j < n; ++j) {
     943       64246 :                     seg[j] = expandMacros(file, seg[j], mode, requestStack);
     944             :                 }
     945       48592 :                 if (n == 1) {
     946       33759 :                     buf.append(lookup(file, mode, false, seg[0], requestStack));
     947       14833 :                 } 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       14833 :                 } 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       14833 :                     if (n == 3 && seg[1].isEmpty()) {
     980             :                         // For backward compatibility, treat ${file::key} the
     981             :                         // same as just ${file:key}:
     982         819 :                         seg[1] = seg[2];
     983         819 :                         n = 2;
     984             :                     }
     985       14833 :                     if (n == 2) {
     986             :                         buf.append(
     987             :                             lookup(
     988             :                                 static_cast< Bootstrap_Impl * >(
     989       29662 :                                     rtl::Bootstrap(seg[0]).getHandle()),
     990       14831 :                                 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           2 :                                 RTL_TEXTENCODING_UTF8));
    1005             :                     }
    1006      194368 :                 }
    1007             :             } else {
    1008      109013 :                 rtl::OUStringBuffer kbuf;
    1009      109013 :                 for (; i < text.getLength();) {
    1010     1736097 :                     sal_Int32 j = i;
    1011     1736097 :                     c = read(text, &j, &escaped);
    1012     1736097 :                     if (!escaped &&
    1013     1736097 :                         (c == ' ' || c == '$' || c == '-' || c == '/' ||
    1014     1630609 :                          c == ';' || c == '\\'))
    1015             :                     {
    1016             :                         break;
    1017             :                     }
    1018     1630609 :                     kbuf.append(c);
    1019     1630609 :                     i = j;
    1020             :                 }
    1021             :                 buf.append(
    1022             :                     lookup(
    1023             :                         file, mode, false, kbuf.makeStringAndClear(),
    1024      109013 :                         requestStack));
    1025             :             }
    1026             :         }
    1027             :     }
    1028      248393 :     return buf.makeStringAndClear();
    1029             : }
    1030             : 
    1031             : }
    1032             : 
    1033             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.10