xref: /trunk/main/stoc/source/uriproc/UriReferenceFactory.cxx (revision 91144cd0085a7583d2099b982122deb2184ab956)
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     { return m_base.getUriReference(); }
144 
isAbsolute()145     virtual sal_Bool SAL_CALL isAbsolute()
146     { return m_base.isAbsolute(); }
147 
getScheme()148     virtual rtl::OUString SAL_CALL getScheme()
149     { return m_base.getScheme(); }
150 
getSchemeSpecificPart()151     virtual rtl::OUString SAL_CALL getSchemeSpecificPart()
152     { return m_base.getSchemeSpecificPart(); }
153 
isHierarchical()154     virtual sal_Bool SAL_CALL isHierarchical()
155     { return m_base.isHierarchical(); }
156 
hasAuthority()157     virtual sal_Bool SAL_CALL hasAuthority()
158     { return m_base.hasAuthority(); }
159 
getAuthority()160     virtual rtl::OUString SAL_CALL getAuthority()
161     { return m_base.getAuthority(); }
162 
getPath()163     virtual rtl::OUString SAL_CALL getPath()
164     { return m_base.getPath(); }
165 
hasRelativePath()166     virtual sal_Bool SAL_CALL hasRelativePath()
167     { return m_base.hasRelativePath(); }
168 
getPathSegmentCount()169     virtual sal_Int32 SAL_CALL getPathSegmentCount()
170     { return m_base.getPathSegmentCount(); }
171 
getPathSegment(sal_Int32 index)172     virtual rtl::OUString SAL_CALL getPathSegment(sal_Int32 index)
173     { return m_base.getPathSegment(index); }
174 
hasQuery()175     virtual sal_Bool SAL_CALL hasQuery()
176     { return m_base.hasQuery(); }
177 
getQuery()178     virtual rtl::OUString SAL_CALL getQuery()
179     { return m_base.getQuery(); }
180 
hasFragment()181     virtual sal_Bool SAL_CALL hasFragment()
182     { return m_base.hasFragment(); }
183 
getFragment()184     virtual rtl::OUString SAL_CALL getFragment()
185     { return m_base.getFragment(); }
186 
setFragment(rtl::OUString const & fragment)187     virtual void SAL_CALL setFragment(rtl::OUString const & fragment)
188     { m_base.setFragment(fragment); }
189 
clearFragment()190     virtual void SAL_CALL clearFragment()
191     { m_base.clearFragment(); }
192 
193 private:
194     UriReference(UriReference &); // not implemented
195     void operator =(UriReference); // not implemented
196 
~UriReference()197     virtual ~UriReference() {}
198 
199     stoc::uriproc::UriReference m_base;
200 };
201 
202 // throws std::bad_alloc
parseGeneric(rtl::OUString const & scheme,rtl::OUString const & schemeSpecificPart)203 css::uno::Reference< css::uri::XUriReference > parseGeneric(
204     rtl::OUString const & scheme, rtl::OUString const & schemeSpecificPart)
205 {
206     bool isAbsolute = scheme.getLength() != 0;
207     bool isHierarchical
208         = !isAbsolute
209         || (schemeSpecificPart.getLength() > 0 && schemeSpecificPart[0] == '/');
210     bool hasAuthority = false;
211     rtl::OUString authority;
212     rtl::OUString path;
213     bool hasQuery = false;
214     rtl::OUString query;
215     if (isHierarchical) {
216         sal_Int32 len = schemeSpecificPart.getLength();
217         sal_Int32 i = 0;
218         if (len - i >= 2 && schemeSpecificPart[i] == '/'
219             && schemeSpecificPart[i + 1] == '/')
220         {
221             i += 2;
222             sal_Int32 n = i;
223             while (i < len && schemeSpecificPart[i] != '/'
224                    && schemeSpecificPart[i] != '?') {
225                 ++i;
226             }
227             hasAuthority = true;
228             authority = schemeSpecificPart.copy(n, i - n);
229         }
230         sal_Int32 n = i;
231         i = schemeSpecificPart.indexOf('?', i);
232         if (i == -1) {
233             i = len;
234         }
235         path = schemeSpecificPart.copy(n, i - n);
236         if (i != len) {
237             hasQuery = true;
238             query = schemeSpecificPart.copy(i + 1);
239         }
240     } else {
241         if (schemeSpecificPart.getLength() == 0) {
242             // The scheme-specific part of an opaque URI must not be empty:
243             return 0;
244         }
245         path = schemeSpecificPart;
246     }
247     return new UriReference(
248         scheme, isHierarchical, hasAuthority, authority, path, hasQuery, query);
249 }
250 
251 typedef std::vector< sal_Int32 > Segments;
252 
processSegments(Segments & segments,css::uno::Reference<css::uri::XUriReference> const & uriReference,bool base,bool processSpecialSegments)253 void processSegments(
254     Segments & segments,
255     css::uno::Reference< css::uri::XUriReference > const & uriReference,
256     bool base, bool processSpecialSegments)
257 {
258     sal_Int32 count = uriReference->getPathSegmentCount() - (base ? 1 : 0);
259     OSL_ASSERT(count <= SAL_MAX_INT32 - 1 && -count >= SAL_MIN_INT32 + 1);
260     for (sal_Int32 i = 0; i < count; ++i) {
261         if (processSpecialSegments) {
262             rtl::OUString segment(uriReference->getPathSegment(i));
263             if (segment.equalsAsciiL(RTL_CONSTASCII_STRINGPARAM("."))) {
264                 if (!base && i == count - 1) {
265                     segments.push_back(0);
266                 }
267                 continue;
268             } else if (segment.equalsAsciiL(RTL_CONSTASCII_STRINGPARAM(".."))) {
269                 if (segments.empty()
270                     || /*MSVC trouble: std::*/abs(segments.back()) == 1)
271                 {
272                     segments.push_back(base ? -1 : 1);
273                 } else {
274                     segments.pop_back();
275                 }
276                 continue;
277             }
278         }
279         segments.push_back(base ? -(i + 2) : i + 2);
280     }
281 }
282 
283 class Factory: public cppu::WeakImplHelper2<
284     css::lang::XServiceInfo, css::uri::XUriReferenceFactory >
285 {
286 public:
Factory(css::uno::Reference<css::uno::XComponentContext> const & context)287     explicit Factory(
288         css::uno::Reference< css::uno::XComponentContext > const & context):
289         m_context(context) {}
290 
291     virtual rtl::OUString SAL_CALL getImplementationName();
292 
293     virtual sal_Bool SAL_CALL supportsService(rtl::OUString const & serviceName);
294 
295     virtual css::uno::Sequence< rtl::OUString > SAL_CALL
296     getSupportedServiceNames();
297 
298     virtual css::uno::Reference< css::uri::XUriReference > SAL_CALL
299     parse(rtl::OUString const & uriReference);
300 
301     virtual css::uno::Reference< css::uri::XUriReference > SAL_CALL
302     makeAbsolute(
303         css::uno::Reference< css::uri::XUriReference > const & baseUriReference,
304         css::uno::Reference< css::uri::XUriReference > const & uriReference,
305         sal_Bool processSpecialBaseSegments,
306         css::uri::RelativeUriExcessParentSegments excessParentSegments);
307 
308     virtual css::uno::Reference< css::uri::XUriReference > SAL_CALL
309     makeRelative(
310         css::uno::Reference< css::uri::XUriReference > const & baseUriReference,
311         css::uno::Reference< css::uri::XUriReference > const & uriReference,
312         sal_Bool preferAuthorityOverRelativePath,
313         sal_Bool preferAbsoluteOverRelativePath,
314         sal_Bool encodeRetainedSpecialSegments);
315 
316 private:
317     Factory(Factory &); // not implemented
318     void operator =(Factory); // not implemented
319 
~Factory()320     virtual ~Factory() {}
321 
clone(css::uno::Reference<css::uri::XUriReference> const & uriReference)322     css::uno::Reference< css::uri::XUriReference > clone(
323         css::uno::Reference< css::uri::XUriReference > const & uriReference)
324     { return parse(uriReference->getUriReference()); }
325 
326     css::uno::Reference< css::uno::XComponentContext > m_context;
327 };
328 
getImplementationName()329 rtl::OUString Factory::getImplementationName()
330 {
331     return stoc_services::UriReferenceFactory::getImplementationName();
332 }
333 
supportsService(rtl::OUString const & serviceName)334 sal_Bool Factory::supportsService(rtl::OUString const & serviceName)
335 {
336     return stoc::uriproc::supportsService(
337         getSupportedServiceNames(), serviceName);
338 }
339 
getSupportedServiceNames()340 css::uno::Sequence< rtl::OUString > Factory::getSupportedServiceNames()
341 {
342     return stoc_services::UriReferenceFactory::getSupportedServiceNames();
343 }
344 
parse(rtl::OUString const & uriReference)345 css::uno::Reference< css::uri::XUriReference > Factory::parse(
346     rtl::OUString const & uriReference)
347 {
348     sal_Int32 fragment = uriReference.indexOf('#');
349     if (fragment == -1) {
350         fragment = uriReference.getLength();
351     }
352     rtl::OUString scheme;
353     rtl::OUString schemeSpecificPart;
354     rtl::OUString serviceName;
355     sal_Int32 n = parseScheme(uriReference);
356     OSL_ASSERT(n < fragment);
357     if (n >= 0) {
358         scheme = uriReference.copy(0, n);
359         schemeSpecificPart = uriReference.copy(n + 1, fragment - (n + 1));
360         rtl::OUStringBuffer buf;
361         buf.appendAscii(
362             RTL_CONSTASCII_STRINGPARAM("com.sun.star.uri.UriSchemeParser_"));
363         for (sal_Int32 i = 0; i < scheme.getLength(); ++i) {
364             sal_Unicode c = scheme[i];
365             if (isUpperCase(c)) {
366                 buf.append(toLowerCase(c));
367             } else if (c == '+') {
368                 buf.appendAscii(RTL_CONSTASCII_STRINGPARAM("PLUS"));
369             } else if (c == '-') {
370                 buf.appendAscii(RTL_CONSTASCII_STRINGPARAM("HYPHEN"));
371             } else if (c == '.') {
372                 buf.appendAscii(RTL_CONSTASCII_STRINGPARAM("DOT"));
373             } else {
374                 OSL_ASSERT(isLowerCase(c) || isDigit(c));
375                 buf.append(c);
376             }
377         }
378         serviceName = buf.makeStringAndClear();
379     } else {
380         schemeSpecificPart = uriReference.copy(0, fragment);
381     }
382     css::uno::Reference< css::uri::XUriSchemeParser > parser;
383     if (serviceName.getLength() != 0) {
384         css::uno::Reference< css::lang::XMultiComponentFactory > factory(
385             m_context->getServiceManager());
386         if (factory.is()) {
387             css::uno::Reference< css::uno::XInterface > service;
388             try {
389                 service = factory->createInstanceWithContext(
390                     serviceName, m_context);
391             } catch (css::uno::RuntimeException &) {
392                 throw;
393             } catch (css::uno::Exception & e) {
394                 throw css::lang::WrappedTargetRuntimeException(
395                     rtl::OUString::createFromAscii("creating service ")
396                         + serviceName,
397                     static_cast< cppu::OWeakObject * >(this),
398                     css::uno::makeAny(e)); //TODO: preserve type of e
399             }
400             if (service.is()) {
401                 parser = css::uno::Reference< css::uri::XUriSchemeParser >(
402                     service, css::uno::UNO_QUERY_THROW);
403             }
404         }
405     }
406     css::uno::Reference< css::uri::XUriReference > uriRef;
407     if (parser.is()) {
408         uriRef = parser->parse(scheme, schemeSpecificPart);
409     } else {
410         try {
411             uriRef = parseGeneric(scheme, schemeSpecificPart);
412         } catch (std::bad_alloc &) {
413             throw css::uno::RuntimeException(
414                 rtl::OUString::createFromAscii("std::bad_alloc"),
415                 static_cast< cppu::OWeakObject * >(this));
416         }
417     }
418     if (uriRef.is() && fragment != uriReference.getLength()) {
419         uriRef->setFragment(uriReference.copy(fragment + 1));
420     }
421     return uriRef;
422 }
423 
makeAbsolute(css::uno::Reference<css::uri::XUriReference> const & baseUriReference,css::uno::Reference<css::uri::XUriReference> const & uriReference,sal_Bool processSpecialBaseSegments,css::uri::RelativeUriExcessParentSegments excessParentSegments)424 css::uno::Reference< css::uri::XUriReference > Factory::makeAbsolute(
425     css::uno::Reference< css::uri::XUriReference > const & baseUriReference,
426     css::uno::Reference< css::uri::XUriReference > const & uriReference,
427     sal_Bool processSpecialBaseSegments,
428     css::uri::RelativeUriExcessParentSegments excessParentSegments)
429 {
430     if (!baseUriReference.is() || !baseUriReference->isAbsolute()
431         || !baseUriReference->isHierarchical() || !uriReference.is()) {
432         return 0;
433     } else if (uriReference->isAbsolute()) {
434         return clone(uriReference);
435     } else if (!uriReference->hasAuthority()
436                && uriReference->getPath().getLength() == 0
437                && !uriReference->hasQuery()) {
438         css::uno::Reference< css::uri::XUriReference > abs(
439             clone(baseUriReference));
440         if (uriReference->hasFragment()) {
441             abs->setFragment(uriReference->getFragment());
442         } else {
443             abs->clearFragment();
444         }
445         return abs;
446     } else {
447         rtl::OUStringBuffer abs(baseUriReference->getScheme());
448         abs.append(static_cast< sal_Unicode >(':'));
449         if (uriReference->hasAuthority()) {
450             abs.appendAscii(RTL_CONSTASCII_STRINGPARAM("//"));
451             abs.append(uriReference->getAuthority());
452         } else if (baseUriReference->hasAuthority()) {
453             abs.appendAscii(RTL_CONSTASCII_STRINGPARAM("//"));
454             abs.append(baseUriReference->getAuthority());
455         }
456         if (uriReference->hasRelativePath()) {
457             Segments segments;
458             processSegments(
459                 segments, baseUriReference, true, processSpecialBaseSegments);
460             processSegments(segments, uriReference, false, true);
461             // If the path component of the base URI reference is empty (which
462             // implies that the base URI reference denotes a "root entity"), and
463             // the resulting URI reference denotes the same root entity, make
464             // sure the path component of the resulting URI reference is also
465             // empty (and not "/").  RFC 2396 is unclear about this, and I chose
466             // these rules for consistent results.
467             bool slash = baseUriReference->getPath().getLength() != 0;
468             if (slash) {
469                 abs.append(static_cast< sal_Unicode >('/'));
470             }
471             for (Segments::iterator i(segments.begin()); i != segments.end();
472                  ++i)
473             {
474                 if (*i < -1) {
475                     rtl::OUString segment(
476                         baseUriReference->getPathSegment(-(*i + 2)));
477                     if (segment.getLength() != 0 || segments.size() > 1) {
478                         if (!slash) {
479                             abs.append(static_cast< sal_Unicode >('/'));
480                         }
481                         abs.append(segment);
482                         slash = true;
483                         abs.append(static_cast< sal_Unicode >('/'));
484                     }
485                 } else if (*i > 1) {
486                     rtl::OUString segment(uriReference->getPathSegment(*i - 2));
487                     if (segment.getLength() != 0 || segments.size() > 1) {
488                         if (!slash) {
489                             abs.append(static_cast< sal_Unicode >('/'));
490                         }
491                         abs.append(segment);
492                         slash = false;
493                     }
494                 } else if (*i == 0) {
495                     if (segments.size() > 1 && !slash) {
496                         abs.append(static_cast< sal_Unicode >('/'));
497                     }
498                 } else {
499                     switch (excessParentSegments) {
500                     case css::uri::RelativeUriExcessParentSegments_ERROR:
501                         return 0;
502 
503                     case css::uri::RelativeUriExcessParentSegments_RETAIN:
504                         if (!slash) {
505                             abs.append(static_cast< sal_Unicode >('/'));
506                         }
507                         abs.appendAscii(RTL_CONSTASCII_STRINGPARAM(".."));
508                         slash = *i < 0;
509                         if (slash) {
510                             abs.append(static_cast< sal_Unicode >('/'));
511                         }
512                         break;
513 
514                     case css::uri::RelativeUriExcessParentSegments_REMOVE:
515                         break;
516 
517                     default:
518                         OSL_ASSERT(false);
519                         break;
520                     }
521                 }
522             }
523         } else {
524             abs.append(uriReference->getPath());
525         }
526         if (uriReference->hasQuery()) {
527             abs.append(static_cast< sal_Unicode >('?'));
528             abs.append(uriReference->getQuery());
529         }
530         if (uriReference->hasFragment()) {
531             abs.append(static_cast< sal_Unicode >('#'));
532             abs.append(uriReference->getFragment());
533         }
534         return parse(abs.makeStringAndClear());
535     }
536 }
537 
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)538 css::uno::Reference< css::uri::XUriReference > Factory::makeRelative(
539     css::uno::Reference< css::uri::XUriReference > const & baseUriReference,
540     css::uno::Reference< css::uri::XUriReference > const & uriReference,
541     sal_Bool preferAuthorityOverRelativePath,
542     sal_Bool preferAbsoluteOverRelativePath,
543     sal_Bool encodeRetainedSpecialSegments)
544 {
545     if (!baseUriReference.is() || !baseUriReference->isAbsolute()
546         || !baseUriReference->isHierarchical() || !uriReference.is()) {
547         return 0;
548     } else if (!uriReference->isAbsolute() || !uriReference->isHierarchical()
549                || !baseUriReference->getScheme().equalsIgnoreAsciiCase(
550                    uriReference->getScheme())) {
551         return clone(uriReference);
552     } else {
553         rtl::OUStringBuffer rel;
554         bool omitQuery = false;
555         if ((baseUriReference->hasAuthority() != uriReference->hasAuthority())
556             || !equalIgnoreEscapeCase(
557                 baseUriReference->getAuthority(),
558                 uriReference->getAuthority()))
559         {
560             if (uriReference->hasAuthority()) {
561                 rel.appendAscii(RTL_CONSTASCII_STRINGPARAM("//"));
562                 rel.append(uriReference->getAuthority());
563             }
564             rel.append(uriReference->getPath());
565         } else if ((equalIgnoreEscapeCase(
566                         baseUriReference->getPath(), uriReference->getPath())
567                     || (baseUriReference->getPath().getLength() <= 1
568                         && uriReference->getPath().getLength() <= 1))
569                    && baseUriReference->hasQuery() == uriReference->hasQuery()
570                    && equalIgnoreEscapeCase(
571                        baseUriReference->getQuery(), uriReference->getQuery()))
572         {
573             omitQuery = true;
574         } else {
575             sal_Int32 count1 = std::max< sal_Int32 >(
576                 baseUriReference->getPathSegmentCount(), 1);
577             sal_Int32 count2 = std::max< sal_Int32 >(
578                 uriReference->getPathSegmentCount(), 1);
579             sal_Int32 i = 0;
580             for (; i < std::min(count1, count2) - 1; ++i) {
581                 if (!equalIgnoreEscapeCase(
582                         baseUriReference->getPathSegment(i),
583                         uriReference->getPathSegment(i)))
584                 {
585                     break;
586                 }
587             }
588             if (i == 0 && preferAbsoluteOverRelativePath
589                 && (preferAuthorityOverRelativePath
590                     || !uriReference->getPath().matchAsciiL(
591                         RTL_CONSTASCII_STRINGPARAM("//"))))
592             {
593                 if (baseUriReference->getPath().getLength() > 1
594                     || uriReference->getPath().getLength() > 1)
595                 {
596                     if (uriReference->getPath().getLength() == 0) {
597                         rel.append(static_cast< sal_Unicode >('/'));
598                     } else {
599                         OSL_ASSERT(uriReference->getPath()[0] == '/');
600                         if (uriReference->getPath().matchAsciiL(
601                                 RTL_CONSTASCII_STRINGPARAM("//"))) {
602                             OSL_ASSERT(uriReference->hasAuthority());
603                             rel.appendAscii(RTL_CONSTASCII_STRINGPARAM("//"));
604                             rel.append(uriReference->getAuthority());
605                         }
606                         rel.append(uriReference->getPath());
607                     }
608                 }
609             } else {
610                 bool segments = false;
611                 for (sal_Int32 j = i; j < count1 - 1; ++j) {
612                     if (segments) {
613                         rel.append(static_cast< sal_Unicode >('/'));
614                     }
615                     rel.appendAscii(RTL_CONSTASCII_STRINGPARAM(".."));
616                     segments = true;
617                 }
618                 if (i < count2 - 1
619                     || (uriReference->getPathSegment(count2 - 1).getLength()
620                         != 0))
621                 {
622                     if (!segments
623                         && (uriReference->getPathSegment(i).getLength() == 0
624                             || (parseScheme(uriReference->getPathSegment(i))
625                                 >= 0)))
626                     {
627                         rel.append(static_cast< sal_Unicode >('.'));
628                         segments = true;
629                     }
630                     for (; i < count2; ++i) {
631                         if (segments) {
632                             rel.append(static_cast< sal_Unicode >('/'));
633                         }
634                         rtl::OUString s(uriReference->getPathSegment(i));
635                         if (encodeRetainedSpecialSegments
636                             && s.equalsAsciiL(RTL_CONSTASCII_STRINGPARAM(".")))
637                         {
638                             rel.appendAscii(RTL_CONSTASCII_STRINGPARAM("%2E"));
639                         } else if (encodeRetainedSpecialSegments
640                                    && s.equalsAsciiL(
641                                        RTL_CONSTASCII_STRINGPARAM("..")))
642                         {
643                             rel.appendAscii(
644                                 RTL_CONSTASCII_STRINGPARAM("%2E%2E"));
645                         } else {
646                             rel.append(s);
647                         }
648                         segments = true;
649                     }
650                 }
651             }
652         }
653         if (!omitQuery && uriReference->hasQuery()) {
654             rel.append(static_cast< sal_Unicode >('?'));
655             rel.append(uriReference->getQuery());
656         }
657         if (uriReference->hasFragment()) {
658             rel.append(static_cast< sal_Unicode >('#'));
659             rel.append(uriReference->getFragment());
660         }
661         return parse(rel.makeStringAndClear());
662     }
663 }
664 
665 }
666 
667 namespace stoc_services { namespace UriReferenceFactory {
668 
create(css::uno::Reference<css::uno::XComponentContext> const & context)669 css::uno::Reference< css::uno::XInterface > create(
670     css::uno::Reference< css::uno::XComponentContext > const & context)
671 {
672     try {
673         return static_cast< cppu::OWeakObject * >(new Factory(context));
674     } catch (std::bad_alloc &) {
675         throw css::uno::RuntimeException(
676             rtl::OUString::createFromAscii("std::bad_alloc"), 0);
677     }
678 }
679 
getImplementationName()680 rtl::OUString getImplementationName() {
681     return rtl::OUString::createFromAscii(
682         "com.sun.star.comp.uri.UriReferenceFactory");
683 }
684 
getSupportedServiceNames()685 css::uno::Sequence< rtl::OUString > getSupportedServiceNames() {
686     css::uno::Sequence< rtl::OUString > s(1);
687     s[0] = rtl::OUString::createFromAscii(
688         "com.sun.star.uri.UriReferenceFactory");
689     return s;
690 }
691 
692 } }
693