2010-10-14 08:27:31 +02:00
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2012-07-11 09:51:50 +01:00
/*
* This file is part of the LibreOffice project .
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License , v . 2.0 . If a copy of the MPL was not distributed with this
* file , You can obtain one at http : //mozilla.org/MPL/2.0/.
*
* This file incorporates work covered by the following license notice :
*
* Licensed to the Apache Software Foundation ( ASF ) under one or more
* contributor license agreements . See the NOTICE file distributed
* with this work for additional information regarding copyright
* ownership . The ASF licenses this file to you under the Apache
* License , Version 2.0 ( the " License " ) ; you may not use this file
* except in compliance with the License . You may obtain a copy of
* the License at http : //www.apache.org/licenses/LICENSE-2.0 .
*/
2001-07-10 10:13:39 +00:00
2014-05-10 18:12:32 +02:00
# include <unotools/configpaths.hxx>
2001-07-10 10:13:39 +00:00
# include <rtl/ustring.hxx>
# include <rtl/ustrbuf.hxx>
# include <osl/diagnose.h>
namespace utl
{
2004-04-29 15:57:31 +00:00
static
void lcl_resolveCharEntities ( OUString & aLocalString )
{
sal_Int32 nEscapePos = aLocalString . indexOf ( ' & ' ) ;
if ( nEscapePos < 0 ) return ;
OUStringBuffer aResult ;
sal_Int32 nStart = 0 ;
do
{
sal_Unicode ch = 0 ;
2013-03-10 20:44:01 +01:00
if ( aLocalString . match ( " & " , nEscapePos ) )
2004-04-29 15:57:31 +00:00
ch = ' & ' ;
2013-03-10 20:44:01 +01:00
else if ( aLocalString . match ( " ' " , nEscapePos ) )
2004-04-29 15:57:31 +00:00
ch = ' \' ' ;
2013-03-10 20:44:01 +01:00
else if ( aLocalString . match ( " " " , nEscapePos ) )
2004-04-29 15:57:31 +00:00
ch = ' " ' ;
OSL_ENSURE ( ch , " Configuration path contains '&' that is not part of a valid character escape " ) ;
if ( ch )
{
aResult . append ( aLocalString . copy ( nStart , nEscapePos - nStart ) ) . append ( ch ) ;
sal_Int32 nEscapeEnd = aLocalString . indexOf ( ' ; ' , nEscapePos ) ;
nStart = nEscapeEnd + 1 ;
nEscapePos = aLocalString . indexOf ( ' & ' , nStart ) ;
}
else
{
nEscapePos = aLocalString . indexOf ( ' & ' , nEscapePos + 1 ) ;
}
}
while ( nEscapePos > 0 ) ;
aResult . append ( aLocalString . copy ( nStart ) ) ;
aLocalString = aResult . makeStringAndClear ( ) ;
}
2014-02-19 12:30:34 +01:00
bool splitLastFromConfigurationPath ( OUString const & _sInPath ,
2001-07-10 10:13:39 +00:00
OUString & _rsOutPath ,
OUString & _rsLocalName )
{
sal_Int32 nStart , nEnd ;
sal_Int32 nPos = _sInPath . getLength ( ) - 1 ;
// strip trailing slash
2013-11-14 08:16:35 +02:00
if ( nPos > 0 & & _sInPath [ nPos ] = = ' / ' )
2001-07-10 10:13:39 +00:00
{
2011-03-12 11:47:36 +01:00
OSL_FAIL ( " Invalid config path: trailing '/' is not allowed " ) ;
2001-07-10 10:13:39 +00:00
- - nPos ;
}
// check for predicate ['xxx'] or ["yyy"]
2013-11-14 08:16:35 +02:00
if ( nPos > 0 & & _sInPath [ nPos ] = = ' ] ' )
2001-07-10 10:13:39 +00:00
{
sal_Unicode chQuote = _sInPath [ - - nPos ] ;
if ( chQuote = = ' \' ' | | chQuote = = ' \" ' )
{
nEnd = nPos ;
nPos = _sInPath . lastIndexOf ( chQuote , nEnd ) ;
nStart = nPos + 1 ;
- - nPos ; // nPos = rInPath.lastIndexOf('[',nPos);
}
else // allow [xxx]
{
nEnd = nPos + 1 ;
nPos = _sInPath . lastIndexOf ( ' [ ' , nEnd ) ;
nStart = nPos + 1 ;
}
OSL_ENSURE ( nPos > = 0 & & _sInPath [ nPos ] = = ' [ ' , " Invalid config path: unmatched quotes or brackets " ) ;
if ( nPos > = 0 & & _sInPath [ nPos ] = = ' [ ' )
{
nPos = _sInPath . lastIndexOf ( ' / ' , nPos ) ;
}
2012-02-01 14:42:58 +01:00
else // defined behavior for invalid paths
2001-07-10 10:13:39 +00:00
{
nStart = 0 , nEnd = _sInPath . getLength ( ) ;
nPos = - 1 ;
}
}
else
{
nEnd = nPos + 1 ;
nPos = _sInPath . lastIndexOf ( ' / ' , nEnd ) ;
nStart = nPos + 1 ;
}
OSL_ASSERT ( - 1 < = nPos & &
nPos < nStart & &
nStart < nEnd & &
nEnd < = _sInPath . getLength ( ) ) ;
OSL_ASSERT ( nPos = = - 1 | | _sInPath [ nPos ] = = ' / ' ) ;
OSL_ENSURE ( nPos ! = 0 , " Invalid config child path: immediate child of root " ) ;
_rsLocalName = _sInPath . copy ( nStart , nEnd - nStart ) ;
_rsOutPath = ( nPos > 0 ) ? _sInPath . copy ( 0 , nPos ) : OUString ( ) ;
2004-04-29 15:57:31 +00:00
lcl_resolveCharEntities ( _rsLocalName ) ;
2001-07-10 10:13:39 +00:00
return nPos > = 0 ;
}
2010-07-27 18:11:00 +02:00
OUString extractFirstFromConfigurationPath ( OUString const & _sInPath , OUString * _sOutPath )
2001-07-10 10:13:39 +00:00
{
sal_Int32 nSep = _sInPath . indexOf ( ' / ' ) ;
sal_Int32 nBracket = _sInPath . indexOf ( ' [ ' ) ;
sal_Int32 nStart = nBracket + 1 ;
sal_Int32 nEnd = nSep ;
if ( 0 < = nBracket ) // found a bracket-quoted relative path
{
if ( nSep < 0 | | nBracket < nSep ) // and the separator comes after it
{
sal_Unicode chQuote = _sInPath [ nStart ] ;
if ( chQuote = = ' \' ' | | chQuote = = ' \" ' )
{
+ + nStart ;
nEnd = _sInPath . indexOf ( chQuote , nStart + 1 ) ;
nBracket = nEnd + 1 ;
}
else
{
nEnd = _sInPath . indexOf ( ' ] ' , nStart ) ;
nBracket = nEnd ;
}
OSL_ENSURE ( nEnd > nStart & & _sInPath [ nBracket ] = = ' ] ' , " Invalid config path: improper mismatch of quote or bracket " ) ;
2010-07-27 18:11:00 +02:00
OSL_ENSURE ( ( nBracket + 1 = = _sInPath . getLength ( ) & & nSep = = - 1 ) | | ( _sInPath [ nBracket + 1 ] = = ' / ' & & nSep = = nBracket + 1 ) , " Invalid config path: brackets not followed by slash " ) ;
2001-07-10 10:13:39 +00:00
}
else // ... but our initial element name is in simple form
nStart = 0 ;
}
OUString sResult = ( nEnd > = 0 ) ? _sInPath . copy ( nStart , nEnd - nStart ) : _sInPath ;
2004-04-29 15:57:31 +00:00
lcl_resolveCharEntities ( sResult ) ;
2010-07-27 18:11:00 +02:00
if ( _sOutPath ! = 0 )
{
* _sOutPath = ( nSep > = 0 ) ? _sInPath . copy ( nSep + 1 ) : OUString ( ) ;
}
2001-07-10 10:13:39 +00:00
return sResult ;
}
// find the position after the prefix in the nested path
static inline
sal_Int32 lcl_findPrefixEnd ( OUString const & _sNestedPath , OUString const & _sPrefixPath )
{
// TODO: currently handles only exact prefix matches
sal_Int32 nPrefixLength = _sPrefixPath . getLength ( ) ;
OSL_ENSURE ( nPrefixLength = = 0 | | _sPrefixPath [ nPrefixLength - 1 ] ! = ' / ' ,
2012-02-01 14:42:58 +01:00
" Cannot handle slash-terminated prefix paths " ) ;
2001-07-10 10:13:39 +00:00
2014-02-19 12:30:34 +01:00
bool bIsPrefix ;
2001-07-10 10:13:39 +00:00
if ( _sNestedPath . getLength ( ) > nPrefixLength )
{
bIsPrefix = _sNestedPath [ nPrefixLength ] = = ' / ' & &
2014-06-04 11:43:58 +02:00
_sNestedPath . startsWith ( _sPrefixPath ) ;
2001-07-10 10:13:39 +00:00
+ + nPrefixLength ;
}
else if ( _sNestedPath . getLength ( ) = = nPrefixLength )
{
bIsPrefix = _sNestedPath . equals ( _sPrefixPath ) ;
}
else
{
bIsPrefix = false ;
}
return bIsPrefix ? nPrefixLength : 0 ;
}
2014-02-19 12:30:34 +01:00
bool isPrefixOfConfigurationPath ( OUString const & _sNestedPath ,
2001-07-10 10:13:39 +00:00
OUString const & _sPrefixPath )
{
2012-01-19 16:01:33 -02:00
return _sPrefixPath . isEmpty ( ) | | lcl_findPrefixEnd ( _sNestedPath , _sPrefixPath ) ! = 0 ;
2001-07-10 10:13:39 +00:00
}
OUString dropPrefixFromConfigurationPath ( OUString const & _sNestedPath ,
OUString const & _sPrefixPath )
{
if ( sal_Int32 nPrefixEnd = lcl_findPrefixEnd ( _sNestedPath , _sPrefixPath ) )
{
return _sNestedPath . copy ( nPrefixEnd ) ;
}
else
{
2012-01-19 16:01:33 -02:00
OSL_ENSURE ( _sPrefixPath . isEmpty ( ) , " Path does not start with expected prefix " ) ;
2001-07-10 10:13:39 +00:00
return _sNestedPath ;
}
}
static
OUString lcl_wrapName ( const OUString & _sContent , const OUString & _sType )
{
const sal_Unicode * const pBeginContent = _sContent . getStr ( ) ;
const sal_Unicode * const pEndContent = pBeginContent + _sContent . getLength ( ) ;
2012-01-19 16:01:33 -02:00
OSL_PRECOND ( ! _sType . isEmpty ( ) , " Unexpected config type name: empty " ) ;
2001-07-10 10:13:39 +00:00
OSL_PRECOND ( pBeginContent < = pEndContent , " Invalid config name: empty " ) ;
if ( pBeginContent = = pEndContent )
return _sType ;
2013-04-07 12:06:47 +02:00
OUStringBuffer aNormalized ( _sType . getLength ( ) + _sContent . getLength ( ) + 4 ) ; // reserve approximate size initially
2001-07-10 10:13:39 +00:00
// prefix: type, opening bracket and quote
2013-03-10 20:44:01 +01:00
aNormalized . append ( _sType ) . append ( " [' " ) ;
2001-07-10 10:13:39 +00:00
// content: copy over each char and handle escaping
for ( const sal_Unicode * pCur = pBeginContent ; pCur ! = pEndContent ; + + pCur )
{
// append (escape if needed)
switch ( * pCur )
{
2013-03-10 20:44:01 +01:00
case sal_Unicode ( ' & ' ) : aNormalized . append ( " & ; " ); break;
case sal_Unicode ( ' \' ' ) : aNormalized . append ( " &apos ; " ); break;
case sal_Unicode ( ' \" ' ) : aNormalized . append ( " " ; " ); break;
2001-07-10 10:13:39 +00:00
default : aNormalized . append ( * pCur ) ;
}
}
// suffix: closing quote and bracket
2013-03-10 20:44:01 +01:00
aNormalized . append ( " '] " ) ;
2001-07-10 10:13:39 +00:00
return aNormalized . makeStringAndClear ( ) ;
}
OUString wrapConfigurationElementName ( OUString const & _sElementName )
{
2013-03-10 20:44:01 +01:00
return lcl_wrapName ( _sElementName , " * " ) ;
2001-07-10 10:13:39 +00:00
}
OUString wrapConfigurationElementName ( OUString const & _sElementName ,
OUString const & _sTypeName )
{
// todo: check that _sTypeName is valid
return lcl_wrapName ( _sElementName , _sTypeName ) ;
}
} // namespace utl
2010-10-14 08:27:31 +02:00
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */