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 <sal/config.h>
21 :
22 : #include <algorithm>
23 : #include <cassert>
24 : #include <cstdlib>
25 : #include <exception>
26 : #include <vector>
27 :
28 : #include <boost/noncopyable.hpp>
29 : #include <com/sun/star/lang/WrappedTargetRuntimeException.hpp>
30 : #include <com/sun/star/lang/XMultiComponentFactory.hpp>
31 : #include <com/sun/star/lang/XServiceInfo.hpp>
32 : #include <com/sun/star/uno/Any.hxx>
33 : #include <com/sun/star/uno/Exception.hpp>
34 : #include <com/sun/star/uno/Reference.hxx>
35 : #include <com/sun/star/uno/RuntimeException.hpp>
36 : #include <com/sun/star/uno/Sequence.hxx>
37 : #include <com/sun/star/uno/XComponentContext.hpp>
38 : #include <com/sun/star/uno/XInterface.hpp>
39 : #include <com/sun/star/uri/RelativeUriExcessParentSegments.hpp>
40 : #include <com/sun/star/uri/XUriReference.hpp>
41 : #include <com/sun/star/uri/XUriReferenceFactory.hpp>
42 : #include <com/sun/star/uri/XUriSchemeParser.hpp>
43 : #include <cppuhelper/implbase1.hxx>
44 : #include <cppuhelper/implbase2.hxx>
45 : #include <cppuhelper/supportsservice.hxx>
46 : #include <cppuhelper/weak.hxx>
47 : #include <rtl/character.hxx>
48 : #include <rtl/ustrbuf.hxx>
49 : #include <rtl/ustring.hxx>
50 : #include <sal/types.h>
51 :
52 : #include "UriReference.hxx"
53 :
54 : namespace {
55 :
56 101 : bool equalIgnoreEscapeCase(OUString const & s1, OUString const & s2) {
57 101 : if (s1.getLength() == s2.getLength()) {
58 281 : for (sal_Int32 i = 0; i < s1.getLength();) {
59 288 : if (s1[i] == '%' && s2[i] == '%' && s1.getLength() - i > 2
60 0 : && rtl::isAsciiHexDigit(s1[i + 1])
61 0 : && rtl::isAsciiHexDigit(s1[i + 2])
62 0 : && rtl::isAsciiHexDigit(s2[i + 1])
63 0 : && rtl::isAsciiHexDigit(s2[i + 2])
64 0 : && rtl::compareIgnoreAsciiCase(s1[i + 1], s2[i + 1]) == 0
65 144 : && rtl::compareIgnoreAsciiCase(s1[i + 2], s2[i + 2]) == 0)
66 : {
67 0 : i += 3;
68 144 : } else if (s1[i] != s2[i]) {
69 1 : return false;
70 : } else {
71 143 : ++i;
72 : }
73 : }
74 68 : return true;
75 : } else {
76 32 : return false;
77 : }
78 : }
79 :
80 202144 : sal_Int32 parseScheme(OUString const & uriReference) {
81 202144 : if (uriReference.getLength() >= 2 && rtl::isAsciiAlpha(uriReference[0])) {
82 2046798 : for (sal_Int32 i = 0; i < uriReference.getLength(); ++i) {
83 2037043 : sal_Unicode c = uriReference[i];
84 2037043 : if (c == ':') {
85 181902 : return i;
86 3927206 : } else if (!rtl::isAsciiAlpha(c) && !rtl::isAsciiDigit(c)
87 2064243 : && c != '+' && c != '-' && c != '.')
88 : {
89 9370 : break;
90 : }
91 : }
92 : }
93 20242 : return -1;
94 : }
95 :
96 : class UriReference:
97 : public cppu::WeakImplHelper1<css::uri::XUriReference>,
98 : private boost::noncopyable
99 : {
100 : public:
101 138984 : UriReference(
102 : OUString const & scheme, bool bIsHierarchical, bool bHasAuthority,
103 : OUString const & authority, OUString const & path,
104 : bool bHasQuery, OUString const & query):
105 : m_base(
106 : scheme, bIsHierarchical, bHasAuthority, authority, path, bHasQuery,
107 138984 : query)
108 138984 : {}
109 :
110 7966 : virtual OUString SAL_CALL getUriReference()
111 : throw (css::uno::RuntimeException, std::exception) SAL_OVERRIDE
112 7966 : { return m_base.getUriReference(); }
113 :
114 40584 : virtual sal_Bool SAL_CALL isAbsolute()
115 : throw (css::uno::RuntimeException, std::exception) SAL_OVERRIDE
116 40584 : { return m_base.isAbsolute(); }
117 :
118 20362 : virtual OUString SAL_CALL getScheme()
119 : throw (css::uno::RuntimeException, std::exception) SAL_OVERRIDE
120 20362 : { return m_base.getScheme(); }
121 :
122 0 : virtual OUString SAL_CALL getSchemeSpecificPart()
123 : throw (css::uno::RuntimeException, std::exception) SAL_OVERRIDE
124 0 : { return m_base.getSchemeSpecificPart(); }
125 :
126 20308 : virtual sal_Bool SAL_CALL isHierarchical()
127 : throw (css::uno::RuntimeException, std::exception) SAL_OVERRIDE
128 20308 : { return m_base.isHierarchical(); }
129 :
130 60614 : virtual sal_Bool SAL_CALL hasAuthority()
131 : throw (css::uno::RuntimeException, std::exception) SAL_OVERRIDE
132 60614 : { return m_base.hasAuthority(); }
133 :
134 20250 : virtual OUString SAL_CALL getAuthority()
135 : throw (css::uno::RuntimeException, std::exception) SAL_OVERRIDE
136 20250 : { return m_base.getAuthority(); }
137 :
138 60279 : virtual OUString SAL_CALL getPath()
139 : throw (css::uno::RuntimeException, std::exception) SAL_OVERRIDE
140 60279 : { return m_base.getPath(); }
141 :
142 20194 : virtual sal_Bool SAL_CALL hasRelativePath()
143 : throw (css::uno::RuntimeException, std::exception) SAL_OVERRIDE
144 20194 : { return m_base.hasRelativePath(); }
145 :
146 40886 : virtual sal_Int32 SAL_CALL getPathSegmentCount()
147 : throw (css::uno::RuntimeException, std::exception) SAL_OVERRIDE
148 40886 : { return m_base.getPathSegmentCount(); }
149 :
150 106712 : virtual OUString SAL_CALL getPathSegment(sal_Int32 index)
151 : throw (css::uno::RuntimeException, std::exception) SAL_OVERRIDE
152 106712 : { return m_base.getPathSegment(index); }
153 :
154 20225 : virtual sal_Bool SAL_CALL hasQuery()
155 : throw (css::uno::RuntimeException, std::exception) SAL_OVERRIDE
156 20225 : { return m_base.hasQuery(); }
157 :
158 8 : virtual OUString SAL_CALL getQuery()
159 : throw (css::uno::RuntimeException, std::exception) SAL_OVERRIDE
160 8 : { return m_base.getQuery(); }
161 :
162 20222 : virtual sal_Bool SAL_CALL hasFragment()
163 : throw (css::uno::RuntimeException, std::exception) SAL_OVERRIDE
164 20222 : { return m_base.hasFragment(); }
165 :
166 5 : virtual OUString SAL_CALL getFragment()
167 : throw (css::uno::RuntimeException, std::exception) SAL_OVERRIDE
168 5 : { return m_base.getFragment(); }
169 :
170 12 : virtual void SAL_CALL setFragment(OUString const & fragment)
171 : throw (css::uno::RuntimeException, std::exception) SAL_OVERRIDE
172 12 : { m_base.setFragment(fragment); }
173 :
174 7438 : virtual void SAL_CALL clearFragment()
175 : throw (css::uno::RuntimeException, std::exception) SAL_OVERRIDE
176 7438 : { m_base.clearFragment(); }
177 :
178 : private:
179 277968 : virtual ~UriReference() {}
180 :
181 : stoc::uriproc::UriReference m_base;
182 : };
183 :
184 138984 : css::uno::Reference< css::uri::XUriReference > parseGeneric(
185 : OUString const & scheme, OUString const & schemeSpecificPart)
186 : {
187 138984 : bool isAbsolute = !scheme.isEmpty();
188 138984 : bool isHierarchical = !isAbsolute || schemeSpecificPart.startsWith("/");
189 138984 : bool hasAuthority = false;
190 138984 : OUString authority;
191 277968 : OUString path;
192 138984 : bool hasQuery = false;
193 277968 : OUString query;
194 138984 : if (isHierarchical) {
195 138952 : sal_Int32 len = schemeSpecificPart.getLength();
196 138952 : sal_Int32 i = 0;
197 416848 : if (len - i >= 2 && schemeSpecificPart[i] == '/'
198 257688 : && schemeSpecificPart[i + 1] == '/')
199 : {
200 118686 : i += 2;
201 118686 : sal_Int32 n = i;
202 356620 : while (i < len && schemeSpecificPart[i] != '/'
203 119248 : && schemeSpecificPart[i] != '?') {
204 281 : ++i;
205 : }
206 118686 : hasAuthority = true;
207 118686 : authority = schemeSpecificPart.copy(n, i - n);
208 : }
209 138952 : sal_Int32 n = i;
210 138952 : i = schemeSpecificPart.indexOf('?', i);
211 138952 : if (i == -1) {
212 138946 : i = len;
213 : }
214 138952 : path = schemeSpecificPart.copy(n, i - n);
215 138952 : if (i != len) {
216 6 : hasQuery = true;
217 6 : query = schemeSpecificPart.copy(i + 1);
218 : }
219 : } else {
220 32 : if (schemeSpecificPart.isEmpty()) {
221 : // The scheme-specific part of an opaque URI must not be empty:
222 0 : return 0;
223 : }
224 32 : path = schemeSpecificPart;
225 : }
226 : return new UriReference(
227 277968 : scheme, isHierarchical, hasAuthority, authority, path, hasQuery, query);
228 : }
229 :
230 : typedef std::vector< sal_Int32 > Segments;
231 :
232 40356 : void processSegments(
233 : Segments & segments,
234 : css::uno::Reference< css::uri::XUriReference > const & uriReference,
235 : bool base, bool processSpecialSegments)
236 : {
237 40356 : sal_Int32 count = uriReference->getPathSegmentCount() - (base ? 1 : 0);
238 : assert(count <= SAL_MAX_INT32 - 1 && -count >= SAL_MIN_INT32 + 1);
239 94509 : for (sal_Int32 i = 0; i < count; ++i) {
240 54153 : if (processSpecialSegments) {
241 54153 : OUString segment(uriReference->getPathSegment(i));
242 54153 : if ( segment == "." ) {
243 0 : if (!base && i == count - 1) {
244 0 : segments.push_back(0);
245 : }
246 0 : continue;
247 54153 : } else if ( segment == ".." ) {
248 1074 : if (segments.empty() || std::abs(segments.back()) == 1) {
249 0 : segments.push_back(base ? -1 : 1);
250 : } else {
251 1074 : segments.pop_back();
252 : }
253 1074 : continue;
254 53079 : }
255 : }
256 53079 : segments.push_back(base ? -(i + 2) : i + 2);
257 : }
258 40356 : }
259 :
260 : class Factory:
261 : public cppu::WeakImplHelper2<
262 : css::lang::XServiceInfo, css::uri::XUriReferenceFactory>,
263 : private boost::noncopyable
264 : {
265 : public:
266 130279 : explicit Factory(
267 : css::uno::Reference< css::uno::XComponentContext > const & context):
268 130279 : m_context(context) {}
269 :
270 : virtual OUString SAL_CALL getImplementationName()
271 : throw (css::uno::RuntimeException, std::exception) SAL_OVERRIDE;
272 :
273 : virtual sal_Bool SAL_CALL supportsService(OUString const & serviceName)
274 : throw (css::uno::RuntimeException, std::exception) SAL_OVERRIDE;
275 :
276 : virtual css::uno::Sequence< OUString > SAL_CALL
277 : getSupportedServiceNames() throw (css::uno::RuntimeException, std::exception) SAL_OVERRIDE;
278 :
279 : virtual css::uno::Reference< css::uri::XUriReference > SAL_CALL
280 : parse(OUString const & uriReference)
281 : throw (css::uno::RuntimeException, std::exception) SAL_OVERRIDE;
282 :
283 : virtual css::uno::Reference< css::uri::XUriReference > SAL_CALL
284 : makeAbsolute(
285 : css::uno::Reference< css::uri::XUriReference > const & baseUriReference,
286 : css::uno::Reference< css::uri::XUriReference > const & uriReference,
287 : sal_Bool processSpecialBaseSegments,
288 : css::uri::RelativeUriExcessParentSegments excessParentSegments)
289 : throw (css::uno::RuntimeException, std::exception) SAL_OVERRIDE;
290 :
291 : virtual css::uno::Reference< css::uri::XUriReference > SAL_CALL
292 : makeRelative(
293 : css::uno::Reference< css::uri::XUriReference > const & baseUriReference,
294 : css::uno::Reference< css::uri::XUriReference > const & uriReference,
295 : sal_Bool preferAuthorityOverRelativePath,
296 : sal_Bool preferAbsoluteOverRelativePath,
297 : sal_Bool encodeRetainedSpecialSegments)
298 : throw (css::uno::RuntimeException, std::exception) SAL_OVERRIDE;
299 :
300 : private:
301 260558 : virtual ~Factory() {}
302 :
303 22 : css::uno::Reference< css::uri::XUriReference > clone(
304 : css::uno::Reference< css::uri::XUriReference > const & uriReference)
305 22 : { return parse(uriReference->getUriReference()); }
306 :
307 : css::uno::Reference< css::uno::XComponentContext > m_context;
308 : };
309 :
310 1 : OUString Factory::getImplementationName()
311 : throw (css::uno::RuntimeException, std::exception)
312 : {
313 1 : return OUString("com.sun.star.comp.uri.UriReferenceFactory");
314 : }
315 :
316 0 : sal_Bool Factory::supportsService(OUString const & serviceName)
317 : throw (css::uno::RuntimeException, std::exception)
318 : {
319 0 : return cppu::supportsService(this, serviceName);
320 : }
321 :
322 1 : css::uno::Sequence< OUString > Factory::getSupportedServiceNames()
323 : throw (css::uno::RuntimeException, std::exception)
324 : {
325 1 : css::uno::Sequence< OUString > s(1);
326 1 : s[0] = "com.sun.star.uri.UriReferenceFactory";
327 1 : return s;
328 : }
329 :
330 202138 : css::uno::Reference< css::uri::XUriReference > Factory::parse(
331 : OUString const & uriReference)
332 : throw (css::uno::RuntimeException, std::exception)
333 : {
334 202138 : sal_Int32 fragment = uriReference.indexOf('#');
335 202138 : if (fragment == -1) {
336 202126 : fragment = uriReference.getLength();
337 : }
338 202138 : OUString scheme;
339 404276 : OUString schemeSpecificPart;
340 404276 : OUString serviceName;
341 202138 : sal_Int32 n = parseScheme(uriReference);
342 : assert(n < fragment);
343 202138 : if (n >= 0) {
344 181902 : scheme = uriReference.copy(0, n);
345 181902 : schemeSpecificPart = uriReference.copy(n + 1, fragment - (n + 1));
346 181902 : OUStringBuffer buf;
347 181902 : buf.append("com.sun.star.uri.UriSchemeParser_");
348 1856856 : for (sal_Int32 i = 0; i < scheme.getLength(); ++i) {
349 1674954 : sal_Unicode c = scheme[i];
350 1674954 : if (rtl::isAsciiUpperCase(c)) {
351 58 : buf.append(static_cast<sal_Unicode>(rtl::toAsciiLowerCase(c)));
352 1674896 : } else if (c == '+') {
353 0 : buf.append("PLUS");
354 1674896 : } else if (c == '-') {
355 0 : buf.append("HYPHEN");
356 1674896 : } else if (c == '.') {
357 189462 : buf.append("DOT");
358 : } else {
359 : assert(rtl::isAsciiLowerCase(c) || rtl::isAsciiDigit(c));
360 1485434 : buf.append(c);
361 : }
362 : }
363 181902 : serviceName = buf.makeStringAndClear();
364 : } else {
365 20236 : schemeSpecificPart = uriReference.copy(0, fragment);
366 : }
367 404276 : css::uno::Reference< css::uri::XUriSchemeParser > parser;
368 202138 : if (!serviceName.isEmpty()) {
369 : css::uno::Reference< css::lang::XMultiComponentFactory > factory(
370 181902 : m_context->getServiceManager());
371 181902 : if (factory.is()) {
372 181902 : css::uno::Reference< css::uno::XInterface > service;
373 : try {
374 545706 : service = factory->createInstanceWithContext(
375 363804 : serviceName, m_context);
376 0 : } catch (css::uno::RuntimeException &) {
377 0 : throw;
378 0 : } catch (const css::uno::Exception & e) {
379 : throw css::lang::WrappedTargetRuntimeException(
380 0 : "creating service " + serviceName,
381 : static_cast< cppu::OWeakObject * >(this),
382 0 : css::uno::makeAny(e)); //TODO: preserve type of e
383 : }
384 181902 : if (service.is()) {
385 126308 : parser = css::uno::Reference< css::uri::XUriSchemeParser >(
386 63154 : service, css::uno::UNO_QUERY_THROW);
387 181902 : }
388 181902 : }
389 : }
390 : css::uno::Reference< css::uri::XUriReference > uriRef(
391 202138 : parser.is()
392 63154 : ? parser->parse(scheme, schemeSpecificPart)
393 265292 : : parseGeneric(scheme, schemeSpecificPart));
394 202138 : if (uriRef.is() && fragment != uriReference.getLength()) {
395 12 : uriRef->setFragment(uriReference.copy(fragment + 1));
396 : }
397 404276 : return uriRef;
398 : }
399 :
400 20178 : css::uno::Reference< css::uri::XUriReference > Factory::makeAbsolute(
401 : css::uno::Reference< css::uri::XUriReference > const & baseUriReference,
402 : css::uno::Reference< css::uri::XUriReference > const & uriReference,
403 : sal_Bool processSpecialBaseSegments,
404 : css::uri::RelativeUriExcessParentSegments excessParentSegments)
405 : throw (css::uno::RuntimeException, std::exception)
406 : {
407 60534 : if (!baseUriReference.is() || !baseUriReference->isAbsolute()
408 40356 : || !baseUriReference->isHierarchical() || !uriReference.is()) {
409 0 : return 0;
410 20178 : } else if (uriReference->isAbsolute()) {
411 0 : return clone(uriReference);
412 60534 : } else if (!uriReference->hasAuthority()
413 60534 : && uriReference->getPath().isEmpty()
414 40356 : && !uriReference->hasQuery()) {
415 : css::uno::Reference< css::uri::XUriReference > abs(
416 0 : clone(baseUriReference));
417 0 : if (uriReference->hasFragment()) {
418 0 : abs->setFragment(uriReference->getFragment());
419 : } else {
420 0 : abs->clearFragment();
421 : }
422 0 : return abs;
423 : } else {
424 20178 : OUStringBuffer abs(baseUriReference->getScheme());
425 20178 : abs.append(':');
426 20178 : if (uriReference->hasAuthority()) {
427 0 : abs.append("//");
428 0 : abs.append(uriReference->getAuthority());
429 20178 : } else if (baseUriReference->hasAuthority()) {
430 20178 : abs.append("//");
431 20178 : abs.append(baseUriReference->getAuthority());
432 : }
433 20178 : if (uriReference->hasRelativePath()) {
434 20178 : Segments segments;
435 : processSegments(
436 20178 : segments, baseUriReference, true, processSpecialBaseSegments);
437 20178 : processSegments(segments, uriReference, false, true);
438 : // If the path component of the base URI reference is empty (which
439 : // implies that the base URI reference denotes a "root entity"), and
440 : // the resulting URI reference denotes the same root entity, make
441 : // sure the path component of the resulting URI reference is also
442 : // empty (and not "/"). RFC 2396 is unclear about this, and I chose
443 : // these rules for consistent results.
444 20178 : bool slash = !baseUriReference->getPath().isEmpty();
445 20178 : if (slash) {
446 20178 : abs.append('/');
447 : }
448 72183 : for (Segments::iterator i(segments.begin()); i != segments.end();
449 : ++i)
450 : {
451 52005 : if (*i < -1) {
452 : OUString segment(
453 21382 : baseUriReference->getPathSegment(-(*i + 2)));
454 21382 : if (!segment.isEmpty() || segments.size() > 1) {
455 21382 : if (!slash) {
456 0 : abs.append('/');
457 : }
458 21382 : abs.append(segment);
459 21382 : slash = true;
460 21382 : abs.append('/');
461 21382 : }
462 30623 : } else if (*i > 1) {
463 30623 : OUString segment(uriReference->getPathSegment(*i - 2));
464 30623 : if (!segment.isEmpty() || segments.size() > 1) {
465 30623 : if (!slash) {
466 10445 : abs.append('/');
467 : }
468 30623 : abs.append(segment);
469 30623 : slash = false;
470 30623 : }
471 0 : } else if (*i == 0) {
472 0 : if (segments.size() > 1 && !slash) {
473 0 : abs.append('/');
474 : }
475 : } else {
476 0 : switch (excessParentSegments) {
477 : case css::uri::RelativeUriExcessParentSegments_ERROR:
478 0 : return 0;
479 :
480 : case css::uri::RelativeUriExcessParentSegments_RETAIN:
481 0 : if (!slash) {
482 0 : abs.append('/');
483 : }
484 0 : abs.append("..");
485 0 : slash = *i < 0;
486 0 : if (slash) {
487 0 : abs.append('/');
488 : }
489 0 : break;
490 :
491 : case css::uri::RelativeUriExcessParentSegments_REMOVE:
492 0 : break;
493 :
494 : default:
495 : assert(false);
496 0 : break;
497 : }
498 : }
499 20178 : }
500 : } else {
501 0 : abs.append(uriReference->getPath());
502 : }
503 20178 : if (uriReference->hasQuery()) {
504 0 : abs.append('?');
505 0 : abs.append(uriReference->getQuery());
506 : }
507 20178 : if (uriReference->hasFragment()) {
508 0 : abs.append('#');
509 0 : abs.append(uriReference->getFragment());
510 : }
511 20178 : return parse(abs.makeStringAndClear());
512 : }
513 : }
514 :
515 58 : css::uno::Reference< css::uri::XUriReference > Factory::makeRelative(
516 : css::uno::Reference< css::uri::XUriReference > const & baseUriReference,
517 : css::uno::Reference< css::uri::XUriReference > const & uriReference,
518 : sal_Bool preferAuthorityOverRelativePath,
519 : sal_Bool preferAbsoluteOverRelativePath,
520 : sal_Bool encodeRetainedSpecialSegments)
521 : throw (css::uno::RuntimeException, std::exception)
522 : {
523 174 : if (!baseUriReference.is() || !baseUriReference->isAbsolute()
524 116 : || !baseUriReference->isHierarchical() || !uriReference.is()) {
525 0 : return 0;
526 248 : } else if (!uriReference->isAbsolute() || !uriReference->isHierarchical()
527 236 : || !baseUriReference->getScheme().equalsIgnoreAsciiCase(
528 218 : uriReference->getScheme())) {
529 22 : return clone(uriReference);
530 : } else {
531 36 : OUStringBuffer rel;
532 36 : bool omitQuery = false;
533 108 : if ((baseUriReference->hasAuthority() != uriReference->hasAuthority())
534 180 : || !equalIgnoreEscapeCase(
535 36 : baseUriReference->getAuthority(),
536 180 : uriReference->getAuthority()))
537 : {
538 0 : if (uriReference->hasAuthority()) {
539 0 : rel.append("//");
540 0 : rel.append(uriReference->getAuthority());
541 : }
542 0 : rel.append(uriReference->getPath());
543 72 : } else if ((equalIgnoreEscapeCase(
544 180 : baseUriReference->getPath(), uriReference->getPath())
545 69 : || (baseUriReference->getPath().getLength() <= 1
546 36 : && uriReference->getPath().getLength() <= 1))
547 3 : && baseUriReference->hasQuery() == uriReference->hasQuery()
548 153 : && equalIgnoreEscapeCase(
549 45 : baseUriReference->getQuery(), uriReference->getQuery()))
550 : {
551 3 : omitQuery = true;
552 : } else {
553 : sal_Int32 count1 = std::max< sal_Int32 >(
554 33 : baseUriReference->getPathSegmentCount(), 1);
555 : sal_Int32 count2 = std::max< sal_Int32 >(
556 33 : uriReference->getPathSegmentCount(), 1);
557 33 : sal_Int32 i = 0;
558 59 : for (; i < std::min(count1, count2) - 1; ++i) {
559 52 : if (!equalIgnoreEscapeCase(
560 26 : baseUriReference->getPathSegment(i),
561 78 : uriReference->getPathSegment(i)))
562 : {
563 0 : break;
564 : }
565 : }
566 121 : if (i == 0 && preferAbsoluteOverRelativePath
567 77 : && (preferAuthorityOverRelativePath
568 33 : || !uriReference->getPath().startsWith("//")))
569 : {
570 88 : if (baseUriReference->getPath().getLength() > 1
571 88 : || uriReference->getPath().getLength() > 1)
572 : {
573 22 : if (uriReference->getPath().isEmpty()) {
574 0 : rel.append('/');
575 : } else {
576 : assert(uriReference->getPath()[0] == '/');
577 22 : if (uriReference->getPath().startsWith("//")) {
578 : assert(uriReference->hasAuthority());
579 0 : rel.append("//");
580 0 : rel.append(uriReference->getAuthority());
581 : }
582 22 : rel.append(uriReference->getPath());
583 : }
584 : }
585 : } else {
586 11 : bool segments = false;
587 17 : for (sal_Int32 j = i; j < count1 - 1; ++j) {
588 6 : if (segments) {
589 1 : rel.append('/');
590 : }
591 6 : rel.append("..");
592 6 : segments = true;
593 : }
594 36 : if (i < count2 - 1
595 41 : || (!uriReference->getPathSegment(count2 - 1).isEmpty()))
596 : {
597 38 : if (!segments
598 39 : && (uriReference->getPathSegment(i).isEmpty()
599 17 : || (parseScheme(uriReference->getPathSegment(i))
600 : >= 0)))
601 : {
602 0 : rel.append('.');
603 0 : segments = true;
604 : }
605 25 : for (; i < count2; ++i) {
606 14 : if (segments) {
607 8 : rel.append('/');
608 : }
609 14 : OUString s(uriReference->getPathSegment(i));
610 14 : if (encodeRetainedSpecialSegments && s == ".") {
611 0 : rel.append("%2E");
612 14 : } else if (encodeRetainedSpecialSegments && s == "..") {
613 0 : rel.append("%2E%2E");
614 : } else {
615 14 : rel.append(s);
616 : }
617 14 : segments = true;
618 14 : }
619 : }
620 : }
621 : }
622 36 : if (!omitQuery && uriReference->hasQuery()) {
623 2 : rel.append('?');
624 2 : rel.append(uriReference->getQuery());
625 : }
626 36 : if (uriReference->hasFragment()) {
627 4 : rel.append('#');
628 4 : rel.append(uriReference->getFragment());
629 : }
630 36 : return parse(rel.makeStringAndClear());
631 : }
632 : }
633 :
634 : }
635 :
636 : extern "C" SAL_DLLPUBLIC_EXPORT ::com::sun::star::uno::XInterface* SAL_CALL
637 130279 : com_sun_star_comp_uri_UriReferenceFactory_get_implementation(::com::sun::star::uno::XComponentContext* rxContext,
638 : ::com::sun::star::uno::Sequence<css::uno::Any> const &)
639 : {
640 130279 : return ::cppu::acquire(new Factory(rxContext));
641 : }
642 :
643 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|