1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: configpathes.cxx,v $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_unotools.hxx"
34 #include "unotools/configpathes.hxx"
35 #include <rtl/ustring.hxx>
36 #include <rtl/ustrbuf.hxx>
37 #include <osl/diagnose.h>
39 //----------------------------------------------------------------------------
42 //----------------------------------------------------------------------------
44 using ::rtl::OUString
;
45 using ::rtl::OUStringBuffer
;
47 //----------------------------------------------------------------------------
50 void lcl_resolveCharEntities(OUString
& aLocalString
)
52 sal_Int32 nEscapePos
=aLocalString
.indexOf('&');
53 if (nEscapePos
< 0) return;
55 OUStringBuffer aResult
;
61 if (aLocalString
.matchAsciiL(RTL_CONSTASCII_STRINGPARAM("&"),nEscapePos
))
64 else if (aLocalString
.matchAsciiL(RTL_CONSTASCII_STRINGPARAM("'"),nEscapePos
))
67 else if (aLocalString
.matchAsciiL(RTL_CONSTASCII_STRINGPARAM("""),nEscapePos
))
70 OSL_ENSURE(ch
,"Configuration path contains '&' that is not part of a valid character escape");
73 aResult
.append(aLocalString
.copy(nStart
,nEscapePos
-nStart
)).append(ch
);
75 sal_Int32 nEscapeEnd
=aLocalString
.indexOf(';',nEscapePos
);
76 nStart
= nEscapeEnd
+1;
77 nEscapePos
=aLocalString
.indexOf('&',nStart
);
81 nEscapePos
=aLocalString
.indexOf('&',nEscapePos
+1);
84 while ( nEscapePos
> 0);
86 aResult
.append(aLocalString
.copy(nStart
));
88 aLocalString
= aResult
.makeStringAndClear();
91 //----------------------------------------------------------------------------
92 sal_Bool
splitLastFromConfigurationPath(OUString
const& _sInPath
,
94 OUString
& _rsLocalName
)
96 sal_Int32 nStart
,nEnd
;
98 sal_Int32 nPos
= _sInPath
.getLength()-1;
100 // strip trailing slash
101 if (nPos
> 0 && _sInPath
[ nPos
] == sal_Unicode('/'))
103 OSL_ENSURE(false, "Invalid config path: trailing '/' is not allowed");
107 // check for predicate ['xxx'] or ["yyy"]
108 if (nPos
> 0 && _sInPath
[ nPos
] == sal_Unicode(']'))
110 sal_Unicode chQuote
= _sInPath
[--nPos
];
112 if (chQuote
== '\'' || chQuote
== '\"')
115 nPos
= _sInPath
.lastIndexOf(chQuote
,nEnd
);
117 --nPos
; // nPos = rInPath.lastIndexOf('[',nPos);
122 nPos
= _sInPath
.lastIndexOf('[',nEnd
);
126 OSL_ENSURE(nPos
>= 0 && _sInPath
[nPos
] == '[', "Invalid config path: unmatched quotes or brackets");
127 if (nPos
>= 0 && _sInPath
[nPos
] == '[')
129 nPos
= _sInPath
.lastIndexOf('/',nPos
);
131 else // defined behavior for invalid pathes
133 nStart
= 0, nEnd
= _sInPath
.getLength();
141 nPos
= _sInPath
.lastIndexOf('/',nEnd
);
144 OSL_ASSERT( -1 <= nPos
&&
147 nEnd
<= _sInPath
.getLength() );
149 OSL_ASSERT(nPos
== -1 || _sInPath
[nPos
] == '/');
150 OSL_ENSURE(nPos
!= 0 , "Invalid config child path: immediate child of root");
152 _rsLocalName
= _sInPath
.copy(nStart
, nEnd
-nStart
);
153 _rsOutPath
= (nPos
> 0) ? _sInPath
.copy(0,nPos
) : OUString();
154 lcl_resolveCharEntities(_rsLocalName
);
159 //----------------------------------------------------------------------------
160 OUString
extractFirstFromConfigurationPath(OUString
const& _sInPath
)
162 sal_Int32 nSep
= _sInPath
.indexOf('/');
163 sal_Int32 nBracket
= _sInPath
.indexOf('[');
165 sal_Int32 nStart
= nBracket
+ 1;
166 sal_Int32 nEnd
= nSep
;
168 if (0 <= nBracket
) // found a bracket-quoted relative path
170 if (nSep
< 0 || nBracket
< nSep
) // and the separator comes after it
172 sal_Unicode chQuote
= _sInPath
[nStart
];
173 if (chQuote
== '\'' || chQuote
== '\"')
176 nEnd
= _sInPath
.indexOf(chQuote
, nStart
+1);
181 nEnd
= _sInPath
.indexOf(']',nStart
);
184 OSL_ENSURE(nEnd
> nStart
&& _sInPath
[nBracket
] == ']', "Invalid config path: improper mismatch of quote or bracket");
185 OSL_DEBUG_ONLY(nSep
= nBracket
+1);
186 OSL_ENSURE(nSep
== _sInPath
.getLength() || _sInPath
[nSep
] == '/', "Invalid config path: brackets not followed by slash");
188 else // ... but our initial element name is in simple form
192 OUString sResult
= (nEnd
>= 0) ? _sInPath
.copy(nStart
, nEnd
-nStart
) : _sInPath
;
193 lcl_resolveCharEntities(sResult
);
197 //----------------------------------------------------------------------------
199 // find the position after the prefix in the nested path
201 sal_Int32
lcl_findPrefixEnd(OUString
const& _sNestedPath
, OUString
const& _sPrefixPath
)
203 // TODO: currently handles only exact prefix matches
204 sal_Int32 nPrefixLength
= _sPrefixPath
.getLength();
206 OSL_ENSURE(nPrefixLength
== 0 || _sPrefixPath
[nPrefixLength
-1] != '/',
207 "Cannot handle slash-terminated prefix pathes");
210 if (_sNestedPath
.getLength() > nPrefixLength
)
212 bIsPrefix
= _sNestedPath
[nPrefixLength
] == '/' &&
213 _sNestedPath
.compareTo(_sPrefixPath
,nPrefixLength
) == 0;
216 else if (_sNestedPath
.getLength() == nPrefixLength
)
218 bIsPrefix
= _sNestedPath
.equals(_sPrefixPath
);
225 return bIsPrefix
? nPrefixLength
: 0;
228 //----------------------------------------------------------------------------
229 sal_Bool
isPrefixOfConfigurationPath(OUString
const& _sNestedPath
,
230 OUString
const& _sPrefixPath
)
232 return _sPrefixPath
.getLength() == 0 || lcl_findPrefixEnd(_sNestedPath
,_sPrefixPath
) != 0;
235 //----------------------------------------------------------------------------
236 OUString
dropPrefixFromConfigurationPath(OUString
const& _sNestedPath
,
237 OUString
const& _sPrefixPath
)
239 if ( sal_Int32 nPrefixEnd
= lcl_findPrefixEnd(_sNestedPath
,_sPrefixPath
) )
241 return _sNestedPath
.copy(nPrefixEnd
);
245 OSL_ENSURE(_sPrefixPath
.getLength() == 0, "Path does not start with expected prefix");
251 //----------------------------------------------------------------------------
253 OUString
lcl_wrapName(const OUString
& _sContent
, const OUString
& _sType
)
255 const sal_Unicode
* const pBeginContent
= _sContent
.getStr();
256 const sal_Unicode
* const pEndContent
= pBeginContent
+ _sContent
.getLength();
258 OSL_PRECOND(_sType
.getLength(), "Unexpected config type name: empty");
259 OSL_PRECOND(pBeginContent
<= pEndContent
, "Invalid config name: empty");
261 if (pBeginContent
== pEndContent
)
264 rtl::OUStringBuffer
aNormalized(_sType
.getLength() + _sContent
.getLength() + 4); // reserve approximate size initially
266 // prefix: type, opening bracket and quote
267 aNormalized
.append( _sType
).appendAscii( RTL_CONSTASCII_STRINGPARAM("['") );
269 // content: copy over each char and handle escaping
270 for(const sal_Unicode
* pCur
= pBeginContent
; pCur
!= pEndContent
; ++pCur
)
272 // append (escape if needed)
275 case sal_Unicode('&') : aNormalized
.appendAscii( RTL_CONSTASCII_STRINGPARAM("&") ); break;
276 case sal_Unicode('\''): aNormalized
.appendAscii( RTL_CONSTASCII_STRINGPARAM("'") ); break;
277 case sal_Unicode('\"'): aNormalized
.appendAscii( RTL_CONSTASCII_STRINGPARAM(""") ); break;
279 default: aNormalized
.append( *pCur
);
283 // suffix: closing quote and bracket
284 aNormalized
.appendAscii( RTL_CONSTASCII_STRINGPARAM("']") );
286 return aNormalized
.makeStringAndClear();
289 //----------------------------------------------------------------------------
291 OUString
wrapConfigurationElementName(OUString
const& _sElementName
)
293 return lcl_wrapName(_sElementName
, OUString(RTL_CONSTASCII_USTRINGPARAM("*")) );
296 //----------------------------------------------------------------------------
298 OUString
wrapConfigurationElementName(OUString
const& _sElementName
,
299 OUString
const& _sTypeName
)
301 // todo: check that _sTypeName is valid
302 return lcl_wrapName(_sElementName
, _sTypeName
);
305 //----------------------------------------------------------------------------