LCOV - code coverage report
Current view: top level - stoc/source/uriproc - UriReferenceFactory.cxx (source / functions) Hit Total Coverage
Test: commit 10e77ab3ff6f4314137acd6e2702a6e5c1ce1fae Lines: 259 327 79.2 %
Date: 2014-11-03 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         178 : bool equalIgnoreEscapeCase(OUString const & s1, OUString const & s2) {
      58         178 :     if (s1.getLength() == s2.getLength()) {
      59         496 :         for (sal_Int32 i = 0; i < s1.getLength();) {
      60         508 :             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         254 :                 && rtl::compareIgnoreAsciiCase(s1[i + 2], s2[i + 2]) == 0)
      67             :             {
      68           0 :                 i += 3;
      69         254 :             } else if (s1[i] != s2[i]) {
      70           2 :                 return false;
      71             :             } else {
      72         252 :                 ++i;
      73             :             }
      74             :         }
      75         120 :         return true;
      76             :     } else {
      77          56 :         return false;
      78             :     }
      79             : }
      80             : 
      81      164203 : sal_Int32 parseScheme(OUString const & uriReference) {
      82      164203 :     if (uriReference.getLength() >= 2 && rtl::isAsciiAlpha(uriReference[0])) {
      83     1125592 :         for (sal_Int32 i = 0; i < uriReference.getLength(); ++i) {
      84     1107102 :             sal_Unicode c = uriReference[i];
      85     1107102 :             if (c == ':') {
      86      126063 :                 return i;
      87     2040812 :             } else if (!rtl::isAsciiAlpha(c) && !rtl::isAsciiDigit(c)
      88     1045252 :                        && c != '+' && c != '-' && c != '.')
      89             :             {
      90       17479 :                 break;
      91             :             }
      92             :         }
      93             :     }
      94       38140 :     return -1;
      95             : }
      96             : 
      97             : class UriReference:
      98             :     public cppu::WeakImplHelper1<css::uri::XUriReference>,
      99             :     private boost::noncopyable
     100             : {
     101             : public:
     102      155023 :     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      155023 :             query)
     109      155023 :     {}
     110             : 
     111       11835 :     virtual OUString SAL_CALL getUriReference()
     112             :         throw (css::uno::RuntimeException, std::exception) SAL_OVERRIDE
     113       11835 :     { return m_base.getUriReference(); }
     114             : 
     115       76472 :     virtual sal_Bool SAL_CALL isAbsolute()
     116             :         throw (css::uno::RuntimeException, std::exception) SAL_OVERRIDE
     117       76472 :     { return m_base.isAbsolute(); }
     118             : 
     119       38362 :     virtual OUString SAL_CALL getScheme()
     120             :         throw (css::uno::RuntimeException, std::exception) SAL_OVERRIDE
     121       38362 :     { return m_base.getScheme(); }
     122             : 
     123           0 :     virtual OUString SAL_CALL getSchemeSpecificPart()
     124             :         throw (css::uno::RuntimeException, std::exception) SAL_OVERRIDE
     125           0 :     { return m_base.getSchemeSpecificPart(); }
     126             : 
     127       38260 :     virtual sal_Bool SAL_CALL isHierarchical()
     128             :         throw (css::uno::RuntimeException, std::exception) SAL_OVERRIDE
     129       38260 :     { return m_base.isHierarchical(); }
     130             : 
     131      114218 :     virtual sal_Bool SAL_CALL hasAuthority()
     132             :         throw (css::uno::RuntimeException, std::exception) SAL_OVERRIDE
     133      114218 :     { return m_base.hasAuthority(); }
     134             : 
     135       38150 :     virtual OUString SAL_CALL getAuthority()
     136             :         throw (css::uno::RuntimeException, std::exception) SAL_OVERRIDE
     137       38150 :     { return m_base.getAuthority(); }
     138             : 
     139      113834 :     virtual OUString SAL_CALL getPath()
     140             :         throw (css::uno::RuntimeException, std::exception) SAL_OVERRIDE
     141      113834 :     { return m_base.getPath(); }
     142             : 
     143       38058 :     virtual sal_Bool SAL_CALL hasRelativePath()
     144             :         throw (css::uno::RuntimeException, std::exception) SAL_OVERRIDE
     145       38058 :     { return m_base.hasRelativePath(); }
     146             : 
     147       76770 :     virtual sal_Int32 SAL_CALL getPathSegmentCount()
     148             :         throw (css::uno::RuntimeException, std::exception) SAL_OVERRIDE
     149       76770 :     { return m_base.getPathSegmentCount(); }
     150             : 
     151      196602 :     virtual OUString SAL_CALL getPathSegment(sal_Int32 index)
     152             :         throw (css::uno::RuntimeException, std::exception) SAL_OVERRIDE
     153      196602 :     { return m_base.getPathSegment(index); }
     154             : 
     155       38108 :     virtual sal_Bool SAL_CALL hasQuery()
     156             :         throw (css::uno::RuntimeException, std::exception) SAL_OVERRIDE
     157       38108 :     { return m_base.hasQuery(); }
     158             : 
     159          12 :     virtual OUString SAL_CALL getQuery()
     160             :         throw (css::uno::RuntimeException, std::exception) SAL_OVERRIDE
     161          12 :     { return m_base.getQuery(); }
     162             : 
     163       38104 :     virtual sal_Bool SAL_CALL hasFragment()
     164             :         throw (css::uno::RuntimeException, std::exception) SAL_OVERRIDE
     165       38104 :     { return m_base.hasFragment(); }
     166             : 
     167          10 :     virtual OUString SAL_CALL getFragment()
     168             :         throw (css::uno::RuntimeException, std::exception) SAL_OVERRIDE
     169          10 :     { return m_base.getFragment(); }
     170             : 
     171          20 :     virtual void SAL_CALL setFragment(OUString const & fragment)
     172             :         throw (css::uno::RuntimeException, std::exception) SAL_OVERRIDE
     173          20 :     { m_base.setFragment(fragment); }
     174             : 
     175       11123 :     virtual void SAL_CALL clearFragment()
     176             :         throw (css::uno::RuntimeException, std::exception) SAL_OVERRIDE
     177       11123 :     { m_base.clearFragment(); }
     178             : 
     179             : private:
     180      310046 :     virtual ~UriReference() {}
     181             : 
     182             :     stoc::uriproc::UriReference m_base;
     183             : };
     184             : 
     185      155023 : css::uno::Reference< css::uri::XUriReference > parseGeneric(
     186             :     OUString const & scheme, OUString const & schemeSpecificPart)
     187             : {
     188      155023 :     bool isAbsolute = !scheme.isEmpty();
     189      155023 :     bool isHierarchical = !isAbsolute || schemeSpecificPart.startsWith("/");
     190      155023 :     bool hasAuthority = false;
     191      155023 :     OUString authority;
     192      310046 :     OUString path;
     193      155023 :     bool hasQuery = false;
     194      310046 :     OUString query;
     195      155023 :     if (isHierarchical) {
     196      154959 :         sal_Int32 len = schemeSpecificPart.getLength();
     197      154959 :         sal_Int32 i = 0;
     198      464867 :         if (len - i >= 2 && schemeSpecificPart[i] == '/'
     199      271822 :             && schemeSpecificPart[i + 1] == '/')
     200             :         {
     201      116771 :             i += 2;
     202      116771 :             sal_Int32 n = i;
     203      350953 :             while (i < len && schemeSpecificPart[i] != '/'
     204      117411 :                    && schemeSpecificPart[i] != '?') {
     205         320 :                 ++i;
     206             :             }
     207      116771 :             hasAuthority = true;
     208      116771 :             authority = schemeSpecificPart.copy(n, i - n);
     209             :         }
     210      154959 :         sal_Int32 n = i;
     211      154959 :         i = schemeSpecificPart.indexOf('?', i);
     212      154959 :         if (i == -1) {
     213      154951 :             i = len;
     214             :         }
     215      154959 :         path = schemeSpecificPart.copy(n, i - n);
     216      154959 :         if (i != len) {
     217           8 :             hasQuery = true;
     218           8 :             query = schemeSpecificPart.copy(i + 1);
     219             :         }
     220             :     } else {
     221          64 :         if (schemeSpecificPart.isEmpty()) {
     222             :             // The scheme-specific part of an opaque URI must not be empty:
     223           0 :             return 0;
     224             :         }
     225          64 :         path = schemeSpecificPart;
     226             :     }
     227             :     return new UriReference(
     228      310046 :         scheme, isHierarchical, hasAuthority, authority, path, hasQuery, query);
     229             : }
     230             : 
     231             : typedef std::vector< sal_Int32 > Segments;
     232             : 
     233       76052 : void processSegments(
     234             :     Segments & segments,
     235             :     css::uno::Reference< css::uri::XUriReference > const & uriReference,
     236             :     bool base, bool processSpecialSegments)
     237             : {
     238       76052 :     sal_Int32 count = uriReference->getPathSegmentCount() - (base ? 1 : 0);
     239             :     assert(count <= SAL_MAX_INT32 - 1 && -count >= SAL_MIN_INT32 + 1);
     240      176076 :     for (sal_Int32 i = 0; i < count; ++i) {
     241      100024 :         if (processSpecialSegments) {
     242      100024 :             OUString segment(uriReference->getPathSegment(i));
     243      100024 :             if ( segment == "." ) {
     244           0 :                 if (!base && i == count - 1) {
     245           0 :                     segments.push_back(0);
     246             :                 }
     247           0 :                 continue;
     248      100024 :             } else if ( segment == ".." ) {
     249        2112 :                 if (segments.empty() || std::abs(segments.back()) == 1) {
     250           0 :                     segments.push_back(base ? -1 : 1);
     251             :                 } else {
     252        2112 :                     segments.pop_back();
     253             :                 }
     254        2112 :                 continue;
     255       97912 :             }
     256             :         }
     257       97912 :         segments.push_back(base ? -(i + 2) : i + 2);
     258             :     }
     259       76052 : }
     260             : 
     261             : class Factory:
     262             :     public cppu::WeakImplHelper2<
     263             :         css::lang::XServiceInfo, css::uri::XUriReferenceFactory>,
     264             :     private boost::noncopyable
     265             : {
     266             : public:
     267       28065 :     explicit Factory(
     268             :         css::uno::Reference< css::uno::XComponentContext > const & context):
     269       28065 :         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       56130 :     virtual ~Factory() {}
     303             : 
     304          40 :     css::uno::Reference< css::uri::XUriReference > clone(
     305             :         css::uno::Reference< css::uri::XUriReference > const & uriReference)
     306          40 :     { 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      164191 : css::uno::Reference< css::uri::XUriReference > Factory::parse(
     330             :     OUString const & uriReference)
     331             :     throw (css::uno::RuntimeException, std::exception)
     332             : {
     333      164191 :     sal_Int32 fragment = uriReference.indexOf('#');
     334      164191 :     if (fragment == -1) {
     335      164171 :         fragment = uriReference.getLength();
     336             :     }
     337      164191 :     OUString scheme;
     338      328382 :     OUString schemeSpecificPart;
     339      328382 :     OUString serviceName;
     340      164191 :     sal_Int32 n = parseScheme(uriReference);
     341             :     assert(n < fragment);
     342      164191 :     if (n >= 0) {
     343      126063 :         scheme = uriReference.copy(0, n);
     344      126063 :         schemeSpecificPart = uriReference.copy(n + 1, fragment - (n + 1));
     345      126063 :         OUStringBuffer buf;
     346      126063 :         buf.append("com.sun.star.uri.UriSchemeParser_");
     347      767907 :         for (sal_Int32 i = 0; i < scheme.getLength(); ++i) {
     348      641844 :             sal_Unicode c = scheme[i];
     349      641844 :             if (rtl::isAsciiUpperCase(c)) {
     350         108 :                 buf.append(static_cast<sal_Unicode>(rtl::toAsciiLowerCase(c)));
     351      641736 :             } else if (c == '+') {
     352           0 :                 buf.append("PLUS");
     353      641736 :             } else if (c == '-') {
     354           0 :                 buf.append("HYPHEN");
     355      641736 :             } else if (c == '.') {
     356       27504 :                 buf.append("DOT");
     357             :             } else {
     358             :                 assert(rtl::isAsciiLowerCase(c) || rtl::isAsciiDigit(c));
     359      614232 :                 buf.append(c);
     360             :             }
     361             :         }
     362      126063 :         serviceName = buf.makeStringAndClear();
     363             :     } else {
     364       38128 :         schemeSpecificPart = uriReference.copy(0, fragment);
     365             :     }
     366      328382 :     css::uno::Reference< css::uri::XUriSchemeParser > parser;
     367      164191 :     if (!serviceName.isEmpty()) {
     368             :         css::uno::Reference< css::lang::XMultiComponentFactory > factory(
     369      126063 :             m_context->getServiceManager());
     370      126063 :         if (factory.is()) {
     371      126063 :             css::uno::Reference< css::uno::XInterface > service;
     372             :             try {
     373      378189 :                 service = factory->createInstanceWithContext(
     374      252126 :                     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      126063 :             if (service.is()) {
     384       18336 :                 parser = css::uno::Reference< css::uri::XUriSchemeParser >(
     385        9168 :                     service, css::uno::UNO_QUERY_THROW);
     386      126063 :             }
     387      126063 :         }
     388             :     }
     389             :     css::uno::Reference< css::uri::XUriReference > uriRef(
     390      164191 :         parser.is()
     391        9168 :         ? parser->parse(scheme, schemeSpecificPart)
     392      173359 :         : parseGeneric(scheme, schemeSpecificPart));
     393      164191 :     if (uriRef.is() && fragment != uriReference.getLength()) {
     394          20 :         uriRef->setFragment(uriReference.copy(fragment + 1));
     395             :     }
     396      328382 :     return uriRef;
     397             : }
     398             : 
     399       38026 : 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      114078 :     if (!baseUriReference.is() || !baseUriReference->isAbsolute()
     407       76052 :         || !baseUriReference->isHierarchical() || !uriReference.is()) {
     408           0 :         return 0;
     409       38026 :     } else if (uriReference->isAbsolute()) {
     410           0 :         return clone(uriReference);
     411      114078 :     } else if (!uriReference->hasAuthority()
     412      114078 :                && uriReference->getPath().isEmpty()
     413       76052 :                && !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       38026 :         OUStringBuffer abs(baseUriReference->getScheme());
     424       38026 :         abs.append(':');
     425       38026 :         if (uriReference->hasAuthority()) {
     426           0 :             abs.append("//");
     427           0 :             abs.append(uriReference->getAuthority());
     428       38026 :         } else if (baseUriReference->hasAuthority()) {
     429       38026 :             abs.append("//");
     430       38026 :             abs.append(baseUriReference->getAuthority());
     431             :         }
     432       38026 :         if (uriReference->hasRelativePath()) {
     433       38026 :             Segments segments;
     434             :             processSegments(
     435       38026 :                 segments, baseUriReference, true, processSpecialBaseSegments);
     436       38026 :             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       38026 :             bool slash = !baseUriReference->getPath().isEmpty();
     444       38026 :             if (slash) {
     445       38026 :                 abs.append('/');
     446             :             }
     447      133826 :             for (Segments::iterator i(segments.begin()); i != segments.end();
     448             :                  ++i)
     449             :             {
     450       95800 :                 if (*i < -1) {
     451             :                     OUString segment(
     452       38194 :                         baseUriReference->getPathSegment(-(*i + 2)));
     453       38194 :                     if (!segment.isEmpty() || segments.size() > 1) {
     454       38194 :                         if (!slash) {
     455           0 :                             abs.append('/');
     456             :                         }
     457       38194 :                         abs.append(segment);
     458       38194 :                         slash = true;
     459       38194 :                         abs.append('/');
     460       38194 :                     }
     461       57606 :                 } else if (*i > 1) {
     462       57606 :                     OUString segment(uriReference->getPathSegment(*i - 2));
     463       57606 :                     if (!segment.isEmpty() || segments.size() > 1) {
     464       57606 :                         if (!slash) {
     465       19580 :                             abs.append('/');
     466             :                         }
     467       57606 :                         abs.append(segment);
     468       57606 :                         slash = false;
     469       57606 :                     }
     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       38026 :             }
     499             :         } else {
     500           0 :             abs.append(uriReference->getPath());
     501             :         }
     502       38026 :         if (uriReference->hasQuery()) {
     503           0 :             abs.append('?');
     504           0 :             abs.append(uriReference->getQuery());
     505             :         }
     506       38026 :         if (uriReference->hasFragment()) {
     507           0 :             abs.append('#');
     508           0 :             abs.append(uriReference->getFragment());
     509             :         }
     510       38026 :         return parse(abs.makeStringAndClear());
     511             :     }
     512             : }
     513             : 
     514         102 : 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         306 :     if (!baseUriReference.is() || !baseUriReference->isAbsolute()
     523         204 :         || !baseUriReference->isHierarchical() || !uriReference.is()) {
     524           0 :         return 0;
     525         440 :     } else if (!uriReference->isAbsolute() || !uriReference->isHierarchical()
     526         408 :                || !baseUriReference->getScheme().equalsIgnoreAsciiCase(
     527         374 :                    uriReference->getScheme())) {
     528          40 :         return clone(uriReference);
     529             :     } else {
     530          62 :         OUStringBuffer rel;
     531          62 :         bool omitQuery = false;
     532         186 :         if ((baseUriReference->hasAuthority() != uriReference->hasAuthority())
     533         310 :             || !equalIgnoreEscapeCase(
     534          62 :                 baseUriReference->getAuthority(),
     535         310 :                 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         124 :         } else if ((equalIgnoreEscapeCase(
     543         310 :                         baseUriReference->getPath(), uriReference->getPath())
     544         120 :                     || (baseUriReference->getPath().getLength() <= 1
     545          62 :                         && uriReference->getPath().getLength() <= 1))
     546           4 :                    && baseUriReference->hasQuery() == uriReference->hasQuery()
     547         260 :                    && equalIgnoreEscapeCase(
     548          74 :                        baseUriReference->getQuery(), uriReference->getQuery()))
     549             :         {
     550           4 :             omitQuery = true;
     551             :         } else {
     552             :             sal_Int32 count1 = std::max< sal_Int32 >(
     553          58 :                 baseUriReference->getPathSegmentCount(), 1);
     554             :             sal_Int32 count2 = std::max< sal_Int32 >(
     555          58 :                 uriReference->getPathSegmentCount(), 1);
     556          58 :             sal_Int32 i = 0;
     557         108 :             for (; i < std::min(count1, count2) - 1; ++i) {
     558         100 :                 if (!equalIgnoreEscapeCase(
     559          50 :                         baseUriReference->getPathSegment(i),
     560         150 :                         uriReference->getPathSegment(i)))
     561             :                 {
     562           0 :                     break;
     563             :                 }
     564             :             }
     565         210 :             if (i == 0 && preferAbsoluteOverRelativePath
     566         130 :                 && (preferAuthorityOverRelativePath
     567          58 :                     || !uriReference->getPath().startsWith("//")))
     568             :             {
     569         144 :                 if (baseUriReference->getPath().getLength() > 1
     570         144 :                     || uriReference->getPath().getLength() > 1)
     571             :                 {
     572          36 :                     if (uriReference->getPath().isEmpty()) {
     573           0 :                         rel.append('/');
     574             :                     } else {
     575             :                         assert(uriReference->getPath()[0] == '/');
     576          36 :                         if (uriReference->getPath().startsWith("//")) {
     577             :                             assert(uriReference->hasAuthority());
     578           0 :                             rel.append("//");
     579           0 :                             rel.append(uriReference->getAuthority());
     580             :                         }
     581          36 :                         rel.append(uriReference->getPath());
     582             :                     }
     583             :                 }
     584             :             } else {
     585          22 :                 bool segments = false;
     586          34 :                 for (sal_Int32 j = i; j < count1 - 1; ++j) {
     587          12 :                     if (segments) {
     588           2 :                         rel.append('/');
     589             :                     }
     590          12 :                     rel.append("..");
     591          12 :                     segments = true;
     592             :                 }
     593          72 :                 if (i < count2 - 1
     594          82 :                     || (!uriReference->getPathSegment(count2 - 1).isEmpty()))
     595             :                 {
     596          76 :                     if (!segments
     597          78 :                         && (uriReference->getPathSegment(i).isEmpty()
     598          34 :                             || (parseScheme(uriReference->getPathSegment(i))
     599             :                                 >= 0)))
     600             :                     {
     601           0 :                         rel.append('.');
     602           0 :                         segments = true;
     603             :                     }
     604          50 :                     for (; i < count2; ++i) {
     605          28 :                         if (segments) {
     606          16 :                             rel.append('/');
     607             :                         }
     608          28 :                         OUString s(uriReference->getPathSegment(i));
     609          28 :                         if (encodeRetainedSpecialSegments && s == ".") {
     610           0 :                             rel.append("%2E");
     611          28 :                         } else if (encodeRetainedSpecialSegments && s == "..") {
     612           0 :                             rel.append("%2E%2E");
     613             :                         } else {
     614          28 :                             rel.append(s);
     615             :                         }
     616          28 :                         segments = true;
     617          28 :                     }
     618             :                 }
     619             :             }
     620             :         }
     621          62 :         if (!omitQuery && uriReference->hasQuery()) {
     622           4 :             rel.append('?');
     623           4 :             rel.append(uriReference->getQuery());
     624             :         }
     625          62 :         if (uriReference->hasFragment()) {
     626           8 :             rel.append('#');
     627           8 :             rel.append(uriReference->getFragment());
     628             :         }
     629          62 :         return parse(rel.makeStringAndClear());
     630             :     }
     631             : }
     632             : 
     633             : }
     634             : 
     635             : namespace stoc_services { namespace UriReferenceFactory {
     636             : 
     637       28065 : css::uno::Reference< css::uno::XInterface > create(
     638             :     css::uno::Reference< css::uno::XComponentContext > const & context)
     639             : {
     640       28065 :     return static_cast< cppu::OWeakObject * >(new Factory(context));
     641             : }
     642             : 
     643         411 : OUString getImplementationName() {
     644         411 :     return OUString("com.sun.star.comp.uri.UriReferenceFactory");
     645             : }
     646             : 
     647         187 : css::uno::Sequence< OUString > getSupportedServiceNames() {
     648         187 :     css::uno::Sequence< OUString > s(1);
     649         187 :     s[0] = "com.sun.star.uri.UriReferenceFactory";
     650         187 :     return s;
     651             : }
     652             : 
     653             : } }
     654             : 
     655             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.10