summaryrefslogtreecommitdiffstats
path: root/stoc/source/uriproc
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-15 05:54:39 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-15 05:54:39 +0000
commit267c6f2ac71f92999e969232431ba04678e7437e (patch)
tree358c9467650e1d0a1d7227a21dac2e3d08b622b2 /stoc/source/uriproc
parentInitial commit. (diff)
downloadlibreoffice-267c6f2ac71f92999e969232431ba04678e7437e.tar.xz
libreoffice-267c6f2ac71f92999e969232431ba04678e7437e.zip
Adding upstream version 4:24.2.0.upstream/4%24.2.0
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'stoc/source/uriproc')
-rw-r--r--stoc/source/uriproc/ExternalUriReferenceTranslator.cxx187
-rw-r--r--stoc/source/uriproc/UriReference.cxx182
-rw-r--r--stoc/source/uriproc/UriReference.hxx112
-rw-r--r--stoc/source/uriproc/UriReferenceFactory.cxx701
-rw-r--r--stoc/source/uriproc/UriSchemeParser_vndDOTsunDOTstarDOTexpand.cxx198
-rw-r--r--stoc/source/uriproc/UriSchemeParser_vndDOTsunDOTstarDOTscript.cxx385
-rw-r--r--stoc/source/uriproc/VndSunStarPkgUrlReferenceFactory.cxx120
7 files changed, 1885 insertions, 0 deletions
diff --git a/stoc/source/uriproc/ExternalUriReferenceTranslator.cxx b/stoc/source/uriproc/ExternalUriReferenceTranslator.cxx
new file mode 100644
index 0000000000..b9e2ca4e99
--- /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 0000000000..fc27201414
--- /dev/null
+++ b/stoc/source/uriproc/UriReference.cxx
@@ -0,0 +1,182 @@
+/* -*- 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 <utility>
+#include <sal/types.h>
+
+using stoc::uriproc::UriReference;
+
+UriReference::UriReference(
+ OUString scheme, bool bHasAuthority,
+ OUString const & authority, OUString path,
+ bool bHasQuery, OUString const & query):
+ m_path(std::move(path)),
+ m_scheme(std::move(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 + ":");
+ }
+ appendSchemeSpecificPart(buf);
+ if (m_hasFragment) {
+ 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 0000000000..1b373f56a7
--- /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 scheme, bool hasAuthority,
+ OUString const & authority, OUString 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 0000000000..2573917713
--- /dev/null
+++ b/stoc/source/uriproc/UriReferenceFactory.cxx
@@ -0,0 +1,701 @@
+/* -*- 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 > 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 "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,
+ 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: */
diff --git a/stoc/source/uriproc/UriSchemeParser_vndDOTsunDOTstarDOTexpand.cxx b/stoc/source/uriproc/UriSchemeParser_vndDOTsunDOTstarDOTexpand.cxx
new file mode 100644
index 0000000000..dde6fcb060
--- /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 0000000000..1f53351693
--- /dev/null
+++ b/stoc/source/uriproc/UriSchemeParser_vndDOTsunDOTstarDOTscript.cxx
@@ -0,0 +1,385 @@
+/* -*- 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(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 0000000000..7520c460f1
--- /dev/null
+++ b/stoc/source/uriproc/VndSunStarPkgUrlReferenceFactory.cxx
@@ -0,0 +1,120 @@
+/* -*- 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 <utility>
+#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 > 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
+ 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: */