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