Branch data 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 <svl/urihelper.hxx>
21 : : #include <com/sun/star/beans/XPropertySet.hpp>
22 : : #include "com/sun/star/lang/WrappedTargetRuntimeException.hpp"
23 : : #include "com/sun/star/lang/XMultiComponentFactory.hpp"
24 : : #include "com/sun/star/ucb/Command.hpp"
25 : : #include <com/sun/star/ucb/FileSystemNotation.hpp>
26 : : #include "com/sun/star/ucb/IllegalIdentifierException.hpp"
27 : : #include "com/sun/star/ucb/UnsupportedCommandException.hpp"
28 : : #include "com/sun/star/ucb/XCommandEnvironment.hpp"
29 : : #include "com/sun/star/ucb/XCommandProcessor.hpp"
30 : : #include "com/sun/star/ucb/XContent.hpp"
31 : : #include "com/sun/star/ucb/XContentIdentifierFactory.hpp"
32 : : #include "com/sun/star/ucb/XContentProvider.hpp"
33 : : #include <com/sun/star/ucb/XContentProviderManager.hpp>
34 : : #include "com/sun/star/uno/Any.hxx"
35 : : #include "com/sun/star/uno/Exception.hpp"
36 : : #include "com/sun/star/uno/Reference.hxx"
37 : : #include "com/sun/star/uno/RuntimeException.hpp"
38 : : #include "com/sun/star/uno/Sequence.hxx"
39 : : #include "com/sun/star/uno/XComponentContext.hpp"
40 : : #include "com/sun/star/uno/XInterface.hpp"
41 : : #include "com/sun/star/uri/UriReferenceFactory.hpp"
42 : : #include "com/sun/star/uri/XUriReference.hpp"
43 : : #include "com/sun/star/uri/XUriReferenceFactory.hpp"
44 : : #include "cppuhelper/exc_hlp.hxx"
45 : : #include "comphelper/processfactory.hxx"
46 : : #include "osl/diagnose.h"
47 : : #include "rtl/ustrbuf.hxx"
48 : : #include "rtl/ustring.h"
49 : : #include "rtl/ustring.hxx"
50 : : #include "sal/types.h"
51 : : #include <tools/inetmime.hxx>
52 : : #include <ucbhelper/contentbroker.hxx>
53 : : #include <unotools/charclass.hxx>
54 : : #include "rtl/instance.hxx"
55 : :
56 : : namespace css = com::sun::star;
57 : : using namespace com::sun::star;
58 : :
59 : : //============================================================================
60 : : //
61 : : // SmartRel2Abs
62 : : //
63 : : //============================================================================
64 : :
65 : : rtl::OUString
66 : 34 : URIHelper::SmartRel2Abs(INetURLObject const & rTheBaseURIRef,
67 : : rtl::OUString const & rTheRelURIRef,
68 : : Link const & rMaybeFileHdl,
69 : : bool bCheckFileExists,
70 : : bool bIgnoreFragment,
71 : : INetURLObject::EncodeMechanism eEncodeMechanism,
72 : : INetURLObject::DecodeMechanism eDecodeMechanism,
73 : : rtl_TextEncoding eCharset,
74 : : bool bRelativeNonURIs,
75 : : INetURLObject::FSysStyle eStyle)
76 : : {
77 : : // Backwards compatibility:
78 [ + - ][ - + ]: 34 : if (!rTheRelURIRef.isEmpty() && rTheRelURIRef[0] == '#')
[ - + ]
79 : 0 : return rTheRelURIRef;
80 : :
81 [ + - ]: 34 : INetURLObject aAbsURIRef;
82 [ + + ]: 34 : if (rTheBaseURIRef.HasError())
83 : : aAbsURIRef.
84 [ + - ]: 28 : SetSmartURL(rTheRelURIRef, eEncodeMechanism, eCharset, eStyle);
85 : : else
86 : : {
87 : : bool bWasAbsolute;
88 : : aAbsURIRef = rTheBaseURIRef.smartRel2Abs(rTheRelURIRef,
89 : : bWasAbsolute,
90 : : bIgnoreFragment,
91 : : eEncodeMechanism,
92 : : eCharset,
93 : : bRelativeNonURIs,
94 [ + - ][ + - ]: 6 : eStyle);
[ + - ]
95 [ - + ]: 6 : if (bCheckFileExists
[ # # # # ]
[ - + ]
96 : 0 : && !bWasAbsolute
97 : 0 : && (aAbsURIRef.GetProtocol() == INET_PROT_FILE))
98 : : {
99 [ # # ]: 0 : INetURLObject aNonFileURIRef;
100 : : aNonFileURIRef.SetSmartURL(rTheRelURIRef,
101 : : eEncodeMechanism,
102 : : eCharset,
103 [ # # ]: 0 : eStyle);
104 [ # # # # ]: 0 : if (!aNonFileURIRef.HasError()
[ # # ]
105 : 0 : && aNonFileURIRef.GetProtocol() != INET_PROT_FILE)
106 : : {
107 : 0 : bool bMaybeFile = false;
108 [ # # ][ # # ]: 0 : if (rMaybeFileHdl.IsSet())
109 : : {
110 [ # # ]: 0 : UniString aFilePath(rTheRelURIRef);
111 [ # # ][ # # ]: 0 : bMaybeFile = rMaybeFileHdl.Call(&aFilePath) != 0;
112 : : }
113 [ # # ]: 0 : if (!bMaybeFile)
114 [ # # ]: 0 : aAbsURIRef = aNonFileURIRef;
115 [ # # ]: 6 : }
116 : : }
117 : : }
118 [ + - ][ + - ]: 34 : return aAbsURIRef.GetMainURL(eDecodeMechanism, eCharset);
119 : : }
120 : :
121 : : //============================================================================
122 : : //
123 : : // SetMaybeFileHdl
124 : : //
125 : : //============================================================================
126 : :
127 : : namespace { struct MaybeFileHdl : public rtl::Static< Link, MaybeFileHdl > {}; }
128 : :
129 : 66 : void URIHelper::SetMaybeFileHdl(Link const & rTheMaybeFileHdl)
130 : : {
131 : 66 : MaybeFileHdl::get() = rTheMaybeFileHdl;
132 : 66 : }
133 : :
134 : : //============================================================================
135 : : //
136 : : // GetMaybeFileHdl
137 : : //
138 : : //============================================================================
139 : :
140 : 28 : Link URIHelper::GetMaybeFileHdl()
141 : : {
142 : 28 : return MaybeFileHdl::get();
143 : : }
144 : :
145 : : namespace {
146 : :
147 : 32 : bool isAbsoluteHierarchicalUriReference(
148 : : css::uno::Reference< css::uri::XUriReference > const & uriReference)
149 : : {
150 : 64 : return uriReference.is() && uriReference->isAbsolute()
151 [ + - ][ + - ]: 64 : && uriReference->isHierarchical() && !uriReference->hasRelativePath();
[ + - + - ]
152 : : }
153 : :
154 : : // To improve performance, assume that if for any prefix URL of a given
155 : : // hierarchical URL either a UCB content cannot be created, or the UCB content
156 : : // does not support the getCasePreservingURL command, then this will hold for
157 : : // any other prefix URL of the given URL, too:
158 : : enum Result { Success, GeneralFailure, SpecificFailure };
159 : :
160 : 64 : Result normalizePrefix(
161 : : css::uno::Reference< css::ucb::XContentProvider > const & broker,
162 : : rtl::OUString const & uri, rtl::OUString * normalized)
163 : : {
164 : : OSL_ASSERT(broker.is() && normalized != 0);
165 : 64 : css::uno::Reference< css::ucb::XContent > content;
166 : : try {
167 [ + - ]: 64 : content = broker->queryContent(
168 : : css::uno::Reference< css::ucb::XContentIdentifierFactory >(
169 [ + - ]: 128 : broker, css::uno::UNO_QUERY_THROW)->createContentIdentifier(
[ + - # # ]
170 [ + - ][ + - ]: 64 : uri));
[ + - ]
171 [ # # ]: 0 : } catch (css::ucb::IllegalIdentifierException &) {}
172 [ + + ]: 64 : if (!content.is()) {
173 : 32 : return GeneralFailure;
174 : : }
175 : : try {
176 : : #if OSL_DEBUG_LEVEL > 0
177 : : bool ok =
178 : : #endif
179 : : (css::uno::Reference< css::ucb::XCommandProcessor >(
180 [ + - ][ + - ]: 64 : content, css::uno::UNO_QUERY_THROW)->execute(
181 : : css::ucb::Command("getCasePreservingURL",
182 : : -1, css::uno::Any()),
183 : : 0,
184 : 32 : css::uno::Reference< css::ucb::XCommandEnvironment >())
185 [ + + ]: 32 : >>= *normalized);
186 : : OSL_ASSERT(ok);
187 [ - - - + ]: 16 : } catch (css::uno::RuntimeException &) {
188 : 0 : throw;
189 [ # # ]: 0 : } catch (css::ucb::UnsupportedCommandException &) {
190 : 0 : return GeneralFailure;
191 [ + - ]: 16 : } catch (css::uno::Exception &) {
192 : 16 : return SpecificFailure;
193 : : }
194 : 64 : return Success;
195 : : }
196 : :
197 : 48 : rtl::OUString normalize(
198 : : css::uno::Reference< css::ucb::XContentProvider > const & broker,
199 : : css::uno::Reference< css::uri::XUriReferenceFactory > const & uriFactory,
200 : : rtl::OUString const & uriReference)
201 : : {
202 : : // normalizePrefix can potentially fail (a typically example being a file
203 : : // URL that denotes a non-existing resource); in such a case, try to
204 : : // normalize as long a prefix of the given URL as possible (i.e., normalize
205 : : // all the existing directories within the path):
206 : 48 : rtl::OUString normalized;
207 : 48 : sal_Int32 n = uriReference.indexOf('#');
208 [ + + ]: 48 : normalized = n == -1 ? uriReference : uriReference.copy(0, n);
209 [ - + + ]: 48 : switch (normalizePrefix(broker, normalized, &normalized)) {
[ + - ]
210 : : case Success:
211 [ # # ][ # # ]: 0 : return n == -1 ? normalized : normalized + uriReference.copy(n);
212 : : case GeneralFailure:
213 : 32 : return uriReference;
214 : : case SpecificFailure:
215 : : default:
216 : 16 : break;
217 : : }
218 : : css::uno::Reference< css::uri::XUriReference > ref(
219 [ + - ][ + - ]: 16 : uriFactory->parse(uriReference));
220 [ + - ][ - + ]: 16 : if (!isAbsoluteHierarchicalUriReference(ref)) {
221 : 0 : return uriReference;
222 : : }
223 [ + - ][ + - ]: 16 : sal_Int32 count = ref->getPathSegmentCount();
224 [ - + ]: 16 : if (count < 2) {
225 : 0 : return uriReference;
226 : : }
227 [ + - ][ + - ]: 16 : rtl::OUStringBuffer head(ref->getScheme());
[ + - ]
228 [ + - ]: 16 : head.append(static_cast< sal_Unicode >(':'));
229 [ + - ][ + - ]: 16 : if (ref->hasAuthority()) {
[ - + ]
230 [ # # ]: 0 : head.appendAscii(RTL_CONSTASCII_STRINGPARAM("//"));
231 [ # # ][ # # ]: 0 : head.append(ref->getAuthority());
[ # # ]
232 : : }
233 [ + - ]: 32 : for (sal_Int32 i = count - 1; i > 0; --i) {
234 [ + - ]: 16 : rtl::OUStringBuffer buf(head);
235 [ + + ]: 40 : for (sal_Int32 j = 0; j < i; ++j) {
236 [ + - ]: 24 : buf.append(static_cast< sal_Unicode >('/'));
237 [ + - ][ + - ]: 24 : buf.append(ref->getPathSegment(j));
[ + - ]
238 : : }
239 [ + - ]: 16 : normalized = buf.makeStringAndClear();
240 [ + - ][ + - ]: 16 : if (normalizePrefix(broker, normalized, &normalized) != SpecificFailure)
241 : : {
242 [ + - ]: 16 : buf.append(normalized);
243 : : css::uno::Reference< css::uri::XUriReference > preRef(
244 [ + - ][ + - ]: 16 : uriFactory->parse(normalized));
245 [ + - ][ - + ]: 16 : if (!isAbsoluteHierarchicalUriReference(preRef)) {
246 : : // This could only happen if something is inconsistent:
247 : : break;
248 : : }
249 [ + - ][ + - ]: 16 : sal_Int32 preCount = preRef->getPathSegmentCount();
250 : : // normalizePrefix may have added or removed a final slash:
251 [ + + ]: 16 : if (preCount != i) {
252 [ + + ]: 6 : if (preCount == i - 1) {
253 [ + - ]: 2 : buf.append(static_cast< sal_Unicode >('/'));
254 [ + - ]: 8 : } else if (preCount - 1 == i && buf.getLength() > 0
[ + - + - ]
[ + - ]
255 : 4 : && buf[buf.getLength() - 1] == '/')
256 : : {
257 [ + - ]: 4 : buf.setLength(buf.getLength() - 1);
258 : : } else {
259 : : // This could only happen if something is inconsistent:
260 : : break;
261 : : }
262 : : }
263 [ + + ]: 32 : for (sal_Int32 j = i; j < count; ++j) {
264 [ + - ]: 16 : buf.append(static_cast< sal_Unicode >('/'));
265 [ + - ][ + - ]: 16 : buf.append(ref->getPathSegment(j));
[ + - ]
266 : : }
267 [ + - ][ + - ]: 16 : if (ref->hasQuery()) {
[ - + ]
268 [ # # ]: 0 : buf.append(static_cast< sal_Unicode >('?'));
269 [ # # ][ # # ]: 0 : buf.append(ref->getQuery());
[ # # ]
270 : : }
271 [ + - ][ + - ]: 16 : if (ref->hasFragment()) {
[ + + ]
272 [ + - ]: 2 : buf.append(static_cast< sal_Unicode >('#'));
273 [ + - ][ + - ]: 2 : buf.append(ref->getFragment());
[ + - ]
274 : : }
275 [ + - ][ - + ]: 16 : return buf.makeStringAndClear();
276 : : }
277 [ - - + ]: 16 : }
278 : 48 : return uriReference;
279 : : }
280 : :
281 : : }
282 : :
283 : : css::uno::Reference< css::uri::XUriReference >
284 : 24 : URIHelper::normalizedMakeRelative(
285 : : css::uno::Reference< css::uno::XComponentContext > const & context,
286 : : rtl::OUString const & baseUriReference, rtl::OUString const & uriReference)
287 : : {
288 : : OSL_ASSERT(context.is());
289 : : css::uno::Reference< css::lang::XMultiComponentFactory > componentFactory(
290 [ + - ][ + - ]: 24 : context->getServiceManager());
291 [ - + ]: 24 : if (!componentFactory.is()) {
292 : : throw css::uno::RuntimeException("component context has no service manager",
293 [ # # ]: 0 : css::uno::Reference< css::uno::XInterface >());
294 : : }
295 [ + - ]: 24 : css::uno::Sequence< css::uno::Any > args(2);
296 [ + - ][ + - ]: 24 : args[0] <<= rtl::OUString("Local");
297 [ + - ][ + - ]: 24 : args[1] <<= rtl::OUString("Office");
298 : 24 : css::uno::Reference< css::ucb::XContentProvider > broker;
299 : : try {
300 : : broker = css::uno::Reference< css::ucb::XContentProvider >(
301 [ + - ]: 24 : componentFactory->createInstanceWithArgumentsAndContext(
302 : : "com.sun.star.ucb.UniversalContentBroker",
303 : 24 : args, context),
304 [ + - ][ + - ]: 24 : css::uno::UNO_QUERY_THROW);
[ + - ]
305 : 0 : } catch (css::uno::RuntimeException &) {
306 : 0 : throw;
307 [ # # # ]: 0 : } catch (css::uno::Exception &) {
308 [ # # ]: 0 : css::uno::Any exception(cppu::getCaughtException());
309 : : throw css::lang::WrappedTargetRuntimeException(
310 : : "creating com.sun.star.ucb.UniversalContentBroker failed",
311 : : css::uno::Reference< css::uno::XInterface >(),
312 [ # # ]: 0 : exception);
313 : : }
314 : : css::uno::Reference< css::uri::XUriReferenceFactory > uriFactory(
315 [ + - ]: 24 : css::uri::UriReferenceFactory::create(context));
316 [ + - ]: 24 : return uriFactory->makeRelative(
317 [ + - ]: 24 : uriFactory->parse(normalize(broker, uriFactory, baseUriReference)),
318 [ + - ]: 24 : uriFactory->parse(normalize(broker, uriFactory, uriReference)), true,
319 [ + - ][ + - ]: 48 : true, false);
[ + - ][ + - ]
[ + - ][ + - ]
320 : : }
321 : :
322 : 0 : rtl::OUString URIHelper::simpleNormalizedMakeRelative(
323 : : rtl::OUString const & baseUriReference, rtl::OUString const & uriReference)
324 : : {
325 : : com::sun::star::uno::Reference< com::sun::star::uri::XUriReference > rel(
326 : : URIHelper::normalizedMakeRelative(
327 : : com::sun::star::uno::Reference<
328 : : com::sun::star::uno::XComponentContext >(
329 : : (com::sun::star::uno::Reference<
330 : : com::sun::star::beans::XPropertySet >(
331 : : comphelper::getProcessServiceFactory(),
332 [ # # ][ # # ]: 0 : com::sun::star::uno::UNO_QUERY_THROW)->
[ # # ]
333 : 0 : getPropertyValue("DefaultContext")),
334 : : com::sun::star::uno::UNO_QUERY_THROW),
335 [ # # ][ # # ]: 0 : baseUriReference, uriReference));
[ # # ]
336 [ # # ][ # # ]: 0 : return rel.is() ? rel->getUriReference() : uriReference;
[ # # ]
337 : : }
338 : :
339 : : //============================================================================
340 : : //
341 : : // FindFirstURLInText
342 : : //
343 : : //============================================================================
344 : :
345 : : namespace {
346 : :
347 : 1492 : inline xub_StrLen nextChar(UniString const & rStr, xub_StrLen nPos)
348 : : {
349 : 1492 : return INetMIME::isHighSurrogate(rStr.GetChar(nPos))
350 : 0 : && rStr.Len() - nPos >= 2
351 : 0 : && INetMIME::isLowSurrogate(rStr.GetChar(nPos + 1)) ?
352 [ - + # # : 1492 : nPos + 2 : nPos + 1;
# # ]
353 : : }
354 : :
355 : 1542 : bool isBoundary1(CharClass const & rCharClass, UniString const & rStr,
356 : : xub_StrLen nPos, xub_StrLen nEnd)
357 : : {
358 [ + + ]: 1542 : if (nPos == nEnd)
359 : 16 : return true;
360 [ + + ]: 1526 : if (rCharClass.isLetterNumeric(rStr, nPos))
361 : 1194 : return false;
362 [ + + ]: 332 : switch (rStr.GetChar(nPos))
363 : : {
364 : : case '$':
365 : : case '%':
366 : : case '&':
367 : : case '-':
368 : : case '/':
369 : : case '@':
370 : : case '\\':
371 : 34 : return false;
372 : : default:
373 : 1542 : return true;
374 : : }
375 : : }
376 : :
377 : 1492 : bool isBoundary2(CharClass const & rCharClass, UniString const & rStr,
378 : : xub_StrLen nPos, xub_StrLen nEnd)
379 : : {
380 [ - + ]: 1492 : if (nPos == nEnd)
381 : 0 : return true;
382 [ + + ]: 1492 : if (rCharClass.isLetterNumeric(rStr, nPos))
383 : 1194 : return false;
384 [ + + ]: 298 : switch (rStr.GetChar(nPos))
385 : : {
386 : : case '!':
387 : : case '#':
388 : : case '$':
389 : : case '%':
390 : : case '&':
391 : : case '\'':
392 : : case '*':
393 : : case '+':
394 : : case '-':
395 : : case '/':
396 : : case '=':
397 : : case '?':
398 : : case '@':
399 : : case '^':
400 : : case '_':
401 : : case '`':
402 : : case '{':
403 : : case '|':
404 : : case '}':
405 : : case '~':
406 : 26 : return false;
407 : : default:
408 : 1492 : return true;
409 : : }
410 : : }
411 : :
412 : 442 : bool checkWChar(CharClass const & rCharClass, UniString const & rStr,
413 : : xub_StrLen * pPos, xub_StrLen * pEnd, bool bBackslash = false,
414 : : bool bPipe = false)
415 : : {
416 : 442 : sal_Unicode c = rStr.GetChar(*pPos);
417 [ + - ]: 442 : if (INetMIME::isUSASCII(c))
418 : : {
419 : : static sal_uInt8 const aMap[128]
420 : : = { 0, 0, 0, 0, 0, 0, 0, 0,
421 : : 0, 0, 0, 0, 0, 0, 0, 0,
422 : : 0, 0, 0, 0, 0, 0, 0, 0,
423 : : 0, 0, 0, 0, 0, 0, 0, 0,
424 : : 0, 1, 0, 0, 4, 4, 4, 1, // !"#$%&'
425 : : 1, 1, 1, 1, 1, 4, 1, 4, // ()*+,-./
426 : : 4, 4, 4, 4, 4, 4, 4, 4, // 01234567
427 : : 4, 4, 1, 1, 0, 1, 0, 1, // 89:;<=>?
428 : : 4, 4, 4, 4, 4, 4, 4, 4, // @ABCDEFG
429 : : 4, 4, 4, 4, 4, 4, 4, 4, // HIJKLMNO
430 : : 4, 4, 4, 4, 4, 4, 4, 4, // PQRSTUVW
431 : : 4, 4, 4, 1, 2, 1, 0, 1, // XYZ[\]^_
432 : : 0, 4, 4, 4, 4, 4, 4, 4, // `abcdefg
433 : : 4, 4, 4, 4, 4, 4, 4, 4, // hijklmno
434 : : 4, 4, 4, 4, 4, 4, 4, 4, // pqrstuvw
435 : : 4, 4, 4, 0, 3, 0, 1, 0 }; // xyz{|}~
436 [ + + - + : 442 : switch (aMap[c])
+ ]
437 : : {
438 : : default: // not uric
439 : 8 : return false;
440 : :
441 : : case 1: // uric
442 : 82 : ++(*pPos);
443 : 82 : return true;
444 : :
445 : : case 2: // "\"
446 [ # # ]: 0 : if (bBackslash)
447 : : {
448 : 0 : *pEnd = ++(*pPos);
449 : 0 : return true;
450 : : }
451 : : else
452 : 0 : return false;
453 : :
454 : : case 3: // "|"
455 [ + - ]: 10 : if (bPipe)
456 : : {
457 : 10 : *pEnd = ++(*pPos);
458 : 10 : return true;
459 : : }
460 : : else
461 : 0 : return false;
462 : :
463 : : case 4: // alpha, digit, "$", "%", "&", "-", "/", "@" (see
464 : : // isBoundary1)
465 : 342 : *pEnd = ++(*pPos);
466 : 342 : return true;
467 : : }
468 : : }
469 [ # # ]: 0 : else if (rCharClass.isLetterNumeric(rStr, *pPos))
470 : : {
471 : 0 : *pEnd = *pPos = nextChar(rStr, *pPos);
472 : 0 : return true;
473 : : }
474 : : else
475 : 442 : return false;
476 : : }
477 : :
478 : 270 : sal_uInt32 scanDomain(UniString const & rStr, xub_StrLen * pPos,
479 : : xub_StrLen nEnd)
480 : : {
481 : 270 : sal_Unicode const * pBuffer = rStr.GetBuffer();
482 : 270 : sal_Unicode const * p = pBuffer + *pPos;
483 [ + - ]: 270 : sal_uInt32 nLabels = INetURLObject::scanDomain(p, pBuffer + nEnd, false);
484 : 270 : *pPos = sal::static_int_cast< xub_StrLen >(p - pBuffer);
485 : 270 : return nLabels;
486 : : }
487 : :
488 : : }
489 : :
490 : : rtl::OUString
491 : 144 : URIHelper::FindFirstURLInText(rtl::OUString const & rText,
492 : : xub_StrLen & rBegin,
493 : : xub_StrLen & rEnd,
494 : : CharClass const & rCharClass,
495 : : INetURLObject::EncodeMechanism eMechanism,
496 : : rtl_TextEncoding eCharset,
497 : : INetURLObject::FSysStyle eStyle)
498 : : {
499 [ + - ][ - + ]: 144 : if (!(rBegin <= rEnd && rEnd <= rText.getLength()))
[ - + ]
500 : 0 : return rtl::OUString();
501 : :
502 : : // Search for the first substring of [rBegin..rEnd[ that matches any of the
503 : : // following productions (for which the appropriate style bit is set in
504 : : // eStyle, if applicable).
505 : : //
506 : : // 1st Production (known scheme):
507 : : // \B1 <one of the known schemes, except file> ":" 1*wchar ["#" 1*wchar]
508 : : // \B1
509 : : //
510 : : // 2nd Production (file):
511 : : // \B1 "FILE:" 1*(wchar / "\" / "|") ["#" 1*wchar] \B1
512 : : //
513 : : // 3rd Production (ftp):
514 : : // \B1 "FTP" 2*("." label) ["/" *wchar] ["#" 1*wchar] \B1
515 : : //
516 : : // 4th Production (http):
517 : : // \B1 "WWW" 2*("." label) ["/" *wchar] ["#" 1*wchar] \B1
518 : : //
519 : : // 5th Production (mailto):
520 : : // \B2 local-part "@" domain \B1
521 : : //
522 : : // 6th Production (UNC file):
523 : : // \B1 "\\" domain "\" *(wchar / "\") \B1
524 : : //
525 : : // 7th Production (DOS file):
526 : : // \B1 ALPHA ":\" *(wchar / "\") \B1
527 : : //
528 : : // 8th Production (Unix-like DOS file):
529 : : // \B1 ALPHA ":/" *(wchar / "\") \B1
530 : : //
531 : : // The productions use the following auxiliary rules.
532 : : //
533 : : // local-part = atom *("." atom)
534 : : // atom = 1*(alphanum / "!" / "#" / "$" / "%" / "&" / "'" / "*" / "+"
535 : : // / "-" / "/" / "=" / "?" / "^" / "_" / "`" / "{" / "|" / "}"
536 : : // / "~")
537 : : // domain = label *("." label)
538 : : // label = alphanum [*(alphanum / "-") alphanum]
539 : : // alphanum = ALPHA / DIGIT
540 : : // wchar = <any uric character (ignoring the escaped rule), or "%", or
541 : : // a letter or digit (according to rCharClass)>
542 : : //
543 : : // "\B1" (boundary 1) stands for the beginning or end of the block of text,
544 : : // or a character that is neither (a) a letter or digit (according to
545 : : // rCharClass), nor (b) any of "$", "%", "&", "-", "/", "@", or "\".
546 : : // (FIXME: What was the rationale for this set of punctuation characters?)
547 : : //
548 : : // "\B2" (boundary 2) stands for the beginning or end of the block of text,
549 : : // or a character that is neither (a) a letter or digit (according to
550 : : // rCharClass), nor (b) any of "!", "#", "$", "%", "&", "'", "*", "+", "-",
551 : : // "/", "=", "?", "@", "^", "_", "`", "{", "|", "}", or "~" (i.e., an RFC
552 : : // 822 <atom> character, or "@" from \B1's set above).
553 : : //
554 : : // Productions 1--4, and 6--8 try to find a maximum-length match, but they
555 : : // stop at the first <wchar> character that is a "\B1" character which is
556 : : // only followed by "\B1" characters (taking "\" and "|" characters into
557 : : // account appropriately). Production 5 simply tries to find a maximum-
558 : : // length match.
559 : : //
560 : : // Productions 1--4 use the given eMechanism and eCharset. Productions 5--9
561 : : // use ENCODE_ALL.
562 : : //
563 : : // Productions 6--9 are only applicable if the FSYS_DOS bit is set in
564 : : // eStyle.
565 : :
566 : 144 : bool bBoundary1 = true;
567 : 144 : bool bBoundary2 = true;
568 [ + + ]: 1636 : for (xub_StrLen nPos = rBegin; nPos != rEnd; nPos = nextChar(rText, nPos))
569 : : {
570 : 1532 : sal_Unicode c = rText[nPos];
571 [ + + ]: 1532 : if (bBoundary1)
572 : : {
573 [ + + ]: 324 : if (INetMIME::isAlpha(c))
574 : : {
575 : 268 : xub_StrLen i = nPos;
576 : : INetProtocol eScheme
577 : : = INetURLObject::CompareProtocolScheme(UniString(rText, i,
578 [ + - ][ + - ]: 268 : rEnd));
[ + - ][ + - ]
[ + - ][ + - ]
579 [ + + ]: 268 : if (eScheme == INET_PROT_FILE) // 2nd
580 : : {
581 [ + + ]: 50 : while (rText[i++] != ':') ;
582 : 10 : xub_StrLen nPrefixEnd = i;
583 : 10 : xub_StrLen nUriEnd = i;
584 [ + + ][ + + ]: 156 : while (i != rEnd
[ + + ]
585 : : && checkWChar(rCharClass, rText, &i, &nUriEnd, true,
586 [ + - ][ + - ]: 146 : true)) ;
[ + + ][ + - ]
[ # # ]
587 [ + + ][ + + ]: 10 : if (i != nPrefixEnd && rText[i] == '#')
[ + + ]
588 : : {
589 : 4 : ++i;
590 [ + + ][ + - ]: 40 : while (i != rEnd
[ + + ]
591 [ + - ][ + - ]: 36 : && checkWChar(rCharClass, rText, &i, &nUriEnd)) ;
[ + + ][ + - ]
[ # # ]
592 : : }
593 [ + + ][ + - ]: 28 : if (nUriEnd != nPrefixEnd
[ + + ]
594 [ + - ][ + - ]: 18 : && isBoundary1(rCharClass, rText, nUriEnd, rEnd))
[ + + ][ + - ]
[ # # ]
595 : : {
596 : : INetURLObject aUri(UniString(rText, nPos,
597 : : nUriEnd - nPos),
598 : : INET_PROT_FILE, eMechanism, eCharset,
599 [ + - ][ + - ]: 8 : eStyle);
[ + - ][ + - ]
[ + - ][ + - ]
600 [ + - ]: 8 : if (!aUri.HasError())
601 : : {
602 : 8 : rBegin = nPos;
603 : 8 : rEnd = nUriEnd;
604 : : return
605 [ + - ]: 8 : aUri.GetMainURL(INetURLObject::DECODE_TO_IURI);
606 [ + - ][ - + ]: 10 : }
607 : : }
608 : : }
609 [ + + ]: 258 : else if (eScheme != INET_PROT_NOT_VALID) // 1st
610 : : {
611 [ + + ]: 1028 : while (rText[i++] != ':') ;
612 : 100 : xub_StrLen nPrefixEnd = i;
613 : 100 : xub_StrLen nUriEnd = i;
614 [ + + ][ + - ]: 744 : while (i != rEnd
[ + + ]
615 [ + - ][ + - ]: 644 : && checkWChar(rCharClass, rText, &i, &nUriEnd)) ;
[ + + ][ + - ]
[ # # ]
616 [ + + ][ - + ]: 100 : if (i != nPrefixEnd && rText[i] == '#')
[ - + ]
617 : : {
618 : 0 : ++i;
619 [ # # ][ # # ]: 0 : while (i != rEnd
[ # # ]
620 [ # # ][ # # ]: 0 : && checkWChar(rCharClass, rText, &i, &nUriEnd)) ;
[ # # ][ # # ]
[ # # ]
621 : : }
622 [ + + ]: 210 : if (nUriEnd != nPrefixEnd
[ - + # # ]
[ + + ]
623 [ + - ][ + - ]: 110 : && (isBoundary1(rCharClass, rText, nUriEnd, rEnd)
[ + + ][ + - ]
[ # # ]
624 : 0 : || rText[nUriEnd] == '\\'))
625 : : {
626 : : INetURLObject aUri(UniString(rText, nPos,
627 : : nUriEnd - nPos),
628 : : INET_PROT_HTTP, eMechanism,
629 [ + - ][ + - ]: 10 : eCharset);
[ + - ][ + - ]
[ + - ][ + - ]
630 [ + + ]: 10 : if (!aUri.HasError())
631 : : {
632 : 8 : rBegin = nPos;
633 : 8 : rEnd = nUriEnd;
634 : : return
635 [ + - ]: 10 : aUri.GetMainURL(INetURLObject::DECODE_TO_IURI);
636 [ + - ][ + + ]: 100 : }
637 : : }
638 : : }
639 : :
640 : : // 3rd, 4th:
641 : 252 : i = nPos;
642 [ + - ][ + - ]: 252 : sal_uInt32 nLabels = scanDomain(rText, &i, rEnd);
[ + - ]
643 [ + + + + : 522 : if (nLabels >= 3
+ + - + +
+ + - + +
- + + + +
+ - + # #
- + # # ]
[ + + ]
644 : 56 : && rText[nPos + 3] == '.'
645 : 52 : && (((rText[nPos] == 'w'
646 : 48 : || rText[nPos] == 'W')
647 : 4 : && (rText[nPos + 1] == 'w'
648 : 2 : || rText[nPos + 1] == 'W')
649 : 4 : && (rText[nPos + 2] == 'w'
650 : 2 : || rText[nPos + 2] == 'W'))
651 : 48 : || ((rText[nPos] == 'f'
652 : 46 : || rText[nPos] == 'F')
653 : 4 : && (rText[nPos + 1] == 't'
654 : 0 : || rText[nPos + 1] == 'T')
655 : 4 : && (rText[nPos + 2] == 'p'
656 : 0 : || rText[nPos + 2] == 'P'))))
657 : : // (note that rText.GetChar(nPos + 3) is guaranteed to be
658 : : // valid)
659 : : {
660 : 8 : xub_StrLen nUriEnd = i;
661 [ + - ][ + + ]: 8 : if (i != rEnd && rText[i] == '/')
[ + + ]
662 : : {
663 : 4 : nUriEnd = ++i;
664 [ + + ][ + - ]: 56 : while (i != rEnd
[ + + ]
665 [ + - ][ + - ]: 52 : && checkWChar(rCharClass, rText, &i, &nUriEnd)) ;
[ + + ][ + - ]
[ # # ]
666 : : }
667 [ + + ][ - + ]: 8 : if (i != rEnd && rText[i] == '#')
[ - + ]
668 : : {
669 : 0 : ++i;
670 [ # # ][ # # ]: 0 : while (i != rEnd
[ # # ]
671 [ # # ][ # # ]: 0 : && checkWChar(rCharClass, rText, &i, &nUriEnd)) ;
[ # # ][ # # ]
[ # # ]
672 : : }
673 [ + - ][ + - ]: 8 : if (isBoundary1(rCharClass, rText, nUriEnd, rEnd)
[ - + # # ]
[ + - ][ + - ]
[ + - # # ]
674 : 0 : || rText[nUriEnd] == '\\')
675 : : {
676 : : INetURLObject aUri(UniString(rText, nPos,
677 : : nUriEnd - nPos),
678 : : INET_PROT_HTTP, eMechanism,
679 [ + - ][ + - ]: 8 : eCharset);
[ + - ][ + - ]
[ + - ][ + - ]
680 [ + - ]: 8 : if (!aUri.HasError())
681 : : {
682 : 8 : rBegin = nPos;
683 : 8 : rEnd = nUriEnd;
684 : : return
685 [ + - ]: 8 : aUri.GetMainURL(INetURLObject::DECODE_TO_IURI);
686 [ + - ][ - + ]: 8 : }
687 : : }
688 : : }
689 : :
690 [ + - ][ + + : 494 : if ((eStyle & INetURLObject::FSYS_DOS) != 0 && rEnd - nPos >= 3
+ + + + +
- ][ + + ]
691 : 242 : && rText[nPos + 1] == ':'
692 : 6 : && (rText[nPos + 2] == '/'
693 : 2 : || rText[nPos + 2] == '\\')) // 7th, 8th
694 : : {
695 : 6 : i = nPos + 3;
696 : 6 : xub_StrLen nUriEnd = i;
697 [ + + ][ + + ]: 84 : while (i != rEnd
[ + + ]
698 [ + - ][ + - ]: 78 : && checkWChar(rCharClass, rText, &i, &nUriEnd)) ;
[ + + ][ + - ]
[ # # ]
699 [ + - ][ + - ]: 6 : if (isBoundary1(rCharClass, rText, nUriEnd, rEnd))
[ + - ][ + - ]
700 : : {
701 : : INetURLObject aUri(UniString(rText, nPos,
702 : : nUriEnd - nPos),
703 : : INET_PROT_FILE,
704 : : INetURLObject::ENCODE_ALL,
705 : : RTL_TEXTENCODING_UTF8,
706 [ + - ][ + - ]: 6 : INetURLObject::FSYS_DOS);
[ + - ][ + - ]
[ + - ][ + - ]
707 [ + - ]: 6 : if (!aUri.HasError())
708 : : {
709 : 6 : rBegin = nPos;
710 : 6 : rEnd = nUriEnd;
711 : : return
712 [ + - ]: 6 : aUri.GetMainURL(INetURLObject::DECODE_TO_IURI);
713 [ + - ][ - + ]: 268 : }
714 : : }
715 : : }
716 : : }
717 [ + - ][ + + : 110 : else if ((eStyle & INetURLObject::FSYS_DOS) != 0 && rEnd - nPos >= 2
+ + + + ]
[ + + ]
718 : 48 : && rText[nPos] == '\\'
719 : 6 : && rText[nPos + 1] == '\\') // 6th
720 : : {
721 : 2 : xub_StrLen i = nPos + 2;
722 [ + - ][ + - ]: 2 : sal_uInt32 nLabels = scanDomain(rText, &i, rEnd);
[ + - ]
723 [ + - ][ + - ]: 2 : if (nLabels >= 1 && i != rEnd && rText[i] == '\\')
[ + - ][ + - ]
724 : : {
725 : 2 : xub_StrLen nUriEnd = ++i;
726 [ + + ][ + - ]: 48 : while (i != rEnd
[ + + ]
727 : : && checkWChar(rCharClass, rText, &i, &nUriEnd,
728 [ + - ][ + - ]: 46 : true)) ;
[ + + ][ + - ]
[ # # ]
729 [ + - ][ + - ]: 2 : if (isBoundary1(rCharClass, rText, nUriEnd, rEnd))
[ + - ][ + - ]
730 : : {
731 : : INetURLObject aUri(UniString(rText, nPos,
732 : : nUriEnd - nPos),
733 : : INET_PROT_FILE,
734 : : INetURLObject::ENCODE_ALL,
735 : : RTL_TEXTENCODING_UTF8,
736 [ + - ][ + - ]: 2 : INetURLObject::FSYS_DOS);
[ + - ][ + - ]
[ + - ][ + - ]
737 [ + - ]: 2 : if (!aUri.HasError())
738 : : {
739 : 2 : rBegin = nPos;
740 : 2 : rEnd = nUriEnd;
741 : : return
742 [ + - ]: 2 : aUri.GetMainURL(INetURLObject::DECODE_TO_IURI);
743 [ + - ][ - + ]: 2 : }
744 : : }
745 : : }
746 : : }
747 : : }
748 [ + + ][ + + ]: 1500 : if (bBoundary2 && INetMIME::isAtomChar(c)) // 5th
[ + + ]
749 : : {
750 : 266 : bool bDot = false;
751 [ + + ]: 2472 : for (xub_StrLen i = nPos + 1; i != rEnd; ++i)
752 : : {
753 : 2214 : sal_Unicode c2 = rText[i];
754 [ + + ][ + - ]: 2214 : if (INetMIME::isAtomChar(c2))
755 : 1760 : bDot = false;
756 [ + + ]: 454 : else if (bDot)
757 : 12 : break;
758 [ + + ]: 442 : else if (c2 == '.')
759 : 216 : bDot = true;
760 : : else
761 : : {
762 [ + + ]: 226 : if (c2 == '@')
763 : : {
764 : 16 : ++i;
765 [ + - ][ + - ]: 16 : sal_uInt32 nLabels = scanDomain(rText, &i, rEnd);
[ + - ]
766 [ + - ][ + + ]: 48 : if (nLabels >= 1
[ + + ]
767 [ + - ][ + - ]: 32 : && isBoundary1(rCharClass, rText, i, rEnd))
[ + - ][ + - ]
[ # # ]
768 : : {
769 : : INetURLObject aUri(UniString(rText, nPos, i - nPos),
770 : : INET_PROT_MAILTO,
771 [ + - ][ + - ]: 8 : INetURLObject::ENCODE_ALL);
[ + - ][ + - ]
[ + - ][ + - ]
772 [ + - ]: 8 : if (!aUri.HasError())
773 : : {
774 : 8 : rBegin = nPos;
775 : 8 : rEnd = i;
776 : : return aUri.GetMainURL(
777 [ + - ]: 8 : INetURLObject::DECODE_TO_IURI);
778 [ + - ][ - + ]: 8 : }
779 : : }
780 : : }
781 : 218 : break;
782 : : }
783 : : }
784 : : }
785 [ + - ]: 1492 : bBoundary1 = isBoundary1(rCharClass, rText, nPos, rEnd);
786 [ + - ]: 1492 : bBoundary2 = isBoundary2(rCharClass, rText, nPos, rEnd);
787 : : }
788 : 104 : rBegin = rEnd;
789 : 144 : return rtl::OUString();
790 : : }
791 : :
792 : : //============================================================================
793 : : //
794 : : // removePassword
795 : : //
796 : : //============================================================================
797 : :
798 : : rtl::OUString
799 : 54 : URIHelper::removePassword(rtl::OUString const & rURI,
800 : : INetURLObject::EncodeMechanism eEncodeMechanism,
801 : : INetURLObject::DecodeMechanism eDecodeMechanism,
802 : : rtl_TextEncoding eCharset)
803 : : {
804 [ + - ]: 54 : INetURLObject aObj(rURI, eEncodeMechanism, eCharset);
805 : 54 : return aObj.HasError() ?
806 : : rURI :
807 [ + - ][ + - ]: 54 : aObj.GetURLNoPass(eDecodeMechanism, eCharset);
[ + + ]
808 : : }
809 : :
810 : : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|