diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 09:06:44 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 09:06:44 +0000 |
commit | ed5640d8b587fbcfed7dd7967f3de04b37a76f26 (patch) | |
tree | 7a5f7c6c9d02226d7471cb3cc8fbbf631b415303 /stoc/source/uriproc | |
parent | Initial commit. (diff) | |
download | libreoffice-upstream.tar.xz libreoffice-upstream.zip |
Adding upstream version 4:7.4.7.upstream/4%7.4.7upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'stoc/source/uriproc')
-rw-r--r-- | stoc/source/uriproc/ExternalUriReferenceTranslator.cxx | 187 | ||||
-rw-r--r-- | stoc/source/uriproc/UriReference.cxx | 183 | ||||
-rw-r--r-- | stoc/source/uriproc/UriReference.hxx | 112 | ||||
-rw-r--r-- | stoc/source/uriproc/UriReferenceFactory.cxx | 719 | ||||
-rw-r--r-- | stoc/source/uriproc/UriSchemeParser_vndDOTsunDOTstarDOTexpand.cxx | 198 | ||||
-rw-r--r-- | stoc/source/uriproc/UriSchemeParser_vndDOTsunDOTstarDOTscript.cxx | 386 | ||||
-rw-r--r-- | stoc/source/uriproc/VndSunStarPkgUrlReferenceFactory.cxx | 119 |
7 files changed, 1904 insertions, 0 deletions
diff --git a/stoc/source/uriproc/ExternalUriReferenceTranslator.cxx b/stoc/source/uriproc/ExternalUriReferenceTranslator.cxx new file mode 100644 index 000000000..b9e2ca4e9 --- /dev/null +++ b/stoc/source/uriproc/ExternalUriReferenceTranslator.cxx @@ -0,0 +1,187 @@ +/* -*- 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 <com/sun/star/lang/XServiceInfo.hpp> +#include <com/sun/star/uno/Sequence.hxx> +#include <com/sun/star/uri/XExternalUriReferenceTranslator.hpp> +#include <cppuhelper/implbase.hxx> +#include <cppuhelper/supportsservice.hxx> +#include <cppuhelper/weak.hxx> +#include <osl/thread.h> +#include <rtl/string.h> +#include <rtl/textenc.h> +#include <rtl/uri.h> +#include <rtl/uri.hxx> +#include <rtl/ustrbuf.hxx> +#include <rtl/ustring.hxx> +#include <sal/types.h> + +namespace com::sun::star::uno { class XInterface; } +namespace com::sun::star::uno { class XComponentContext; } + +namespace { + +class Translator: + public cppu::WeakImplHelper< + css::lang::XServiceInfo, css::uri::XExternalUriReferenceTranslator> +{ +public: + Translator() {} + + Translator(const Translator&) = delete; + Translator& operator=(const Translator&) = 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 OUString SAL_CALL + translateToInternal(OUString const & externalUriReference) override; + + virtual OUString SAL_CALL + translateToExternal(OUString const & internalUriReference) override; + +private: + virtual ~Translator() override {} +}; + +OUString Translator::getImplementationName() +{ + return "com.sun.star.comp.uri.ExternalUriReferenceTranslator"; +} + +sal_Bool Translator::supportsService(OUString const & serviceName) +{ + return cppu::supportsService(this, serviceName); +} + +css::uno::Sequence< OUString > Translator::getSupportedServiceNames() +{ + css::uno::Sequence< OUString > s { "com.sun.star.uri.ExternalUriReferenceTranslator" }; + return s; +} + +OUString Translator::translateToInternal( + OUString const & externalUriReference) +{ + if (!externalUriReference.matchIgnoreAsciiCase("file:/")) + { + return externalUriReference; + } + sal_Int32 i = RTL_CONSTASCII_LENGTH("file:"); + OUStringBuffer buf(128); + buf.append(externalUriReference.subView(0, i)); + // Some environments (e.g., Java) produce illegal file URLs without an + // authority part; treat them as having an empty authority part: + if (!externalUriReference.match("//", i)) + { + buf.append("//"); + } + rtl_TextEncoding encoding = osl_getThreadTextEncoding(); + for (bool path = true;;) { + sal_Int32 j = i; + while (j != externalUriReference.getLength() + && externalUriReference[j] != '#' + && (!path || externalUriReference[j] != '/')) + { + ++j; + } + if (j != i) { + OUString seg( + rtl::Uri::encode( + rtl::Uri::decode( + externalUriReference.copy(i, j - i), + rtl_UriDecodeStrict, encoding), + rtl_UriCharClassPchar, rtl_UriEncodeStrict, + RTL_TEXTENCODING_UTF8)); + if (seg.isEmpty()) { + return OUString(); + } + buf.append(seg); + } + if (j == externalUriReference.getLength()) { + break; + } + buf.append(externalUriReference[j]); + path = externalUriReference[j] == '/'; + i = j + 1; + } + return buf.makeStringAndClear(); +} + +OUString Translator::translateToExternal( + OUString const & internalUriReference) +{ + if (!internalUriReference.matchIgnoreAsciiCase("file://")) + { + return internalUriReference; + } + sal_Int32 i = RTL_CONSTASCII_LENGTH("file://"); + OUStringBuffer buf(128); + buf.append(internalUriReference.subView(0, i)); + rtl_TextEncoding encoding = osl_getThreadTextEncoding(); + for (bool path = true;;) { + sal_Int32 j = i; + while (j != internalUriReference.getLength() + && internalUriReference[j] != '#' + && (!path || internalUriReference[j] != '/')) + { + ++j; + } + if (j != i) { + // Use rtl_UriDecodeToIuri -> rtl_UriEncodeStrictKeepEscapes instead + // of rtl_UriDecodeStrict -> rtl_UriEncodeStrict, so that spurious + // non--UTF-8 octets like "%FE" are copied verbatim: + OUString seg( + rtl::Uri::encode( + rtl::Uri::decode( + internalUriReference.copy(i, j - i), + rtl_UriDecodeToIuri, RTL_TEXTENCODING_UTF8), + rtl_UriCharClassPchar, rtl_UriEncodeStrictKeepEscapes, + encoding)); + if (seg.isEmpty()) { + return OUString(); + } + buf.append(seg); + } + if (j == internalUriReference.getLength()) { + break; + } + buf.append(internalUriReference[j]); + path = internalUriReference[j] == '/'; + i = j + 1; + } + return buf.makeStringAndClear(); +} + +} + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface* +com_sun_star_comp_uri_ExternalUriReferenceTranslator_get_implementation(css::uno::XComponentContext* , + css::uno::Sequence<css::uno::Any> const &) +{ + return ::cppu::acquire(new Translator); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/stoc/source/uriproc/UriReference.cxx b/stoc/source/uriproc/UriReference.cxx new file mode 100644 index 000000000..e8f7db0bf --- /dev/null +++ b/stoc/source/uriproc/UriReference.cxx @@ -0,0 +1,183 @@ +/* -*- 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 <cassert> + +#include "UriReference.hxx" + +#include <rtl/ustrbuf.hxx> +#include <rtl/ustring.hxx> +#include <sal/types.h> + +using stoc::uriproc::UriReference; + +UriReference::UriReference( + OUString const & scheme, bool bHasAuthority, + OUString const & authority, OUString const & path, + bool bHasQuery, OUString const & query): + m_path(path), + m_scheme(scheme), + m_authority(authority), + m_query(query), + m_hasAuthority(bHasAuthority), + m_hasQuery(bHasQuery), + m_hasFragment(false) +{ + assert(authority.isEmpty() || bHasAuthority); + assert(query.isEmpty() || bHasQuery); +} + +UriReference::~UriReference() {} + +OUString UriReference::getUriReference() +{ + std::lock_guard g(m_mutex); + OUStringBuffer buf(128); + if (!m_scheme.isEmpty()) { + buf.append(m_scheme); + buf.append(':'); + } + appendSchemeSpecificPart(buf); + if (m_hasFragment) { + buf.append('#'); + buf.append(m_fragment); + } + return buf.makeStringAndClear(); +} + +bool UriReference::isAbsolute() const { + return !m_scheme.isEmpty(); +} + + +OUString UriReference::getSchemeSpecificPart() +{ + std::lock_guard g(m_mutex); + OUStringBuffer buf; + appendSchemeSpecificPart(buf); + return buf.makeStringAndClear(); +} + +bool UriReference::isHierarchical() { + std::lock_guard g(m_mutex); + return m_scheme.isEmpty() || m_hasAuthority || m_path.startsWith("/"); +} + +bool UriReference::hasAuthority() const { + return m_hasAuthority; +} + +const OUString& UriReference::getAuthority() const { + return m_authority; +} + +OUString UriReference::getPath() { + std::lock_guard g(m_mutex); + return m_path; +} + +bool UriReference::hasRelativePath() { + std::lock_guard g(m_mutex); + return !m_hasAuthority + && (m_path.isEmpty() || m_path[0] != '/'); +} + +sal_Int32 UriReference::getPathSegmentCount() +{ + std::lock_guard g(m_mutex); + if (m_path.isEmpty()) { + return 0; + } else { + sal_Int32 n = m_path[0] == '/' ? 0 : 1; + for (sal_Int32 i = 0;; ++i) { + i = m_path.indexOf('/', i); + if (i < 0) { + break; + } + ++n; + } + return n; + } +} + +OUString UriReference::getPathSegment(sal_Int32 index) +{ + std::lock_guard g(m_mutex); + if (!m_path.isEmpty() && index >= 0) { + for (sal_Int32 i = m_path[0] == '/' ? 1 : 0;; ++i) { + if (index-- == 0) { + sal_Int32 j = m_path.indexOf('/', i); + return j < 0 ? m_path.copy(i) : m_path.copy(i, j - i); + } + i = m_path.indexOf('/', i); + if (i < 0) { + break; + } + } + } + return OUString(); +} + +bool UriReference::hasQuery() const { + return m_hasQuery; +} + +const OUString& UriReference::getQuery() const { + return m_query; +} + +bool UriReference::hasFragment() { + std::lock_guard g(m_mutex); + return m_hasFragment; +} + +OUString UriReference::getFragment() { + std::lock_guard g(m_mutex); + return m_fragment; +} + +void UriReference::setFragment(OUString const & fragment) +{ + std::lock_guard g(m_mutex); + m_hasFragment = true; + m_fragment = fragment; +} + +void UriReference::clearFragment() { + std::lock_guard g(m_mutex); + m_hasFragment = false; + m_fragment.clear(); +} + +void UriReference::appendSchemeSpecificPart(OUStringBuffer & buffer) const +{ + if (m_hasAuthority) { + buffer.append("//"); + buffer.append(m_authority); + } + buffer.append(m_path); + if (m_hasQuery) { + buffer.append('?'); + buffer.append(m_query); + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/stoc/source/uriproc/UriReference.hxx b/stoc/source/uriproc/UriReference.hxx new file mode 100644 index 000000000..e16453720 --- /dev/null +++ b/stoc/source/uriproc/UriReference.hxx @@ -0,0 +1,112 @@ +/* -*- 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 . + */ + +#ifndef INCLUDED_STOC_SOURCE_URIPROC_URIREFERENCE_HXX +#define INCLUDED_STOC_SOURCE_URIPROC_URIREFERENCE_HXX + +#include <mutex> +#include <rtl/ustring.hxx> +#include <sal/types.h> +#include <rtl/ustrbuf.hxx> + +namespace stoc::uriproc { + +class UriReference { +public: + UriReference( + OUString const & scheme, bool hasAuthority, + OUString const & authority, OUString const & path, + bool hasQuery, OUString const & query); + + ~UriReference(); + + /// @throws css::uno::RuntimeException + OUString getUriReference(); + + /// @throws css::uno::RuntimeException + bool isAbsolute() const; + + /// @throws css::uno::RuntimeException + const OUString& getScheme() const { return m_scheme;} + + /// @throws css::uno::RuntimeException + OUString getSchemeSpecificPart(); + + /// @throws css::uno::RuntimeException + bool isHierarchical(); + + /// @throws css::uno::RuntimeException + bool hasAuthority() const; + + /// @throws css::uno::RuntimeException + const OUString& getAuthority() const; + + /// @throws css::uno::RuntimeException + OUString getPath(); + + /// @throws css::uno::RuntimeException + bool hasRelativePath(); + + /// @throws css::uno::RuntimeException + sal_Int32 getPathSegmentCount(); + + /// @throws css::uno::RuntimeException + OUString getPathSegment(sal_Int32 index); + + /// @throws css::uno::RuntimeException + bool hasQuery() const; + + /// @throws css::uno::RuntimeException + const OUString& getQuery() const; + + /// @throws css::uno::RuntimeException + bool hasFragment(); + + /// @throws css::uno::RuntimeException + OUString getFragment(); + + /// @throws css::uno::RuntimeException + void setFragment(OUString const & fragment); + + /// @throws css::uno::RuntimeException + void clearFragment(); + + std::mutex m_mutex; + OUString m_path; + +private: + UriReference(UriReference const &) = delete; + void operator =(UriReference const &) = delete; + + void appendSchemeSpecificPart(OUStringBuffer & buffer) const; + + OUString m_scheme; + OUString m_authority; + OUString m_query; + OUString m_fragment; + bool m_hasAuthority; + bool m_hasQuery; + bool m_hasFragment; +}; + +} + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/stoc/source/uriproc/UriReferenceFactory.cxx b/stoc/source/uriproc/UriReferenceFactory.cxx new file mode 100644 index 000000000..254097c17 --- /dev/null +++ b/stoc/source/uriproc/UriReferenceFactory.cxx @@ -0,0 +1,719 @@ +/* -*- 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, OUString const & schemeSpecificPart) +{ + sal_Int32 len = schemeSpecificPart.getLength(); + sal_Int32 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.copy(n, i - n); + } + sal_Int32 n = i; + i = schemeSpecificPart.indexOf('?', i); + if (i == -1) { + i = len; + } + OUString path = schemeSpecificPart.copy(n, i - n); + bool hasQuery = false; + OUString query; + if (i != len) { + hasQuery = true; + query = schemeSpecificPart.copy(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 > const & context): + m_context(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 "com.sun.star.comp.uri.UriReferenceFactory"; +} + +sal_Bool Factory::supportsService(OUString const & serviceName) +{ + return cppu::supportsService(this, serviceName); +} + +css::uno::Sequence< OUString > Factory::getSupportedServiceNames() +{ + css::uno::Sequence< OUString > s { "com.sun.star.uri.UriReferenceFactory" }; + 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, + static_cast< cppu::OWeakObject * >(this), + 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()); + abs.append(':'); + if (uriReference->hasAuthority()) { + abs.append("//"); + 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('?'); + abs.append(uriReference->getQuery()); + } + if (uriReference->hasFragment()) { + abs.append('#'); + abs.append(uriReference->getFragment()); + } + return parse(abs.makeStringAndClear()); + } + } + return clone(uriReference); + } else if (!uriReference->hasAuthority() + && uriReference->getPath().isEmpty()) { + OUStringBuffer abs(baseUriReference->getScheme()); + abs.append(':'); + if (baseUriReference->hasAuthority()) { + abs.append("//"); + abs.append(baseUriReference->getAuthority()); + } + abs.append(baseUriReference->getPath()); + if (uriReference->hasQuery()) { + abs.append('?'); + abs.append(uriReference->getQuery()); + } else if (baseUriReference->hasQuery()) { + abs.append('?'); + abs.append(baseUriReference->getQuery()); + } + if (uriReference->hasFragment()) { + abs.append('#'); + abs.append(uriReference->getFragment()); + } + return parse(abs.makeStringAndClear()); + } else { + OUStringBuffer abs(128); + abs.append(baseUriReference->getScheme()); + abs.append(':'); + if (uriReference->hasAuthority()) { + abs.append("//"); + abs.append(uriReference->getAuthority()); + } else if (baseUriReference->hasAuthority()) { + abs.append("//"); + 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('?'); + abs.append(uriReference->getQuery()); + } + if (uriReference->hasFragment()) { + abs.append('#'); + 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("//"); + 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("//"); + 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('?'); + rel.append(uriReference->getQuery()); + } + if (uriReference->hasFragment()) { + rel.append('#'); + 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: */ diff --git a/stoc/source/uriproc/UriSchemeParser_vndDOTsunDOTstarDOTexpand.cxx b/stoc/source/uriproc/UriSchemeParser_vndDOTsunDOTstarDOTexpand.cxx new file mode 100644 index 000000000..dde6fcb06 --- /dev/null +++ b/stoc/source/uriproc/UriSchemeParser_vndDOTsunDOTstarDOTexpand.cxx @@ -0,0 +1,198 @@ +/* -*- 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 <com/sun/star/lang/XServiceInfo.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/uri/XUriSchemeParser.hpp> +#include <com/sun/star/uri/XVndSunStarExpandUrlReference.hpp> +#include <com/sun/star/util/XMacroExpander.hpp> +#include <cppuhelper/implbase.hxx> +#include <cppuhelper/supportsservice.hxx> +#include <cppuhelper/weak.hxx> +#include <rtl/textenc.h> +#include <rtl/uri.h> +#include <rtl/uri.hxx> +#include <rtl/ustring.hxx> +#include <sal/types.h> + +#include "UriReference.hxx" + +namespace com::sun::star::uno { class XComponentContext; } +namespace com::sun::star::uno { class XInterface; } +namespace com::sun::star::uri { class XUriReference; } + +namespace { + +bool parseSchemeSpecificPart(OUString const & part) { + // Liberally accepts both an empty opaque_part and an opaque_part that + // starts with a non-escaped "/": + return part.isEmpty() + || (!::rtl::Uri::decode(part, ::rtl_UriDecodeStrict, RTL_TEXTENCODING_UTF8).isEmpty()); +} + +class UrlReference: + public ::cppu::WeakImplHelper<css::uri::XVndSunStarExpandUrlReference> +{ +public: + UrlReference(OUString const & scheme, OUString const & path): + base_( + scheme, false, OUString(), path, false, + OUString()) + {} + + UrlReference(const UrlReference&) = delete; + UrlReference& operator=(const UrlReference&) = delete; + + virtual OUString SAL_CALL getUriReference() override + { return base_.getUriReference(); } + + virtual sal_Bool SAL_CALL isAbsolute() override + { return base_.isAbsolute(); } + + virtual OUString SAL_CALL getScheme() override + { return base_.getScheme(); } + + virtual OUString SAL_CALL getSchemeSpecificPart() override + { return base_.getSchemeSpecificPart(); } + + virtual sal_Bool SAL_CALL isHierarchical() override + { return base_.isHierarchical(); } + + virtual sal_Bool SAL_CALL hasAuthority() override + { return base_.hasAuthority(); } + + virtual OUString SAL_CALL getAuthority() override + { return base_.getAuthority(); } + + virtual OUString SAL_CALL getPath() override + { return base_.getPath(); } + + virtual sal_Bool SAL_CALL hasRelativePath() override + { return base_.hasRelativePath(); } + + virtual ::sal_Int32 SAL_CALL getPathSegmentCount() override + { return base_.getPathSegmentCount(); } + + virtual OUString SAL_CALL getPathSegment(sal_Int32 index) override + { return base_.getPathSegment(index); } + + virtual sal_Bool SAL_CALL hasQuery() override + { return base_.hasQuery(); } + + virtual OUString SAL_CALL getQuery() override + { return base_.getQuery(); } + + virtual sal_Bool SAL_CALL hasFragment() override + { return base_.hasFragment(); } + + virtual OUString SAL_CALL getFragment() override + { return base_.getFragment(); } + + virtual void SAL_CALL setFragment(OUString const & fragment) override + { base_.setFragment(fragment); } + + virtual void SAL_CALL clearFragment() override + { base_.clearFragment(); } + + virtual OUString SAL_CALL expand( + css::uno::Reference< css::util::XMacroExpander > const & expander) override; + +private: + virtual ~UrlReference() override {} + + stoc::uriproc::UriReference base_; +}; + +OUString UrlReference::expand( + css::uno::Reference< css::util::XMacroExpander > const & expander) +{ + if (!expander.is()) { + throw css::uno::RuntimeException("null expander passed to XVndSunStarExpandUrl.expand"); + } + return expander->expandMacros( + ::rtl::Uri::decode( + getPath(), ::rtl_UriDecodeWithCharset, RTL_TEXTENCODING_UTF8)); +} + +class Parser: + public ::cppu::WeakImplHelper< + css::lang::XServiceInfo, css::uri::XUriSchemeParser> +{ +public: + Parser() {} + + Parser(const Parser&) = delete; + Parser& operator=(const Parser&) = 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 & scheme, + OUString const & schemeSpecificPart) override; + +private: + virtual ~Parser() override {} +}; + +OUString Parser::getImplementationName() +{ + return "com.sun.star.comp.uri.UriSchemeParser_vndDOTsunDOTstarDOTexpand"; +} + +sal_Bool Parser::supportsService(OUString const & serviceName) +{ + return cppu::supportsService(this, serviceName); +} + +css::uno::Sequence< OUString > Parser::getSupportedServiceNames() +{ + return { "com.sun.star.uri.UriSchemeParser_vndDOTsunDOTstarDOTexpand" }; +} + +css::uno::Reference< css::uri::XUriReference > Parser::parse( + OUString const & scheme, OUString const & schemeSpecificPart) +{ + if (!parseSchemeSpecificPart(schemeSpecificPart)) { + return css::uno::Reference< css::uri::XUriReference >(); + } + return new UrlReference(scheme, schemeSpecificPart); +} + +} + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface* +com_sun_star_comp_uri_UriSchemeParser_vndDOTsunDOTstarDOTexpand_get_implementation(css::uno::XComponentContext*, + css::uno::Sequence<css::uno::Any> const &) +{ + //TODO: single instance + return ::cppu::acquire(new Parser()); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/stoc/source/uriproc/UriSchemeParser_vndDOTsunDOTstarDOTscript.cxx b/stoc/source/uriproc/UriSchemeParser_vndDOTsunDOTstarDOTscript.cxx new file mode 100644 index 000000000..a8203a811 --- /dev/null +++ b/stoc/source/uriproc/UriSchemeParser_vndDOTsunDOTstarDOTscript.cxx @@ -0,0 +1,386 @@ +/* -*- 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 "UriReference.hxx" + +#include <com/sun/star/lang/IllegalArgumentException.hpp> +#include <com/sun/star/lang/XServiceInfo.hpp> +#include <com/sun/star/uno/Reference.hxx> +#include <com/sun/star/uno/Sequence.hxx> +#include <com/sun/star/uri/XUriSchemeParser.hpp> +#include <com/sun/star/uri/XVndSunStarScriptUrlReference.hpp> +#include <cppuhelper/implbase.hxx> +#include <cppuhelper/supportsservice.hxx> +#include <cppuhelper/weak.hxx> +#include <rtl/character.hxx> +#include <rtl/uri.hxx> +#include <rtl/ustrbuf.hxx> +#include <rtl/ustring.hxx> +#include <sal/types.h> +#include <o3tl/safeint.hxx> + +#include <string_view> + +namespace com::sun::star::uno { class XComponentContext; } +namespace com::sun::star::uno { class XInterface; } +namespace com::sun::star::uri { class XUriReference; } + +namespace { + +int getHexWeight(sal_Unicode c) { + return c >= '0' && c <= '9' ? static_cast< int >(c - '0') + : c >= 'A' && c <= 'F' ? static_cast< int >(c - 'A' + 10) + : c >= 'a' && c <= 'f' ? static_cast< int >(c - 'a' + 10) + : -1; +} + +int parseEscaped(std::u16string_view part, sal_Int32 * index) { + if (part.size() - *index < 3 || part[*index] != '%') { + return -1; + } + int n1 = getHexWeight(part[*index + 1]); + int n2 = getHexWeight(part[*index + 2]); + if (n1 < 0 || n2 < 0) { + return -1; + } + *index += 3; + return (n1 << 4) | n2; +} + +OUString parsePart( + std::u16string_view part, bool namePart, sal_Int32 * index) +{ + OUStringBuffer buf(64); + while (o3tl::make_unsigned(*index) < part.size()) { + sal_Unicode c = part[*index]; + if (namePart ? c == '?' : c == '&' || c == '=') { + break; + } else if (c == '%') { + sal_Int32 i = *index; + int n = parseEscaped(part, &i); + if (n >= 0 && n <= 0x7F) { + buf.append(static_cast< sal_Unicode >(n)); + } else if (n >= 0xC0 && n <= 0xFC) { + sal_Int32 encoded; + int shift; + sal_Int32 min; + if (n <= 0xDF) { + encoded = (n & 0x1F) << 6; + shift = 0; + min = 0x80; + } else if (n <= 0xEF) { + encoded = (n & 0x0F) << 12; + shift = 6; + min = 0x800; + } else if (n <= 0xF7) { + encoded = (n & 0x07) << 18; + shift = 12; + min = 0x10000; + } else if (n <= 0xFB) { + encoded = (n & 0x03) << 24; + shift = 18; + min = 0x200000; + } else { + encoded = 0; + shift = 24; + min = 0x4000000; + } + bool utf8 = true; + for (; shift >= 0; shift -= 6) { + n = parseEscaped(part, &i); + if (n < 0x80 || n > 0xBF) { + utf8 = false; + break; + } + encoded |= (n & 0x3F) << shift; + } + if (!utf8 || !rtl::isUnicodeScalarValue(encoded) + || encoded < min) + { + break; + } + buf.appendUtf32(encoded); + } else { + break; + } + *index = i; + } else { + buf.append(c); + ++*index; + } + } + return buf.makeStringAndClear(); +} + +OUString encodeNameOrParamFragment(OUString const & fragment) { + static constexpr auto nameOrParamFragment = rtl::createUriCharClass( + u8"!$'()*+,-.0123456789:;@ABCDEFGHIJKLMNOPQRSTUVWXYZ[]_abcdefghijklmnopqrstuvwxyz~"); + return rtl::Uri::encode( + fragment, nameOrParamFragment.data(), rtl_UriEncodeIgnoreEscapes, + RTL_TEXTENCODING_UTF8); +} + +bool parseSchemeSpecificPart(std::u16string_view part) { + size_t len = part.size(); + sal_Int32 i = 0; + if (parsePart(part, true, &i).isEmpty() || part[0] == '/') { + return false; + } + if (o3tl::make_unsigned(i) == len) { + return true; + } + for (;;) { + ++i; // skip '?' or '&' + if (parsePart(part, false, &i).isEmpty() || o3tl::make_unsigned(i) == len + || part[i] != '=') + { + return false; + } + ++i; + parsePart(part, false, &i); + if (o3tl::make_unsigned(i) == len) { + return true; + } + if (part[i] != '&') { + return false; + } + } +} + +class UrlReference: + public cppu::WeakImplHelper<css::uri::XVndSunStarScriptUrlReference> +{ +public: + UrlReference(OUString const & scheme, OUString const & path): + m_base( + scheme, false, OUString(), path, false, OUString()) + {} + + UrlReference(const UrlReference&) = delete; + UrlReference& operator=(const UrlReference&) = 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(); } + + virtual OUString SAL_CALL getName() override; + + virtual void SAL_CALL setName(OUString const & name) override; + + virtual sal_Bool SAL_CALL hasParameter(OUString const & key) override; + + virtual OUString SAL_CALL getParameter(OUString const & key) override; + + virtual void SAL_CALL setParameter(OUString const & key, OUString const & value) override; + +private: + virtual ~UrlReference() override {} + + sal_Int32 findParameter(std::u16string_view key) const; + + stoc::uriproc::UriReference m_base; +}; + +OUString UrlReference::getName() { + std::lock_guard g(m_base.m_mutex); + sal_Int32 i = 0; + return parsePart(m_base.m_path, true, &i); +} + +void SAL_CALL UrlReference::setName(OUString const & name) +{ + if (name.isEmpty()) + throw css::lang::IllegalArgumentException( + OUString(), *this, 1); + + std::lock_guard g(m_base.m_mutex); + sal_Int32 i = 0; + parsePart(m_base.m_path, true, &i); + + m_base.m_path = encodeNameOrParamFragment(name) + m_base.m_path.subView(i); +} + +sal_Bool UrlReference::hasParameter(OUString const & key) +{ + std::lock_guard g(m_base.m_mutex); + return findParameter(key) >= 0; +} + +OUString UrlReference::getParameter(OUString const & key) +{ + std::lock_guard g(m_base.m_mutex); + sal_Int32 i = findParameter(key); + return i >= 0 ? parsePart(m_base.m_path, false, &i) : OUString(); +} + +void UrlReference::setParameter(OUString const & key, OUString const & value) +{ + if (key.isEmpty()) + throw css::lang::IllegalArgumentException( + OUString(), *this, 1); + + std::lock_guard g(m_base.m_mutex); + sal_Int32 i = findParameter(key); + bool bExistent = ( i>=0 ); + if (!bExistent) { + i = m_base.m_path.getLength(); + } + + OUStringBuffer newPath(128); + newPath.append(m_base.m_path.subView(0, i)); + if (!bExistent) { + newPath.append( m_base.m_path.indexOf('?') < 0 ? '?' : '&' ); + newPath.append(encodeNameOrParamFragment(key)); + newPath.append('='); + } + newPath.append(encodeNameOrParamFragment(value)); + if (bExistent) { + /*oldValue = */ + parsePart(m_base.m_path, false, &i); // skip key + newPath.append(m_base.m_path.subView(i)); + } + + m_base.m_path = newPath.makeStringAndClear(); +} + +sal_Int32 UrlReference::findParameter(std::u16string_view key) const { + sal_Int32 i = 0; + parsePart(m_base.m_path, true, &i); // skip name + for (;;) { + if (i == m_base.m_path.getLength()) { + return -1; + } + ++i; // skip '?' or '&' + OUString k = parsePart(m_base.m_path, false, &i); + ++i; // skip '=' + if (k == key) { + return i; + } + parsePart(m_base.m_path, false, &i); // skip value + } +} + +class Parser: + public cppu::WeakImplHelper< + css::lang::XServiceInfo, css::uri::XUriSchemeParser> +{ +public: + Parser() {} + + Parser(const Parser&) = delete; + Parser& operator=(const Parser&) = 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 & scheme, OUString const & schemeSpecificPart) override; + +private: + virtual ~Parser() override {} +}; + +OUString Parser::getImplementationName() +{ + return "com.sun.star.comp.uri.UriSchemeParser_vndDOTsunDOTstarDOTscript"; +} + +sal_Bool Parser::supportsService(OUString const & serviceName) +{ + return cppu::supportsService(this, serviceName); +} + +css::uno::Sequence< OUString > Parser::getSupportedServiceNames() +{ + return { "com.sun.star.uri.UriSchemeParser_vndDOTsunDOTstarDOTscript" }; +} + +css::uno::Reference< css::uri::XUriReference > +Parser::parse( + OUString const & scheme, OUString const & schemeSpecificPart) +{ + if (!parseSchemeSpecificPart(schemeSpecificPart)) { + return nullptr; + } + return new UrlReference(scheme, schemeSpecificPart); +} + +} + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface* +com_sun_star_comp_uri_UriSchemeParser_vndDOTsunDOTstarDOTscript_get_implementation(css::uno::XComponentContext*, + css::uno::Sequence<css::uno::Any> const &) +{ + //TODO: single instance + return ::cppu::acquire(new Parser()); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/stoc/source/uriproc/VndSunStarPkgUrlReferenceFactory.cxx b/stoc/source/uriproc/VndSunStarPkgUrlReferenceFactory.cxx new file mode 100644 index 000000000..2a3211a08 --- /dev/null +++ b/stoc/source/uriproc/VndSunStarPkgUrlReferenceFactory.cxx @@ -0,0 +1,119 @@ +/* -*- 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 <com/sun/star/lang/XServiceInfo.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/uri/UriReferenceFactory.hpp> +#include <com/sun/star/uri/XUriReference.hpp> +#include <com/sun/star/uri/XVndSunStarPkgUrlReferenceFactory.hpp> +#include <cppuhelper/implbase.hxx> +#include <cppuhelper/supportsservice.hxx> +#include <cppuhelper/weak.hxx> +#include <rtl/textenc.h> +#include <rtl/uri.h> +#include <rtl/uri.hxx> +#include <rtl/ustring.hxx> +#include <sal/types.h> + +namespace com::sun::star::uno { class XComponentContext; } +namespace com::sun::star::uno { class XInterface; } + +namespace { + +class Factory: + public cppu::WeakImplHelper< + css::lang::XServiceInfo, css::uri::XVndSunStarPkgUrlReferenceFactory> +{ +public: + explicit Factory( + css::uno::Reference< css::uno::XComponentContext > const & context): + m_context(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 + createVndSunStarPkgUrlReference( + css::uno::Reference< css::uri::XUriReference > const & authority) override; + +private: + virtual ~Factory() override {} + + css::uno::Reference< css::uno::XComponentContext > m_context; +}; + +OUString Factory::getImplementationName() +{ + return "com.sun.star.comp.uri.VndSunStarPkgUrlReferenceFactory"; +} + +sal_Bool Factory::supportsService(OUString const & serviceName) +{ + return cppu::supportsService(this, serviceName); +} + +css::uno::Sequence< OUString > Factory::getSupportedServiceNames() +{ + css::uno::Sequence< OUString > s { "com.sun.star.uri.VndSunStarPkgUrlReferenceFactory" }; + return s; +} + +css::uno::Reference< css::uri::XUriReference > +Factory::createVndSunStarPkgUrlReference( + css::uno::Reference< css::uri::XUriReference > const & authority) +{ + if (!authority.is()) { + throw css::uno::RuntimeException( + "null authority passed to" + " XVndSunStarPkgUrlReferenceFactory.createVndSunStarPkgUrlReference"); + } + if (authority->isAbsolute() && !authority->hasFragment()) { + OUString buf = + "vnd.sun.star.pkg://" + + rtl::Uri::encode( + authority->getUriReference(), rtl_UriCharClassRegName, + rtl_UriEncodeIgnoreEscapes, RTL_TEXTENCODING_UTF8); + css::uno::Reference< css::uri::XUriReference > uriRef( + css::uri::UriReferenceFactory::create(m_context)->parse( + buf)); + return uriRef; + } else { + return css::uno::Reference< css::uri::XUriReference >(); + } +} + +} + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface* +com_sun_star_comp_uri_VndSunStarPkgUrlReferenceFactory_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: */ |