1*b5088357SAndrew Rist /**************************************************************
2cdf0e10cSrcweir *
3*b5088357SAndrew Rist * Licensed to the Apache Software Foundation (ASF) under one
4*b5088357SAndrew Rist * or more contributor license agreements. See the NOTICE file
5*b5088357SAndrew Rist * distributed with this work for additional information
6*b5088357SAndrew Rist * regarding copyright ownership. The ASF licenses this file
7*b5088357SAndrew Rist * to you under the Apache License, Version 2.0 (the
8*b5088357SAndrew Rist * "License"); you may not use this file except in compliance
9*b5088357SAndrew Rist * with the License. You may obtain a copy of the License at
10*b5088357SAndrew Rist *
11*b5088357SAndrew Rist * http://www.apache.org/licenses/LICENSE-2.0
12*b5088357SAndrew Rist *
13*b5088357SAndrew Rist * Unless required by applicable law or agreed to in writing,
14*b5088357SAndrew Rist * software distributed under the License is distributed on an
15*b5088357SAndrew Rist * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16*b5088357SAndrew Rist * KIND, either express or implied. See the License for the
17*b5088357SAndrew Rist * specific language governing permissions and limitations
18*b5088357SAndrew Rist * under the License.
19*b5088357SAndrew Rist *
20*b5088357SAndrew Rist *************************************************************/
21*b5088357SAndrew Rist
22*b5088357SAndrew Rist
23cdf0e10cSrcweir
24cdf0e10cSrcweir // MARKER(update_precomp.py): autogen include statement, do not remove
25cdf0e10cSrcweir #include "precompiled_unotools.hxx"
26cdf0e10cSrcweir
27cdf0e10cSrcweir #include "unotools/configpathes.hxx"
28cdf0e10cSrcweir #include <rtl/ustring.hxx>
29cdf0e10cSrcweir #include <rtl/ustrbuf.hxx>
30cdf0e10cSrcweir #include <osl/diagnose.h>
31cdf0e10cSrcweir
32cdf0e10cSrcweir //----------------------------------------------------------------------------
33cdf0e10cSrcweir namespace utl
34cdf0e10cSrcweir {
35cdf0e10cSrcweir //----------------------------------------------------------------------------
36cdf0e10cSrcweir
37cdf0e10cSrcweir using ::rtl::OUString;
38cdf0e10cSrcweir using ::rtl::OUStringBuffer;
39cdf0e10cSrcweir
40cdf0e10cSrcweir //----------------------------------------------------------------------------
41cdf0e10cSrcweir
42cdf0e10cSrcweir static
lcl_resolveCharEntities(OUString & aLocalString)43cdf0e10cSrcweir void lcl_resolveCharEntities(OUString & aLocalString)
44cdf0e10cSrcweir {
45cdf0e10cSrcweir sal_Int32 nEscapePos=aLocalString.indexOf('&');
46cdf0e10cSrcweir if (nEscapePos < 0) return;
47cdf0e10cSrcweir
48cdf0e10cSrcweir OUStringBuffer aResult;
49cdf0e10cSrcweir sal_Int32 nStart = 0;
50cdf0e10cSrcweir
51cdf0e10cSrcweir do
52cdf0e10cSrcweir {
53cdf0e10cSrcweir sal_Unicode ch = 0;
54cdf0e10cSrcweir if (aLocalString.matchAsciiL(RTL_CONSTASCII_STRINGPARAM("&"),nEscapePos))
55cdf0e10cSrcweir ch = '&';
56cdf0e10cSrcweir
57cdf0e10cSrcweir else if (aLocalString.matchAsciiL(RTL_CONSTASCII_STRINGPARAM("'"),nEscapePos))
58cdf0e10cSrcweir ch = '\'';
59cdf0e10cSrcweir
60cdf0e10cSrcweir else if (aLocalString.matchAsciiL(RTL_CONSTASCII_STRINGPARAM("""),nEscapePos))
61cdf0e10cSrcweir ch = '"';
62cdf0e10cSrcweir
63cdf0e10cSrcweir OSL_ENSURE(ch,"Configuration path contains '&' that is not part of a valid character escape");
64cdf0e10cSrcweir if (ch)
65cdf0e10cSrcweir {
66cdf0e10cSrcweir aResult.append(aLocalString.copy(nStart,nEscapePos-nStart)).append(ch);
67cdf0e10cSrcweir
68cdf0e10cSrcweir sal_Int32 nEscapeEnd=aLocalString.indexOf(';',nEscapePos);
69cdf0e10cSrcweir nStart = nEscapeEnd+1;
70cdf0e10cSrcweir nEscapePos=aLocalString.indexOf('&',nStart);
71cdf0e10cSrcweir }
72cdf0e10cSrcweir else
73cdf0e10cSrcweir {
74cdf0e10cSrcweir nEscapePos=aLocalString.indexOf('&',nEscapePos+1);
75cdf0e10cSrcweir }
76cdf0e10cSrcweir }
77cdf0e10cSrcweir while ( nEscapePos > 0);
78cdf0e10cSrcweir
79cdf0e10cSrcweir aResult.append(aLocalString.copy(nStart));
80cdf0e10cSrcweir
81cdf0e10cSrcweir aLocalString = aResult.makeStringAndClear();
82cdf0e10cSrcweir }
83cdf0e10cSrcweir
84cdf0e10cSrcweir //----------------------------------------------------------------------------
splitLastFromConfigurationPath(OUString const & _sInPath,OUString & _rsOutPath,OUString & _rsLocalName)85cdf0e10cSrcweir sal_Bool splitLastFromConfigurationPath(OUString const& _sInPath,
86cdf0e10cSrcweir OUString& _rsOutPath,
87cdf0e10cSrcweir OUString& _rsLocalName)
88cdf0e10cSrcweir {
89cdf0e10cSrcweir sal_Int32 nStart,nEnd;
90cdf0e10cSrcweir
91cdf0e10cSrcweir sal_Int32 nPos = _sInPath.getLength()-1;
92cdf0e10cSrcweir
93cdf0e10cSrcweir // strip trailing slash
94cdf0e10cSrcweir if (nPos > 0 && _sInPath[ nPos ] == sal_Unicode('/'))
95cdf0e10cSrcweir {
96cdf0e10cSrcweir OSL_ENSURE(false, "Invalid config path: trailing '/' is not allowed");
97cdf0e10cSrcweir --nPos;
98cdf0e10cSrcweir }
99cdf0e10cSrcweir
100cdf0e10cSrcweir // check for predicate ['xxx'] or ["yyy"]
101cdf0e10cSrcweir if (nPos > 0 && _sInPath[ nPos ] == sal_Unicode(']'))
102cdf0e10cSrcweir {
103cdf0e10cSrcweir sal_Unicode chQuote = _sInPath[--nPos];
104cdf0e10cSrcweir
105cdf0e10cSrcweir if (chQuote == '\'' || chQuote == '\"')
106cdf0e10cSrcweir {
107cdf0e10cSrcweir nEnd = nPos;
108cdf0e10cSrcweir nPos = _sInPath.lastIndexOf(chQuote,nEnd);
109cdf0e10cSrcweir nStart = nPos + 1;
110cdf0e10cSrcweir --nPos; // nPos = rInPath.lastIndexOf('[',nPos);
111cdf0e10cSrcweir }
112cdf0e10cSrcweir else // allow [xxx]
113cdf0e10cSrcweir {
114cdf0e10cSrcweir nEnd = nPos + 1;
115cdf0e10cSrcweir nPos = _sInPath.lastIndexOf('[',nEnd);
116cdf0e10cSrcweir nStart = nPos + 1;
117cdf0e10cSrcweir }
118cdf0e10cSrcweir
119cdf0e10cSrcweir OSL_ENSURE(nPos >= 0 && _sInPath[nPos] == '[', "Invalid config path: unmatched quotes or brackets");
120cdf0e10cSrcweir if (nPos >= 0 && _sInPath[nPos] == '[')
121cdf0e10cSrcweir {
122cdf0e10cSrcweir nPos = _sInPath.lastIndexOf('/',nPos);
123cdf0e10cSrcweir }
124cdf0e10cSrcweir else // defined behavior for invalid pathes
125cdf0e10cSrcweir {
126cdf0e10cSrcweir nStart = 0, nEnd = _sInPath.getLength();
127cdf0e10cSrcweir nPos = -1;
128cdf0e10cSrcweir }
129cdf0e10cSrcweir
130cdf0e10cSrcweir }
131cdf0e10cSrcweir else
132cdf0e10cSrcweir {
133cdf0e10cSrcweir nEnd = nPos+1;
134cdf0e10cSrcweir nPos = _sInPath.lastIndexOf('/',nEnd);
135cdf0e10cSrcweir nStart = nPos + 1;
136cdf0e10cSrcweir }
137cdf0e10cSrcweir OSL_ASSERT( -1 <= nPos &&
138cdf0e10cSrcweir nPos < nStart &&
139cdf0e10cSrcweir nStart < nEnd &&
140cdf0e10cSrcweir nEnd <= _sInPath.getLength() );
141cdf0e10cSrcweir
142cdf0e10cSrcweir OSL_ASSERT(nPos == -1 || _sInPath[nPos] == '/');
143cdf0e10cSrcweir OSL_ENSURE(nPos != 0 , "Invalid config child path: immediate child of root");
144cdf0e10cSrcweir
145cdf0e10cSrcweir _rsLocalName = _sInPath.copy(nStart, nEnd-nStart);
146cdf0e10cSrcweir _rsOutPath = (nPos > 0) ? _sInPath.copy(0,nPos) : OUString();
147cdf0e10cSrcweir lcl_resolveCharEntities(_rsLocalName);
148cdf0e10cSrcweir
149cdf0e10cSrcweir return nPos >= 0;
150cdf0e10cSrcweir }
151cdf0e10cSrcweir
152cdf0e10cSrcweir //----------------------------------------------------------------------------
extractFirstFromConfigurationPath(OUString const & _sInPath,OUString * _sOutPath)153cdf0e10cSrcweir OUString extractFirstFromConfigurationPath(OUString const& _sInPath, OUString* _sOutPath)
154cdf0e10cSrcweir {
155cdf0e10cSrcweir sal_Int32 nSep = _sInPath.indexOf('/');
156cdf0e10cSrcweir sal_Int32 nBracket = _sInPath.indexOf('[');
157cdf0e10cSrcweir
158cdf0e10cSrcweir sal_Int32 nStart = nBracket + 1;
159cdf0e10cSrcweir sal_Int32 nEnd = nSep;
160cdf0e10cSrcweir
161cdf0e10cSrcweir if (0 <= nBracket) // found a bracket-quoted relative path
162cdf0e10cSrcweir {
163cdf0e10cSrcweir if (nSep < 0 || nBracket < nSep) // and the separator comes after it
164cdf0e10cSrcweir {
165cdf0e10cSrcweir sal_Unicode chQuote = _sInPath[nStart];
166cdf0e10cSrcweir if (chQuote == '\'' || chQuote == '\"')
167cdf0e10cSrcweir {
168cdf0e10cSrcweir ++nStart;
169cdf0e10cSrcweir nEnd = _sInPath.indexOf(chQuote, nStart+1);
170cdf0e10cSrcweir nBracket = nEnd+1;
171cdf0e10cSrcweir }
172cdf0e10cSrcweir else
173cdf0e10cSrcweir {
174cdf0e10cSrcweir nEnd = _sInPath.indexOf(']',nStart);
175cdf0e10cSrcweir nBracket = nEnd;
176cdf0e10cSrcweir }
177cdf0e10cSrcweir OSL_ENSURE(nEnd > nStart && _sInPath[nBracket] == ']', "Invalid config path: improper mismatch of quote or bracket");
178cdf0e10cSrcweir OSL_ENSURE((nBracket+1 == _sInPath.getLength() && nSep == -1) || (_sInPath[nBracket+1] == '/' && nSep == nBracket+1), "Invalid config path: brackets not followed by slash");
179cdf0e10cSrcweir }
180cdf0e10cSrcweir else // ... but our initial element name is in simple form
181cdf0e10cSrcweir nStart = 0;
182cdf0e10cSrcweir }
183cdf0e10cSrcweir
184cdf0e10cSrcweir OUString sResult = (nEnd >= 0) ? _sInPath.copy(nStart, nEnd-nStart) : _sInPath;
185cdf0e10cSrcweir lcl_resolveCharEntities(sResult);
186cdf0e10cSrcweir
187cdf0e10cSrcweir if (_sOutPath != 0)
188cdf0e10cSrcweir {
189cdf0e10cSrcweir *_sOutPath = (nSep >= 0) ? _sInPath.copy(nSep + 1) : OUString();
190cdf0e10cSrcweir }
191cdf0e10cSrcweir
192cdf0e10cSrcweir return sResult;
193cdf0e10cSrcweir }
194cdf0e10cSrcweir
195cdf0e10cSrcweir //----------------------------------------------------------------------------
196cdf0e10cSrcweir
197cdf0e10cSrcweir // find the position after the prefix in the nested path
198cdf0e10cSrcweir static inline
lcl_findPrefixEnd(OUString const & _sNestedPath,OUString const & _sPrefixPath)199cdf0e10cSrcweir sal_Int32 lcl_findPrefixEnd(OUString const& _sNestedPath, OUString const& _sPrefixPath)
200cdf0e10cSrcweir {
201cdf0e10cSrcweir // TODO: currently handles only exact prefix matches
202cdf0e10cSrcweir sal_Int32 nPrefixLength = _sPrefixPath.getLength();
203cdf0e10cSrcweir
204cdf0e10cSrcweir OSL_ENSURE(nPrefixLength == 0 || _sPrefixPath[nPrefixLength-1] != '/',
205cdf0e10cSrcweir "Cannot handle slash-terminated prefix pathes");
206cdf0e10cSrcweir
207cdf0e10cSrcweir sal_Bool bIsPrefix;
208cdf0e10cSrcweir if (_sNestedPath.getLength() > nPrefixLength)
209cdf0e10cSrcweir {
210cdf0e10cSrcweir bIsPrefix = _sNestedPath[nPrefixLength] == '/' &&
211cdf0e10cSrcweir _sNestedPath.compareTo(_sPrefixPath,nPrefixLength) == 0;
212cdf0e10cSrcweir ++nPrefixLength;
213cdf0e10cSrcweir }
214cdf0e10cSrcweir else if (_sNestedPath.getLength() == nPrefixLength)
215cdf0e10cSrcweir {
216cdf0e10cSrcweir bIsPrefix = _sNestedPath.equals(_sPrefixPath);
217cdf0e10cSrcweir }
218cdf0e10cSrcweir else
219cdf0e10cSrcweir {
220cdf0e10cSrcweir bIsPrefix = false;
221cdf0e10cSrcweir }
222cdf0e10cSrcweir
223cdf0e10cSrcweir return bIsPrefix ? nPrefixLength : 0;
224cdf0e10cSrcweir }
225cdf0e10cSrcweir
226cdf0e10cSrcweir //----------------------------------------------------------------------------
isPrefixOfConfigurationPath(OUString const & _sNestedPath,OUString const & _sPrefixPath)227cdf0e10cSrcweir sal_Bool isPrefixOfConfigurationPath(OUString const& _sNestedPath,
228cdf0e10cSrcweir OUString const& _sPrefixPath)
229cdf0e10cSrcweir {
230cdf0e10cSrcweir return _sPrefixPath.getLength() == 0 || lcl_findPrefixEnd(_sNestedPath,_sPrefixPath) != 0;
231cdf0e10cSrcweir }
232cdf0e10cSrcweir
233cdf0e10cSrcweir //----------------------------------------------------------------------------
dropPrefixFromConfigurationPath(OUString const & _sNestedPath,OUString const & _sPrefixPath)234cdf0e10cSrcweir OUString dropPrefixFromConfigurationPath(OUString const& _sNestedPath,
235cdf0e10cSrcweir OUString const& _sPrefixPath)
236cdf0e10cSrcweir {
237cdf0e10cSrcweir if ( sal_Int32 nPrefixEnd = lcl_findPrefixEnd(_sNestedPath,_sPrefixPath) )
238cdf0e10cSrcweir {
239cdf0e10cSrcweir return _sNestedPath.copy(nPrefixEnd);
240cdf0e10cSrcweir }
241cdf0e10cSrcweir else
242cdf0e10cSrcweir {
243cdf0e10cSrcweir OSL_ENSURE(_sPrefixPath.getLength() == 0, "Path does not start with expected prefix");
244cdf0e10cSrcweir
245cdf0e10cSrcweir return _sNestedPath;
246cdf0e10cSrcweir }
247cdf0e10cSrcweir }
248cdf0e10cSrcweir
249cdf0e10cSrcweir //----------------------------------------------------------------------------
250cdf0e10cSrcweir static
lcl_wrapName(const OUString & _sContent,const OUString & _sType)251cdf0e10cSrcweir OUString lcl_wrapName(const OUString& _sContent, const OUString& _sType)
252cdf0e10cSrcweir {
253cdf0e10cSrcweir const sal_Unicode * const pBeginContent = _sContent.getStr();
254cdf0e10cSrcweir const sal_Unicode * const pEndContent = pBeginContent + _sContent.getLength();
255cdf0e10cSrcweir
256cdf0e10cSrcweir OSL_PRECOND(_sType.getLength(), "Unexpected config type name: empty");
257cdf0e10cSrcweir OSL_PRECOND(pBeginContent <= pEndContent, "Invalid config name: empty");
258cdf0e10cSrcweir
259cdf0e10cSrcweir if (pBeginContent == pEndContent)
260cdf0e10cSrcweir return _sType;
261cdf0e10cSrcweir
262cdf0e10cSrcweir rtl::OUStringBuffer aNormalized(_sType.getLength() + _sContent.getLength() + 4); // reserve approximate size initially
263cdf0e10cSrcweir
264cdf0e10cSrcweir // prefix: type, opening bracket and quote
265cdf0e10cSrcweir aNormalized.append( _sType ).appendAscii( RTL_CONSTASCII_STRINGPARAM("['") );
266cdf0e10cSrcweir
267cdf0e10cSrcweir // content: copy over each char and handle escaping
268cdf0e10cSrcweir for(const sal_Unicode* pCur = pBeginContent; pCur != pEndContent; ++pCur)
269cdf0e10cSrcweir {
270cdf0e10cSrcweir // append (escape if needed)
271cdf0e10cSrcweir switch(*pCur)
272cdf0e10cSrcweir {
273cdf0e10cSrcweir case sal_Unicode('&') : aNormalized.appendAscii( RTL_CONSTASCII_STRINGPARAM("&") ); break;
274cdf0e10cSrcweir case sal_Unicode('\''): aNormalized.appendAscii( RTL_CONSTASCII_STRINGPARAM("'") ); break;
275cdf0e10cSrcweir case sal_Unicode('\"'): aNormalized.appendAscii( RTL_CONSTASCII_STRINGPARAM(""") ); break;
276cdf0e10cSrcweir
277cdf0e10cSrcweir default: aNormalized.append( *pCur );
278cdf0e10cSrcweir }
279cdf0e10cSrcweir }
280cdf0e10cSrcweir
281cdf0e10cSrcweir // suffix: closing quote and bracket
282cdf0e10cSrcweir aNormalized.appendAscii( RTL_CONSTASCII_STRINGPARAM("']") );
283cdf0e10cSrcweir
284cdf0e10cSrcweir return aNormalized.makeStringAndClear();
285cdf0e10cSrcweir }
286cdf0e10cSrcweir
287cdf0e10cSrcweir //----------------------------------------------------------------------------
288cdf0e10cSrcweir
wrapConfigurationElementName(OUString const & _sElementName)289cdf0e10cSrcweir OUString wrapConfigurationElementName(OUString const& _sElementName)
290cdf0e10cSrcweir {
291cdf0e10cSrcweir return lcl_wrapName(_sElementName, OUString(RTL_CONSTASCII_USTRINGPARAM("*")) );
292cdf0e10cSrcweir }
293cdf0e10cSrcweir
294cdf0e10cSrcweir //----------------------------------------------------------------------------
295cdf0e10cSrcweir
wrapConfigurationElementName(OUString const & _sElementName,OUString const & _sTypeName)296cdf0e10cSrcweir OUString wrapConfigurationElementName(OUString const& _sElementName,
297cdf0e10cSrcweir OUString const& _sTypeName)
298cdf0e10cSrcweir {
299cdf0e10cSrcweir // todo: check that _sTypeName is valid
300cdf0e10cSrcweir return lcl_wrapName(_sElementName, _sTypeName);
301cdf0e10cSrcweir }
302cdf0e10cSrcweir
303cdf0e10cSrcweir //----------------------------------------------------------------------------
304cdf0e10cSrcweir } // namespace utl
305