LCOV - code coverage report
Current view: top level - stoc/source/uriproc - UriReferenceFactory.cxx (source / functions) Hit Total Coverage
Test: commit 0e63ca4fde4e446f346e35849c756a30ca294aab Lines: 259 327 79.2 %
Date: 2014-04-11 Functions: 33 37 89.2 %
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             : #include "stocservices.hxx"
      54             : 
      55             : namespace {
      56             : 
      57          77 : bool equalIgnoreEscapeCase(OUString const & s1, OUString const & s2) {
      58          77 :     if (s1.getLength() == s2.getLength()) {
      59         219 :         for (sal_Int32 i = 0; i < s1.getLength();) {
      60         224 :             if (s1[i] == '%' && s2[i] == '%' && s1.getLength() - i > 2
      61           0 :                 && rtl::isAsciiHexDigit(s1[i + 1])
      62           0 :                 && rtl::isAsciiHexDigit(s1[i + 2])
      63           0 :                 && rtl::isAsciiHexDigit(s2[i + 1])
      64           0 :                 && rtl::isAsciiHexDigit(s2[i + 2])
      65           0 :                 && rtl::compareIgnoreAsciiCase(s1[i + 1], s2[i + 1]) == 0
      66         112 :                 && rtl::compareIgnoreAsciiCase(s1[i + 2], s2[i + 2]) == 0)
      67             :             {
      68           0 :                 i += 3;
      69         112 :             } else if (s1[i] != s2[i]) {
      70           1 :                 return false;
      71             :             } else {
      72         111 :                 ++i;
      73             :             }
      74             :         }
      75          53 :         return true;
      76             :     } else {
      77          23 :         return false;
      78             :     }
      79             : }
      80             : 
      81       57590 : sal_Int32 parseScheme(OUString const & uriReference) {
      82       57590 :     if (uriReference.getLength() >= 2 && rtl::isAsciiAlpha(uriReference[0])) {
      83      414861 :         for (sal_Int32 i = 0; i < uriReference.getLength(); ++i) {
      84      408578 :             sal_Unicode c = uriReference[i];
      85      408578 :             if (c == ':') {
      86       44135 :                 return i;
      87      761134 :             } else if (!rtl::isAsciiAlpha(c) && !rtl::isAsciiDigit(c)
      88      390797 :                        && c != '+' && c != '-' && c != '.')
      89             :             {
      90        6579 :                 break;
      91             :             }
      92             :         }
      93             :     }
      94       13455 :     return -1;
      95             : }
      96             : 
      97             : class UriReference:
      98             :     public cppu::WeakImplHelper1<css::uri::XUriReference>,
      99             :     private boost::noncopyable
     100             : {
     101             : public:
     102       53173 :     UriReference(
     103             :         OUString const & scheme, bool bIsHierarchical, bool bHasAuthority,
     104             :         OUString const & authority, OUString const & path,
     105             :         bool bHasQuery, OUString const & query):
     106             :         m_base(
     107             :             scheme, bIsHierarchical, bHasAuthority, authority, path, bHasQuery,
     108       53173 :             query)
     109       53173 :     {}
     110             : 
     111        4551 :     virtual OUString SAL_CALL getUriReference()
     112             :         throw (com::sun::star::uno::RuntimeException, std::exception) SAL_OVERRIDE
     113        4551 :     { return m_base.getUriReference(); }
     114             : 
     115       26999 :     virtual sal_Bool SAL_CALL isAbsolute()
     116             :         throw (com::sun::star::uno::RuntimeException, std::exception) SAL_OVERRIDE
     117       26999 :     { return m_base.isAbsolute(); }
     118             : 
     119       13553 :     virtual OUString SAL_CALL getScheme()
     120             :         throw (com::sun::star::uno::RuntimeException, std::exception) SAL_OVERRIDE
     121       13553 :     { return m_base.getScheme(); }
     122             : 
     123           0 :     virtual OUString SAL_CALL getSchemeSpecificPart()
     124             :         throw (com::sun::star::uno::RuntimeException, std::exception) SAL_OVERRIDE
     125           0 :     { return m_base.getSchemeSpecificPart(); }
     126             : 
     127       13505 :     virtual sal_Bool SAL_CALL isHierarchical()
     128             :         throw (com::sun::star::uno::RuntimeException, std::exception) SAL_OVERRIDE
     129       13505 :     { return m_base.isHierarchical(); }
     130             : 
     131       40272 :     virtual sal_Bool SAL_CALL hasAuthority()
     132             :         throw (com::sun::star::uno::RuntimeException, std::exception) SAL_OVERRIDE
     133       40272 :     { return m_base.hasAuthority(); }
     134             : 
     135       13456 :     virtual OUString SAL_CALL getAuthority()
     136             :         throw (com::sun::star::uno::RuntimeException, std::exception) SAL_OVERRIDE
     137       13456 :     { return m_base.getAuthority(); }
     138             : 
     139       40126 :     virtual OUString SAL_CALL getPath()
     140             :         throw (com::sun::star::uno::RuntimeException, std::exception) SAL_OVERRIDE
     141       40126 :     { return m_base.getPath(); }
     142             : 
     143       13420 :     virtual sal_Bool SAL_CALL hasRelativePath()
     144             :         throw (com::sun::star::uno::RuntimeException, std::exception) SAL_OVERRIDE
     145       13420 :     { return m_base.hasRelativePath(); }
     146             : 
     147       27090 :     virtual sal_Int32 SAL_CALL getPathSegmentCount()
     148             :         throw (com::sun::star::uno::RuntimeException, std::exception) SAL_OVERRIDE
     149       27090 :     { return m_base.getPathSegmentCount(); }
     150             : 
     151       71050 :     virtual OUString SAL_CALL getPathSegment(sal_Int32 index)
     152             :         throw (com::sun::star::uno::RuntimeException, std::exception) SAL_OVERRIDE
     153       71050 :     { return m_base.getPathSegment(index); }
     154             : 
     155       13440 :     virtual sal_Bool SAL_CALL hasQuery()
     156             :         throw (com::sun::star::uno::RuntimeException, std::exception) SAL_OVERRIDE
     157       13440 :     { return m_base.hasQuery(); }
     158             : 
     159           6 :     virtual OUString SAL_CALL getQuery()
     160             :         throw (com::sun::star::uno::RuntimeException, std::exception) SAL_OVERRIDE
     161           6 :     { return m_base.getQuery(); }
     162             : 
     163       13438 :     virtual sal_Bool SAL_CALL hasFragment()
     164             :         throw (com::sun::star::uno::RuntimeException, std::exception) SAL_OVERRIDE
     165       13438 :     { return m_base.hasFragment(); }
     166             : 
     167           5 :     virtual OUString SAL_CALL getFragment()
     168             :         throw (com::sun::star::uno::RuntimeException, std::exception) SAL_OVERRIDE
     169           5 :     { return m_base.getFragment(); }
     170             : 
     171          10 :     virtual void SAL_CALL setFragment(OUString const & fragment)
     172             :         throw (com::sun::star::uno::RuntimeException, std::exception) SAL_OVERRIDE
     173          10 :     { m_base.setFragment(fragment); }
     174             : 
     175        4273 :     virtual void SAL_CALL clearFragment()
     176             :         throw (com::sun::star::uno::RuntimeException, std::exception) SAL_OVERRIDE
     177        4273 :     { m_base.clearFragment(); }
     178             : 
     179             : private:
     180      106346 :     virtual ~UriReference() {}
     181             : 
     182             :     stoc::uriproc::UriReference m_base;
     183             : };
     184             : 
     185       53173 : css::uno::Reference< css::uri::XUriReference > parseGeneric(
     186             :     OUString const & scheme, OUString const & schemeSpecificPart)
     187             : {
     188       53173 :     bool isAbsolute = !scheme.isEmpty();
     189       53173 :     bool isHierarchical = !isAbsolute || schemeSpecificPart.startsWith("/");
     190       53173 :     bool hasAuthority = false;
     191       53173 :     OUString authority;
     192      106346 :     OUString path;
     193       53173 :     bool hasQuery = false;
     194      106346 :     OUString query;
     195       53173 :     if (isHierarchical) {
     196       53141 :         sal_Int32 len = schemeSpecificPart.getLength();
     197       53141 :         sal_Int32 i = 0;
     198      159418 :         if (len - i >= 2 && schemeSpecificPart[i] == '/'
     199       92844 :             && schemeSpecificPart[i + 1] == '/')
     200             :         {
     201       39661 :             i += 2;
     202       39661 :             sal_Int32 n = i;
     203      119043 :             while (i < len && schemeSpecificPart[i] != '/'
     204       39721 :                    && schemeSpecificPart[i] != '?') {
     205          30 :                 ++i;
     206             :             }
     207       39661 :             hasAuthority = true;
     208       39661 :             authority = schemeSpecificPart.copy(n, i - n);
     209             :         }
     210       53141 :         sal_Int32 n = i;
     211       53141 :         i = schemeSpecificPart.indexOf('?', i);
     212       53141 :         if (i == -1) {
     213       53137 :             i = len;
     214             :         }
     215       53141 :         path = schemeSpecificPart.copy(n, i - n);
     216       53141 :         if (i != len) {
     217           4 :             hasQuery = true;
     218           4 :             query = schemeSpecificPart.copy(i + 1);
     219             :         }
     220             :     } else {
     221          32 :         if (schemeSpecificPart.isEmpty()) {
     222             :             // The scheme-specific part of an opaque URI must not be empty:
     223           0 :             return 0;
     224             :         }
     225          32 :         path = schemeSpecificPart;
     226             :     }
     227             :     return new UriReference(
     228      106346 :         scheme, isHierarchical, hasAuthority, authority, path, hasQuery, query);
     229             : }
     230             : 
     231             : typedef std::vector< sal_Int32 > Segments;
     232             : 
     233       26808 : void processSegments(
     234             :     Segments & segments,
     235             :     css::uno::Reference< css::uri::XUriReference > const & uriReference,
     236             :     bool base, bool processSpecialSegments)
     237             : {
     238       26808 :     sal_Int32 count = uriReference->getPathSegmentCount() - (base ? 1 : 0);
     239             :     assert(count <= SAL_MAX_INT32 - 1 && -count >= SAL_MIN_INT32 + 1);
     240       62745 :     for (sal_Int32 i = 0; i < count; ++i) {
     241       35937 :         if (processSpecialSegments) {
     242       35937 :             OUString segment(uriReference->getPathSegment(i));
     243       35937 :             if ( segment == "." ) {
     244           0 :                 if (!base && i == count - 1) {
     245           0 :                     segments.push_back(0);
     246             :                 }
     247           0 :                 continue;
     248       35937 :             } else if ( segment == ".." ) {
     249         569 :                 if (segments.empty() || std::abs(segments.back()) == 1) {
     250           0 :                     segments.push_back(base ? -1 : 1);
     251             :                 } else {
     252         569 :                     segments.pop_back();
     253             :                 }
     254         569 :                 continue;
     255       35368 :             }
     256             :         }
     257       35368 :         segments.push_back(base ? -(i + 2) : i + 2);
     258             :     }
     259       26808 : }
     260             : 
     261             : class Factory:
     262             :     public cppu::WeakImplHelper2<
     263             :         css::lang::XServiceInfo, css::uri::XUriReferenceFactory>,
     264             :     private boost::noncopyable
     265             : {
     266             : public:
     267       11733 :     explicit Factory(
     268             :         css::uno::Reference< css::uno::XComponentContext > const & context):
     269       11733 :         m_context(context) {}
     270             : 
     271             :     virtual OUString SAL_CALL getImplementationName()
     272             :         throw (css::uno::RuntimeException, std::exception) SAL_OVERRIDE;
     273             : 
     274             :     virtual sal_Bool SAL_CALL supportsService(OUString const & serviceName)
     275             :         throw (css::uno::RuntimeException, std::exception) SAL_OVERRIDE;
     276             : 
     277             :     virtual css::uno::Sequence< OUString > SAL_CALL
     278             :     getSupportedServiceNames() throw (css::uno::RuntimeException, std::exception) SAL_OVERRIDE;
     279             : 
     280             :     virtual css::uno::Reference< css::uri::XUriReference > SAL_CALL
     281             :     parse(OUString const & uriReference)
     282             :         throw (css::uno::RuntimeException, std::exception) SAL_OVERRIDE;
     283             : 
     284             :     virtual css::uno::Reference< css::uri::XUriReference > SAL_CALL
     285             :     makeAbsolute(
     286             :         css::uno::Reference< css::uri::XUriReference > const & baseUriReference,
     287             :         css::uno::Reference< css::uri::XUriReference > const & uriReference,
     288             :         sal_Bool processSpecialBaseSegments,
     289             :         css::uri::RelativeUriExcessParentSegments excessParentSegments)
     290             :         throw (css::uno::RuntimeException, std::exception) SAL_OVERRIDE;
     291             : 
     292             :     virtual css::uno::Reference< css::uri::XUriReference > SAL_CALL
     293             :     makeRelative(
     294             :         css::uno::Reference< css::uri::XUriReference > const & baseUriReference,
     295             :         css::uno::Reference< css::uri::XUriReference > const & uriReference,
     296             :         sal_Bool preferAuthorityOverRelativePath,
     297             :         sal_Bool preferAbsoluteOverRelativePath,
     298             :         sal_Bool encodeRetainedSpecialSegments)
     299             :         throw (css::uno::RuntimeException, std::exception) SAL_OVERRIDE;
     300             : 
     301             : private:
     302       23466 :     virtual ~Factory() {}
     303             : 
     304          17 :     css::uno::Reference< css::uri::XUriReference > clone(
     305             :         css::uno::Reference< css::uri::XUriReference > const & uriReference)
     306          17 :     { return parse(uriReference->getUriReference()); }
     307             : 
     308             :     css::uno::Reference< css::uno::XComponentContext > m_context;
     309             : };
     310             : 
     311           0 : OUString Factory::getImplementationName()
     312             :     throw (css::uno::RuntimeException, std::exception)
     313             : {
     314           0 :     return stoc_services::UriReferenceFactory::getImplementationName();
     315             : }
     316             : 
     317           0 : sal_Bool Factory::supportsService(OUString const & serviceName)
     318             :     throw (css::uno::RuntimeException, std::exception)
     319             : {
     320           0 :     return cppu::supportsService(this, serviceName);
     321             : }
     322             : 
     323           0 : css::uno::Sequence< OUString > Factory::getSupportedServiceNames()
     324             :     throw (css::uno::RuntimeException, std::exception)
     325             : {
     326           0 :     return stoc_services::UriReferenceFactory::getSupportedServiceNames();
     327             : }
     328             : 
     329       57585 : css::uno::Reference< css::uri::XUriReference > Factory::parse(
     330             :     OUString const & uriReference)
     331             :     throw (css::uno::RuntimeException, std::exception)
     332             : {
     333       57585 :     sal_Int32 fragment = uriReference.indexOf('#');
     334       57585 :     if (fragment == -1) {
     335       57575 :         fragment = uriReference.getLength();
     336             :     }
     337       57585 :     OUString scheme;
     338      115170 :     OUString schemeSpecificPart;
     339      115170 :     OUString serviceName;
     340       57585 :     sal_Int32 n = parseScheme(uriReference);
     341             :     assert(n < fragment);
     342       57585 :     if (n >= 0) {
     343       44135 :         scheme = uriReference.copy(0, n);
     344       44135 :         schemeSpecificPart = uriReference.copy(n + 1, fragment - (n + 1));
     345       44135 :         OUStringBuffer buf;
     346       44135 :         buf.append("com.sun.star.uri.UriSchemeParser_");
     347      286891 :         for (sal_Int32 i = 0; i < scheme.getLength(); ++i) {
     348      242756 :             sal_Unicode c = scheme[i];
     349      242756 :             if (rtl::isAsciiUpperCase(c)) {
     350          54 :                 buf.append(static_cast<sal_Unicode>(rtl::toAsciiLowerCase(c)));
     351      242702 :             } else if (c == '+') {
     352           0 :                 buf.append("PLUS");
     353      242702 :             } else if (c == '-') {
     354           0 :                 buf.append("HYPHEN");
     355      242702 :             } else if (c == '.') {
     356       13236 :                 buf.append("DOT");
     357             :             } else {
     358             :                 assert(rtl::isAsciiLowerCase(c) || rtl::isAsciiDigit(c));
     359      229466 :                 buf.append(c);
     360             :             }
     361             :         }
     362       44135 :         serviceName = buf.makeStringAndClear();
     363             :     } else {
     364       13450 :         schemeSpecificPart = uriReference.copy(0, fragment);
     365             :     }
     366      115170 :     css::uno::Reference< css::uri::XUriSchemeParser > parser;
     367       57585 :     if (!serviceName.isEmpty()) {
     368             :         css::uno::Reference< css::lang::XMultiComponentFactory > factory(
     369       44135 :             m_context->getServiceManager());
     370       44135 :         if (factory.is()) {
     371       44135 :             css::uno::Reference< css::uno::XInterface > service;
     372             :             try {
     373      132405 :                 service = factory->createInstanceWithContext(
     374       88270 :                     serviceName, m_context);
     375           0 :             } catch (css::uno::RuntimeException &) {
     376           0 :                 throw;
     377           0 :             } catch (const css::uno::Exception & e) {
     378             :                 throw css::lang::WrappedTargetRuntimeException(
     379           0 :                     "creating service " + serviceName,
     380             :                     static_cast< cppu::OWeakObject * >(this),
     381           0 :                     css::uno::makeAny(e)); //TODO: preserve type of e
     382             :             }
     383       44135 :             if (service.is()) {
     384        8824 :                 parser = css::uno::Reference< css::uri::XUriSchemeParser >(
     385        4412 :                     service, css::uno::UNO_QUERY_THROW);
     386       44135 :             }
     387       44135 :         }
     388             :     }
     389             :     css::uno::Reference< css::uri::XUriReference > uriRef(
     390       57585 :         parser.is()
     391        4412 :         ? parser->parse(scheme, schemeSpecificPart)
     392       61997 :         : parseGeneric(scheme, schemeSpecificPart));
     393       57585 :     if (uriRef.is() && fragment != uriReference.getLength()) {
     394          10 :         uriRef->setFragment(uriReference.copy(fragment + 1));
     395             :     }
     396      115170 :     return uriRef;
     397             : }
     398             : 
     399       13404 : css::uno::Reference< css::uri::XUriReference > Factory::makeAbsolute(
     400             :     css::uno::Reference< css::uri::XUriReference > const & baseUriReference,
     401             :     css::uno::Reference< css::uri::XUriReference > const & uriReference,
     402             :     sal_Bool processSpecialBaseSegments,
     403             :     css::uri::RelativeUriExcessParentSegments excessParentSegments)
     404             :     throw (css::uno::RuntimeException, std::exception)
     405             : {
     406       40212 :     if (!baseUriReference.is() || !baseUriReference->isAbsolute()
     407       26808 :         || !baseUriReference->isHierarchical() || !uriReference.is()) {
     408           0 :         return 0;
     409       13404 :     } else if (uriReference->isAbsolute()) {
     410           0 :         return clone(uriReference);
     411       40212 :     } else if (!uriReference->hasAuthority()
     412       40212 :                && uriReference->getPath().isEmpty()
     413       26808 :                && !uriReference->hasQuery()) {
     414             :         css::uno::Reference< css::uri::XUriReference > abs(
     415           0 :             clone(baseUriReference));
     416           0 :         if (uriReference->hasFragment()) {
     417           0 :             abs->setFragment(uriReference->getFragment());
     418             :         } else {
     419           0 :             abs->clearFragment();
     420             :         }
     421           0 :         return abs;
     422             :     } else {
     423       13404 :         OUStringBuffer abs(baseUriReference->getScheme());
     424       13404 :         abs.append(':');
     425       13404 :         if (uriReference->hasAuthority()) {
     426           0 :             abs.append("//");
     427           0 :             abs.append(uriReference->getAuthority());
     428       13404 :         } else if (baseUriReference->hasAuthority()) {
     429       13404 :             abs.append("//");
     430       13404 :             abs.append(baseUriReference->getAuthority());
     431             :         }
     432       13404 :         if (uriReference->hasRelativePath()) {
     433       13404 :             Segments segments;
     434             :             processSegments(
     435       13404 :                 segments, baseUriReference, true, processSpecialBaseSegments);
     436       13404 :             processSegments(segments, uriReference, false, true);
     437             :             // If the path component of the base URI reference is empty (which
     438             :             // implies that the base URI reference denotes a "root entity"), and
     439             :             // the resulting URI reference denotes the same root entity, make
     440             :             // sure the path component of the resulting URI reference is also
     441             :             // empty (and not "/").  RFC 2396 is unclear about this, and I chose
     442             :             // these rules for consistent results.
     443       13404 :             bool slash = !baseUriReference->getPath().isEmpty();
     444       13404 :             if (slash) {
     445       13404 :                 abs.append('/');
     446             :             }
     447       48203 :             for (Segments::iterator i(segments.begin()); i != segments.end();
     448             :                  ++i)
     449             :             {
     450       34799 :                 if (*i < -1) {
     451             :                     OUString segment(
     452       14252 :                         baseUriReference->getPathSegment(-(*i + 2)));
     453       14252 :                     if (!segment.isEmpty() || segments.size() > 1) {
     454       14252 :                         if (!slash) {
     455           0 :                             abs.append('/');
     456             :                         }
     457       14252 :                         abs.append(segment);
     458       14252 :                         slash = true;
     459       14252 :                         abs.append('/');
     460       14252 :                     }
     461       20547 :                 } else if (*i > 1) {
     462       20547 :                     OUString segment(uriReference->getPathSegment(*i - 2));
     463       20547 :                     if (!segment.isEmpty() || segments.size() > 1) {
     464       20547 :                         if (!slash) {
     465        7143 :                             abs.append('/');
     466             :                         }
     467       20547 :                         abs.append(segment);
     468       20547 :                         slash = false;
     469       20547 :                     }
     470           0 :                 } else if (*i == 0) {
     471           0 :                     if (segments.size() > 1 && !slash) {
     472           0 :                         abs.append('/');
     473             :                     }
     474             :                 } else {
     475           0 :                     switch (excessParentSegments) {
     476             :                     case css::uri::RelativeUriExcessParentSegments_ERROR:
     477           0 :                         return 0;
     478             : 
     479             :                     case css::uri::RelativeUriExcessParentSegments_RETAIN:
     480           0 :                         if (!slash) {
     481           0 :                             abs.append('/');
     482             :                         }
     483           0 :                         abs.append("..");
     484           0 :                         slash = *i < 0;
     485           0 :                         if (slash) {
     486           0 :                             abs.append('/');
     487             :                         }
     488           0 :                         break;
     489             : 
     490             :                     case css::uri::RelativeUriExcessParentSegments_REMOVE:
     491           0 :                         break;
     492             : 
     493             :                     default:
     494             :                         assert(false);
     495           0 :                         break;
     496             :                     }
     497             :                 }
     498       13404 :             }
     499             :         } else {
     500           0 :             abs.append(uriReference->getPath());
     501             :         }
     502       13404 :         if (uriReference->hasQuery()) {
     503           0 :             abs.append('?');
     504           0 :             abs.append(uriReference->getQuery());
     505             :         }
     506       13404 :         if (uriReference->hasFragment()) {
     507           0 :             abs.append('#');
     508           0 :             abs.append(uriReference->getFragment());
     509             :         }
     510       13404 :         return parse(abs.makeStringAndClear());
     511             :     }
     512             : }
     513             : 
     514          43 : css::uno::Reference< css::uri::XUriReference > Factory::makeRelative(
     515             :     css::uno::Reference< css::uri::XUriReference > const & baseUriReference,
     516             :     css::uno::Reference< css::uri::XUriReference > const & uriReference,
     517             :     sal_Bool preferAuthorityOverRelativePath,
     518             :     sal_Bool preferAbsoluteOverRelativePath,
     519             :     sal_Bool encodeRetainedSpecialSegments)
     520             :     throw (css::uno::RuntimeException, std::exception)
     521             : {
     522         129 :     if (!baseUriReference.is() || !baseUriReference->isAbsolute()
     523          86 :         || !baseUriReference->isHierarchical() || !uriReference.is()) {
     524           0 :         return 0;
     525         188 :     } else if (!uriReference->isAbsolute() || !uriReference->isHierarchical()
     526         164 :                || !baseUriReference->getScheme().equalsIgnoreAsciiCase(
     527         147 :                    uriReference->getScheme())) {
     528          17 :         return clone(uriReference);
     529             :     } else {
     530          26 :         OUStringBuffer rel;
     531          26 :         bool omitQuery = false;
     532          78 :         if ((baseUriReference->hasAuthority() != uriReference->hasAuthority())
     533         130 :             || !equalIgnoreEscapeCase(
     534          26 :                 baseUriReference->getAuthority(),
     535         130 :                 uriReference->getAuthority()))
     536             :         {
     537           0 :             if (uriReference->hasAuthority()) {
     538           0 :                 rel.append("//");
     539           0 :                 rel.append(uriReference->getAuthority());
     540             :             }
     541           0 :             rel.append(uriReference->getPath());
     542          52 :         } else if ((equalIgnoreEscapeCase(
     543         130 :                         baseUriReference->getPath(), uriReference->getPath())
     544          50 :                     || (baseUriReference->getPath().getLength() <= 1
     545          26 :                         && uriReference->getPath().getLength() <= 1))
     546           2 :                    && baseUriReference->hasQuery() == uriReference->hasQuery()
     547         110 :                    && equalIgnoreEscapeCase(
     548          32 :                        baseUriReference->getQuery(), uriReference->getQuery()))
     549             :         {
     550           2 :             omitQuery = true;
     551             :         } else {
     552             :             sal_Int32 count1 = std::max< sal_Int32 >(
     553          24 :                 baseUriReference->getPathSegmentCount(), 1);
     554             :             sal_Int32 count2 = std::max< sal_Int32 >(
     555          24 :                 uriReference->getPathSegmentCount(), 1);
     556          24 :             sal_Int32 i = 0;
     557          47 :             for (; i < std::min(count1, count2) - 1; ++i) {
     558          46 :                 if (!equalIgnoreEscapeCase(
     559          23 :                         baseUriReference->getPathSegment(i),
     560          69 :                         uriReference->getPathSegment(i)))
     561             :                 {
     562           0 :                     break;
     563             :                 }
     564             :             }
     565          86 :             if (i == 0 && preferAbsoluteOverRelativePath
     566          52 :                 && (preferAuthorityOverRelativePath
     567          24 :                     || !uriReference->getPath().startsWith("//")))
     568             :             {
     569          56 :                 if (baseUriReference->getPath().getLength() > 1
     570          56 :                     || uriReference->getPath().getLength() > 1)
     571             :                 {
     572          14 :                     if (uriReference->getPath().isEmpty()) {
     573           0 :                         rel.append('/');
     574             :                     } else {
     575             :                         assert(uriReference->getPath()[0] == '/');
     576          14 :                         if (uriReference->getPath().startsWith("//")) {
     577             :                             assert(uriReference->hasAuthority());
     578           0 :                             rel.append("//");
     579           0 :                             rel.append(uriReference->getAuthority());
     580             :                         }
     581          14 :                         rel.append(uriReference->getPath());
     582             :                     }
     583             :                 }
     584             :             } else {
     585          10 :                 bool segments = false;
     586          16 :                 for (sal_Int32 j = i; j < count1 - 1; ++j) {
     587           6 :                     if (segments) {
     588           1 :                         rel.append('/');
     589             :                     }
     590           6 :                     rel.append("..");
     591           6 :                     segments = true;
     592             :                 }
     593          33 :                 if (i < count2 - 1
     594          37 :                     || (!uriReference->getPathSegment(count2 - 1).isEmpty()))
     595             :                 {
     596          35 :                     if (!segments
     597          35 :                         && (uriReference->getPathSegment(i).isEmpty()
     598          15 :                             || (parseScheme(uriReference->getPathSegment(i))
     599             :                                 >= 0)))
     600             :                     {
     601           0 :                         rel.append('.');
     602           0 :                         segments = true;
     603             :                     }
     604          23 :                     for (; i < count2; ++i) {
     605          13 :                         if (segments) {
     606           8 :                             rel.append('/');
     607             :                         }
     608          13 :                         OUString s(uriReference->getPathSegment(i));
     609          13 :                         if (encodeRetainedSpecialSegments && s == ".") {
     610           0 :                             rel.append("%2E");
     611          13 :                         } else if (encodeRetainedSpecialSegments && s == "..") {
     612           0 :                             rel.append("%2E%2E");
     613             :                         } else {
     614          13 :                             rel.append(s);
     615             :                         }
     616          13 :                         segments = true;
     617          13 :                     }
     618             :                 }
     619             :             }
     620             :         }
     621          26 :         if (!omitQuery && uriReference->hasQuery()) {
     622           2 :             rel.append('?');
     623           2 :             rel.append(uriReference->getQuery());
     624             :         }
     625          26 :         if (uriReference->hasFragment()) {
     626           4 :             rel.append('#');
     627           4 :             rel.append(uriReference->getFragment());
     628             :         }
     629          26 :         return parse(rel.makeStringAndClear());
     630             :     }
     631             : }
     632             : 
     633             : }
     634             : 
     635             : namespace stoc_services { namespace UriReferenceFactory {
     636             : 
     637       11733 : css::uno::Reference< css::uno::XInterface > create(
     638             :     css::uno::Reference< css::uno::XComponentContext > const & context)
     639             :     SAL_THROW((css::uno::Exception))
     640             : {
     641       11733 :     return static_cast< cppu::OWeakObject * >(new Factory(context));
     642             : }
     643             : 
     644         187 : OUString getImplementationName() {
     645         187 :     return OUString("com.sun.star.comp.uri.UriReferenceFactory");
     646             : }
     647             : 
     648          85 : css::uno::Sequence< OUString > getSupportedServiceNames() {
     649          85 :     css::uno::Sequence< OUString > s(1);
     650          85 :     s[0] = "com.sun.star.uri.UriReferenceFactory";
     651          85 :     return s;
     652             : }
     653             : 
     654             : } }
     655             : 
     656             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.10