df4b0ba2f6
Change-Id: I638b1e12781264770ce742d3303693e3b7fa82c1 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/167597 Tested-by: Jenkins Reviewed-by: Noel Grandin <noel.grandin@collabora.co.uk>
701 lines
25 KiB
C++
701 lines
25 KiB
C++
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
|
/*
|
|
* This file is part of the LibreOffice project.
|
|
*
|
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
*
|
|
* This file incorporates work covered by the following license notice:
|
|
*
|
|
* Licensed to the Apache Software Foundation (ASF) under one or more
|
|
* contributor license agreements. See the NOTICE file distributed
|
|
* with this work for additional information regarding copyright
|
|
* ownership. The ASF licenses this file to you under the Apache
|
|
* License, Version 2.0 (the "License"); you may not use this file
|
|
* except in compliance with the License. You may obtain a copy of
|
|
* the License at http://www.apache.org/licenses/LICENSE-2.0 .
|
|
*/
|
|
|
|
#include <sal/config.h>
|
|
|
|
#include <algorithm>
|
|
#include <cassert>
|
|
#include <cstddef>
|
|
#include <string_view>
|
|
#include <utility>
|
|
#include <vector>
|
|
|
|
#include <com/sun/star/lang/WrappedTargetRuntimeException.hpp>
|
|
#include <com/sun/star/lang/XMultiComponentFactory.hpp>
|
|
#include <com/sun/star/lang/XServiceInfo.hpp>
|
|
#include <com/sun/star/uno/Any.hxx>
|
|
#include <com/sun/star/uno/Exception.hpp>
|
|
#include <com/sun/star/uno/Reference.hxx>
|
|
#include <com/sun/star/uno/RuntimeException.hpp>
|
|
#include <com/sun/star/uno/Sequence.hxx>
|
|
#include <com/sun/star/uno/XComponentContext.hpp>
|
|
#include <com/sun/star/uno/XInterface.hpp>
|
|
#include <com/sun/star/uri/RelativeUriExcessParentSegments.hpp>
|
|
#include <com/sun/star/uri/XUriReference.hpp>
|
|
#include <com/sun/star/uri/XUriReferenceFactory.hpp>
|
|
#include <com/sun/star/uri/XUriSchemeParser.hpp>
|
|
#include <cppuhelper/exc_hlp.hxx>
|
|
#include <cppuhelper/implbase.hxx>
|
|
#include <cppuhelper/supportsservice.hxx>
|
|
#include <cppuhelper/weak.hxx>
|
|
#include <rtl/character.hxx>
|
|
#include <rtl/ustrbuf.hxx>
|
|
#include <rtl/ustring.hxx>
|
|
#include <sal/types.h>
|
|
|
|
#include "UriReference.hxx"
|
|
|
|
namespace {
|
|
|
|
bool equalIgnoreEscapeCase(std::u16string_view s1, std::u16string_view s2) {
|
|
if (s1.size() == s2.size()) {
|
|
for (size_t i = 0; i < s1.size();) {
|
|
if (s1[i] == '%' && s2[i] == '%' && s1.size() - i > 2
|
|
&& rtl::isAsciiHexDigit(s1[i + 1])
|
|
&& rtl::isAsciiHexDigit(s1[i + 2])
|
|
&& rtl::isAsciiHexDigit(s2[i + 1])
|
|
&& rtl::isAsciiHexDigit(s2[i + 2])
|
|
&& rtl::compareIgnoreAsciiCase(s1[i + 1], s2[i + 1]) == 0
|
|
&& rtl::compareIgnoreAsciiCase(s1[i + 2], s2[i + 2]) == 0)
|
|
{
|
|
i += 3;
|
|
} else if (s1[i] != s2[i]) {
|
|
return false;
|
|
} else {
|
|
++i;
|
|
}
|
|
}
|
|
return true;
|
|
} else {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
sal_Int32 parseScheme(std::u16string_view uriReference) {
|
|
if (uriReference.size() >= 2 && rtl::isAsciiAlpha(uriReference[0])) {
|
|
for (size_t i = 0; i < uriReference.size(); ++i) {
|
|
sal_Unicode c = uriReference[i];
|
|
if (c == ':') {
|
|
return i;
|
|
} else if (!rtl::isAsciiAlpha(c) && !rtl::isAsciiDigit(c)
|
|
&& c != '+' && c != '-' && c != '.')
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
class UriReference:
|
|
public cppu::WeakImplHelper<css::uri::XUriReference>
|
|
{
|
|
public:
|
|
UriReference(
|
|
OUString const & scheme, bool bHasAuthority,
|
|
OUString const & authority, OUString const & path,
|
|
bool bHasQuery, OUString const & query):
|
|
m_base(
|
|
scheme, bHasAuthority, authority, path, bHasQuery,
|
|
query)
|
|
{}
|
|
|
|
UriReference(const UriReference&) = delete;
|
|
UriReference& operator=(const UriReference&) = delete;
|
|
|
|
virtual OUString SAL_CALL getUriReference() override
|
|
{ return m_base.getUriReference(); }
|
|
|
|
virtual sal_Bool SAL_CALL isAbsolute() override
|
|
{ return m_base.isAbsolute(); }
|
|
|
|
virtual OUString SAL_CALL getScheme() override
|
|
{ return m_base.getScheme(); }
|
|
|
|
virtual OUString SAL_CALL getSchemeSpecificPart() override
|
|
{ return m_base.getSchemeSpecificPart(); }
|
|
|
|
virtual sal_Bool SAL_CALL isHierarchical() override
|
|
{ return m_base.isHierarchical(); }
|
|
|
|
virtual sal_Bool SAL_CALL hasAuthority() override
|
|
{ return m_base.hasAuthority(); }
|
|
|
|
virtual OUString SAL_CALL getAuthority() override
|
|
{ return m_base.getAuthority(); }
|
|
|
|
virtual OUString SAL_CALL getPath() override
|
|
{ return m_base.getPath(); }
|
|
|
|
virtual sal_Bool SAL_CALL hasRelativePath() override
|
|
{ return m_base.hasRelativePath(); }
|
|
|
|
virtual sal_Int32 SAL_CALL getPathSegmentCount() override
|
|
{ return m_base.getPathSegmentCount(); }
|
|
|
|
virtual OUString SAL_CALL getPathSegment(sal_Int32 index) override
|
|
{ return m_base.getPathSegment(index); }
|
|
|
|
virtual sal_Bool SAL_CALL hasQuery() override
|
|
{ return m_base.hasQuery(); }
|
|
|
|
virtual OUString SAL_CALL getQuery() override
|
|
{ return m_base.getQuery(); }
|
|
|
|
virtual sal_Bool SAL_CALL hasFragment() override
|
|
{ return m_base.hasFragment(); }
|
|
|
|
virtual OUString SAL_CALL getFragment() override
|
|
{ return m_base.getFragment(); }
|
|
|
|
virtual void SAL_CALL setFragment(OUString const & fragment) override
|
|
{ m_base.setFragment(fragment); }
|
|
|
|
virtual void SAL_CALL clearFragment() override
|
|
{ m_base.clearFragment(); }
|
|
|
|
private:
|
|
virtual ~UriReference() override {}
|
|
|
|
stoc::uriproc::UriReference m_base;
|
|
};
|
|
|
|
css::uno::Reference< css::uri::XUriReference > parseGeneric(
|
|
OUString const & scheme, std::u16string_view schemeSpecificPart)
|
|
{
|
|
size_t len = schemeSpecificPart.size();
|
|
size_t i = 0;
|
|
bool hasAuthority = false;
|
|
OUString authority;
|
|
if (len - i >= 2 && schemeSpecificPart[i] == '/'
|
|
&& schemeSpecificPart[i + 1] == '/')
|
|
{
|
|
i += 2;
|
|
sal_Int32 n = i;
|
|
while (i < len && schemeSpecificPart[i] != '/'
|
|
&& schemeSpecificPart[i] != '?') {
|
|
++i;
|
|
}
|
|
hasAuthority = true;
|
|
authority = schemeSpecificPart.substr(n, i - n);
|
|
}
|
|
sal_Int32 n = i;
|
|
i = schemeSpecificPart.find('?', i);
|
|
if (i == std::u16string_view::npos) {
|
|
i = len;
|
|
}
|
|
OUString path( schemeSpecificPart.substr(n, i - n) );
|
|
bool hasQuery = false;
|
|
OUString query;
|
|
if (i != len) {
|
|
hasQuery = true;
|
|
query = schemeSpecificPart.substr(i + 1);
|
|
}
|
|
return new UriReference(
|
|
scheme, hasAuthority, authority, path, hasQuery, query);
|
|
}
|
|
|
|
struct Segment {
|
|
bool leadingSlash;
|
|
bool excessParent;
|
|
std::u16string_view segment;
|
|
|
|
Segment(bool theLeadingSlash, bool theExcessParent, std::u16string_view theSegment):
|
|
leadingSlash(theLeadingSlash), excessParent(theExcessParent), segment(theSegment) {}
|
|
};
|
|
|
|
std::pair<std::vector<Segment>, bool> processSegments(
|
|
std::u16string_view first, std::u16string_view second, bool processSpecialSegments)
|
|
{
|
|
std::vector<Segment> segments;
|
|
bool processed = false;
|
|
std::u16string_view const * half = &first;
|
|
// later checks for `half == &first` and `half == &second` rely on the fact that `first` and
|
|
// `second` are passed by value, in case a caller passes the same object for both arguments
|
|
std::size_t index = 0;
|
|
bool slash = false;
|
|
if (index == half->length()) {
|
|
half = &second;
|
|
index = 0;
|
|
}
|
|
if (index != half->length()) {
|
|
if ((*half)[index] == u'/') {
|
|
slash = true;
|
|
++index;
|
|
}
|
|
for (;;) {
|
|
if (index == half->length() && half == &first) {
|
|
half = &second;
|
|
index = 0;
|
|
}
|
|
if (index == half->length()) {
|
|
if (slash) {
|
|
segments.emplace_back(true, false, std::u16string_view());
|
|
}
|
|
break;
|
|
}
|
|
auto const n = std::min(half->find(u'/', index), half->length());
|
|
auto const leadingSlash = slash;
|
|
auto const segment = half->substr(index, n - index);
|
|
auto const process = processSpecialSegments || half == &second;
|
|
index = n;
|
|
slash = false;
|
|
if (index == half->length() && half == &first) {
|
|
half = &second;
|
|
index = 0;
|
|
}
|
|
if (index != half->length() && (*half)[index] == u'/') {
|
|
slash = true;
|
|
++index;
|
|
}
|
|
if (process) {
|
|
if (segment == u".") {
|
|
slash = leadingSlash;
|
|
processed = true;
|
|
continue;
|
|
} else if (segment == u"..") {
|
|
if (segments.empty() || segments.back().excessParent) {
|
|
segments.emplace_back(leadingSlash, true, segment);
|
|
} else {
|
|
if (leadingSlash) {
|
|
segments.pop_back();
|
|
}
|
|
slash = leadingSlash;
|
|
}
|
|
processed = true;
|
|
continue;
|
|
}
|
|
}
|
|
segments.emplace_back(leadingSlash, false, segment);
|
|
}
|
|
}
|
|
return {segments, processed};
|
|
}
|
|
|
|
class Factory:
|
|
public cppu::WeakImplHelper<
|
|
css::lang::XServiceInfo, css::uri::XUriReferenceFactory>
|
|
{
|
|
public:
|
|
explicit Factory(
|
|
css::uno::Reference< css::uno::XComponentContext > context):
|
|
m_context(std::move(context)) {}
|
|
|
|
Factory(const Factory&) = delete;
|
|
Factory& operator=(const Factory&) = delete;
|
|
|
|
virtual OUString SAL_CALL getImplementationName() override;
|
|
|
|
virtual sal_Bool SAL_CALL supportsService(OUString const & serviceName) override;
|
|
|
|
virtual css::uno::Sequence< OUString > SAL_CALL
|
|
getSupportedServiceNames() override;
|
|
|
|
virtual css::uno::Reference< css::uri::XUriReference > SAL_CALL
|
|
parse(OUString const & uriReference) override;
|
|
|
|
virtual css::uno::Reference< css::uri::XUriReference > SAL_CALL
|
|
makeAbsolute(
|
|
css::uno::Reference< css::uri::XUriReference > const & baseUriReference,
|
|
css::uno::Reference< css::uri::XUriReference > const & uriReference,
|
|
sal_Bool processAdditionalSpecialSegments,
|
|
css::uri::RelativeUriExcessParentSegments excessParentSegments) override;
|
|
|
|
virtual css::uno::Reference< css::uri::XUriReference > SAL_CALL
|
|
makeRelative(
|
|
css::uno::Reference< css::uri::XUriReference > const & baseUriReference,
|
|
css::uno::Reference< css::uri::XUriReference > const & uriReference,
|
|
sal_Bool preferAuthorityOverRelativePath,
|
|
sal_Bool preferAbsoluteOverRelativePath,
|
|
sal_Bool encodeRetainedSpecialSegments) override;
|
|
|
|
private:
|
|
virtual ~Factory() override {}
|
|
|
|
css::uno::Reference< css::uri::XUriReference > clone(
|
|
css::uno::Reference< css::uri::XUriReference > const & uriReference)
|
|
{ return parse(uriReference->getUriReference()); }
|
|
|
|
css::uno::Reference< css::uno::XComponentContext > m_context;
|
|
};
|
|
|
|
OUString Factory::getImplementationName()
|
|
{
|
|
return u"com.sun.star.comp.uri.UriReferenceFactory"_ustr;
|
|
}
|
|
|
|
sal_Bool Factory::supportsService(OUString const & serviceName)
|
|
{
|
|
return cppu::supportsService(this, serviceName);
|
|
}
|
|
|
|
css::uno::Sequence< OUString > Factory::getSupportedServiceNames()
|
|
{
|
|
css::uno::Sequence< OUString > s { u"com.sun.star.uri.UriReferenceFactory"_ustr };
|
|
return s;
|
|
}
|
|
|
|
css::uno::Reference< css::uri::XUriReference > Factory::parse(
|
|
OUString const & uriReference)
|
|
{
|
|
sal_Int32 fragment = uriReference.indexOf('#');
|
|
if (fragment == -1) {
|
|
fragment = uriReference.getLength();
|
|
}
|
|
OUString scheme;
|
|
OUString schemeSpecificPart;
|
|
OUString serviceName;
|
|
sal_Int32 n = parseScheme(uriReference);
|
|
assert(n < fragment);
|
|
if (n >= 0) {
|
|
scheme = uriReference.copy(0, n);
|
|
schemeSpecificPart = uriReference.copy(n + 1, fragment - (n + 1));
|
|
OUStringBuffer buf(128);
|
|
buf.append("com.sun.star.uri.UriSchemeParser_");
|
|
for (sal_Int32 i = 0; i < scheme.getLength(); ++i) {
|
|
sal_Unicode c = scheme[i];
|
|
if (rtl::isAsciiUpperCase(c)) {
|
|
buf.append(static_cast<sal_Unicode>(rtl::toAsciiLowerCase(c)));
|
|
} else if (c == '+') {
|
|
buf.append("PLUS");
|
|
} else if (c == '-') {
|
|
buf.append("HYPHEN");
|
|
} else if (c == '.') {
|
|
buf.append("DOT");
|
|
} else {
|
|
assert(rtl::isAsciiLowerCase(c) || rtl::isAsciiDigit(c));
|
|
buf.append(c);
|
|
}
|
|
}
|
|
serviceName = buf.makeStringAndClear();
|
|
} else {
|
|
schemeSpecificPart = uriReference.copy(0, fragment);
|
|
}
|
|
css::uno::Reference< css::uri::XUriSchemeParser > parser;
|
|
if (!serviceName.isEmpty()) {
|
|
css::uno::Reference< css::lang::XMultiComponentFactory > factory(
|
|
m_context->getServiceManager());
|
|
if (factory.is()) {
|
|
css::uno::Reference< css::uno::XInterface > service;
|
|
try {
|
|
service = factory->createInstanceWithContext(
|
|
serviceName, m_context);
|
|
} catch (css::uno::RuntimeException &) {
|
|
throw;
|
|
} catch (const css::uno::Exception &) {
|
|
css::uno::Any anyEx = cppu::getCaughtException();
|
|
throw css::lang::WrappedTargetRuntimeException(
|
|
"creating service " + serviceName,
|
|
getXWeak(),
|
|
anyEx);
|
|
}
|
|
if (service.is()) {
|
|
parser.set( service, css::uno::UNO_QUERY_THROW);
|
|
}
|
|
}
|
|
}
|
|
css::uno::Reference< css::uri::XUriReference > uriRef(
|
|
parser.is()
|
|
? parser->parse(scheme, schemeSpecificPart)
|
|
: parseGeneric(scheme, schemeSpecificPart));
|
|
if (uriRef.is() && fragment != uriReference.getLength()) {
|
|
uriRef->setFragment(uriReference.copy(fragment + 1));
|
|
}
|
|
return uriRef;
|
|
}
|
|
|
|
css::uno::Reference< css::uri::XUriReference > Factory::makeAbsolute(
|
|
css::uno::Reference< css::uri::XUriReference > const & baseUriReference,
|
|
css::uno::Reference< css::uri::XUriReference > const & uriReference,
|
|
sal_Bool processAdditionalSpecialSegments,
|
|
css::uri::RelativeUriExcessParentSegments excessParentSegments)
|
|
{
|
|
if (!baseUriReference.is() || !baseUriReference->isAbsolute()
|
|
|| !uriReference.is()) {
|
|
return nullptr;
|
|
} else if (uriReference->isAbsolute()) {
|
|
if (processAdditionalSpecialSegments) {
|
|
auto const path = uriReference->getPath();
|
|
auto [segments, proc] = processSegments(path, {}, true);
|
|
if (proc) {
|
|
OUStringBuffer abs(uriReference->getScheme() + ":");
|
|
if (uriReference->hasAuthority()) {
|
|
abs.append("//" + uriReference->getAuthority());
|
|
}
|
|
for (auto const & i : segments)
|
|
{
|
|
if (i.excessParent) {
|
|
switch (excessParentSegments) {
|
|
case css::uri::RelativeUriExcessParentSegments_ERROR:
|
|
return nullptr;
|
|
|
|
case css::uri::RelativeUriExcessParentSegments_RETAIN:
|
|
assert(i.segment == u"..");
|
|
break;
|
|
|
|
case css::uri::RelativeUriExcessParentSegments_REMOVE:
|
|
continue;
|
|
|
|
default:
|
|
assert(false);
|
|
break;
|
|
}
|
|
}
|
|
if (i.leadingSlash) {
|
|
abs.append('/');
|
|
}
|
|
abs.append(i.segment);
|
|
}
|
|
if (uriReference->hasQuery()) {
|
|
abs.append("?" + uriReference->getQuery());
|
|
}
|
|
if (uriReference->hasFragment()) {
|
|
abs.append("#" + uriReference->getFragment());
|
|
}
|
|
return parse(abs.makeStringAndClear());
|
|
}
|
|
}
|
|
return clone(uriReference);
|
|
} else if (!uriReference->hasAuthority()
|
|
&& uriReference->getPath().isEmpty()) {
|
|
OUStringBuffer abs(baseUriReference->getScheme() + ":");
|
|
if (baseUriReference->hasAuthority()) {
|
|
abs.append("//" + baseUriReference->getAuthority());
|
|
}
|
|
abs.append(baseUriReference->getPath());
|
|
if (uriReference->hasQuery()) {
|
|
abs.append("?" + uriReference->getQuery());
|
|
} else if (baseUriReference->hasQuery()) {
|
|
abs.append("?" + baseUriReference->getQuery());
|
|
}
|
|
if (uriReference->hasFragment()) {
|
|
abs.append("#" + uriReference->getFragment());
|
|
}
|
|
return parse(abs.makeStringAndClear());
|
|
} else {
|
|
OUStringBuffer abs(128);
|
|
abs.append(baseUriReference->getScheme() + ":");
|
|
if (uriReference->hasAuthority()) {
|
|
abs.append("//" + uriReference->getAuthority());
|
|
} else if (baseUriReference->hasAuthority()) {
|
|
abs.append("//" + baseUriReference->getAuthority());
|
|
}
|
|
if (uriReference->hasRelativePath()) {
|
|
auto path1 = baseUriReference->getPath();
|
|
if (path1.isEmpty()) {
|
|
if (baseUriReference->hasAuthority()) {
|
|
path1 = "/";
|
|
}
|
|
} else {
|
|
path1 = path1.copy(0, path1.lastIndexOf('/') + 1);
|
|
}
|
|
auto const path2 = uriReference->getPath();
|
|
auto [segments, _] = processSegments(path1, path2, processAdditionalSpecialSegments);
|
|
(void)_;
|
|
for (auto const & i : segments)
|
|
{
|
|
if (i.excessParent) {
|
|
switch (excessParentSegments) {
|
|
case css::uri::RelativeUriExcessParentSegments_ERROR:
|
|
return nullptr;
|
|
|
|
case css::uri::RelativeUriExcessParentSegments_RETAIN:
|
|
assert(i.segment == u"..");
|
|
break;
|
|
|
|
case css::uri::RelativeUriExcessParentSegments_REMOVE:
|
|
continue;
|
|
|
|
default:
|
|
assert(false);
|
|
break;
|
|
}
|
|
}
|
|
if (i.leadingSlash) {
|
|
abs.append('/');
|
|
}
|
|
abs.append(i.segment);
|
|
}
|
|
} else {
|
|
bool processed = false;
|
|
if (processAdditionalSpecialSegments) {
|
|
auto const path = uriReference->getPath();
|
|
auto [segments, proc] = processSegments(path, {}, true);
|
|
if (proc) {
|
|
for (auto const & i : segments)
|
|
{
|
|
if (i.excessParent) {
|
|
switch (excessParentSegments) {
|
|
case css::uri::RelativeUriExcessParentSegments_ERROR:
|
|
return nullptr;
|
|
|
|
case css::uri::RelativeUriExcessParentSegments_RETAIN:
|
|
assert(i.segment == u"..");
|
|
break;
|
|
|
|
case css::uri::RelativeUriExcessParentSegments_REMOVE:
|
|
continue;
|
|
|
|
default:
|
|
assert(false);
|
|
break;
|
|
}
|
|
}
|
|
if (i.leadingSlash) {
|
|
abs.append('/');
|
|
}
|
|
abs.append(i.segment);
|
|
}
|
|
processed = true;
|
|
}
|
|
}
|
|
if (!processed) {
|
|
abs.append(uriReference->getPath());
|
|
}
|
|
}
|
|
if (uriReference->hasQuery()) {
|
|
abs.append("?" + uriReference->getQuery());
|
|
}
|
|
if (uriReference->hasFragment()) {
|
|
abs.append("#" + uriReference->getFragment());
|
|
}
|
|
return parse(abs.makeStringAndClear());
|
|
}
|
|
}
|
|
|
|
css::uno::Reference< css::uri::XUriReference > Factory::makeRelative(
|
|
css::uno::Reference< css::uri::XUriReference > const & baseUriReference,
|
|
css::uno::Reference< css::uri::XUriReference > const & uriReference,
|
|
sal_Bool preferAuthorityOverRelativePath,
|
|
sal_Bool preferAbsoluteOverRelativePath,
|
|
sal_Bool encodeRetainedSpecialSegments)
|
|
{
|
|
if (!baseUriReference.is() || !baseUriReference->isAbsolute()
|
|
|| !uriReference.is()) {
|
|
return nullptr;
|
|
} else if (!uriReference->isAbsolute() || uriReference->hasRelativePath()
|
|
|| !baseUriReference->getScheme().equalsIgnoreAsciiCase(
|
|
uriReference->getScheme())) {
|
|
return clone(uriReference);
|
|
} else {
|
|
OUStringBuffer rel(128);
|
|
bool omitQuery = false;
|
|
if ((baseUriReference->hasAuthority() != uriReference->hasAuthority())
|
|
|| !equalIgnoreEscapeCase(
|
|
baseUriReference->getAuthority(),
|
|
uriReference->getAuthority()))
|
|
{
|
|
if (uriReference->hasAuthority()) {
|
|
rel.append("//" + uriReference->getAuthority());
|
|
}
|
|
rel.append(uriReference->getPath());
|
|
} else if ((equalIgnoreEscapeCase(
|
|
baseUriReference->getPath(), uriReference->getPath())
|
|
|| (baseUriReference->getPath() == "/"
|
|
&& uriReference->getPath().isEmpty()))
|
|
&& baseUriReference->hasQuery() == uriReference->hasQuery()
|
|
&& equalIgnoreEscapeCase(
|
|
baseUriReference->getQuery(), uriReference->getQuery()))
|
|
{
|
|
omitQuery = true;
|
|
} else {
|
|
sal_Int32 count1 = std::max< sal_Int32 >(
|
|
baseUriReference->getPathSegmentCount(), 1);
|
|
sal_Int32 count2 = std::max< sal_Int32 >(
|
|
uriReference->getPathSegmentCount(), 1);
|
|
sal_Int32 i = 0;
|
|
for (; i < std::min(count1, count2) - 1; ++i) {
|
|
if (!equalIgnoreEscapeCase(
|
|
baseUriReference->getPathSegment(i),
|
|
uriReference->getPathSegment(i)))
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
if (i == 0
|
|
&& (preferAbsoluteOverRelativePath || uriReference->hasQuery())
|
|
&& (preferAuthorityOverRelativePath
|
|
|| !uriReference->getPath().startsWith("//")))
|
|
{
|
|
if (uriReference->getPath().isEmpty()) {
|
|
if (!baseUriReference->getPath().isEmpty()
|
|
&& baseUriReference->getPath() != "/")
|
|
{
|
|
rel.append('/');
|
|
}
|
|
} else if (uriReference->getPath() == "/") {
|
|
if (baseUriReference->getPath().isEmpty()
|
|
|| baseUriReference->getPath() != "/")
|
|
{
|
|
rel.append('/');
|
|
}
|
|
} else {
|
|
if (uriReference->getPath().startsWith("//")) {
|
|
assert(uriReference->hasAuthority());
|
|
rel.append("//" + uriReference->getAuthority());
|
|
}
|
|
rel.append(uriReference->getPath());
|
|
}
|
|
} else {
|
|
bool segments = false;
|
|
for (sal_Int32 j = i; j < count1 - 1; ++j) {
|
|
if (segments) {
|
|
rel.append('/');
|
|
}
|
|
rel.append("..");
|
|
segments = true;
|
|
}
|
|
if (i < count2 - 1
|
|
|| (!uriReference->getPathSegment(count2 - 1).isEmpty()))
|
|
{
|
|
if (!segments
|
|
&& (uriReference->getPathSegment(i).isEmpty()
|
|
|| (parseScheme(uriReference->getPathSegment(i))
|
|
>= 0)))
|
|
{
|
|
rel.append('.');
|
|
segments = true;
|
|
}
|
|
for (; i < count2; ++i) {
|
|
if (segments) {
|
|
rel.append('/');
|
|
}
|
|
OUString s(uriReference->getPathSegment(i));
|
|
if (encodeRetainedSpecialSegments && s == ".") {
|
|
rel.append("%2E");
|
|
} else if (encodeRetainedSpecialSegments && s == "..") {
|
|
rel.append("%2E%2E");
|
|
} else {
|
|
rel.append(s);
|
|
}
|
|
segments = true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (!omitQuery && uriReference->hasQuery()) {
|
|
rel.append("?" + uriReference->getQuery());
|
|
}
|
|
if (uriReference->hasFragment()) {
|
|
rel.append("#" + uriReference->getFragment());
|
|
}
|
|
return parse(rel.makeStringAndClear());
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
|
|
com_sun_star_comp_uri_UriReferenceFactory_get_implementation(css::uno::XComponentContext* rxContext,
|
|
css::uno::Sequence<css::uno::Any> const &)
|
|
{
|
|
return ::cppu::acquire(new Factory(rxContext));
|
|
}
|
|
|
|
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|