LCOV - code coverage report
Current view: top level - stoc/source/uriproc - UriReferenceFactory.cxx (source / functions) Hit Total Coverage
Test: commit c8344322a7af75b84dd3ca8f78b05543a976dfd5 Lines: 259 323 80.2 %
Date: 2015-06-13 12:38:46 Functions: 33 35 94.3 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.11