LCOV - code coverage report
Current view: top level - framework/source/services - substitutepathvars.cxx (source / functions) Hit Total Coverage
Test: commit c8344322a7af75b84dd3ca8f78b05543a976dfd5 Lines: 258 468 55.1 %
Date: 2015-06-13 12:38:46 Functions: 27 50 54.0 %
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_folders.h>
      21             : 
      22             : #include <helper/networkdomain.hxx>
      23             : 
      24             : #include <cppuhelper/basemutex.hxx>
      25             : #include <cppuhelper/compbase2.hxx>
      26             : #include <cppuhelper/supportsservice.hxx>
      27             : #include <unotools/configitem.hxx>
      28             : #include <unotools/localfilehelper.hxx>
      29             : #include <unotools/configmgr.hxx>
      30             : 
      31             : #include <unotools/bootstrap.hxx>
      32             : #include <osl/mutex.hxx>
      33             : #include <osl/file.hxx>
      34             : #include <osl/security.hxx>
      35             : #include <osl/socket.hxx>
      36             : #include <osl/process.h>
      37             : #include <i18nlangtag/languagetag.hxx>
      38             : #include <i18nlangtag/mslangid.hxx>
      39             : #include <tools/link.hxx>
      40             : #include <tools/urlobj.hxx>
      41             : #include <tools/resmgr.hxx>
      42             : #include <tools/wldcrd.hxx>
      43             : #include <rtl/ustrbuf.hxx>
      44             : #include <rtl/bootstrap.hxx>
      45             : 
      46             : #include <officecfg/Office/Paths.hxx>
      47             : 
      48             : #include <com/sun/star/lang/XServiceInfo.hpp>
      49             : #include <com/sun/star/container/NoSuchElementException.hpp>
      50             : #include <com/sun/star/container/XHierarchicalNameAccess.hpp>
      51             : #include <com/sun/star/util/XStringSubstitution.hpp>
      52             : 
      53             : #include <unordered_map>
      54             : #include <string.h>
      55             : 
      56             : using namespace com::sun::star::uno;
      57             : using namespace com::sun::star::beans;
      58             : using namespace com::sun::star::util;
      59             : using namespace com::sun::star::lang;
      60             : using namespace com::sun::star::container;
      61             : using namespace framework;
      62             : 
      63             : namespace {
      64             : 
      65             : // Must be zero value based
      66             : enum EnvironmentType
      67             : {
      68             :         ET_HOST = 0             ,
      69             :         ET_YPDOMAIN             ,
      70             :         ET_DNSDOMAIN    ,
      71             :         ET_NTDOMAIN             ,
      72             :         ET_OS                   ,
      73             :         ET_UNKNOWN              ,
      74             :         ET_COUNT
      75             : };
      76             : 
      77             : // Must be zero value based
      78             : enum OperatingSystem
      79             : {
      80             :         OS_WINDOWS = 0,
      81             :         OS_UNIX         ,
      82             :         OS_SOLARIS      ,
      83             :         OS_LINUX        ,
      84             :         OS_UNKNOWN      ,
      85             :         OS_COUNT
      86             : };
      87             : 
      88           0 : struct SubstituteRule
      89             : {
      90           0 :     SubstituteRule()
      91           0 :         : aEnvType(ET_UNKNOWN)
      92           0 :     {}
      93             : 
      94           0 :     SubstituteRule( const OUString& aVarName,
      95             :                     const OUString& aValue,
      96             :                     const com::sun::star::uno::Any& aVal,
      97             :                     EnvironmentType aType )
      98             :         : aSubstVariable(aVarName)
      99             :         , aSubstValue(aValue)
     100             :         , aEnvValue(aVal)
     101           0 :         , aEnvType(aType)
     102           0 :     {}
     103             : 
     104             :     OUString            aSubstVariable;
     105             :     OUString            aSubstValue;
     106             :     com::sun::star::uno::Any aEnvValue;
     107             :     EnvironmentType          aEnvType;
     108             : };
     109             : 
     110             : typedef std::unordered_map<OUString, SubstituteRule, OUStringHash>
     111             :     SubstituteVariables;
     112             : 
     113             : typedef std::vector< SubstituteRule > SubstituteRuleVector;
     114             : class SubstitutePathVariables_Impl : public utl::ConfigItem
     115             : {
     116             :     public:
     117             :         SubstitutePathVariables_Impl();
     118             :         virtual ~SubstitutePathVariables_Impl();
     119             : 
     120             :         static OperatingSystem GetOperatingSystemFromString( const OUString& );
     121             :         static EnvironmentType GetEnvTypeFromString( const OUString& );
     122             : 
     123             :         void                   GetSharePointsRules( SubstituteVariables& aSubstVarMap );
     124             : 
     125             :         /** is called from the ConfigManager before application ends or from the
     126             :             PropertyChangeListener if the sub tree broadcasts changes. */
     127             :         virtual void Notify( const com::sun::star::uno::Sequence< OUString >& aPropertyNames ) SAL_OVERRIDE;
     128             : 
     129             :     private:
     130             : 
     131             :         virtual void ImplCommit() SAL_OVERRIDE;
     132             : 
     133             :         // Wrapper methods for low-level functions
     134             :         const OUString&    GetYPDomainName();
     135             :         const OUString&    GetDNSDomainName();
     136             :         const OUString&    GetNTDomainName();
     137             :         const OUString&    GetHostName();
     138             : 
     139             :         bool  FilterRuleSet(const SubstituteRuleVector& aRuleSet, SubstituteRule& aActiveRule);
     140             : 
     141             :         void  ReadSharePointsFromConfiguration(com::sun::star::uno::Sequence< OUString >& aSharePointsSeq);
     142             :         void  ReadSharePointRuleSetFromConfiguration(const OUString& aSharePointName,
     143             :                   const OUString& aSharePointNodeName,
     144             :                   SubstituteRuleVector& aRuleSet);
     145             : 
     146             :         // Stored values for domains and host
     147             :         bool      m_bYPDomainRetrieved;
     148             :         OUString  m_aYPDomain;
     149             :         bool      m_bDNSDomainRetrieved;
     150             :         OUString  m_aDNSDomain;
     151             :         bool      m_bNTDomainRetrieved;
     152             :         OUString  m_aNTDomain;
     153             :         bool      m_bHostRetrieved;
     154             :         OUString  m_aHost;
     155             : 
     156             :         const OUString    m_aSharePointsNodeName;
     157             :         const OUString    m_aDirPropertyName;
     158             :         const OUString    m_aEnvPropertyName;
     159             :         const OUString    m_aLevelSep;
     160             : };
     161             : 
     162             : enum PreDefVariable
     163             : {
     164             :     PREDEFVAR_INST,
     165             :     PREDEFVAR_PROG,
     166             :     PREDEFVAR_USER,
     167             :     PREDEFVAR_WORK,
     168             :     PREDEFVAR_HOME,
     169             :     PREDEFVAR_TEMP,
     170             :     PREDEFVAR_PATH,
     171             :     PREDEFVAR_LANGID,
     172             :     PREDEFVAR_VLANG,
     173             :     PREDEFVAR_INSTPATH,
     174             :     PREDEFVAR_PROGPATH,
     175             :     PREDEFVAR_USERPATH,
     176             :     PREDEFVAR_INSTURL,
     177             :     PREDEFVAR_PROGURL,
     178             :     PREDEFVAR_USERURL,
     179             :     PREDEFVAR_WORKDIRURL,
     180             :     // New variable of hierarchy service (#i32656#)
     181             :     PREDEFVAR_BASEINSTURL,
     182             :     PREDEFVAR_USERDATAURL,
     183             :     PREDEFVAR_BRANDBASEURL,
     184             :     PREDEFVAR_COUNT
     185             : };
     186             : 
     187         352 : struct PredefinedPathVariables
     188             : {
     189             :     // Predefined variables supported by substitute variables
     190             :     LanguageType    m_eLanguageType;                    // Lanuage type of Office
     191             :     OUString   m_FixedVar[ PREDEFVAR_COUNT ];      // Variable value access by PreDefVariable
     192             :     OUString   m_FixedVarNames[ PREDEFVAR_COUNT ]; // Variable name access by PreDefVariable
     193             : };
     194             : 
     195             : struct ReSubstFixedVarOrder
     196             : {
     197             :     sal_Int32       nVarValueLength;
     198             :     PreDefVariable  eVariable;
     199             : 
     200       11119 :     bool operator< ( const ReSubstFixedVarOrder& aFixedVarOrder ) const
     201             :     {
     202             :         // Reverse operator< to have high to low ordering
     203       11119 :         return ( nVarValueLength > aFixedVarOrder.nVarValueLength );
     204             :     }
     205             : };
     206             : 
     207           0 : struct ReSubstUserVarOrder
     208             : {
     209             :     sal_Int32       nVarValueLength;
     210             :     OUString   aVarName;
     211             : 
     212           0 :     bool operator< ( const ReSubstUserVarOrder& aUserVarOrder ) const
     213             :     {
     214             :         // Reverse operator< to have high to low ordering
     215           0 :         return ( nVarValueLength > aUserVarOrder.nVarValueLength );
     216             :     }
     217             : };
     218             : 
     219             : typedef std::list< ReSubstFixedVarOrder > ReSubstFixedVarOrderVector;
     220             : typedef std::list< ReSubstUserVarOrder > ReSubstUserVarOrderVector;
     221             : typedef ::cppu::WeakComponentImplHelper2<
     222             :     css::util::XStringSubstitution,
     223             :     css::lang::XServiceInfo > SubstitutePathVariables_BASE;
     224             : 
     225             : class SubstitutePathVariables : private cppu::BaseMutex,
     226             :                                 public SubstitutePathVariables_BASE
     227             : {
     228             : friend class SubstitutePathVariables_Impl;
     229             : 
     230             : public:
     231             :     SubstitutePathVariables( const ::com::sun::star::uno::Reference< ::com::sun::star::uno::XComponentContext >& xContext );
     232             :     virtual ~SubstitutePathVariables();
     233             : 
     234           2 :     virtual OUString SAL_CALL getImplementationName()
     235             :         throw (css::uno::RuntimeException, std::exception) SAL_OVERRIDE
     236             :     {
     237           2 :         return OUString("com.sun.star.comp.framework.PathSubstitution");
     238             :     }
     239             : 
     240           0 :     virtual sal_Bool SAL_CALL supportsService(OUString const & ServiceName)
     241             :         throw (css::uno::RuntimeException, std::exception) SAL_OVERRIDE
     242             :     {
     243           0 :         return cppu::supportsService(this, ServiceName);
     244             :     }
     245             : 
     246           1 :     virtual css::uno::Sequence<OUString> SAL_CALL getSupportedServiceNames()
     247             :         throw (css::uno::RuntimeException, std::exception) SAL_OVERRIDE
     248             :     {
     249           1 :         css::uno::Sequence< OUString > aSeq(1);
     250           1 :         aSeq[0] = "com.sun.star.util.PathSubstitution";
     251           1 :         return aSeq;
     252             :     }
     253             : 
     254             :     // XStringSubstitution
     255             :     virtual OUString SAL_CALL substituteVariables( const OUString& aText, sal_Bool bSubstRequired )
     256             :         throw (::com::sun::star::container::NoSuchElementException, ::com::sun::star::uno::RuntimeException, std::exception) SAL_OVERRIDE;
     257             :     virtual OUString SAL_CALL reSubstituteVariables( const OUString& aText )
     258             :         throw (::com::sun::star::uno::RuntimeException, std::exception) SAL_OVERRIDE;
     259             :     virtual OUString SAL_CALL getSubstituteVariableValue( const OUString& variable )
     260             :         throw (::com::sun::star::container::NoSuchElementException, ::com::sun::star::uno::RuntimeException, std::exception) SAL_OVERRIDE;
     261             : 
     262             : protected:
     263             :     void            SetPredefinedPathVariables();
     264             :     OUString   ConvertOSLtoUCBURL( const OUString& aOSLCompliantURL ) const;
     265             : 
     266             :     // Special case (transient) values can change during runtime!
     267             :     // Don't store them in the pre defined struct
     268             :     OUString   GetWorkPath() const;
     269             :     OUString   GetWorkVariableValue() const;
     270             :     OUString   GetPathVariableValue() const;
     271             : 
     272             :     OUString   GetHomeVariableValue() const;
     273             : 
     274             :     // XStringSubstitution implementation methods
     275             :     OUString impl_substituteVariable( const OUString& aText, bool bSustRequired )
     276             :         throw (::com::sun::star::container::NoSuchElementException, ::com::sun::star::uno::RuntimeException);
     277             :     OUString impl_reSubstituteVariables( const OUString& aText )
     278             :         throw (::com::sun::star::uno::RuntimeException);
     279             :     OUString impl_getSubstituteVariableValue( const OUString& variable )
     280             :         throw (::com::sun::star::container::NoSuchElementException, ::com::sun::star::uno::RuntimeException);
     281             : 
     282             : private:
     283             :     typedef std::unordered_map<OUString, PreDefVariable, OUStringHash>
     284             :         VarNameToIndexMap;
     285             : 
     286             :     VarNameToIndexMap            m_aPreDefVarMap;         // Mapping from pre-def variable names to enum for array access
     287             :     SubstituteVariables          m_aSubstVarMap;          // Active rule set map indexed by variable name!
     288             :     PredefinedPathVariables      m_aPreDefVars;           // All predefined variables
     289             :     SubstitutePathVariables_Impl m_aImpl;                 // Implementation class that access the configuration
     290             :     ReSubstFixedVarOrderVector   m_aReSubstFixedVarOrder; // To speed up resubstitution fixed variables (order for lookup)
     291             :     ReSubstUserVarOrderVector    m_aReSubstUserVarOrder;  // To speed up resubstitution user variables
     292             :     css::uno::Reference< css::uno::XComponentContext > m_xContext;
     293             : };
     294             : 
     295             : struct FixedVariable
     296             : {
     297             :     const char*     pVarName;
     298             :     sal_Int32       nStrLen;
     299             :     PreDefVariable  nEnumValue;
     300             :     bool            bAbsPath;
     301             : };
     302             : 
     303             : struct TableEntry
     304             : {
     305             :     const char* pOSString;
     306             :     sal_Int32   nStrLen;
     307             : };
     308             : 
     309             : // Table with valid operating system strings
     310             : // Name of the os as char* and the length
     311             : // of the string
     312             : static const TableEntry aOSTable[OS_COUNT] =
     313             : {
     314             :     { RTL_CONSTASCII_STRINGPARAM("WINDOWS") },
     315             :     { RTL_CONSTASCII_STRINGPARAM("UNIX") },
     316             :     { RTL_CONSTASCII_STRINGPARAM("SOLARIS") },
     317             :     { RTL_CONSTASCII_STRINGPARAM("LINUX") },
     318             :     { RTL_CONSTASCII_STRINGPARAM("") } // unknown
     319             : };
     320             : 
     321             : // Table with valid environment variables
     322             : // Name of the environment type as a char* and
     323             : // the length of the string.
     324             : static const TableEntry aEnvTable[ET_COUNT] =
     325             : {
     326             :     { RTL_CONSTASCII_STRINGPARAM("HOST") },
     327             :     { RTL_CONSTASCII_STRINGPARAM("YPDOMAIN") },
     328             :     { RTL_CONSTASCII_STRINGPARAM("DNSDOMAIN") },
     329             :     { RTL_CONSTASCII_STRINGPARAM("NTDOMAIN") },
     330             :     { RTL_CONSTASCII_STRINGPARAM("OS") },
     331             :     { RTL_CONSTASCII_STRINGPARAM("") } // unknown
     332             : };
     333             : 
     334             : // Priority table for the environment types. Lower numbers define
     335             : // a higher priority. Equal numbers has the same priority that means
     336             : // that the first match wins!!
     337             : static const sal_Int16 aEnvPrioTable[ET_COUNT] =
     338             : {
     339             :     1,      // ET_HOST
     340             :     2,      // ET_IPDOMAIN
     341             :     2,      // ET_DNSDOMAIN
     342             :     2,      // ET_NTDOMAIN
     343             :     3,      // ET_OS
     344             :     99,     // ET_UNKNOWN
     345             : };
     346             : 
     347             : // Table with all fixed/predefined variables supported.
     348             : static const FixedVariable aFixedVarTable[] =
     349             : {
     350             :     { RTL_CONSTASCII_STRINGPARAM("$(inst)"),        PREDEFVAR_INST,         true  },
     351             :     { RTL_CONSTASCII_STRINGPARAM("$(prog)"),        PREDEFVAR_PROG,         true  },
     352             :     { RTL_CONSTASCII_STRINGPARAM("$(user)"),        PREDEFVAR_USER,         true  },
     353             :     { RTL_CONSTASCII_STRINGPARAM("$(work)"),        PREDEFVAR_WORK,         true  },      // Special variable (transient)!
     354             :     { RTL_CONSTASCII_STRINGPARAM("$(home)"),        PREDEFVAR_HOME,         true  },
     355             :     { RTL_CONSTASCII_STRINGPARAM("$(temp)"),        PREDEFVAR_TEMP,         true  },
     356             :     { RTL_CONSTASCII_STRINGPARAM("$(path)"),        PREDEFVAR_PATH,         true  },
     357             :     { RTL_CONSTASCII_STRINGPARAM("$(langid)"),      PREDEFVAR_LANGID,       false },
     358             :     { RTL_CONSTASCII_STRINGPARAM("$(vlang)"),       PREDEFVAR_VLANG,        false },
     359             :     { RTL_CONSTASCII_STRINGPARAM("$(instpath)"),    PREDEFVAR_INSTPATH,     true  },
     360             :     { RTL_CONSTASCII_STRINGPARAM("$(progpath)"),    PREDEFVAR_PROGPATH,     true  },
     361             :     { RTL_CONSTASCII_STRINGPARAM("$(userpath)"),    PREDEFVAR_USERPATH,     true  },
     362             :     { RTL_CONSTASCII_STRINGPARAM("$(insturl)"),     PREDEFVAR_INSTURL,      true  },
     363             :     { RTL_CONSTASCII_STRINGPARAM("$(progurl)"),     PREDEFVAR_PROGURL,      true  },
     364             :     { RTL_CONSTASCII_STRINGPARAM("$(userurl)"),     PREDEFVAR_USERURL,      true  },
     365             :     { RTL_CONSTASCII_STRINGPARAM("$(workdirurl)"),  PREDEFVAR_WORKDIRURL,   true  },  // Special variable (transient) and don't use for resubstitution!
     366             :     { RTL_CONSTASCII_STRINGPARAM("$(baseinsturl)"), PREDEFVAR_BASEINSTURL,  true  },
     367             :     { RTL_CONSTASCII_STRINGPARAM("$(userdataurl)"), PREDEFVAR_USERDATAURL,  true  },
     368             :     { RTL_CONSTASCII_STRINGPARAM("$(brandbaseurl)"),PREDEFVAR_BRANDBASEURL, true  }
     369             : };
     370             : 
     371             : //      Implementation helper classes
     372             : 
     373           0 : OperatingSystem SubstitutePathVariables_Impl::GetOperatingSystemFromString( const OUString& aOSString )
     374             : {
     375           0 :     for ( int i = 0; i < OS_COUNT; i++ )
     376             :     {
     377           0 :         if ( aOSString.equalsIgnoreAsciiCaseAsciiL( aOSTable[i].pOSString, aOSTable[i].nStrLen ))
     378           0 :             return (OperatingSystem)i;
     379             :     }
     380             : 
     381           0 :     return OS_UNKNOWN;
     382             : }
     383             : 
     384           0 : EnvironmentType SubstitutePathVariables_Impl::GetEnvTypeFromString( const OUString& aEnvTypeString )
     385             : {
     386           0 :     for ( int i = 0; i < ET_COUNT; i++ )
     387             :     {
     388           0 :         if ( aEnvTypeString.equalsIgnoreAsciiCaseAsciiL( aEnvTable[i].pOSString, aEnvTable[i].nStrLen ))
     389           0 :             return (EnvironmentType)i;
     390             :     }
     391             : 
     392           0 :     return ET_UNKNOWN;
     393             : }
     394             : 
     395         210 : SubstitutePathVariables_Impl::SubstitutePathVariables_Impl() :
     396             :     utl::ConfigItem( OUString( "Office.Substitution" )),
     397             :     m_bYPDomainRetrieved( false ),
     398             :     m_bDNSDomainRetrieved( false ),
     399             :     m_bNTDomainRetrieved( false ),
     400             :     m_bHostRetrieved( false ),
     401             :     m_aSharePointsNodeName( OUString( "SharePoints" )),
     402             :     m_aDirPropertyName( OUString( "/Directory" )),
     403             :     m_aEnvPropertyName( OUString( "/Environment" )),
     404         210 :     m_aLevelSep( OUString(  "/" ))
     405             : {
     406             :     // Enable notification mechanism
     407             :     // We need it to get information about changes outside these class on our configuration branch
     408         210 :     Sequence< OUString > aNotifySeq( 1 );
     409         210 :     aNotifySeq[0] = "SharePoints";
     410         210 :     EnableNotification( aNotifySeq, true );
     411         210 : }
     412             : 
     413         142 : SubstitutePathVariables_Impl::~SubstitutePathVariables_Impl()
     414             : {
     415         142 : }
     416             : 
     417         210 : void SubstitutePathVariables_Impl::GetSharePointsRules( SubstituteVariables& aSubstVarMap )
     418             : {
     419         210 :     Sequence< OUString > aSharePointNames;
     420         210 :     ReadSharePointsFromConfiguration( aSharePointNames );
     421             : 
     422         210 :     if ( aSharePointNames.getLength() > 0 )
     423             :     {
     424           0 :         sal_Int32 nSharePoints = 0;
     425             : 
     426             :         // Read SharePoints container from configuration
     427           0 :         while ( nSharePoints < aSharePointNames.getLength() )
     428             :         {
     429           0 :             OUString aSharePointNodeName( m_aSharePointsNodeName );
     430           0 :             aSharePointNodeName += "/";
     431           0 :             aSharePointNodeName += aSharePointNames[ nSharePoints ];
     432             : 
     433           0 :             SubstituteRuleVector aRuleSet;
     434           0 :             ReadSharePointRuleSetFromConfiguration( aSharePointNames[ nSharePoints ], aSharePointNodeName, aRuleSet );
     435           0 :             if ( !aRuleSet.empty() )
     436             :             {
     437             :                 // We have at minimum one rule. Filter the correct rule out of the rule set
     438             :                 // and put into our SubstituteVariable map
     439           0 :                 SubstituteRule aActiveRule;
     440           0 :                 if ( FilterRuleSet( aRuleSet, aActiveRule ))
     441             :                 {
     442             :                     // We have found an active rule
     443           0 :                     aActiveRule.aSubstVariable = aSharePointNames[ nSharePoints ];
     444             :                     aSubstVarMap.insert( SubstituteVariables::value_type(
     445           0 :                     aActiveRule.aSubstVariable, aActiveRule ));
     446           0 :                 }
     447             :             }
     448           0 :             ++nSharePoints;
     449           0 :         }
     450         210 :     }
     451         210 : }
     452             : 
     453           0 : void SubstitutePathVariables_Impl::Notify( const com::sun::star::uno::Sequence< OUString >& /*aPropertyNames*/ )
     454             : {
     455             :     // NOT implemented yet!
     456           0 : }
     457             : 
     458           0 : void SubstitutePathVariables_Impl::ImplCommit()
     459             : {
     460           0 : }
     461             : 
     462           0 : static inline OperatingSystem GetOperatingSystem()
     463             : {
     464             : #ifdef SOLARIS
     465             :     return OS_SOLARIS;
     466             : #elif defined LINUX
     467           0 :     return OS_LINUX;
     468             : #elif defined WIN32
     469             :     return OS_WINDOWS;
     470             : #elif defined UNIX
     471             :     return OS_UNIX;
     472             : #else
     473             :     return OS_UNKNOWN;
     474             : #endif
     475             : }
     476             : 
     477           0 : const OUString& SubstitutePathVariables_Impl::GetYPDomainName()
     478             : {
     479           0 :     if ( !m_bYPDomainRetrieved )
     480             :     {
     481           0 :         m_aYPDomain = NetworkDomain::GetYPDomainName().toAsciiLowerCase();
     482           0 :         m_bYPDomainRetrieved = true;
     483             :     }
     484             : 
     485           0 :     return m_aYPDomain;
     486             : }
     487             : 
     488           0 : const OUString& SubstitutePathVariables_Impl::GetDNSDomainName()
     489             : {
     490           0 :     if ( !m_bDNSDomainRetrieved )
     491             :     {
     492           0 :         OUString   aTemp;
     493           0 :         osl::SocketAddr aSockAddr;
     494             :         oslSocketResult aResult;
     495             : 
     496           0 :         OUString aHostName = GetHostName();
     497           0 :         osl::SocketAddr::resolveHostname( aHostName, aSockAddr );
     498           0 :         aTemp = aSockAddr.getHostname( &aResult );
     499             : 
     500             :         // DNS domain name begins after the first "."
     501           0 :         sal_Int32 nIndex = aTemp.indexOf( '.' );
     502           0 :         if ( nIndex >= 0 && aTemp.getLength() > nIndex+1 )
     503           0 :             m_aDNSDomain = aTemp.copy( nIndex+1 ).toAsciiLowerCase();
     504             :         else
     505           0 :             m_aDNSDomain.clear();
     506             : 
     507           0 :         m_bDNSDomainRetrieved = true;
     508             :     }
     509             : 
     510           0 :     return m_aDNSDomain;
     511             : }
     512             : 
     513           0 : const OUString& SubstitutePathVariables_Impl::GetNTDomainName()
     514             : {
     515           0 :     if ( !m_bNTDomainRetrieved )
     516             :     {
     517           0 :         m_aNTDomain = NetworkDomain::GetNTDomainName().toAsciiLowerCase();
     518           0 :         m_bNTDomainRetrieved = true;
     519             :     }
     520             : 
     521           0 :     return m_aNTDomain;
     522             : }
     523             : 
     524           0 : const OUString& SubstitutePathVariables_Impl::GetHostName()
     525             : {
     526           0 :     if (!m_bHostRetrieved)
     527             :     {
     528             :         oslSocketResult aSocketResult;
     529           0 :         m_aHost = osl::SocketAddr::getLocalHostname( &aSocketResult ).toAsciiLowerCase();
     530             :     }
     531             : 
     532           0 :     return m_aHost;
     533             : }
     534             : 
     535           0 : bool SubstitutePathVariables_Impl::FilterRuleSet( const SubstituteRuleVector& aRuleSet, SubstituteRule& aActiveRule )
     536             : {
     537           0 :     bool bResult = false;
     538             : 
     539           0 :     if ( !aRuleSet.empty() )
     540             :     {
     541           0 :         const sal_uInt32 nCount = aRuleSet.size();
     542             : 
     543           0 :         sal_Int16 nPrioCurrentRule = aEnvPrioTable[ ET_UNKNOWN ];
     544           0 :         for ( sal_uInt32 nIndex = 0; nIndex < nCount; nIndex++ )
     545             :         {
     546           0 :             const SubstituteRule& aRule = aRuleSet[nIndex];
     547           0 :             EnvironmentType eEnvType        = aRule.aEnvType;
     548             : 
     549             :             // Check if environment type has a higher priority than current one!
     550           0 :             if ( nPrioCurrentRule > aEnvPrioTable[eEnvType] )
     551             :             {
     552           0 :                 switch ( eEnvType )
     553             :                 {
     554             :                     case ET_HOST:
     555             :                     {
     556           0 :                         OUString aHost = GetHostName();
     557           0 :                         OUString aHostStr;
     558           0 :                         aRule.aEnvValue >>= aHostStr;
     559           0 :                         aHostStr = aHostStr.toAsciiLowerCase();
     560             : 
     561             :                         // Pattern match if domain environment match
     562           0 :                         WildCard aPattern(aHostStr);
     563           0 :                         bool bMatch = aPattern.Matches(aHost);
     564           0 :                         if ( bMatch )
     565             :                         {
     566           0 :                             aActiveRule      = aRule;
     567           0 :                             bResult          = true;
     568           0 :                             nPrioCurrentRule = aEnvPrioTable[eEnvType];
     569           0 :                         }
     570             :                     }
     571           0 :                     break;
     572             : 
     573             :                     case ET_YPDOMAIN:
     574             :                     case ET_DNSDOMAIN:
     575             :                     case ET_NTDOMAIN:
     576             :                     {
     577           0 :                         OUString   aDomain;
     578           0 :                         OUString   aDomainStr;
     579           0 :                         aRule.aEnvValue >>= aDomainStr;
     580           0 :                         aDomainStr = aDomainStr.toAsciiLowerCase();
     581             : 
     582             :                         // Retrieve the correct domain value
     583           0 :                         if ( eEnvType == ET_YPDOMAIN )
     584           0 :                             aDomain = GetYPDomainName();
     585           0 :                         else if ( eEnvType == ET_DNSDOMAIN )
     586           0 :                             aDomain = GetDNSDomainName();
     587             :                         else
     588           0 :                             aDomain = GetNTDomainName();
     589             : 
     590             :                         // Pattern match if domain environment match
     591           0 :                         WildCard aPattern(aDomainStr);
     592           0 :                         bool bMatch = aPattern.Matches(aDomain);
     593           0 :                         if ( bMatch )
     594             :                         {
     595           0 :                             aActiveRule      = aRule;
     596           0 :                             bResult          = true;
     597           0 :                             nPrioCurrentRule = aEnvPrioTable[eEnvType];
     598           0 :                         }
     599             :                     }
     600           0 :                     break;
     601             : 
     602             :                     case ET_OS:
     603             :                     {
     604             :                         // No pattern matching for OS type
     605           0 :                         OperatingSystem eOSType = GetOperatingSystem();
     606             : 
     607           0 :                         sal_Int16 nValue = 0;
     608           0 :                         aRule.aEnvValue >>= nValue;
     609             : 
     610           0 :                         bool            bUnix = ( eOSType == OS_LINUX ) || ( eOSType == OS_SOLARIS );
     611           0 :                         OperatingSystem eRuleOSType = (OperatingSystem)nValue;
     612             : 
     613             :                         // Match if OS identical or rule is set to UNIX and OS is LINUX/SOLARIS!
     614           0 :                         if (( eRuleOSType == eOSType ) || ( eRuleOSType == OS_UNIX && bUnix ))
     615             :                         {
     616           0 :                             aActiveRule      = aRule;
     617           0 :                             bResult          = true;
     618           0 :                             nPrioCurrentRule = aEnvPrioTable[eEnvType];
     619             :                         }
     620             :                     }
     621           0 :                     break;
     622             : 
     623             :                     case ET_UNKNOWN: // nothing to do
     624           0 :                         break;
     625             : 
     626             :                     default:
     627           0 :                         break;
     628             :                 }
     629             :             }
     630             :         }
     631             :     }
     632             : 
     633           0 :     return bResult;
     634             : }
     635             : 
     636         210 : void SubstitutePathVariables_Impl::ReadSharePointsFromConfiguration( Sequence< OUString >& aSharePointsSeq )
     637             : {
     638             :     //returns all the names of all share point nodes
     639         210 :     aSharePointsSeq = GetNodeNames( m_aSharePointsNodeName );
     640         210 : }
     641             : 
     642           0 : void SubstitutePathVariables_Impl::ReadSharePointRuleSetFromConfiguration(
     643             :         const OUString& aSharePointName,
     644             :         const OUString& aSharePointNodeName,
     645             :         SubstituteRuleVector& rRuleSet )
     646             : {
     647           0 :     Sequence< OUString > aSharePointMappingsNodeNames = GetNodeNames( aSharePointNodeName, utl::CONFIG_NAME_LOCAL_PATH );
     648             : 
     649           0 :     sal_Int32 nSharePointMapping = 0;
     650           0 :     while ( nSharePointMapping < aSharePointMappingsNodeNames.getLength() )
     651             :     {
     652           0 :         OUString aSharePointMapping( aSharePointNodeName );
     653           0 :         aSharePointMapping += m_aLevelSep;
     654           0 :         aSharePointMapping += aSharePointMappingsNodeNames[ nSharePointMapping ];
     655             : 
     656             :         // Read SharePointMapping
     657           0 :         OUString aDirValue;
     658           0 :         OUString aDirProperty( aSharePointMapping );
     659           0 :         aDirProperty += m_aDirPropertyName;
     660             : 
     661             :         // Read only the directory property
     662           0 :         Sequence< OUString > aDirPropertySeq( 1 );
     663           0 :         aDirPropertySeq[0] = aDirProperty;
     664             : 
     665           0 :         Sequence< Any > aValueSeq = GetProperties( aDirPropertySeq );
     666           0 :         if ( aValueSeq.getLength() == 1 )
     667           0 :             aValueSeq[0] >>= aDirValue;
     668             : 
     669             :         // Read the environment setting
     670           0 :         OUString aEnvUsed;
     671           0 :         OUString aEnvProperty( aSharePointMapping );
     672           0 :         aEnvProperty += m_aEnvPropertyName;
     673           0 :         Sequence< OUString > aEnvironmentVariable = GetNodeNames( aEnvProperty );
     674             : 
     675             :         // Filter the property which has a value set
     676           0 :         Sequence< OUString > aEnvUsedPropertySeq( aEnvironmentVariable.getLength() );
     677             : 
     678           0 :         OUString aEnvUsePropNameTemplate( aEnvProperty );
     679           0 :         aEnvUsePropNameTemplate += m_aLevelSep;
     680             : 
     681           0 :         for ( sal_Int32 nProperty = 0; nProperty < aEnvironmentVariable.getLength(); nProperty++ )
     682           0 :             aEnvUsedPropertySeq[nProperty] = aEnvUsePropNameTemplate + aEnvironmentVariable[nProperty];
     683             : 
     684           0 :         Sequence< Any > aEnvUsedValueSeq;
     685           0 :         aEnvUsedValueSeq = GetProperties( aEnvUsedPropertySeq );
     686             : 
     687           0 :         OUString aEnvUsedValue;
     688           0 :         for ( sal_Int32 nIndex = 0; nIndex < aEnvironmentVariable.getLength(); nIndex++ )
     689             :         {
     690           0 :             if ( aEnvUsedValueSeq[nIndex] >>= aEnvUsedValue )
     691             :             {
     692           0 :                 aEnvUsed = aEnvironmentVariable[nIndex];
     693           0 :                 break;
     694             :             }
     695             :         }
     696             : 
     697             :         // Decode the environment and optional the operatng system settings
     698           0 :         Any                             aEnvValue;
     699           0 :         EnvironmentType eEnvType = GetEnvTypeFromString( aEnvUsed );
     700           0 :         if ( eEnvType == ET_OS )
     701             :         {
     702           0 :             OperatingSystem eOSType = GetOperatingSystemFromString( aEnvUsedValue );
     703           0 :             aEnvValue <<= (sal_Int16)eOSType;
     704             :         }
     705             :         else
     706           0 :             aEnvValue <<= aEnvUsedValue;
     707             : 
     708             :         // Create rule struct and push it into the rule set
     709           0 :         SubstituteRule aRule( aSharePointName, aDirValue, aEnvValue, eEnvType );
     710           0 :         rRuleSet.push_back( aRule );
     711             : 
     712           0 :         ++nSharePointMapping;
     713           0 :     }
     714           0 : }
     715             : 
     716         210 : SubstitutePathVariables::SubstitutePathVariables( const Reference< XComponentContext >& xContext ) :
     717             :     SubstitutePathVariables_BASE(m_aMutex),
     718         210 :     m_xContext( xContext )
     719             : {
     720             :     int i;
     721             : 
     722         210 :     SetPredefinedPathVariables();
     723         210 :     m_aImpl.GetSharePointsRules( m_aSubstVarMap );
     724             : 
     725             :     // Init the predefined/fixed variable to index hash map
     726        4200 :     for ( i = 0; i < PREDEFVAR_COUNT; i++ )
     727             :     {
     728             :         // Store variable name into struct of predefined/fixed variables
     729        3990 :         m_aPreDefVars.m_FixedVarNames[i] = OUString::createFromAscii( aFixedVarTable[i].pVarName );
     730             : 
     731             :         // Create hash map entry
     732             :         m_aPreDefVarMap.insert( VarNameToIndexMap::value_type(
     733        3990 :             m_aPreDefVars.m_FixedVarNames[i], aFixedVarTable[i].nEnumValue ) );
     734             :     }
     735             : 
     736             :     // Sort predefined/fixed variable to path length
     737        4200 :     for ( i = 0; i < PREDEFVAR_COUNT; i++ )
     738             :     {
     739        3990 :         if (( i != PREDEFVAR_WORKDIRURL ) && ( i != PREDEFVAR_PATH ))
     740             :         {
     741             :             // Special path variables, don't include into automatic resubstituion search!
     742             :             // $(workdirurl) is not allowed to resubstitute! This variable is the value of path settings entry
     743             :             // and it could be possible that it will be resubstituted by itself!!
     744             :             // Example: WORK_PATH=c:\test, $(workdirurl)=WORK_PATH => WORK_PATH=$(workdirurl) and this cannot be substituted!
     745             :             ReSubstFixedVarOrder aFixedVar;
     746        3570 :             aFixedVar.eVariable       = aFixedVarTable[i].nEnumValue;
     747        3570 :             aFixedVar.nVarValueLength = m_aPreDefVars.m_FixedVar[(sal_Int32)aFixedVar.eVariable].getLength();
     748        3570 :             m_aReSubstFixedVarOrder.push_back( aFixedVar );
     749             :         }
     750             :     }
     751         210 :     m_aReSubstFixedVarOrder.sort();
     752             : 
     753             :     // Sort user variables to path length
     754         210 :     SubstituteVariables::const_iterator pIter;
     755         210 :     for ( pIter = m_aSubstVarMap.begin(); pIter != m_aSubstVarMap.end(); ++pIter )
     756             :     {
     757           0 :         ReSubstUserVarOrder aUserOrderVar;
     758           0 :         aUserOrderVar.aVarName = "$(" + pIter->second.aSubstVariable + ")";
     759           0 :         aUserOrderVar.nVarValueLength = pIter->second.aSubstVariable.getLength();
     760           0 :         m_aReSubstUserVarOrder.push_back( aUserOrderVar );
     761           0 :     }
     762         210 :     m_aReSubstUserVarOrder.sort();
     763         210 : }
     764             : 
     765         284 : SubstitutePathVariables::~SubstitutePathVariables()
     766             : {
     767         284 : }
     768             : 
     769             : // XStringSubstitution
     770       18427 : OUString SAL_CALL SubstitutePathVariables::substituteVariables( const OUString& aText, sal_Bool bSubstRequired )
     771             : throw ( NoSuchElementException, RuntimeException, std::exception )
     772             : {
     773       18427 :     osl::MutexGuard g(rBHelper.rMutex);
     774       18427 :     return impl_substituteVariable( aText, bSubstRequired );
     775             : }
     776             : 
     777          91 : OUString SAL_CALL SubstitutePathVariables::reSubstituteVariables( const OUString& aText )
     778             : throw ( RuntimeException, std::exception )
     779             : {
     780          91 :     osl::MutexGuard g(rBHelper.rMutex);
     781          91 :     return impl_reSubstituteVariables( aText );
     782             : }
     783             : 
     784           4 : OUString SAL_CALL SubstitutePathVariables::getSubstituteVariableValue( const OUString& aVariable )
     785             : throw ( NoSuchElementException, RuntimeException, std::exception )
     786             : {
     787           4 :     osl::MutexGuard g(rBHelper.rMutex);
     788           4 :     return impl_getSubstituteVariableValue( aVariable );
     789             : }
     790             : 
     791        1351 : OUString SubstitutePathVariables::ConvertOSLtoUCBURL( const OUString& aOSLCompliantURL ) const
     792             : {
     793        1351 :     OUString aResult;
     794        2702 :     OUString   aTemp;
     795             : 
     796        1351 :     osl::FileBase::getSystemPathFromFileURL( aOSLCompliantURL, aTemp );
     797        1351 :     utl::LocalFileHelper::ConvertPhysicalNameToURL( aTemp, aResult );
     798             : 
     799             :     // Not all OSL URL's can be mapped to UCB URL's!
     800        1351 :     if ( aResult.isEmpty() )
     801           0 :         return aOSLCompliantURL;
     802             :     else
     803        2702 :         return aResult;
     804             : }
     805             : 
     806         210 : OUString SubstitutePathVariables::GetWorkPath() const
     807             : {
     808         210 :     OUString aWorkPath;
     809         420 :     css::uno::Reference< css::container::XHierarchicalNameAccess > xPaths(officecfg::Office::Paths::Paths::get(m_xContext), css::uno::UNO_QUERY_THROW);
     810         210 :     if (!(xPaths->getByHierarchicalName("['Work']/WritePath") >>= aWorkPath))
     811             :         // fallback in case config layer does not return an useable work dir value.
     812           0 :         aWorkPath = GetWorkVariableValue();
     813             : 
     814         420 :     return aWorkPath;
     815             : }
     816             : 
     817         721 : OUString SubstitutePathVariables::GetWorkVariableValue() const
     818             : {
     819         721 :     OUString aWorkPath;
     820        1442 :     boost::optional<OUString> x(officecfg::Office::Paths::Variables::Work::get(m_xContext));
     821         721 :     if (!x)
     822             :     {
     823             :         // fallback to $HOME in case platform dependent config layer does not return
     824             :         // an usuable work dir value.
     825         721 :         osl::Security aSecurity;
     826         721 :         aSecurity.getHomeDir( aWorkPath );
     827             :     }
     828             :     else
     829           0 :         aWorkPath = x.get();
     830        1442 :     return ConvertOSLtoUCBURL( aWorkPath );
     831             : }
     832             : 
     833         210 : OUString SubstitutePathVariables::GetHomeVariableValue() const
     834             : {
     835         210 :     osl::Security   aSecurity;
     836         420 :     OUString   aHomePath;
     837             : 
     838         210 :     aSecurity.getHomeDir( aHomePath );
     839         420 :     return ConvertOSLtoUCBURL( aHomePath );
     840             : }
     841             : 
     842         210 : OUString SubstitutePathVariables::GetPathVariableValue() const
     843             : {
     844             : 
     845         210 :     OUString aRetStr;
     846         210 :     const char*   pEnv = getenv( "PATH" );
     847             : 
     848         210 :     if ( pEnv )
     849             :     {
     850         210 :         const int PATH_EXTEND_FACTOR = 120;
     851         210 :         OUString       aTmp;
     852         420 :         OUString       aPathList( pEnv, strlen( pEnv ), osl_getThreadTextEncoding() );
     853         420 :         OUStringBuffer aPathStrBuffer( aPathList.getLength() * PATH_EXTEND_FACTOR / 100 );
     854             : 
     855         210 :         bool      bAppendSep = false;
     856         210 :         sal_Int32 nToken = 0;
     857        1890 :         do
     858             :         {
     859        1890 :             OUString sToken = aPathList.getToken(0, SAL_PATHSEPARATOR, nToken);
     860        1890 :             if (!sToken.isEmpty())
     861             :             {
     862        1890 :                 osl::FileBase::getFileURLFromSystemPath( sToken, aTmp );
     863        1890 :                 if ( bAppendSep )
     864        1680 :                     aPathStrBuffer.appendAscii( ";" ); // Office uses ';' as path separator
     865        1890 :                 aPathStrBuffer.append( aTmp );
     866        1890 :                 bAppendSep = true;
     867        1890 :             }
     868             :         }
     869        1890 :         while(nToken>=0);
     870             : 
     871         420 :         aRetStr = aPathStrBuffer.makeStringAndClear();
     872             :     }
     873             : 
     874         210 :     return aRetStr;
     875             : }
     876             : 
     877       18427 : OUString SubstitutePathVariables::impl_substituteVariable( const OUString& rText, bool bSubstRequired )
     878             : throw ( NoSuchElementException, RuntimeException )
     879             : {
     880             :     // This is maximal recursive depth supported!
     881       18427 :     const sal_Int32 nMaxRecursiveDepth = 8;
     882             : 
     883       18427 :     OUString   aWorkText = rText;
     884       18427 :     OUString   aResult;
     885             : 
     886             :     // Use vector with strings to detect endless recursions!
     887       36854 :     std::vector< OUString > aEndlessRecursiveDetector;
     888             : 
     889             :     // Search for first occurrence of "$(...".
     890       18427 :     sal_Int32   nDepth = 0;
     891       18427 :     bool        bSubstitutionCompleted = false;
     892       18427 :     sal_Int32   nPosition = aWorkText.indexOf( "$(" );
     893       18427 :     sal_Int32   nLength = 0; // = count of letters from "$(" to ")" in string
     894       18427 :     bool        bVarNotSubstituted = false;
     895             : 
     896             :     // Have we found any variable like "$(...)"?
     897       18427 :     if ( nPosition != -1 )
     898             :     {
     899             :         // Yes; Get length of found variable.
     900             :         // If no ")" was found - nLength is set to 0 by default! see before.
     901       15865 :         sal_Int32 nEndPosition = aWorkText.indexOf( ')', nPosition );
     902       15865 :         if ( nEndPosition != -1 )
     903       15865 :             nLength = nEndPosition - nPosition + 1;
     904             :     }
     905             : 
     906             :     // Is there something to replace ?
     907       18427 :     bool bWorkRetrieved       = false;
     908       18427 :     bool bWorkDirURLRetrieved = false;
     909       37246 :     while ( !bSubstitutionCompleted && nDepth < nMaxRecursiveDepth )
     910             :     {
     911       54636 :         while ( ( nPosition != -1 ) && ( nLength > 3 ) ) // "$(" ")"
     912             :         {
     913             :             // YES; Get the next variable for replace.
     914       17096 :             sal_Int32     nReplaceLength  = 0;
     915       17096 :             OUString aReplacement;
     916       34192 :             OUString aSubString      = aWorkText.copy( nPosition, nLength );
     917       34192 :             OUString aSubVarString;
     918             : 
     919             :             // Path variables are not case sensitive!
     920       17096 :             aSubVarString = aSubString.toAsciiLowerCase();
     921       17096 :             VarNameToIndexMap::const_iterator pNTOIIter = m_aPreDefVarMap.find( aSubVarString );
     922       17096 :             if ( pNTOIIter != m_aPreDefVarMap.end() )
     923             :             {
     924             :                 // Fixed/Predefined variable found
     925       17088 :                 PreDefVariable nIndex = (PreDefVariable)pNTOIIter->second;
     926             : 
     927             :                 // Determine variable value and length from array/table
     928       17088 :                 if ( nIndex == PREDEFVAR_WORK && !bWorkRetrieved )
     929             :                 {
     930             :                     // Transient value, retrieve it again
     931         420 :                     m_aPreDefVars.m_FixedVar[ (PreDefVariable)nIndex ] = GetWorkVariableValue();
     932         420 :                     bWorkRetrieved = true;
     933             :                 }
     934       16668 :                 else if ( nIndex == PREDEFVAR_WORKDIRURL && !bWorkDirURLRetrieved )
     935             :                 {
     936             :                     // Transient value, retrieve it again
     937           0 :                     m_aPreDefVars.m_FixedVar[ (PreDefVariable)nIndex ] = GetWorkPath();
     938           0 :                     bWorkDirURLRetrieved = true;
     939             :                 }
     940             : 
     941             :                 // Check preconditions to substitue path variables.
     942             :                 // 1. A path variable can only be substituted if it follows a ';'!
     943             :                 // 2. It's located exactly at the start of the string being substituted!
     944       18312 :                 if (( aFixedVarTable[ int( nIndex ) ].bAbsPath && (( nPosition == 0 ) || (( nPosition > 0 ) && ( aWorkText[nPosition-1] == ';')))) ||
     945        1224 :             ( !aFixedVarTable[ int( nIndex ) ].bAbsPath ))
     946             :         {
     947       16704 :                     aReplacement = m_aPreDefVars.m_FixedVar[ (PreDefVariable)nIndex ];
     948       16704 :                     nReplaceLength = nLength;
     949             :                 }
     950             :             }
     951             :             else
     952             :             {
     953             :                 // Extract the variable name and try to find in the user defined variable set
     954           8 :                 OUString aVarName = aSubString.copy( 2, nLength-3 );
     955           8 :                 SubstituteVariables::const_iterator pIter = m_aSubstVarMap.find( aVarName );
     956           8 :                 if ( pIter != m_aSubstVarMap.end() )
     957             :                 {
     958             :                     // Found.
     959           0 :                     aReplacement = pIter->second.aSubstValue;
     960           0 :                     nReplaceLength = nLength;
     961           8 :                 }
     962             :             }
     963             : 
     964             :             // Have we found something to replace?
     965       17096 :             if ( nReplaceLength > 0 )
     966             :             {
     967             :                 // Yes ... then do it.
     968       16704 :                 aWorkText = aWorkText.replaceAt( nPosition, nReplaceLength, aReplacement );
     969             :             }
     970             :             else
     971             :             {
     972             :                 // Variable not known
     973         392 :                 bVarNotSubstituted = true;
     974         392 :                 nPosition += nLength;
     975             :             }
     976             : 
     977             :             // Step after replaced text! If no text was replaced (unknown variable!),
     978             :             // length of aReplacement is 0 ... and we don't step then.
     979       17096 :             nPosition += aReplacement.getLength();
     980             : 
     981             :             // We must control index in string before call something at OUString!
     982             :             // The OUString-implementation don't do it for us :-( but the result is not defined otherwise.
     983       17096 :             if ( nPosition + 1 > aWorkText.getLength() )
     984             :             {
     985             :                 // Position is out of range. Break loop!
     986        2221 :                 nPosition = -1;
     987        2221 :                 nLength = 0;
     988             :             }
     989             :             else
     990             :             {
     991             :                 // Else; Position is valid. Search for next variable to replace.
     992       14875 :                 nPosition = aWorkText.indexOf( "$(", nPosition );
     993             :                 // Have we found any variable like "$(...)"?
     994       14875 :                 if ( nPosition != -1 )
     995             :                 {
     996             :                     // Yes; Get length of found variable. If no ")" was found - nLength must set to 0!
     997         888 :                     nLength = 0;
     998         888 :                     sal_Int32 nEndPosition = aWorkText.indexOf( ')', nPosition );
     999         888 :                     if ( nEndPosition != -1 )
    1000         888 :                         nLength = nEndPosition - nPosition + 1;
    1001             :                 }
    1002             :             }
    1003       17096 :         }
    1004             : 
    1005       18770 :         nPosition = aWorkText.indexOf( "$(" );
    1006       18770 :         if ( nPosition == -1 )
    1007             :         {
    1008       18378 :             bSubstitutionCompleted = true;
    1009       18378 :             break; // All variables are substituted
    1010             :         }
    1011             :         else
    1012             :         {
    1013             :             // Check for recursion
    1014         392 :             const sal_uInt32 nCount = aEndlessRecursiveDetector.size();
    1015         392 :             for ( sal_uInt32 i=0; i < nCount; i++ )
    1016             :             {
    1017         343 :                 if ( aEndlessRecursiveDetector[i] == aWorkText )
    1018             :                 {
    1019         343 :                     if ( bVarNotSubstituted )
    1020         343 :                         break; // Not all variables could be substituted!
    1021             :                     else
    1022             :                     {
    1023           0 :                         nDepth = nMaxRecursiveDepth;
    1024           0 :                         break; // Recursion detected!
    1025             :                     }
    1026             :                 }
    1027             :             }
    1028             : 
    1029         392 :             aEndlessRecursiveDetector.push_back( aWorkText );
    1030             : 
    1031             :             // Initialize values for next
    1032         392 :             sal_Int32 nEndPosition = aWorkText.indexOf( ')', nPosition );
    1033         392 :             if ( nEndPosition != -1 )
    1034         392 :                 nLength = nEndPosition - nPosition + 1;
    1035         392 :             bVarNotSubstituted = false;
    1036         392 :             ++nDepth;
    1037             :         }
    1038             :     }
    1039             : 
    1040             :     // Fill return value with result
    1041       18427 :     if ( bSubstitutionCompleted )
    1042             :     {
    1043             :         // Substitution successful!
    1044       18378 :         aResult = aWorkText;
    1045             :     }
    1046             :     else
    1047             :     {
    1048             :         // Substitution not successful!
    1049          49 :         if ( nDepth == nMaxRecursiveDepth )
    1050             :         {
    1051             :             // recursion depth reached!
    1052          49 :             if ( bSubstRequired )
    1053             :             {
    1054           1 :                 OUString aMsg( "Endless recursion detected. Cannot substitute variables!" );
    1055           1 :                 throw NoSuchElementException( aMsg, static_cast<cppu::OWeakObject *>(this) );
    1056             :             }
    1057             :             else
    1058          48 :                 aResult = rText;
    1059             :         }
    1060             :         else
    1061             :         {
    1062             :             // variable in text but unknown!
    1063           0 :             if ( bSubstRequired )
    1064             :             {
    1065           0 :                 OUString aMsg( "Unknown variable found!" );
    1066           0 :                 throw NoSuchElementException( aMsg, static_cast<cppu::OWeakObject *>(this) );
    1067             :             }
    1068             :             else
    1069           0 :                 aResult = aWorkText;
    1070             :         }
    1071             :     }
    1072             : 
    1073       36853 :     return aResult;
    1074             : }
    1075             : 
    1076          91 : OUString SubstitutePathVariables::impl_reSubstituteVariables( const OUString& rURL )
    1077             : throw ( RuntimeException )
    1078             : {
    1079          91 :     OUString aURL;
    1080             : 
    1081         182 :     INetURLObject aUrl( rURL );
    1082          91 :     if ( !aUrl.HasError() )
    1083          91 :         aURL = aUrl.GetMainURL( INetURLObject::NO_DECODE );
    1084             :     else
    1085             :     {
    1086             :         // Convert a system path to a UCB compliant URL before resubstitution
    1087           0 :         OUString aTemp;
    1088           0 :         if ( osl::FileBase::getFileURLFromSystemPath( rURL, aTemp ) == osl::FileBase::E_None )
    1089             :         {
    1090           0 :             aTemp = ConvertOSLtoUCBURL( aTemp );
    1091           0 :             if ( !aTemp.isEmpty() )
    1092             :             {
    1093           0 :                 aURL = INetURLObject( aTemp ).GetMainURL( INetURLObject::NO_DECODE );
    1094           0 :                 if( aURL.isEmpty() )
    1095           0 :                     return rURL;
    1096             :             }
    1097             :             else
    1098           0 :                 return rURL;
    1099             :         }
    1100             :         else
    1101             :         {
    1102             :             // rURL is not a valid URL nor a osl system path. Give up and return error!
    1103           0 :             return rURL;
    1104           0 :         }
    1105             :     }
    1106             : 
    1107             :     // Get transient predefined path variable $(work) value before starting resubstitution
    1108          91 :     m_aPreDefVars.m_FixedVar[ PREDEFVAR_WORK ] = GetWorkVariableValue();
    1109             : 
    1110             :     for (;;)
    1111             :     {
    1112         271 :         bool bVariableFound = false;
    1113             : 
    1114        7344 :         for (ReSubstFixedVarOrderVector::const_iterator i(
    1115         271 :                  m_aReSubstFixedVarOrder.begin());
    1116        4896 :              i != m_aReSubstFixedVarOrder.end(); ++i)
    1117             :         {
    1118        2357 :             OUString aValue = m_aPreDefVars.m_FixedVar[i->eVariable];
    1119        2357 :             sal_Int32 nPos = aURL.indexOf( aValue );
    1120        2357 :             if ( nPos >= 0 )
    1121             :             {
    1122         180 :                 bool bMatch = true;
    1123         360 :                 if ( i->eVariable == PREDEFVAR_LANGID ||
    1124         180 :                      i->eVariable == PREDEFVAR_VLANG )
    1125             :                 {
    1126             :                     // Special path variables as they can occur in the middle of a path. Only match if they
    1127             :                     // describe a whole directory and not only a substring of a directory!
    1128           0 :                     const sal_Unicode* pStr = aURL.getStr();
    1129             : 
    1130           0 :                     if ( nPos > 0 )
    1131           0 :                         bMatch = ( aURL[ nPos-1 ] == '/' );
    1132             : 
    1133           0 :                     if ( bMatch )
    1134             :                     {
    1135           0 :                         if ( nPos + aValue.getLength() < aURL.getLength() )
    1136           0 :                             bMatch = ( pStr[ nPos + aValue.getLength() ] == '/' );
    1137             :                     }
    1138             :                 }
    1139             : 
    1140         180 :                 if ( bMatch )
    1141             :                 {
    1142         360 :                     aURL = aURL.replaceAt(
    1143             :                         nPos, aValue.getLength(),
    1144         360 :                         m_aPreDefVars.m_FixedVarNames[i->eVariable]);
    1145         180 :                     bVariableFound = true; // Resubstitution not finished yet!
    1146         180 :                     break;
    1147             :                 }
    1148             :             }
    1149        2177 :         }
    1150             : 
    1151             :         // This part can be iteratered more than one time as variables can contain variables again!
    1152         813 :         for (ReSubstUserVarOrderVector::const_iterator i(
    1153         271 :                  m_aReSubstUserVarOrder.begin());
    1154         542 :              i != m_aReSubstUserVarOrder.end(); ++i)
    1155             :         {
    1156           0 :             OUString aVarValue = i->aVarName;
    1157           0 :             sal_Int32 nPos = aURL.indexOf( aVarValue );
    1158           0 :             if ( nPos >= 0 )
    1159             :             {
    1160           0 :                 aURL = aURL.replaceAt(
    1161           0 :                     nPos, aVarValue.getLength(), "$(" + aVarValue + ")");
    1162           0 :                 bVariableFound = true;  // Resubstitution not finished yet!
    1163             :             }
    1164           0 :         }
    1165             : 
    1166         271 :         if ( !bVariableFound )
    1167             :         {
    1168          91 :             return aURL;
    1169             :         }
    1170         271 :     }
    1171             : }
    1172             : 
    1173             : // This method support both request schemes "$("<varname>")" or "<varname>".
    1174           4 : OUString SubstitutePathVariables::impl_getSubstituteVariableValue( const OUString& rVariable )
    1175             : throw ( NoSuchElementException, RuntimeException )
    1176             : {
    1177           4 :     OUString aVariable;
    1178             : 
    1179           4 :     sal_Int32 nPos = rVariable.indexOf( "$(" );
    1180           4 :     if ( nPos == -1 )
    1181             :     {
    1182             :         // Prepare variable name before hash map access
    1183           0 :         aVariable = "$(" + rVariable + ")";
    1184             :     }
    1185             : 
    1186           4 :     VarNameToIndexMap::const_iterator pNTOIIter = m_aPreDefVarMap.find( ( nPos == -1 ) ? aVariable : rVariable );
    1187             : 
    1188             :     // Fixed/Predefined variable
    1189           4 :     if ( pNTOIIter != m_aPreDefVarMap.end() )
    1190             :     {
    1191           3 :         PreDefVariable nIndex = (PreDefVariable)pNTOIIter->second;
    1192           3 :         return m_aPreDefVars.m_FixedVar[(sal_Int32)nIndex];
    1193             :     }
    1194             :     else
    1195             :     {
    1196             :         // Prepare variable name before hash map access
    1197           1 :         if ( nPos >= 0 )
    1198             :         {
    1199           1 :             if ( rVariable.getLength() > 3 )
    1200           1 :                 aVariable = rVariable.copy( 2, rVariable.getLength() - 3 );
    1201             :             else
    1202             :             {
    1203           0 :                 OUString aExceptionText("Unknown variable!");
    1204           0 :                 throw NoSuchElementException(aExceptionText, static_cast<cppu::OWeakObject *>(this));
    1205             :             }
    1206             :         }
    1207             :         else
    1208           0 :             aVariable = rVariable;
    1209             : 
    1210             :         // User defined variable
    1211           1 :         SubstituteVariables::const_iterator pIter = m_aSubstVarMap.find( aVariable );
    1212           1 :         if ( pIter != m_aSubstVarMap.end() )
    1213             :         {
    1214             :             // found!
    1215           0 :             return pIter->second.aSubstValue;
    1216             :         }
    1217             : 
    1218           1 :         OUString aExceptionText("Unknown variable!");
    1219           1 :         throw NoSuchElementException(aExceptionText, static_cast<cppu::OWeakObject *>(this));
    1220           4 :     }
    1221             : }
    1222             : 
    1223         210 : void SubstitutePathVariables::SetPredefinedPathVariables()
    1224             : {
    1225             : 
    1226         210 :     m_aPreDefVars.m_FixedVar[PREDEFVAR_BRANDBASEURL] = "$BRAND_BASE_DIR";
    1227             :     rtl::Bootstrap::expandMacros(
    1228         210 :         m_aPreDefVars.m_FixedVar[PREDEFVAR_BRANDBASEURL]);
    1229             : 
    1230             :     // Get inspath and userpath from bootstrap mechanism in every case as file URL
    1231             :     ::utl::Bootstrap::PathStatus aState;
    1232         210 :     OUString              sVal;
    1233             : 
    1234         210 :     aState = utl::Bootstrap::locateUserData( sVal );
    1235             :     //There can be the valid case that there is no user installation.
    1236             :     //TODO: Is that still the case? (With OOo 3.4, "unopkg sync" was run as part
    1237             :     // of the setup. Then no user installation was required.)
    1238             :     //Therefore we do not assert here.
    1239             :     // It's not possible to detect when an empty value would actually be used.
    1240             :     // (note: getenv is a hack to detect if we're running in a unit test)
    1241         210 :     if (aState == ::utl::Bootstrap::PATH_EXISTS || getenv("SRC_ROOT")) {
    1242         210 :         m_aPreDefVars.m_FixedVar[ PREDEFVAR_USERPATH ] = ConvertOSLtoUCBURL( sVal );
    1243             :     }
    1244             : 
    1245             :     // Set $(inst), $(instpath), $(insturl)
    1246         210 :     m_aPreDefVars.m_FixedVar[ PREDEFVAR_INSTPATH ] = m_aPreDefVars.m_FixedVar[PREDEFVAR_BRANDBASEURL];
    1247         210 :     m_aPreDefVars.m_FixedVar[ PREDEFVAR_INSTURL ]    = m_aPreDefVars.m_FixedVar[ PREDEFVAR_INSTPATH ];
    1248         210 :     m_aPreDefVars.m_FixedVar[ PREDEFVAR_INST ]       = m_aPreDefVars.m_FixedVar[ PREDEFVAR_INSTPATH ];
    1249             :     // New variable of hierarchy service (#i32656#)
    1250         210 :     m_aPreDefVars.m_FixedVar[ PREDEFVAR_BASEINSTURL ]= m_aPreDefVars.m_FixedVar[ PREDEFVAR_INSTPATH ];
    1251             : 
    1252             :     // Set $(user), $(userpath), $(userurl)
    1253         210 :     m_aPreDefVars.m_FixedVar[ PREDEFVAR_USERURL ]    = m_aPreDefVars.m_FixedVar[ PREDEFVAR_USERPATH ];
    1254         210 :     m_aPreDefVars.m_FixedVar[ PREDEFVAR_USER ]       = m_aPreDefVars.m_FixedVar[ PREDEFVAR_USERPATH ];
    1255             :     // New variable of hierarchy service (#i32656#)
    1256         210 :     m_aPreDefVars.m_FixedVar[ PREDEFVAR_USERDATAURL ]= m_aPreDefVars.m_FixedVar[ PREDEFVAR_USERPATH ];
    1257             : 
    1258             :     // Detect the program directory
    1259             :     // Set $(prog), $(progpath), $(progurl)
    1260             :     INetURLObject aProgObj(
    1261         420 :         m_aPreDefVars.m_FixedVar[PREDEFVAR_BRANDBASEURL] );
    1262         210 :     if ( !aProgObj.HasError() && aProgObj.insertName( OUString(LIBO_BIN_FOLDER) ) )
    1263             :     {
    1264         210 :         m_aPreDefVars.m_FixedVar[ PREDEFVAR_PROGPATH ] = aProgObj.GetMainURL(INetURLObject::NO_DECODE);
    1265         210 :         m_aPreDefVars.m_FixedVar[ PREDEFVAR_PROGURL ]  = m_aPreDefVars.m_FixedVar[ PREDEFVAR_PROGPATH ];
    1266         210 :         m_aPreDefVars.m_FixedVar[ PREDEFVAR_PROG ]     = m_aPreDefVars.m_FixedVar[ PREDEFVAR_PROGPATH ];
    1267             :     }
    1268             : 
    1269             :     // Detect the language type of the current office
    1270         210 :     m_aPreDefVars.m_eLanguageType = LANGUAGE_ENGLISH_US;
    1271         420 :     OUString aLocaleStr( utl::ConfigManager::getLocale() );
    1272         210 :     m_aPreDefVars.m_eLanguageType = LanguageTag::convertToLanguageTypeWithFallback( aLocaleStr );
    1273             :     // We used to have an else branch here with a SAL_WARN, but that
    1274             :     // always fired in some unit tests when this code was built with
    1275             :     // debug=t, so it seems fairly pointless, especially as
    1276             :     // m_aPreDefVars.m_eLanguageType has been initialized to a
    1277             :     // default value above anyway.
    1278             : 
    1279             :     // Set $(vlang)
    1280         210 :     m_aPreDefVars.m_FixedVar[ PREDEFVAR_VLANG ] = aLocaleStr;
    1281             : 
    1282             :     // Set $(langid)
    1283         210 :     m_aPreDefVars.m_FixedVar[ PREDEFVAR_LANGID ] = OUString::number( m_aPreDefVars.m_eLanguageType );
    1284             : 
    1285             :     // Set the other pre defined path variables
    1286             :     // Set $(work)
    1287         210 :     m_aPreDefVars.m_FixedVar[ PREDEFVAR_WORK ] = GetWorkVariableValue();
    1288         210 :     m_aPreDefVars.m_FixedVar[ PREDEFVAR_HOME ] = GetHomeVariableValue();
    1289             : 
    1290             :     // Set $(workdirurl) this is the value of the path PATH_WORK which doesn't make sense
    1291             :     // anymore because the path settings service has this value! It can deliver this value more
    1292             :     // quickly than the substitution service!
    1293         210 :     m_aPreDefVars.m_FixedVar[ PREDEFVAR_WORKDIRURL ] = GetWorkPath();
    1294             : 
    1295             :     // Set $(path) variable
    1296         210 :     m_aPreDefVars.m_FixedVar[ PREDEFVAR_PATH ] = GetPathVariableValue();
    1297             : 
    1298             :     // Set $(temp)
    1299         420 :     OUString aTmp;
    1300         210 :     osl::FileBase::getTempDirURL( aTmp );
    1301         420 :     m_aPreDefVars.m_FixedVar[ PREDEFVAR_TEMP ] = ConvertOSLtoUCBURL( aTmp );
    1302         210 : }
    1303             : 
    1304         210 : struct Instance {
    1305         210 :     explicit Instance(
    1306             :         css::uno::Reference<css::uno::XComponentContext> const & context):
    1307             :         instance(
    1308         210 :             static_cast<cppu::OWeakObject *>(new SubstitutePathVariables(context)))
    1309             :     {
    1310         210 :     }
    1311             : 
    1312             :     css::uno::Reference<css::uno::XInterface> instance;
    1313             : };
    1314             : 
    1315             : struct Singleton:
    1316             :     public rtl::StaticWithArg<
    1317             :         Instance, css::uno::Reference<css::uno::XComponentContext>, Singleton>
    1318             : {};
    1319             : 
    1320             : }
    1321             : 
    1322             : extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface * SAL_CALL
    1323        6921 : com_sun_star_comp_framework_PathSubstitution_get_implementation(
    1324             :     css::uno::XComponentContext *context,
    1325             :     css::uno::Sequence<css::uno::Any> const &)
    1326             : {
    1327             :     return cppu::acquire(static_cast<cppu::OWeakObject *>(
    1328        6921 :                 Singleton::get(context).instance.get()));
    1329             : }
    1330             : 
    1331             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.11