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

Generated by: LCOV version 1.10