1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_stoc.hxx"
30 
31 #include "stocservices.hxx"
32 
33 #include "UriReference.hxx"
34 #include "supportsService.hxx"
35 
36 #include "com/sun/star/lang/WrappedTargetRuntimeException.hpp"
37 #include "com/sun/star/lang/XMultiComponentFactory.hpp"
38 #include "com/sun/star/lang/XServiceInfo.hpp"
39 #include "com/sun/star/uno/Any.hxx"
40 #include "com/sun/star/uno/Exception.hpp"
41 #include "com/sun/star/uno/Reference.hxx"
42 #include "com/sun/star/uno/RuntimeException.hpp"
43 #include "com/sun/star/uno/Sequence.hxx"
44 #include "com/sun/star/uno/XComponentContext.hpp"
45 #include "com/sun/star/uno/XInterface.hpp"
46 #include "com/sun/star/uri/RelativeUriExcessParentSegments.hpp"
47 #include "com/sun/star/uri/XUriReference.hpp"
48 #include "com/sun/star/uri/XUriReferenceFactory.hpp"
49 #include "com/sun/star/uri/XUriSchemeParser.hpp"
50 #include "cppuhelper/implbase1.hxx"
51 #include "cppuhelper/implbase2.hxx"
52 #include "cppuhelper/weak.hxx"
53 #include "osl/diagnose.h"
54 #include "rtl/string.h"
55 #include "rtl/ustrbuf.hxx"
56 #include "rtl/ustring.hxx"
57 #include "sal/types.h"
58 
59 #include <algorithm>
60 #include /*MSVC trouble: <cstdlib>*/ <stdlib.h>
61 #include <new>
62 #include <vector>
63 
64 namespace css = com::sun::star;
65 
66 namespace {
67 
68 bool isDigit(sal_Unicode c) { //TODO: generally available?
69     return c >= '0' && c <= '9';
70 }
71 
72 bool isUpperCase(sal_Unicode c) { //TODO: generally available?
73     return c >= 'A' && c <= 'Z';
74 }
75 
76 bool isLowerCase(sal_Unicode c) { //TODO: generally available?
77     return c >= 'a' && c <= 'z';
78 }
79 
80 bool isAlpha(sal_Unicode c) { //TODO: generally available?
81     return isUpperCase(c) || isLowerCase(c);
82 }
83 
84 bool isHexDigit(sal_Unicode c) { //TODO: generally available?
85     return isDigit(c) || (c >= 'A' && c <= 'F') || (c >= 'a' && c <= 'f');
86 }
87 
88 sal_Unicode toLowerCase(sal_Unicode c) { //TODO: generally available?
89     return isUpperCase(c) ? c + ('a' - 'A') : c;
90 }
91 
92 bool equalIgnoreCase(sal_Unicode c1, sal_Unicode c2) {
93     //TODO: generally available?
94     return toLowerCase(c1) == toLowerCase(c2);
95 }
96 
97 bool equalIgnoreEscapeCase(rtl::OUString const & s1, rtl::OUString const & s2) {
98     if (s1.getLength() == s2.getLength()) {
99         for (sal_Int32 i = 0; i < s1.getLength();) {
100             if (s1[i] == '%' && s2[i] == '%' && s1.getLength() - i > 2
101                 && isHexDigit(s1[i + 1]) && isHexDigit(s1[i + 2])
102                 && isHexDigit(s2[i + 1]) && isHexDigit(s2[i + 2])
103                 && equalIgnoreCase(s1[i + 1], s2[i + 1])
104                 && equalIgnoreCase(s1[i + 2], s2[i + 2]))
105             {
106                 i += 3;
107             } else if (s1[i] != s2[i]) {
108                 return false;
109             } else {
110                 ++i;
111             }
112         }
113         return true;
114     } else {
115         return false;
116     }
117 }
118 
119 sal_Int32 parseScheme(rtl::OUString const & uriReference) {
120     if (uriReference.getLength() >= 2 && isAlpha(uriReference[0])) {
121         for (sal_Int32 i = 0; i < uriReference.getLength(); ++i) {
122             sal_Unicode c = uriReference[i];
123             if (c == ':') {
124                 return i;
125             } else if (!isAlpha(c) && !isDigit(c) && c != '+' && c != '-'
126                        && c != '.')
127             {
128                 break;
129             }
130         }
131     }
132     return -1;
133 }
134 
135 class UriReference: public cppu::WeakImplHelper1< css::uri::XUriReference > {
136 public:
137     UriReference(
138         rtl::OUString const & scheme, bool bIsHierarchical, bool bHasAuthority,
139         rtl::OUString const & authority, rtl::OUString const & path,
140         bool bHasQuery, rtl::OUString const & query):
141         m_base(
142             scheme, bIsHierarchical, bHasAuthority, authority, path, bHasQuery,
143             query)
144     {}
145 
146     virtual rtl::OUString SAL_CALL getUriReference()
147         throw (com::sun::star::uno::RuntimeException)
148     { return m_base.getUriReference(); }
149 
150     virtual sal_Bool SAL_CALL isAbsolute()
151         throw (com::sun::star::uno::RuntimeException)
152     { return m_base.isAbsolute(); }
153 
154     virtual rtl::OUString SAL_CALL getScheme()
155         throw (com::sun::star::uno::RuntimeException)
156     { return m_base.getScheme(); }
157 
158     virtual rtl::OUString SAL_CALL getSchemeSpecificPart()
159         throw (com::sun::star::uno::RuntimeException)
160     { return m_base.getSchemeSpecificPart(); }
161 
162     virtual sal_Bool SAL_CALL isHierarchical()
163         throw (com::sun::star::uno::RuntimeException)
164     { return m_base.isHierarchical(); }
165 
166     virtual sal_Bool SAL_CALL hasAuthority()
167         throw (com::sun::star::uno::RuntimeException)
168     { return m_base.hasAuthority(); }
169 
170     virtual rtl::OUString SAL_CALL getAuthority()
171         throw (com::sun::star::uno::RuntimeException)
172     { return m_base.getAuthority(); }
173 
174     virtual rtl::OUString SAL_CALL getPath()
175         throw (com::sun::star::uno::RuntimeException)
176     { return m_base.getPath(); }
177 
178     virtual sal_Bool SAL_CALL hasRelativePath()
179         throw (com::sun::star::uno::RuntimeException)
180     { return m_base.hasRelativePath(); }
181 
182     virtual sal_Int32 SAL_CALL getPathSegmentCount()
183         throw (com::sun::star::uno::RuntimeException)
184     { return m_base.getPathSegmentCount(); }
185 
186     virtual rtl::OUString SAL_CALL getPathSegment(sal_Int32 index)
187         throw (com::sun::star::uno::RuntimeException)
188     { return m_base.getPathSegment(index); }
189 
190     virtual sal_Bool SAL_CALL hasQuery()
191         throw (com::sun::star::uno::RuntimeException)
192     { return m_base.hasQuery(); }
193 
194     virtual rtl::OUString SAL_CALL getQuery()
195         throw (com::sun::star::uno::RuntimeException)
196     { return m_base.getQuery(); }
197 
198     virtual sal_Bool SAL_CALL hasFragment()
199         throw (com::sun::star::uno::RuntimeException)
200     { return m_base.hasFragment(); }
201 
202     virtual rtl::OUString SAL_CALL getFragment()
203         throw (com::sun::star::uno::RuntimeException)
204     { return m_base.getFragment(); }
205 
206     virtual void SAL_CALL setFragment(rtl::OUString const & fragment)
207         throw (com::sun::star::uno::RuntimeException)
208     { m_base.setFragment(fragment); }
209 
210     virtual void SAL_CALL clearFragment()
211         throw (com::sun::star::uno::RuntimeException)
212     { m_base.clearFragment(); }
213 
214 private:
215     UriReference(UriReference &); // not implemented
216     void operator =(UriReference); // not implemented
217 
218     virtual ~UriReference() {}
219 
220     stoc::uriproc::UriReference m_base;
221 };
222 
223 // throws std::bad_alloc
224 css::uno::Reference< css::uri::XUriReference > parseGeneric(
225     rtl::OUString const & scheme, rtl::OUString const & schemeSpecificPart)
226 {
227     bool isAbsolute = scheme.getLength() != 0;
228     bool isHierarchical
229         = !isAbsolute
230         || (schemeSpecificPart.getLength() > 0 && schemeSpecificPart[0] == '/');
231     bool hasAuthority = false;
232     rtl::OUString authority;
233     rtl::OUString path;
234     bool hasQuery = false;
235     rtl::OUString query;
236     if (isHierarchical) {
237         sal_Int32 len = schemeSpecificPart.getLength();
238         sal_Int32 i = 0;
239         if (len - i >= 2 && schemeSpecificPart[i] == '/'
240             && schemeSpecificPart[i + 1] == '/')
241         {
242             i += 2;
243             sal_Int32 n = i;
244             while (i < len && schemeSpecificPart[i] != '/'
245                    && schemeSpecificPart[i] != '?') {
246                 ++i;
247             }
248             hasAuthority = true;
249             authority = schemeSpecificPart.copy(n, i - n);
250         }
251         sal_Int32 n = i;
252         i = schemeSpecificPart.indexOf('?', i);
253         if (i == -1) {
254             i = len;
255         }
256         path = schemeSpecificPart.copy(n, i - n);
257         if (i != len) {
258             hasQuery = true;
259             query = schemeSpecificPart.copy(i + 1);
260         }
261     } else {
262         if (schemeSpecificPart.getLength() == 0) {
263             // The scheme-specific part of an opaque URI must not be empty:
264             return 0;
265         }
266         path = schemeSpecificPart;
267     }
268     return new UriReference(
269         scheme, isHierarchical, hasAuthority, authority, path, hasQuery, query);
270 }
271 
272 typedef std::vector< sal_Int32 > Segments;
273 
274 void processSegments(
275     Segments & segments,
276     css::uno::Reference< css::uri::XUriReference > const & uriReference,
277     bool base, bool processSpecialSegments)
278 {
279     sal_Int32 count = uriReference->getPathSegmentCount() - (base ? 1 : 0);
280     OSL_ASSERT(count <= SAL_MAX_INT32 - 1 && -count >= SAL_MIN_INT32 + 1);
281     for (sal_Int32 i = 0; i < count; ++i) {
282         if (processSpecialSegments) {
283             rtl::OUString segment(uriReference->getPathSegment(i));
284             if (segment.equalsAsciiL(RTL_CONSTASCII_STRINGPARAM("."))) {
285                 if (!base && i == count - 1) {
286                     segments.push_back(0);
287                 }
288                 continue;
289             } else if (segment.equalsAsciiL(RTL_CONSTASCII_STRINGPARAM(".."))) {
290                 if (segments.empty()
291                     || /*MSVC trouble: std::*/abs(segments.back()) == 1)
292                 {
293                     segments.push_back(base ? -1 : 1);
294                 } else {
295                     segments.pop_back();
296                 }
297                 continue;
298             }
299         }
300         segments.push_back(base ? -(i + 2) : i + 2);
301     }
302 }
303 
304 class Factory: public cppu::WeakImplHelper2<
305     css::lang::XServiceInfo, css::uri::XUriReferenceFactory >
306 {
307 public:
308     explicit Factory(
309         css::uno::Reference< css::uno::XComponentContext > const & context):
310         m_context(context) {}
311 
312     virtual rtl::OUString SAL_CALL getImplementationName()
313         throw (css::uno::RuntimeException);
314 
315     virtual sal_Bool SAL_CALL supportsService(rtl::OUString const & serviceName)
316         throw (css::uno::RuntimeException);
317 
318     virtual css::uno::Sequence< rtl::OUString > SAL_CALL
319     getSupportedServiceNames() throw (css::uno::RuntimeException);
320 
321     virtual css::uno::Reference< css::uri::XUriReference > SAL_CALL
322     parse(rtl::OUString const & uriReference)
323         throw (css::uno::RuntimeException);
324 
325     virtual css::uno::Reference< css::uri::XUriReference > SAL_CALL
326     makeAbsolute(
327         css::uno::Reference< css::uri::XUriReference > const & baseUriReference,
328         css::uno::Reference< css::uri::XUriReference > const & uriReference,
329         sal_Bool processSpecialBaseSegments,
330         css::uri::RelativeUriExcessParentSegments excessParentSegments)
331         throw (css::uno::RuntimeException);
332 
333     virtual css::uno::Reference< css::uri::XUriReference > SAL_CALL
334     makeRelative(
335         css::uno::Reference< css::uri::XUriReference > const & baseUriReference,
336         css::uno::Reference< css::uri::XUriReference > const & uriReference,
337         sal_Bool preferAuthorityOverRelativePath,
338         sal_Bool preferAbsoluteOverRelativePath,
339         sal_Bool encodeRetainedSpecialSegments)
340         throw (css::uno::RuntimeException);
341 
342 private:
343     Factory(Factory &); // not implemented
344     void operator =(Factory); // not implemented
345 
346     virtual ~Factory() {}
347 
348     css::uno::Reference< css::uri::XUriReference > clone(
349         css::uno::Reference< css::uri::XUriReference > const & uriReference)
350     { return parse(uriReference->getUriReference()); }
351 
352     css::uno::Reference< css::uno::XComponentContext > m_context;
353 };
354 
355 rtl::OUString Factory::getImplementationName()
356     throw (css::uno::RuntimeException)
357 {
358     return stoc_services::UriReferenceFactory::getImplementationName();
359 }
360 
361 sal_Bool Factory::supportsService(rtl::OUString const & serviceName)
362     throw (css::uno::RuntimeException)
363 {
364     return stoc::uriproc::supportsService(
365         getSupportedServiceNames(), serviceName);
366 }
367 
368 css::uno::Sequence< rtl::OUString > Factory::getSupportedServiceNames()
369     throw (css::uno::RuntimeException)
370 {
371     return stoc_services::UriReferenceFactory::getSupportedServiceNames();
372 }
373 
374 css::uno::Reference< css::uri::XUriReference > Factory::parse(
375     rtl::OUString const & uriReference) throw (css::uno::RuntimeException)
376 {
377     sal_Int32 fragment = uriReference.indexOf('#');
378     if (fragment == -1) {
379         fragment = uriReference.getLength();
380     }
381     rtl::OUString scheme;
382     rtl::OUString schemeSpecificPart;
383     rtl::OUString serviceName;
384     sal_Int32 n = parseScheme(uriReference);
385     OSL_ASSERT(n < fragment);
386     if (n >= 0) {
387         scheme = uriReference.copy(0, n);
388         schemeSpecificPart = uriReference.copy(n + 1, fragment - (n + 1));
389         rtl::OUStringBuffer buf;
390         buf.appendAscii(
391             RTL_CONSTASCII_STRINGPARAM("com.sun.star.uri.UriSchemeParser_"));
392         for (sal_Int32 i = 0; i < scheme.getLength(); ++i) {
393             sal_Unicode c = scheme[i];
394             if (isUpperCase(c)) {
395                 buf.append(toLowerCase(c));
396             } else if (c == '+') {
397                 buf.appendAscii(RTL_CONSTASCII_STRINGPARAM("PLUS"));
398             } else if (c == '-') {
399                 buf.appendAscii(RTL_CONSTASCII_STRINGPARAM("HYPHEN"));
400             } else if (c == '.') {
401                 buf.appendAscii(RTL_CONSTASCII_STRINGPARAM("DOT"));
402             } else {
403                 OSL_ASSERT(isLowerCase(c) || isDigit(c));
404                 buf.append(c);
405             }
406         }
407         serviceName = buf.makeStringAndClear();
408     } else {
409         schemeSpecificPart = uriReference.copy(0, fragment);
410     }
411     css::uno::Reference< css::uri::XUriSchemeParser > parser;
412     if (serviceName.getLength() != 0) {
413         css::uno::Reference< css::lang::XMultiComponentFactory > factory(
414             m_context->getServiceManager());
415         if (factory.is()) {
416             css::uno::Reference< css::uno::XInterface > service;
417             try {
418                 service = factory->createInstanceWithContext(
419                     serviceName, m_context);
420             } catch (css::uno::RuntimeException &) {
421                 throw;
422             } catch (css::uno::Exception & e) {
423                 throw css::lang::WrappedTargetRuntimeException(
424                     rtl::OUString::createFromAscii("creating service ")
425                         + serviceName,
426                     static_cast< cppu::OWeakObject * >(this),
427                     css::uno::makeAny(e)); //TODO: preserve type of e
428             }
429             if (service.is()) {
430                 parser = css::uno::Reference< css::uri::XUriSchemeParser >(
431                     service, css::uno::UNO_QUERY_THROW);
432             }
433         }
434     }
435     css::uno::Reference< css::uri::XUriReference > uriRef;
436     if (parser.is()) {
437         uriRef = parser->parse(scheme, schemeSpecificPart);
438     } else {
439         try {
440             uriRef = parseGeneric(scheme, schemeSpecificPart);
441         } catch (std::bad_alloc &) {
442             throw css::uno::RuntimeException(
443                 rtl::OUString::createFromAscii("std::bad_alloc"),
444                 static_cast< cppu::OWeakObject * >(this));
445         }
446     }
447     if (uriRef.is() && fragment != uriReference.getLength()) {
448         uriRef->setFragment(uriReference.copy(fragment + 1));
449     }
450     return uriRef;
451 }
452 
453 css::uno::Reference< css::uri::XUriReference > Factory::makeAbsolute(
454     css::uno::Reference< css::uri::XUriReference > const & baseUriReference,
455     css::uno::Reference< css::uri::XUriReference > const & uriReference,
456     sal_Bool processSpecialBaseSegments,
457     css::uri::RelativeUriExcessParentSegments excessParentSegments)
458     throw (css::uno::RuntimeException)
459 {
460     if (!baseUriReference.is() || !baseUriReference->isAbsolute()
461         || !baseUriReference->isHierarchical() || !uriReference.is()) {
462         return 0;
463     } else if (uriReference->isAbsolute()) {
464         return clone(uriReference);
465     } else if (!uriReference->hasAuthority()
466                && uriReference->getPath().getLength() == 0
467                && !uriReference->hasQuery()) {
468         css::uno::Reference< css::uri::XUriReference > abs(
469             clone(baseUriReference));
470         if (uriReference->hasFragment()) {
471             abs->setFragment(uriReference->getFragment());
472         } else {
473             abs->clearFragment();
474         }
475         return abs;
476     } else {
477         rtl::OUStringBuffer abs(baseUriReference->getScheme());
478         abs.append(static_cast< sal_Unicode >(':'));
479         if (uriReference->hasAuthority()) {
480             abs.appendAscii(RTL_CONSTASCII_STRINGPARAM("//"));
481             abs.append(uriReference->getAuthority());
482         } else if (baseUriReference->hasAuthority()) {
483             abs.appendAscii(RTL_CONSTASCII_STRINGPARAM("//"));
484             abs.append(baseUriReference->getAuthority());
485         }
486         if (uriReference->hasRelativePath()) {
487             Segments segments;
488             processSegments(
489                 segments, baseUriReference, true, processSpecialBaseSegments);
490             processSegments(segments, uriReference, false, true);
491             // If the path component of the base URI reference is empty (which
492             // implies that the base URI reference denotes a "root entity"), and
493             // the resulting URI reference denotes the same root entity, make
494             // sure the path component of the resulting URI reference is also
495             // empty (and not "/").  RFC 2396 is unclear about this, and I chose
496             // these rules for consistent results.
497             bool slash = baseUriReference->getPath().getLength() != 0;
498             if (slash) {
499                 abs.append(static_cast< sal_Unicode >('/'));
500             }
501             for (Segments::iterator i(segments.begin()); i != segments.end();
502                  ++i)
503             {
504                 if (*i < -1) {
505                     rtl::OUString segment(
506                         baseUriReference->getPathSegment(-(*i + 2)));
507                     if (segment.getLength() != 0 || segments.size() > 1) {
508                         if (!slash) {
509                             abs.append(static_cast< sal_Unicode >('/'));
510                         }
511                         abs.append(segment);
512                         slash = true;
513                         abs.append(static_cast< sal_Unicode >('/'));
514                     }
515                 } else if (*i > 1) {
516                     rtl::OUString segment(uriReference->getPathSegment(*i - 2));
517                     if (segment.getLength() != 0 || segments.size() > 1) {
518                         if (!slash) {
519                             abs.append(static_cast< sal_Unicode >('/'));
520                         }
521                         abs.append(segment);
522                         slash = false;
523                     }
524                 } else if (*i == 0) {
525                     if (segments.size() > 1 && !slash) {
526                         abs.append(static_cast< sal_Unicode >('/'));
527                     }
528                 } else {
529                     switch (excessParentSegments) {
530                     case css::uri::RelativeUriExcessParentSegments_ERROR:
531                         return 0;
532 
533                     case css::uri::RelativeUriExcessParentSegments_RETAIN:
534                         if (!slash) {
535                             abs.append(static_cast< sal_Unicode >('/'));
536                         }
537                         abs.appendAscii(RTL_CONSTASCII_STRINGPARAM(".."));
538                         slash = *i < 0;
539                         if (slash) {
540                             abs.append(static_cast< sal_Unicode >('/'));
541                         }
542                         break;
543 
544                     case css::uri::RelativeUriExcessParentSegments_REMOVE:
545                         break;
546 
547                     default:
548                         OSL_ASSERT(false);
549                         break;
550                     }
551                 }
552             }
553         } else {
554             abs.append(uriReference->getPath());
555         }
556         if (uriReference->hasQuery()) {
557             abs.append(static_cast< sal_Unicode >('?'));
558             abs.append(uriReference->getQuery());
559         }
560         if (uriReference->hasFragment()) {
561             abs.append(static_cast< sal_Unicode >('#'));
562             abs.append(uriReference->getFragment());
563         }
564         return parse(abs.makeStringAndClear());
565     }
566 }
567 
568 css::uno::Reference< css::uri::XUriReference > Factory::makeRelative(
569     css::uno::Reference< css::uri::XUriReference > const & baseUriReference,
570     css::uno::Reference< css::uri::XUriReference > const & uriReference,
571     sal_Bool preferAuthorityOverRelativePath,
572     sal_Bool preferAbsoluteOverRelativePath,
573     sal_Bool encodeRetainedSpecialSegments)
574     throw (css::uno::RuntimeException)
575 {
576     if (!baseUriReference.is() || !baseUriReference->isAbsolute()
577         || !baseUriReference->isHierarchical() || !uriReference.is()) {
578         return 0;
579     } else if (!uriReference->isAbsolute() || !uriReference->isHierarchical()
580                || !baseUriReference->getScheme().equalsIgnoreAsciiCase(
581                    uriReference->getScheme())) {
582         return clone(uriReference);
583     } else {
584         rtl::OUStringBuffer rel;
585         bool omitQuery = false;
586         if ((baseUriReference->hasAuthority() != uriReference->hasAuthority())
587             || !equalIgnoreEscapeCase(
588                 baseUriReference->getAuthority(),
589                 uriReference->getAuthority()))
590         {
591             if (uriReference->hasAuthority()) {
592                 rel.appendAscii(RTL_CONSTASCII_STRINGPARAM("//"));
593                 rel.append(uriReference->getAuthority());
594             }
595             rel.append(uriReference->getPath());
596         } else if ((equalIgnoreEscapeCase(
597                         baseUriReference->getPath(), uriReference->getPath())
598                     || (baseUriReference->getPath().getLength() <= 1
599                         && uriReference->getPath().getLength() <= 1))
600                    && baseUriReference->hasQuery() == uriReference->hasQuery()
601                    && equalIgnoreEscapeCase(
602                        baseUriReference->getQuery(), uriReference->getQuery()))
603         {
604             omitQuery = true;
605         } else {
606             sal_Int32 count1 = std::max< sal_Int32 >(
607                 baseUriReference->getPathSegmentCount(), 1);
608             sal_Int32 count2 = std::max< sal_Int32 >(
609                 uriReference->getPathSegmentCount(), 1);
610             sal_Int32 i = 0;
611             for (; i < std::min(count1, count2) - 1; ++i) {
612                 if (!equalIgnoreEscapeCase(
613                         baseUriReference->getPathSegment(i),
614                         uriReference->getPathSegment(i)))
615                 {
616                     break;
617                 }
618             }
619             if (i == 0 && preferAbsoluteOverRelativePath
620                 && (preferAuthorityOverRelativePath
621                     || !uriReference->getPath().matchAsciiL(
622                         RTL_CONSTASCII_STRINGPARAM("//"))))
623             {
624                 if (baseUriReference->getPath().getLength() > 1
625                     || uriReference->getPath().getLength() > 1)
626                 {
627                     if (uriReference->getPath().getLength() == 0) {
628                         rel.append(static_cast< sal_Unicode >('/'));
629                     } else {
630                         OSL_ASSERT(uriReference->getPath()[0] == '/');
631                         if (uriReference->getPath().matchAsciiL(
632                                 RTL_CONSTASCII_STRINGPARAM("//"))) {
633                             OSL_ASSERT(uriReference->hasAuthority());
634                             rel.appendAscii(RTL_CONSTASCII_STRINGPARAM("//"));
635                             rel.append(uriReference->getAuthority());
636                         }
637                         rel.append(uriReference->getPath());
638                     }
639                 }
640             } else {
641                 bool segments = false;
642                 for (sal_Int32 j = i; j < count1 - 1; ++j) {
643                     if (segments) {
644                         rel.append(static_cast< sal_Unicode >('/'));
645                     }
646                     rel.appendAscii(RTL_CONSTASCII_STRINGPARAM(".."));
647                     segments = true;
648                 }
649                 if (i < count2 - 1
650                     || (uriReference->getPathSegment(count2 - 1).getLength()
651                         != 0))
652                 {
653                     if (!segments
654                         && (uriReference->getPathSegment(i).getLength() == 0
655                             || (parseScheme(uriReference->getPathSegment(i))
656                                 >= 0)))
657                     {
658                         rel.append(static_cast< sal_Unicode >('.'));
659                         segments = true;
660                     }
661                     for (; i < count2; ++i) {
662                         if (segments) {
663                             rel.append(static_cast< sal_Unicode >('/'));
664                         }
665                         rtl::OUString s(uriReference->getPathSegment(i));
666                         if (encodeRetainedSpecialSegments
667                             && s.equalsAsciiL(RTL_CONSTASCII_STRINGPARAM(".")))
668                         {
669                             rel.appendAscii(RTL_CONSTASCII_STRINGPARAM("%2E"));
670                         } else if (encodeRetainedSpecialSegments
671                                    && s.equalsAsciiL(
672                                        RTL_CONSTASCII_STRINGPARAM("..")))
673                         {
674                             rel.appendAscii(
675                                 RTL_CONSTASCII_STRINGPARAM("%2E%2E"));
676                         } else {
677                             rel.append(s);
678                         }
679                         segments = true;
680                     }
681                 }
682             }
683         }
684         if (!omitQuery && uriReference->hasQuery()) {
685             rel.append(static_cast< sal_Unicode >('?'));
686             rel.append(uriReference->getQuery());
687         }
688         if (uriReference->hasFragment()) {
689             rel.append(static_cast< sal_Unicode >('#'));
690             rel.append(uriReference->getFragment());
691         }
692         return parse(rel.makeStringAndClear());
693     }
694 }
695 
696 }
697 
698 namespace stoc_services { namespace UriReferenceFactory {
699 
700 css::uno::Reference< css::uno::XInterface > create(
701     css::uno::Reference< css::uno::XComponentContext > const & context)
702     SAL_THROW((css::uno::Exception))
703 {
704     try {
705         return static_cast< cppu::OWeakObject * >(new Factory(context));
706     } catch (std::bad_alloc &) {
707         throw css::uno::RuntimeException(
708             rtl::OUString::createFromAscii("std::bad_alloc"), 0);
709     }
710 }
711 
712 rtl::OUString getImplementationName() {
713     return rtl::OUString::createFromAscii(
714         "com.sun.star.comp.uri.UriReferenceFactory");
715 }
716 
717 css::uno::Sequence< rtl::OUString > getSupportedServiceNames() {
718     css::uno::Sequence< rtl::OUString > s(1);
719     s[0] = rtl::OUString::createFromAscii(
720         "com.sun.star.uri.UriReferenceFactory");
721     return s;
722 }
723 
724 } }
725