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 <cstddef>
25 #include <string_view>
26 #include <utility>
27 #include <vector>
28
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/exc_hlp.hxx>
44 #include <cppuhelper/implbase.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
equalIgnoreEscapeCase(OUString const & s1,OUString const & s2)56 bool equalIgnoreEscapeCase(OUString const & s1, OUString const & s2) {
57 if (s1.getLength() == s2.getLength()) {
58 for (sal_Int32 i = 0; i < s1.getLength();) {
59 if (s1[i] == '%' && s2[i] == '%' && s1.getLength() - i > 2
60 && rtl::isAsciiHexDigit(s1[i + 1])
61 && rtl::isAsciiHexDigit(s1[i + 2])
62 && rtl::isAsciiHexDigit(s2[i + 1])
63 && rtl::isAsciiHexDigit(s2[i + 2])
64 && rtl::compareIgnoreAsciiCase(s1[i + 1], s2[i + 1]) == 0
65 && rtl::compareIgnoreAsciiCase(s1[i + 2], s2[i + 2]) == 0)
66 {
67 i += 3;
68 } else if (s1[i] != s2[i]) {
69 return false;
70 } else {
71 ++i;
72 }
73 }
74 return true;
75 } else {
76 return false;
77 }
78 }
79
parseScheme(OUString const & uriReference)80 sal_Int32 parseScheme(OUString const & uriReference) {
81 if (uriReference.getLength() >= 2 && rtl::isAsciiAlpha(uriReference[0])) {
82 for (sal_Int32 i = 0; i < uriReference.getLength(); ++i) {
83 sal_Unicode c = uriReference[i];
84 if (c == ':') {
85 return i;
86 } else if (!rtl::isAsciiAlpha(c) && !rtl::isAsciiDigit(c)
87 && c != '+' && c != '-' && c != '.')
88 {
89 break;
90 }
91 }
92 }
93 return -1;
94 }
95
96 class UriReference:
97 public cppu::WeakImplHelper<css::uri::XUriReference>
98 {
99 public:
UriReference(OUString const & scheme,bool bHasAuthority,OUString const & authority,OUString const & path,bool bHasQuery,OUString const & query)100 UriReference(
101 OUString const & scheme, bool bHasAuthority,
102 OUString const & authority, OUString const & path,
103 bool bHasQuery, OUString const & query):
104 m_base(
105 scheme, bHasAuthority, authority, path, bHasQuery,
106 query)
107 {}
108
109 UriReference(const UriReference&) = delete;
110 UriReference& operator=(const UriReference&) = delete;
111
getUriReference()112 virtual OUString SAL_CALL getUriReference() override
113 { return m_base.getUriReference(); }
114
isAbsolute()115 virtual sal_Bool SAL_CALL isAbsolute() override
116 { return m_base.isAbsolute(); }
117
getScheme()118 virtual OUString SAL_CALL getScheme() override
119 { return m_base.getScheme(); }
120
getSchemeSpecificPart()121 virtual OUString SAL_CALL getSchemeSpecificPart() override
122 { return m_base.getSchemeSpecificPart(); }
123
isHierarchical()124 virtual sal_Bool SAL_CALL isHierarchical() override
125 { return m_base.isHierarchical(); }
126
hasAuthority()127 virtual sal_Bool SAL_CALL hasAuthority() override
128 { return m_base.hasAuthority(); }
129
getAuthority()130 virtual OUString SAL_CALL getAuthority() override
131 { return m_base.getAuthority(); }
132
getPath()133 virtual OUString SAL_CALL getPath() override
134 { return m_base.getPath(); }
135
hasRelativePath()136 virtual sal_Bool SAL_CALL hasRelativePath() override
137 { return m_base.hasRelativePath(); }
138
getPathSegmentCount()139 virtual sal_Int32 SAL_CALL getPathSegmentCount() override
140 { return m_base.getPathSegmentCount(); }
141
getPathSegment(sal_Int32 index)142 virtual OUString SAL_CALL getPathSegment(sal_Int32 index) override
143 { return m_base.getPathSegment(index); }
144
hasQuery()145 virtual sal_Bool SAL_CALL hasQuery() override
146 { return m_base.hasQuery(); }
147
getQuery()148 virtual OUString SAL_CALL getQuery() override
149 { return m_base.getQuery(); }
150
hasFragment()151 virtual sal_Bool SAL_CALL hasFragment() override
152 { return m_base.hasFragment(); }
153
getFragment()154 virtual OUString SAL_CALL getFragment() override
155 { return m_base.getFragment(); }
156
setFragment(OUString const & fragment)157 virtual void SAL_CALL setFragment(OUString const & fragment) override
158 { m_base.setFragment(fragment); }
159
clearFragment()160 virtual void SAL_CALL clearFragment() override
161 { m_base.clearFragment(); }
162
163 private:
~UriReference()164 virtual ~UriReference() override {}
165
166 stoc::uriproc::UriReference m_base;
167 };
168
parseGeneric(OUString const & scheme,OUString const & schemeSpecificPart)169 css::uno::Reference< css::uri::XUriReference > parseGeneric(
170 OUString const & scheme, OUString const & schemeSpecificPart)
171 {
172 sal_Int32 len = schemeSpecificPart.getLength();
173 sal_Int32 i = 0;
174 bool hasAuthority = false;
175 OUString authority;
176 if (len - i >= 2 && schemeSpecificPart[i] == '/'
177 && schemeSpecificPart[i + 1] == '/')
178 {
179 i += 2;
180 sal_Int32 n = i;
181 while (i < len && schemeSpecificPart[i] != '/'
182 && schemeSpecificPart[i] != '?') {
183 ++i;
184 }
185 hasAuthority = true;
186 authority = schemeSpecificPart.copy(n, i - n);
187 }
188 sal_Int32 n = i;
189 i = schemeSpecificPart.indexOf('?', i);
190 if (i == -1) {
191 i = len;
192 }
193 OUString path = schemeSpecificPart.copy(n, i - n);
194 bool hasQuery = false;
195 OUString query;
196 if (i != len) {
197 hasQuery = true;
198 query = schemeSpecificPart.copy(i + 1);
199 }
200 return new UriReference(
201 scheme, hasAuthority, authority, path, hasQuery, query);
202 }
203
204 struct Segment {
205 bool leadingSlash;
206 bool excessParent;
207 std::u16string_view segment;
208
Segment__anonfbf9f3780111::Segment209 Segment(bool theLeadingSlash, bool theExcessParent, std::u16string_view theSegment):
210 leadingSlash(theLeadingSlash), excessParent(theExcessParent), segment(theSegment) {}
211 };
212
processSegments(std::u16string_view first,std::u16string_view second,bool processSpecialSegments)213 std::pair<std::vector<Segment>, bool> processSegments(
214 std::u16string_view first, std::u16string_view second, bool processSpecialSegments)
215 {
216 std::vector<Segment> segments;
217 bool processed = false;
218 std::u16string_view const * half = &first;
219 // later checks for `half == &first` and `half == &second` rely on the fact that `first` and
220 // `second` are passed by value, in case a caller passes the same object for both arguments
221 std::size_t index = 0;
222 bool slash = false;
223 if (index == half->length()) {
224 half = &second;
225 index = 0;
226 }
227 if (index != half->length()) {
228 if ((*half)[index] == u'/') {
229 slash = true;
230 ++index;
231 }
232 for (;;) {
233 if (index == half->length() && half == &first) {
234 half = &second;
235 index = 0;
236 }
237 if (index == half->length()) {
238 if (slash) {
239 segments.emplace_back(true, false, std::u16string_view());
240 }
241 break;
242 }
243 auto const n = std::min(half->find(u'/', index), half->length());
244 auto const leadingSlash = slash;
245 auto const segment = half->substr(index, n - index);
246 auto const process = processSpecialSegments || half == &second;
247 index = n;
248 slash = false;
249 if (index == half->length() && half == &first) {
250 half = &second;
251 index = 0;
252 }
253 if (index != half->length() && (*half)[index] == u'/') {
254 slash = true;
255 ++index;
256 }
257 if (process) {
258 if (segment == u".") {
259 slash = leadingSlash;
260 processed = true;
261 continue;
262 } else if (segment == u"..") {
263 if (segments.empty() || segments.back().excessParent) {
264 segments.emplace_back(leadingSlash, true, segment);
265 } else {
266 if (leadingSlash) {
267 segments.pop_back();
268 }
269 slash = leadingSlash;
270 }
271 processed = true;
272 continue;
273 }
274 }
275 segments.emplace_back(leadingSlash, false, segment);
276 }
277 }
278 return {segments, processed};
279 }
280
281 class Factory:
282 public cppu::WeakImplHelper<
283 css::lang::XServiceInfo, css::uri::XUriReferenceFactory>
284 {
285 public:
Factory(css::uno::Reference<css::uno::XComponentContext> const & context)286 explicit Factory(
287 css::uno::Reference< css::uno::XComponentContext > const & context):
288 m_context(context) {}
289
290 Factory(const Factory&) = delete;
291 Factory& operator=(const Factory&) = delete;
292
293 virtual OUString SAL_CALL getImplementationName() override;
294
295 virtual sal_Bool SAL_CALL supportsService(OUString const & serviceName) override;
296
297 virtual css::uno::Sequence< OUString > SAL_CALL
298 getSupportedServiceNames() override;
299
300 virtual css::uno::Reference< css::uri::XUriReference > SAL_CALL
301 parse(OUString const & uriReference) override;
302
303 virtual css::uno::Reference< css::uri::XUriReference > SAL_CALL
304 makeAbsolute(
305 css::uno::Reference< css::uri::XUriReference > const & baseUriReference,
306 css::uno::Reference< css::uri::XUriReference > const & uriReference,
307 sal_Bool processAdditionalSpecialSegments,
308 css::uri::RelativeUriExcessParentSegments excessParentSegments) override;
309
310 virtual css::uno::Reference< css::uri::XUriReference > SAL_CALL
311 makeRelative(
312 css::uno::Reference< css::uri::XUriReference > const & baseUriReference,
313 css::uno::Reference< css::uri::XUriReference > const & uriReference,
314 sal_Bool preferAuthorityOverRelativePath,
315 sal_Bool preferAbsoluteOverRelativePath,
316 sal_Bool encodeRetainedSpecialSegments) override;
317
318 private:
~Factory()319 virtual ~Factory() override {}
320
clone(css::uno::Reference<css::uri::XUriReference> const & uriReference)321 css::uno::Reference< css::uri::XUriReference > clone(
322 css::uno::Reference< css::uri::XUriReference > const & uriReference)
323 { return parse(uriReference->getUriReference()); }
324
325 css::uno::Reference< css::uno::XComponentContext > m_context;
326 };
327
getImplementationName()328 OUString Factory::getImplementationName()
329 {
330 return "com.sun.star.comp.uri.UriReferenceFactory";
331 }
332
supportsService(OUString const & serviceName)333 sal_Bool Factory::supportsService(OUString const & serviceName)
334 {
335 return cppu::supportsService(this, serviceName);
336 }
337
getSupportedServiceNames()338 css::uno::Sequence< OUString > Factory::getSupportedServiceNames()
339 {
340 css::uno::Sequence< OUString > s { "com.sun.star.uri.UriReferenceFactory" };
341 return s;
342 }
343
parse(OUString const & uriReference)344 css::uno::Reference< css::uri::XUriReference > Factory::parse(
345 OUString const & uriReference)
346 {
347 sal_Int32 fragment = uriReference.indexOf('#');
348 if (fragment == -1) {
349 fragment = uriReference.getLength();
350 }
351 OUString scheme;
352 OUString schemeSpecificPart;
353 OUString serviceName;
354 sal_Int32 n = parseScheme(uriReference);
355 assert(n < fragment);
356 if (n >= 0) {
357 scheme = uriReference.copy(0, n);
358 schemeSpecificPart = uriReference.copy(n + 1, fragment - (n + 1));
359 OUStringBuffer buf(128);
360 buf.append("com.sun.star.uri.UriSchemeParser_");
361 for (sal_Int32 i = 0; i < scheme.getLength(); ++i) {
362 sal_Unicode c = scheme[i];
363 if (rtl::isAsciiUpperCase(c)) {
364 buf.append(static_cast<sal_Unicode>(rtl::toAsciiLowerCase(c)));
365 } else if (c == '+') {
366 buf.append("PLUS");
367 } else if (c == '-') {
368 buf.append("HYPHEN");
369 } else if (c == '.') {
370 buf.append("DOT");
371 } else {
372 assert(rtl::isAsciiLowerCase(c) || rtl::isAsciiDigit(c));
373 buf.append(c);
374 }
375 }
376 serviceName = buf.makeStringAndClear();
377 } else {
378 schemeSpecificPart = uriReference.copy(0, fragment);
379 }
380 css::uno::Reference< css::uri::XUriSchemeParser > parser;
381 if (!serviceName.isEmpty()) {
382 css::uno::Reference< css::lang::XMultiComponentFactory > factory(
383 m_context->getServiceManager());
384 if (factory.is()) {
385 css::uno::Reference< css::uno::XInterface > service;
386 try {
387 service = factory->createInstanceWithContext(
388 serviceName, m_context);
389 } catch (css::uno::RuntimeException &) {
390 throw;
391 } catch (const css::uno::Exception &) {
392 css::uno::Any anyEx = cppu::getCaughtException();
393 throw css::lang::WrappedTargetRuntimeException(
394 "creating service " + serviceName,
395 static_cast< cppu::OWeakObject * >(this),
396 anyEx);
397 }
398 if (service.is()) {
399 parser.set( service, css::uno::UNO_QUERY_THROW);
400 }
401 }
402 }
403 css::uno::Reference< css::uri::XUriReference > uriRef(
404 parser.is()
405 ? parser->parse(scheme, schemeSpecificPart)
406 : parseGeneric(scheme, schemeSpecificPart));
407 if (uriRef.is() && fragment != uriReference.getLength()) {
408 uriRef->setFragment(uriReference.copy(fragment + 1));
409 }
410 return uriRef;
411 }
412
makeAbsolute(css::uno::Reference<css::uri::XUriReference> const & baseUriReference,css::uno::Reference<css::uri::XUriReference> const & uriReference,sal_Bool processAdditionalSpecialSegments,css::uri::RelativeUriExcessParentSegments excessParentSegments)413 css::uno::Reference< css::uri::XUriReference > Factory::makeAbsolute(
414 css::uno::Reference< css::uri::XUriReference > const & baseUriReference,
415 css::uno::Reference< css::uri::XUriReference > const & uriReference,
416 sal_Bool processAdditionalSpecialSegments,
417 css::uri::RelativeUriExcessParentSegments excessParentSegments)
418 {
419 if (!baseUriReference.is() || !baseUriReference->isAbsolute()
420 || !uriReference.is()) {
421 return nullptr;
422 } else if (uriReference->isAbsolute()) {
423 if (processAdditionalSpecialSegments) {
424 auto const path = uriReference->getPath();
425 auto [segments, proc] = processSegments(path, {}, true);
426 if (proc) {
427 OUStringBuffer abs(uriReference->getScheme());
428 abs.append(':');
429 if (uriReference->hasAuthority()) {
430 abs.append("//");
431 abs.append(uriReference->getAuthority());
432 }
433 for (auto const & i : segments)
434 {
435 if (i.excessParent) {
436 switch (excessParentSegments) {
437 case css::uri::RelativeUriExcessParentSegments_ERROR:
438 return nullptr;
439
440 case css::uri::RelativeUriExcessParentSegments_RETAIN:
441 assert(i.segment == u"..");
442 break;
443
444 case css::uri::RelativeUriExcessParentSegments_REMOVE:
445 continue;
446
447 default:
448 assert(false);
449 break;
450 }
451 }
452 if (i.leadingSlash) {
453 abs.append('/');
454 }
455 abs.append(i.segment);
456 }
457 if (uriReference->hasQuery()) {
458 abs.append('?');
459 abs.append(uriReference->getQuery());
460 }
461 if (uriReference->hasFragment()) {
462 abs.append('#');
463 abs.append(uriReference->getFragment());
464 }
465 return parse(abs.makeStringAndClear());
466 }
467 }
468 return clone(uriReference);
469 } else if (!uriReference->hasAuthority()
470 && uriReference->getPath().isEmpty()) {
471 OUStringBuffer abs(baseUriReference->getScheme());
472 abs.append(':');
473 if (baseUriReference->hasAuthority()) {
474 abs.append("//");
475 abs.append(baseUriReference->getAuthority());
476 }
477 abs.append(baseUriReference->getPath());
478 if (uriReference->hasQuery()) {
479 abs.append('?');
480 abs.append(uriReference->getQuery());
481 } else if (baseUriReference->hasQuery()) {
482 abs.append('?');
483 abs.append(baseUriReference->getQuery());
484 }
485 if (uriReference->hasFragment()) {
486 abs.append('#');
487 abs.append(uriReference->getFragment());
488 }
489 return parse(abs.makeStringAndClear());
490 } else {
491 OUStringBuffer abs(128);
492 abs.append(baseUriReference->getScheme());
493 abs.append(':');
494 if (uriReference->hasAuthority()) {
495 abs.append("//");
496 abs.append(uriReference->getAuthority());
497 } else if (baseUriReference->hasAuthority()) {
498 abs.append("//");
499 abs.append(baseUriReference->getAuthority());
500 }
501 if (uriReference->hasRelativePath()) {
502 auto path1 = baseUriReference->getPath();
503 if (path1.isEmpty()) {
504 if (baseUriReference->hasAuthority()) {
505 path1 = "/";
506 }
507 } else {
508 path1 = path1.copy(0, path1.lastIndexOf('/') + 1);
509 }
510 auto const path2 = uriReference->getPath();
511 auto [segments, _] = processSegments(path1, path2, processAdditionalSpecialSegments);
512 (void)_;
513 for (auto const & i : segments)
514 {
515 if (i.excessParent) {
516 switch (excessParentSegments) {
517 case css::uri::RelativeUriExcessParentSegments_ERROR:
518 return nullptr;
519
520 case css::uri::RelativeUriExcessParentSegments_RETAIN:
521 assert(i.segment == u"..");
522 break;
523
524 case css::uri::RelativeUriExcessParentSegments_REMOVE:
525 continue;
526
527 default:
528 assert(false);
529 break;
530 }
531 }
532 if (i.leadingSlash) {
533 abs.append('/');
534 }
535 abs.append(i.segment);
536 }
537 } else {
538 bool processed = false;
539 if (processAdditionalSpecialSegments) {
540 auto const path = uriReference->getPath();
541 auto [segments, proc] = processSegments(path, {}, true);
542 if (proc) {
543 for (auto const & i : segments)
544 {
545 if (i.excessParent) {
546 switch (excessParentSegments) {
547 case css::uri::RelativeUriExcessParentSegments_ERROR:
548 return nullptr;
549
550 case css::uri::RelativeUriExcessParentSegments_RETAIN:
551 assert(i.segment == u"..");
552 break;
553
554 case css::uri::RelativeUriExcessParentSegments_REMOVE:
555 continue;
556
557 default:
558 assert(false);
559 break;
560 }
561 }
562 if (i.leadingSlash) {
563 abs.append('/');
564 }
565 abs.append(i.segment);
566 }
567 processed = true;
568 }
569 }
570 if (!processed) {
571 abs.append(uriReference->getPath());
572 }
573 }
574 if (uriReference->hasQuery()) {
575 abs.append('?');
576 abs.append(uriReference->getQuery());
577 }
578 if (uriReference->hasFragment()) {
579 abs.append('#');
580 abs.append(uriReference->getFragment());
581 }
582 return parse(abs.makeStringAndClear());
583 }
584 }
585
makeRelative(css::uno::Reference<css::uri::XUriReference> const & baseUriReference,css::uno::Reference<css::uri::XUriReference> const & uriReference,sal_Bool preferAuthorityOverRelativePath,sal_Bool preferAbsoluteOverRelativePath,sal_Bool encodeRetainedSpecialSegments)586 css::uno::Reference< css::uri::XUriReference > Factory::makeRelative(
587 css::uno::Reference< css::uri::XUriReference > const & baseUriReference,
588 css::uno::Reference< css::uri::XUriReference > const & uriReference,
589 sal_Bool preferAuthorityOverRelativePath,
590 sal_Bool preferAbsoluteOverRelativePath,
591 sal_Bool encodeRetainedSpecialSegments)
592 {
593 if (!baseUriReference.is() || !baseUriReference->isAbsolute()
594 || !uriReference.is()) {
595 return nullptr;
596 } else if (!uriReference->isAbsolute() || uriReference->hasRelativePath()
597 || !baseUriReference->getScheme().equalsIgnoreAsciiCase(
598 uriReference->getScheme())) {
599 return clone(uriReference);
600 } else {
601 OUStringBuffer rel(128);
602 bool omitQuery = false;
603 if ((baseUriReference->hasAuthority() != uriReference->hasAuthority())
604 || !equalIgnoreEscapeCase(
605 baseUriReference->getAuthority(),
606 uriReference->getAuthority()))
607 {
608 if (uriReference->hasAuthority()) {
609 rel.append("//");
610 rel.append(uriReference->getAuthority());
611 }
612 rel.append(uriReference->getPath());
613 } else if ((equalIgnoreEscapeCase(
614 baseUriReference->getPath(), uriReference->getPath())
615 || (baseUriReference->getPath() == "/"
616 && uriReference->getPath().isEmpty()))
617 && baseUriReference->hasQuery() == uriReference->hasQuery()
618 && equalIgnoreEscapeCase(
619 baseUriReference->getQuery(), uriReference->getQuery()))
620 {
621 omitQuery = true;
622 } else {
623 sal_Int32 count1 = std::max< sal_Int32 >(
624 baseUriReference->getPathSegmentCount(), 1);
625 sal_Int32 count2 = std::max< sal_Int32 >(
626 uriReference->getPathSegmentCount(), 1);
627 sal_Int32 i = 0;
628 for (; i < std::min(count1, count2) - 1; ++i) {
629 if (!equalIgnoreEscapeCase(
630 baseUriReference->getPathSegment(i),
631 uriReference->getPathSegment(i)))
632 {
633 break;
634 }
635 }
636 if (i == 0
637 && (preferAbsoluteOverRelativePath || uriReference->hasQuery())
638 && (preferAuthorityOverRelativePath
639 || !uriReference->getPath().startsWith("//")))
640 {
641 if (uriReference->getPath().isEmpty()) {
642 if (!baseUriReference->getPath().isEmpty()
643 && baseUriReference->getPath() != "/")
644 {
645 rel.append('/');
646 }
647 } else if (uriReference->getPath() == "/") {
648 if (baseUriReference->getPath().isEmpty()
649 || baseUriReference->getPath() != "/")
650 {
651 rel.append('/');
652 }
653 } else {
654 if (uriReference->getPath().startsWith("//")) {
655 assert(uriReference->hasAuthority());
656 rel.append("//");
657 rel.append(uriReference->getAuthority());
658 }
659 rel.append(uriReference->getPath());
660 }
661 } else {
662 bool segments = false;
663 for (sal_Int32 j = i; j < count1 - 1; ++j) {
664 if (segments) {
665 rel.append('/');
666 }
667 rel.append("..");
668 segments = true;
669 }
670 if (i < count2 - 1
671 || (!uriReference->getPathSegment(count2 - 1).isEmpty()))
672 {
673 if (!segments
674 && (uriReference->getPathSegment(i).isEmpty()
675 || (parseScheme(uriReference->getPathSegment(i))
676 >= 0)))
677 {
678 rel.append('.');
679 segments = true;
680 }
681 for (; i < count2; ++i) {
682 if (segments) {
683 rel.append('/');
684 }
685 OUString s(uriReference->getPathSegment(i));
686 if (encodeRetainedSpecialSegments && s == ".") {
687 rel.append("%2E");
688 } else if (encodeRetainedSpecialSegments && s == "..") {
689 rel.append("%2E%2E");
690 } else {
691 rel.append(s);
692 }
693 segments = true;
694 }
695 }
696 }
697 }
698 if (!omitQuery && uriReference->hasQuery()) {
699 rel.append('?');
700 rel.append(uriReference->getQuery());
701 }
702 if (uriReference->hasFragment()) {
703 rel.append('#');
704 rel.append(uriReference->getFragment());
705 }
706 return parse(rel.makeStringAndClear());
707 }
708 }
709
710 }
711
712 extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
com_sun_star_comp_uri_UriReferenceFactory_get_implementation(css::uno::XComponentContext * rxContext,css::uno::Sequence<css::uno::Any> const &)713 com_sun_star_comp_uri_UriReferenceFactory_get_implementation(css::uno::XComponentContext* rxContext,
714 css::uno::Sequence<css::uno::Any> const &)
715 {
716 return ::cppu::acquire(new Factory(rxContext));
717 }
718
719 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
720