summaryrefslogtreecommitdiffstats
path: root/cppuhelper/source/unourl.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'cppuhelper/source/unourl.cxx')
-rw-r--r--cppuhelper/source/unourl.cxx267
1 files changed, 267 insertions, 0 deletions
diff --git a/cppuhelper/source/unourl.cxx b/cppuhelper/source/unourl.cxx
new file mode 100644
index 000000000..9656dd078
--- /dev/null
+++ b/cppuhelper/source/unourl.cxx
@@ -0,0 +1,267 @@
+/* -*- 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 <cppuhelper/unourl.hxx>
+
+#include <rtl/malformeduriexception.hxx>
+#include <rtl/string.h>
+#include <rtl/textenc.h>
+#include <rtl/uri.h>
+#include <rtl/uri.hxx>
+#include <rtl/ustring.hxx>
+#include <rtl/character.hxx>
+#include <sal/types.h>
+
+#include <map>
+#include <memory>
+#include <utility>
+
+using cppu::UnoUrl;
+using cppu::UnoUrlDescriptor;
+
+class UnoUrlDescriptor::Impl
+{
+public:
+ typedef std::map< OUString, OUString > Parameters;
+
+ OUString m_aDescriptor;
+ OUString m_aName;
+ Parameters m_aParameters;
+
+ /** @exception rtl::MalformedUriException
+ */
+ explicit inline Impl(OUString const & m_aDescriptor);
+
+ Impl * clone() const { return new Impl(*this); }
+};
+
+inline UnoUrlDescriptor::Impl::Impl(OUString const & rDescriptor)
+{
+ m_aDescriptor = rDescriptor;
+ enum State { STATE_NAME0, STATE_NAME, STATE_KEY0, STATE_KEY, STATE_VALUE };
+ State eState = STATE_NAME0;
+ sal_Int32 nStart = 0;
+ OUString aKey;
+ for (sal_Int32 i = 0;; ++i)
+ {
+ bool bEnd = i == rDescriptor.getLength();
+ sal_Unicode c = bEnd ? 0 : rDescriptor[i];
+ switch (eState)
+ {
+ case STATE_NAME0:
+ if (bEnd || !rtl::isAsciiAlphanumeric(c))
+ throw rtl::MalformedUriException(
+ "UNO URL contains bad descriptor name");
+ nStart = i;
+ eState = STATE_NAME;
+ break;
+
+ case STATE_NAME:
+ if (bEnd || c == 0x2C) // ','
+ {
+ m_aName
+ = rDescriptor.copy(nStart, i - nStart).toAsciiLowerCase();
+ eState = STATE_KEY0;
+ }
+ else if (!rtl::isAsciiAlphanumeric(c))
+ throw rtl::MalformedUriException(
+ "UNO URL contains bad descriptor name");
+ break;
+
+ case STATE_KEY0:
+ if (bEnd || !rtl::isAsciiAlphanumeric(c))
+ throw rtl::MalformedUriException(
+ "UNO URL contains bad parameter key");
+ nStart = i;
+ eState = STATE_KEY;
+ break;
+
+ case STATE_KEY:
+ if (c == 0x3D) // '='
+ {
+ aKey = rDescriptor.copy(nStart, i - nStart).toAsciiLowerCase();
+ nStart = i + 1;
+ eState = STATE_VALUE;
+ }
+ else if (bEnd || !rtl::isAsciiAlphanumeric(c))
+ throw rtl::MalformedUriException(
+ "UNO URL contains bad parameter key");
+ break;
+
+ case STATE_VALUE:
+ if (bEnd || c == 0x2C) // ','
+ {
+ if (!m_aParameters.emplace(
+ aKey,
+ rtl::Uri::decode(rDescriptor.copy(nStart,
+ i - nStart),
+ rtl_UriDecodeWithCharset,
+ RTL_TEXTENCODING_UTF8)).second)
+ throw rtl::MalformedUriException(
+ "UNO URL contains duplicated parameter");
+ eState = STATE_KEY0;
+ }
+ break;
+ }
+ if (bEnd)
+ break;
+ }
+}
+
+UnoUrlDescriptor::UnoUrlDescriptor(OUString const & rDescriptor):
+ m_pImpl(new Impl(rDescriptor))
+{}
+
+UnoUrlDescriptor::UnoUrlDescriptor(UnoUrlDescriptor const & rOther):
+ m_pImpl(rOther.m_pImpl->clone())
+{}
+
+UnoUrlDescriptor::~UnoUrlDescriptor()
+{
+ delete m_pImpl;
+}
+
+UnoUrlDescriptor & UnoUrlDescriptor::operator =(UnoUrlDescriptor const & rOther)
+{
+ if (this != &rOther)
+ {
+ std::unique_ptr<Impl> newImpl(rOther.m_pImpl->clone());
+ delete m_pImpl;
+ m_pImpl = newImpl.release();
+ }
+ return *this;
+}
+
+OUString const & UnoUrlDescriptor::getDescriptor() const
+{
+ return m_pImpl->m_aDescriptor;
+}
+
+OUString const & UnoUrlDescriptor::getName() const
+{
+ return m_pImpl->m_aName;
+}
+
+bool UnoUrlDescriptor::hasParameter(OUString const & rKey) const
+{
+ return m_pImpl->m_aParameters.find(rKey.toAsciiLowerCase())
+ != m_pImpl->m_aParameters.end();
+}
+
+OUString UnoUrlDescriptor::getParameter(OUString const & rKey) const
+{
+ Impl::Parameters::const_iterator
+ aIt(m_pImpl->m_aParameters.find(rKey.toAsciiLowerCase()));
+ return aIt == m_pImpl->m_aParameters.end() ? OUString() : aIt->second;
+}
+
+class UnoUrl::Impl
+{
+public:
+ UnoUrlDescriptor m_aConnection;
+ UnoUrlDescriptor m_aProtocol;
+ OUString m_aObjectName;
+
+ Impl * clone() const { return new Impl(*this); }
+
+ /** @exception rtl::MalformedUriException
+ */
+ static inline Impl * create(OUString const & rUrl);
+
+private:
+ Impl(OUString const & rConnectionDescriptor,
+ OUString const & rProtocolDescriptor,
+ OUString aObjectName):
+ m_aConnection(rConnectionDescriptor),
+ m_aProtocol(rProtocolDescriptor),
+ m_aObjectName(std::move(aObjectName))
+ {}
+};
+
+inline UnoUrl::Impl * UnoUrl::Impl::create(OUString const & rUrl)
+{
+ if (!rUrl.startsWithIgnoreAsciiCase("uno:"))
+ throw rtl::MalformedUriException("UNO URL does not start with \"uno:\"");
+ sal_Int32 i = RTL_CONSTASCII_LENGTH("uno:");
+ sal_Int32 j = rUrl.indexOf(';', i);
+ if (j < 0)
+ throw rtl::MalformedUriException("UNO URL has too few semicolons");
+ OUString aConnection(rUrl.copy(i, j - i));
+ i = j + 1;
+ j = rUrl.indexOf(0x3B, i); // ';'
+ if (j < 0)
+ throw rtl::MalformedUriException("UNO URL has too few semicolons");
+ OUString aProtocol(rUrl.copy(i, j - i));
+ i = j + 1;
+ if (i == rUrl.getLength())
+ throw rtl::MalformedUriException("UNO URL contains empty ObjectName");
+ for (j = i; j < rUrl.getLength(); ++j)
+ {
+ sal_Unicode c = rUrl[j];
+ if (!rtl::isAsciiAlphanumeric(c) && c != 0x21 && c != 0x24 // '!', '$'
+ && c != 0x26 && c != 0x27 && c != 0x28 // '&', ''', '('
+ && c != 0x29 && c != 0x2A && c != 0x2B // ')', '*', '+'
+ && c != 0x2C && c != 0x2D && c != 0x2E // ',', '-', '.'
+ && c != 0x2F && c != 0x3A && c != 0x3D // '/', ':', '='
+ && c != 0x3F && c != 0x40 && c != 0x5F // '?', '@', '_'
+ && c != 0x7E) // '~'
+ throw rtl::MalformedUriException("UNO URL contains invalid ObjectName");
+ }
+ return new Impl(aConnection, aProtocol, rUrl.copy(i));
+}
+
+UnoUrl::UnoUrl(OUString const & rUrl): m_pImpl(Impl::create(rUrl))
+{}
+
+UnoUrl::UnoUrl(UnoUrl const & rOther): m_pImpl(rOther.m_pImpl->clone())
+{}
+
+UnoUrl::~UnoUrl()
+{
+ delete m_pImpl;
+}
+
+UnoUrl & UnoUrl::operator =(UnoUrl const & rOther)
+{
+ if (this != &rOther)
+ {
+ std::unique_ptr<Impl> newImpl(rOther.m_pImpl->clone());
+ delete m_pImpl;
+ m_pImpl = newImpl.release();
+ }
+ return *this;
+}
+
+UnoUrlDescriptor const & UnoUrl::getConnection() const
+{
+ return m_pImpl->m_aConnection;
+}
+
+UnoUrlDescriptor const & UnoUrl::getProtocol() const
+{
+ return m_pImpl->m_aProtocol;
+}
+
+OUString const & UnoUrl::getObjectName() const
+{
+ return m_pImpl->m_aObjectName;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */