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

Generated by: LCOV version 1.10