Branch data Line data Source code
1 : : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : : /*************************************************************************
3 : : *
4 : : * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 : : *
6 : : * Copyright 2000, 2010 Oracle and/or its affiliates.
7 : : *
8 : : * OpenOffice.org - a multi-platform office productivity suite
9 : : *
10 : : * This file is part of OpenOffice.org.
11 : : *
12 : : * OpenOffice.org is free software: you can redistribute it and/or modify
13 : : * it under the terms of the GNU Lesser General Public License version 3
14 : : * only, as published by the Free Software Foundation.
15 : : *
16 : : * OpenOffice.org is distributed in the hope that it will be useful,
17 : : * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 : : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 : : * GNU Lesser General Public License version 3 for more details
20 : : * (a copy is included in the LICENSE file that accompanied this code).
21 : : *
22 : : * You should have received a copy of the GNU Lesser General Public License
23 : : * version 3 along with OpenOffice.org. If not, see
24 : : * <http://www.openoffice.org/license.html>
25 : : * for a copy of the LGPLv3 License.
26 : : *
27 : : ************************************************************************/
28 : :
29 : : #include <regexp.hxx>
30 : :
31 : : #include <cstddef>
32 : :
33 : : #include "osl/diagnose.h"
34 : : #include <com/sun/star/lang/IllegalArgumentException.hpp>
35 : : #include <rtl/ustrbuf.hxx>
36 : : #include <rtl/ustring.hxx>
37 : : #include <comphelper/string.hxx>
38 : :
39 : : namespace unnamed_ucb_regexp {} using namespace unnamed_ucb_regexp;
40 : : // unnamed namespaces don't work well yet...
41 : :
42 : : using namespace com::sun::star;
43 : : using namespace ucb_impl;
44 : :
45 : : //============================================================================
46 : : //
47 : : // Regexp
48 : : //
49 : : //============================================================================
50 : :
51 : 8342 : inline Regexp::Regexp(Kind eTheKind, rtl::OUString const & rThePrefix,
52 : : bool bTheEmptyDomain, rtl::OUString const & rTheInfix,
53 : : bool bTheTranslation,
54 : : rtl::OUString const & rTheReversePrefix):
55 : : m_eKind(eTheKind),
56 : : m_aPrefix(rThePrefix),
57 : : m_aInfix(rTheInfix),
58 : : m_aReversePrefix(rTheReversePrefix),
59 : : m_bEmptyDomain(bTheEmptyDomain),
60 : 8342 : m_bTranslation(bTheTranslation)
61 : : {
62 : : OSL_ASSERT(m_eKind == KIND_DOMAIN
63 : : || (!m_bEmptyDomain && m_aInfix.isEmpty()));
64 : : OSL_ASSERT(m_bTranslation || m_aReversePrefix.isEmpty());
65 : 8342 : }
66 : :
67 : : //============================================================================
68 : : namespace unnamed_ucb_regexp {
69 : :
70 : 2537795 : bool matchStringIgnoreCase(sal_Unicode const ** pBegin,
71 : : sal_Unicode const * pEnd,
72 : : rtl::OUString const & rString)
73 : : {
74 : 2537795 : sal_Unicode const * p = *pBegin;
75 : :
76 : 2537795 : sal_Unicode const * q = rString.getStr();
77 : 2537795 : sal_Unicode const * qEnd = q + rString.getLength();
78 : :
79 [ + + ]: 2537795 : if (pEnd - p < qEnd - q)
80 : 332107 : return false;
81 : :
82 [ + + ]: 9447554 : while (q != qEnd)
83 : : {
84 : 9181026 : sal_Unicode c1 = *p++;
85 : 9181026 : sal_Unicode c2 = *q++;
86 [ + + ][ + - ]: 9181026 : if (c1 >= 'a' && c1 <= 'z')
87 : 7589954 : c1 -= 'a' - 'A';
88 [ + + ][ + - ]: 9181026 : if (c2 >= 'a' && c2 <= 'z')
89 : 7594186 : c2 -= 'a' - 'A';
90 [ + + ]: 9181026 : if (c1 != c2)
91 : 1939160 : return false;
92 : : }
93 : :
94 : 266528 : *pBegin = p;
95 : 2537795 : return true;
96 : : }
97 : :
98 : : }
99 : :
100 : 2537795 : bool Regexp::matches(rtl::OUString const & rString,
101 : : rtl::OUString * pTranslation, bool * pTranslated) const
102 : : {
103 : 2537795 : sal_Unicode const * pBegin = rString.getStr();
104 : 2537795 : sal_Unicode const * pEnd = pBegin + rString.getLength();
105 : :
106 : 2537795 : bool bMatches = false;
107 : :
108 : 2537795 : sal_Unicode const * p = pBegin;
109 [ + + ]: 2537795 : if (matchStringIgnoreCase(&p, pEnd, m_aPrefix))
110 : : {
111 : 266528 : sal_Unicode const * pBlock1Begin = p;
112 : 266528 : sal_Unicode const * pBlock1End = pEnd;
113 : :
114 : 266528 : sal_Unicode const * pBlock2Begin = 0;
115 : 266528 : sal_Unicode const * pBlock2End = 0;
116 : :
117 [ + - - - ]: 266528 : switch (m_eKind)
118 : : {
119 : : case KIND_PREFIX:
120 : 266528 : bMatches = true;
121 : 266528 : break;
122 : :
123 : : case KIND_AUTHORITY:
124 [ # # ][ # # ]: 0 : bMatches = p == pEnd || *p == '/' || *p == '?' || *p == '#';
[ # # ][ # # ]
125 : 0 : break;
126 : :
127 : : case KIND_DOMAIN:
128 [ # # ]: 0 : if (!m_bEmptyDomain)
129 : : {
130 [ # # ][ # # ]: 0 : if (p == pEnd || *p == '/' || *p == '?' || *p == '#')
[ # # ][ # # ]
131 : 0 : break;
132 : 0 : ++p;
133 : : }
134 : 0 : for (;;)
135 : : {
136 : 0 : sal_Unicode const * q = p;
137 [ # # ][ # # ]: 0 : if (matchStringIgnoreCase(&q, pEnd, m_aInfix)
[ # # ][ # # ]
[ # # ][ # # ]
138 : : && (q == pEnd || *q == '/' || *q == '?' || *q == '#'))
139 : : {
140 : 0 : bMatches = true;
141 : 0 : pBlock1End = p;
142 : 0 : pBlock2Begin = q;
143 : 0 : pBlock2End = pEnd;
144 : : break;
145 : : }
146 : :
147 [ # # ]: 0 : if (p == pEnd)
148 : : break;
149 : :
150 : 0 : sal_Unicode c = *p++;
151 [ # # ][ # # ]: 0 : if (c == '/' || c == '?' || c == '#')
[ # # ]
152 : : break;
153 : : }
154 : 0 : break;
155 : : }
156 : :
157 [ + - ]: 266528 : if (bMatches)
158 : : {
159 [ - + ]: 266528 : if (m_bTranslation)
160 : : {
161 [ # # ]: 0 : if (pTranslation)
162 : : {
163 [ # # ]: 0 : rtl::OUStringBuffer aBuffer(m_aReversePrefix);
164 [ # # ]: 0 : aBuffer.append(pBlock1Begin, pBlock1End - pBlock1Begin);
165 [ # # ]: 0 : aBuffer.append(m_aInfix);
166 [ # # ]: 0 : aBuffer.append(pBlock2Begin, pBlock2End - pBlock2Begin);
167 [ # # ]: 0 : *pTranslation = aBuffer.makeStringAndClear();
168 : : }
169 [ # # ]: 0 : if (pTranslated)
170 : 0 : *pTranslated = true;
171 : : }
172 : : else
173 : : {
174 [ - + ]: 266528 : if (pTranslation)
175 : 0 : *pTranslation = rString;
176 [ - + ]: 266528 : if (pTranslated)
177 : 0 : *pTranslated = false;
178 : : }
179 : : }
180 : : }
181 : :
182 : 2537795 : return bMatches;
183 : : }
184 : :
185 : : //============================================================================
186 : : namespace unnamed_ucb_regexp {
187 : :
188 : 9346 : bool isScheme(rtl::OUString const & rString, bool bColon)
189 : : {
190 : : using comphelper::string::isalphaAscii;
191 : : using comphelper::string::isdigitAscii;
192 : : // Return true if rString matches <scheme> (plus a trailing ":" if bColon
193 : : // is true) from RFC 2396:
194 : 9346 : sal_Unicode const * p = rString.getStr();
195 : 9346 : sal_Unicode const * pEnd = p + rString.getLength();
196 [ + + ][ + + ]: 9346 : if (p != pEnd && isalphaAscii(*p))
[ + - ]
197 : 103624 : for (++p;;)
198 : : {
199 [ + + ]: 103624 : if (p == pEnd)
200 : 8216 : return !bColon;
201 : 95408 : sal_Unicode c = *p++;
202 [ + + ]: 205612 : if (!(isalphaAscii(c) || isdigitAscii(c)
203 [ + + ][ + + ]: 110204 : || c == '+' || c == '-' || c == '.'))
[ + + ]
[ + + + - ]
204 [ + - ][ + - ]: 1004 : return bColon && c == ':' && p == pEnd;
[ + - ]
205 : : }
206 : 9346 : return false;
207 : : }
208 : :
209 : 0 : void appendStringLiteral(rtl::OUStringBuffer * pBuffer,
210 : : rtl::OUString const & rString)
211 : : {
212 : : OSL_ASSERT(pBuffer);
213 : :
214 : 0 : pBuffer->append(sal_Unicode('"'));
215 : 0 : sal_Unicode const * p = rString.getStr();
216 : 0 : sal_Unicode const * pEnd = p + rString.getLength();
217 [ # # ]: 0 : while (p != pEnd)
218 : : {
219 : 0 : sal_Unicode c = *p++;
220 [ # # ][ # # ]: 0 : if (c == '"' || c == '\\')
221 : 0 : pBuffer->append(sal_Unicode('\\'));
222 : 0 : pBuffer->append(c);
223 : : }
224 : 0 : pBuffer->append(sal_Unicode('"'));
225 : 0 : }
226 : :
227 : : }
228 : :
229 : 1004 : rtl::OUString Regexp::getRegexp(bool bReverse) const
230 : : {
231 [ - + ]: 1004 : if (m_bTranslation)
232 : : {
233 : 0 : rtl::OUStringBuffer aBuffer;
234 [ # # ]: 0 : if (bReverse)
235 : : {
236 [ # # ]: 0 : if (!m_aReversePrefix.isEmpty())
237 [ # # ]: 0 : appendStringLiteral(&aBuffer, m_aReversePrefix);
238 : : }
239 : : else
240 : : {
241 [ # # ]: 0 : if (!m_aPrefix.isEmpty())
242 [ # # ]: 0 : appendStringLiteral(&aBuffer, m_aPrefix);
243 : : }
244 [ # # # # ]: 0 : switch (m_eKind)
245 : : {
246 : : case KIND_PREFIX:
247 [ # # ]: 0 : aBuffer.appendAscii(RTL_CONSTASCII_STRINGPARAM("(.*)"));
248 : 0 : break;
249 : :
250 : : case KIND_AUTHORITY:
251 : : aBuffer.
252 [ # # ]: 0 : appendAscii(RTL_CONSTASCII_STRINGPARAM("(([/?#].*)?)"));
253 : 0 : break;
254 : :
255 : : case KIND_DOMAIN:
256 [ # # ]: 0 : aBuffer.appendAscii(RTL_CONSTASCII_STRINGPARAM("([^/?#]"));
257 [ # # ][ # # ]: 0 : aBuffer.append(sal_Unicode(m_bEmptyDomain ? '*' : '+'));
258 [ # # ]: 0 : if (!m_aInfix.isEmpty())
259 [ # # ]: 0 : appendStringLiteral(&aBuffer, m_aInfix);
260 : : aBuffer.
261 [ # # ]: 0 : appendAscii(RTL_CONSTASCII_STRINGPARAM("([/?#].*)?)"));
262 : 0 : break;
263 : : }
264 [ # # ]: 0 : aBuffer.appendAscii(RTL_CONSTASCII_STRINGPARAM("->"));
265 [ # # ]: 0 : if (bReverse)
266 : : {
267 [ # # ]: 0 : if (!m_aPrefix.isEmpty())
268 [ # # ]: 0 : appendStringLiteral(&aBuffer, m_aPrefix);
269 : : }
270 : : else
271 : : {
272 [ # # ]: 0 : if (!m_aReversePrefix.isEmpty())
273 [ # # ]: 0 : appendStringLiteral(&aBuffer, m_aReversePrefix);
274 : : }
275 [ # # ]: 0 : aBuffer.appendAscii(RTL_CONSTASCII_STRINGPARAM("\\1"));
276 [ # # ]: 0 : return aBuffer.makeStringAndClear();
277 : : }
278 [ + - ][ + - ]: 1004 : else if (m_eKind == KIND_PREFIX && isScheme(m_aPrefix, true))
[ + - ]
279 : 1004 : return m_aPrefix.copy(0, m_aPrefix.getLength() - 1);
280 : : else
281 : : {
282 : 0 : rtl::OUStringBuffer aBuffer;
283 [ # # ]: 0 : if (!m_aPrefix.isEmpty())
284 [ # # ]: 0 : appendStringLiteral(&aBuffer, m_aPrefix);
285 [ # # # # ]: 0 : switch (m_eKind)
286 : : {
287 : : case KIND_PREFIX:
288 [ # # ]: 0 : aBuffer.appendAscii(RTL_CONSTASCII_STRINGPARAM(".*"));
289 : 0 : break;
290 : :
291 : : case KIND_AUTHORITY:
292 [ # # ]: 0 : aBuffer.appendAscii(RTL_CONSTASCII_STRINGPARAM("([/?#].*)?"));
293 : 0 : break;
294 : :
295 : : case KIND_DOMAIN:
296 [ # # ]: 0 : aBuffer.appendAscii(RTL_CONSTASCII_STRINGPARAM("[^/?#]"));
297 [ # # ][ # # ]: 0 : aBuffer.append(sal_Unicode(m_bEmptyDomain ? '*' : '+'));
298 [ # # ]: 0 : if (!m_aInfix.isEmpty())
299 [ # # ]: 0 : appendStringLiteral(&aBuffer, m_aInfix);
300 [ # # ]: 0 : aBuffer.appendAscii(RTL_CONSTASCII_STRINGPARAM("([/?#].*)?"));
301 : 0 : break;
302 : : }
303 [ # # ]: 1004 : return aBuffer.makeStringAndClear();
304 : : }
305 : : }
306 : :
307 : : //============================================================================
308 : : namespace unnamed_ucb_regexp {
309 : :
310 : 126 : bool matchString(sal_Unicode const ** pBegin, sal_Unicode const * pEnd,
311 : : sal_Char const * pString, size_t nStringLength)
312 : : {
313 : 126 : sal_Unicode const * p = *pBegin;
314 : :
315 : 126 : sal_uChar const * q = reinterpret_cast< sal_uChar const * >(pString);
316 : 126 : sal_uChar const * qEnd = q + nStringLength;
317 : :
318 [ - + ]: 126 : if (pEnd - p < qEnd - q)
319 : 0 : return false;
320 : :
321 [ + + ]: 378 : while (q != qEnd)
322 : : {
323 : 252 : sal_Unicode c1 = *p++;
324 : 252 : sal_Unicode c2 = *q++;
325 [ - + ]: 252 : if (c1 != c2)
326 : 0 : return false;
327 : : }
328 : :
329 : 126 : *pBegin = p;
330 : 126 : return true;
331 : : }
332 : :
333 : 126 : bool scanStringLiteral(sal_Unicode const ** pBegin, sal_Unicode const * pEnd,
334 : : rtl::OUString * pString)
335 : : {
336 : 126 : sal_Unicode const * p = *pBegin;
337 : :
338 [ + - ][ + - ]: 126 : if (p == pEnd || *p++ != '"')
[ + - ]
339 : 126 : return false;
340 : :
341 : 0 : rtl::OUStringBuffer aBuffer;
342 : 0 : for (;;)
343 : : {
344 [ # # ]: 0 : if (p == pEnd)
345 : 0 : return false;
346 : 0 : sal_Unicode c = *p++;
347 [ # # ]: 0 : if (c == '"')
348 : 0 : break;
349 [ # # ]: 0 : if (c == '\\')
350 : : {
351 [ # # ]: 0 : if (p == pEnd)
352 : 0 : return false;
353 : 0 : c = *p++;
354 [ # # ][ # # ]: 0 : if (c != '"' && c != '\\')
355 : 0 : return false;
356 : : }
357 [ # # ]: 0 : aBuffer.append(c);
358 : : }
359 : :
360 : 0 : *pBegin = p;
361 [ # # ]: 0 : *pString = aBuffer.makeStringAndClear();
362 : 126 : return true;
363 : : }
364 : :
365 : : }
366 : :
367 : 8342 : Regexp Regexp::parse(rtl::OUString const & rRegexp)
368 : : {
369 : : // Detect an input of '<scheme>' as an abbreviation of '"<scheme>:".*'
370 : : // where <scheme> is as defined in RFC 2396:
371 [ + - ][ + + ]: 8342 : if (isScheme(rRegexp, false))
372 : : return Regexp(Regexp::KIND_PREFIX,
373 : : rRegexp
374 : : + rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(":")),
375 : : false,
376 : : rtl::OUString(),
377 : : false,
378 [ + - ]: 8216 : rtl::OUString());
379 : :
380 : 126 : sal_Unicode const * p = rRegexp.getStr();
381 : 126 : sal_Unicode const * pEnd = p + rRegexp.getLength();
382 : :
383 : 126 : rtl::OUString aPrefix;
384 [ + - ]: 126 : scanStringLiteral(&p, pEnd, &aPrefix);
385 : :
386 [ - + ]: 126 : if (p == pEnd)
387 [ # # ]: 0 : throw lang::IllegalArgumentException();
388 : :
389 [ + - ]: 126 : if (matchString(&p, pEnd, RTL_CONSTASCII_STRINGPARAM(".*")))
390 : : {
391 [ - + ]: 126 : if (p != pEnd)
392 [ # # ]: 0 : throw lang::IllegalArgumentException();
393 : :
394 : : return Regexp(Regexp::KIND_PREFIX, aPrefix, false, rtl::OUString(),
395 : 126 : false, rtl::OUString());
396 : : }
397 [ # # ]: 0 : else if (matchString(&p, pEnd, RTL_CONSTASCII_STRINGPARAM("(.*)->")))
398 : : {
399 : 0 : rtl::OUString aReversePrefix;
400 [ # # ]: 0 : scanStringLiteral(&p, pEnd, &aReversePrefix);
401 : :
402 [ # # ][ # # ]: 0 : if (!matchString(&p, pEnd, RTL_CONSTASCII_STRINGPARAM("\\1"))
[ # # ]
403 : : || p != pEnd)
404 [ # # ]: 0 : throw lang::IllegalArgumentException();
405 : :
406 : : return Regexp(Regexp::KIND_PREFIX, aPrefix, false, rtl::OUString(),
407 : 0 : true, aReversePrefix);
408 : : }
409 [ # # ]: 0 : else if (matchString(&p, pEnd, RTL_CONSTASCII_STRINGPARAM("([/?#].*)?")))
410 : : {
411 [ # # ]: 0 : if (p != pEnd)
412 [ # # ]: 0 : throw lang::IllegalArgumentException();
413 : :
414 : : return Regexp(Regexp::KIND_AUTHORITY, aPrefix, false, rtl::OUString(),
415 : 0 : false, rtl::OUString());
416 : : }
417 [ # # ]: 0 : else if (matchString(&p, pEnd,
418 : : RTL_CONSTASCII_STRINGPARAM("(([/?#].*)?)->")))
419 : : {
420 : 0 : rtl::OUString aReversePrefix;
421 [ # # ][ # # ]: 0 : if (!(scanStringLiteral(&p, pEnd, &aReversePrefix)
422 : 0 : && matchString(&p, pEnd, RTL_CONSTASCII_STRINGPARAM("\\1"))
423 [ # # # # ]: 0 : && p == pEnd))
[ # # ]
424 [ # # ]: 0 : throw lang::IllegalArgumentException();
425 : :
426 : : return Regexp(Regexp::KIND_AUTHORITY, aPrefix, false, rtl::OUString(),
427 : 0 : true, aReversePrefix);
428 : : }
429 : : else
430 : : {
431 : 0 : bool bOpen = false;
432 [ # # ][ # # ]: 0 : if (p != pEnd && *p == '(')
433 : : {
434 : 0 : ++p;
435 : 0 : bOpen = true;
436 : : }
437 : :
438 [ # # ]: 0 : if (!matchString(&p, pEnd, RTL_CONSTASCII_STRINGPARAM("[^/?#]")))
439 [ # # ]: 0 : throw lang::IllegalArgumentException();
440 : :
441 [ # # ][ # # ]: 0 : if (p == pEnd || (*p != '*' && *p != '+'))
[ # # ]
442 [ # # ]: 0 : throw lang::IllegalArgumentException();
443 : 0 : bool bEmptyDomain = *p++ == '*';
444 : :
445 : 0 : rtl::OUString aInfix;
446 [ # # ]: 0 : scanStringLiteral(&p, pEnd, &aInfix);
447 : :
448 [ # # ]: 0 : if (!matchString(&p, pEnd, RTL_CONSTASCII_STRINGPARAM("([/?#].*)?")))
449 [ # # ]: 0 : throw lang::IllegalArgumentException();
450 : :
451 : 0 : rtl::OUString aReversePrefix;
452 [ # # ]: 0 : if (bOpen
[ # # # # ]
453 : 0 : && !(matchString(&p, pEnd, RTL_CONSTASCII_STRINGPARAM(")->"))
454 [ # # ]: 0 : && scanStringLiteral(&p, pEnd, &aReversePrefix)
455 [ # # ][ # # ]: 0 : && matchString(&p, pEnd, RTL_CONSTASCII_STRINGPARAM("\\1"))))
456 [ # # ]: 0 : throw lang::IllegalArgumentException();
457 : :
458 [ # # ]: 0 : if (p != pEnd)
459 [ # # ]: 0 : throw lang::IllegalArgumentException();
460 : :
461 : : return Regexp(Regexp::KIND_DOMAIN, aPrefix, bEmptyDomain, aInfix,
462 : 0 : bOpen, aReversePrefix);
463 : 8342 : }
464 : : }
465 : :
466 : : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|