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

Generated by: LCOV version 1.11