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

Generated by: LCOV version 1.10