| /************************************************************** |
| * |
| * 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 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| * |
| *************************************************************/ |
| |
| |
| |
| // MARKER(update_precomp.py): autogen include statement, do not remove |
| #include "precompiled_cppuhelper.hxx" |
| |
| #include "cppuhelper/unourl.hxx" |
| |
| #include "osl/diagnose.h" |
| #include "rtl/malformeduriexception.hxx" |
| #include "rtl/string.h" |
| #include "rtl/textenc.h" |
| #include "rtl/uri.h" |
| #include "rtl/uri.hxx" |
| #include "rtl/ustring.h" |
| #include "rtl/ustring.hxx" |
| #include "sal/types.h" |
| |
| #include <map> |
| |
| using cppu::UnoUrl; |
| using cppu::UnoUrlDescriptor; |
| |
| namespace { |
| |
| inline bool isAlphanum(sal_Unicode c) |
| { |
| return (c >= 0x30 && c <= 0x39) // '0'--'9' |
| || (c >= 0x41 && c <= 0x5A) // 'A'--'Z' |
| || (c >= 0x61 && c <= 0x7A); // 'a'--'z' |
| } |
| |
| } |
| |
| class UnoUrlDescriptor::Impl |
| { |
| public: |
| typedef std::map< rtl::OUString, rtl::OUString > Parameters; |
| |
| rtl::OUString m_aDescriptor; |
| rtl::OUString m_aName; |
| Parameters m_aParameters; |
| |
| /** @exception rtl::MalformedUriException |
| */ |
| explicit inline Impl(rtl::OUString const & m_aDescriptor); |
| |
| inline Impl * clone() const { return new Impl(*this); } |
| }; |
| |
| inline UnoUrlDescriptor::Impl::Impl(rtl::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; |
| rtl::OUString aKey; |
| for (sal_Int32 i = 0;; ++i) |
| { |
| bool bEnd = i == rDescriptor.getLength(); |
| sal_Unicode c = bEnd ? 0 : rDescriptor.getStr()[i]; |
| switch (eState) |
| { |
| case STATE_NAME0: |
| if (bEnd || !isAlphanum(c)) |
| throw rtl::MalformedUriException( |
| rtl::OUString(RTL_CONSTASCII_USTRINGPARAM( |
| "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 (!isAlphanum(c)) |
| throw rtl::MalformedUriException( |
| rtl::OUString(RTL_CONSTASCII_USTRINGPARAM( |
| "UNO URL contains bad descriptor name"))); |
| break; |
| |
| case STATE_KEY0: |
| if (bEnd || !isAlphanum(c)) |
| throw rtl::MalformedUriException( |
| rtl::OUString(RTL_CONSTASCII_USTRINGPARAM( |
| "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 || !isAlphanum(c)) |
| throw rtl::MalformedUriException( |
| rtl::OUString(RTL_CONSTASCII_USTRINGPARAM( |
| "UNO URL contains bad parameter key"))); |
| break; |
| |
| case STATE_VALUE: |
| if (bEnd || c == 0x2C) // ',' |
| { |
| if (!m_aParameters.insert( |
| Parameters::value_type( |
| aKey, |
| rtl::Uri::decode(rDescriptor.copy(nStart, |
| i - nStart), |
| rtl_UriDecodeWithCharset, |
| RTL_TEXTENCODING_UTF8))).second) |
| throw rtl::MalformedUriException( |
| rtl::OUString( |
| RTL_CONSTASCII_USTRINGPARAM( |
| "UNO URL contains duplicated parameter"))); |
| eState = STATE_KEY0; |
| } |
| break; |
| } |
| if (bEnd) |
| break; |
| } |
| } |
| |
| UnoUrlDescriptor::UnoUrlDescriptor(rtl::OUString const & rDescriptor): |
| m_xImpl(new Impl(rDescriptor)) |
| {} |
| |
| UnoUrlDescriptor::UnoUrlDescriptor(std::auto_ptr< Impl > & rImpl): |
| m_xImpl(rImpl) |
| {} |
| |
| UnoUrlDescriptor::UnoUrlDescriptor(UnoUrlDescriptor const & rOther): |
| m_xImpl(rOther.m_xImpl->clone()) |
| {} |
| |
| UnoUrlDescriptor::~UnoUrlDescriptor() |
| {} |
| |
| UnoUrlDescriptor & UnoUrlDescriptor::operator =(UnoUrlDescriptor const & rOther) |
| { |
| m_xImpl.reset(rOther.m_xImpl->clone()); |
| return *this; |
| } |
| |
| rtl::OUString const & UnoUrlDescriptor::getDescriptor() const |
| { |
| return m_xImpl->m_aDescriptor; |
| } |
| |
| rtl::OUString const & UnoUrlDescriptor::getName() const |
| { |
| return m_xImpl->m_aName; |
| } |
| |
| bool UnoUrlDescriptor::hasParameter(rtl::OUString const & rKey) const |
| { |
| return m_xImpl->m_aParameters.find(rKey.toAsciiLowerCase()) |
| != m_xImpl->m_aParameters.end(); |
| } |
| |
| rtl::OUString UnoUrlDescriptor::getParameter(rtl::OUString const & rKey) const |
| { |
| Impl::Parameters::const_iterator |
| aIt(m_xImpl->m_aParameters.find(rKey.toAsciiLowerCase())); |
| return aIt == m_xImpl->m_aParameters.end() ? rtl::OUString() : aIt->second; |
| } |
| |
| class UnoUrl::Impl |
| { |
| public: |
| UnoUrlDescriptor m_aConnection; |
| UnoUrlDescriptor m_aProtocol; |
| rtl::OUString m_aObjectName; |
| |
| inline Impl * clone() const { return new Impl(*this); } |
| |
| /** @exception rtl::MalformedUriException |
| */ |
| static inline Impl * create(rtl::OUString const & rUrl); |
| |
| private: |
| inline Impl(std::auto_ptr< UnoUrlDescriptor::Impl > & rConnection, |
| std::auto_ptr< UnoUrlDescriptor::Impl > & rProtocol, |
| rtl::OUString const & rObjectName); |
| }; |
| |
| inline UnoUrl::Impl::Impl(std::auto_ptr< UnoUrlDescriptor::Impl > & rConnection, |
| std::auto_ptr< UnoUrlDescriptor::Impl > & rProtocol, |
| rtl::OUString const & rObjectName): |
| m_aConnection(rConnection), |
| m_aProtocol(rProtocol), |
| m_aObjectName(rObjectName) |
| {} |
| |
| inline UnoUrl::Impl * UnoUrl::Impl::create(rtl::OUString const & rUrl) |
| { |
| if (!rUrl.matchIgnoreAsciiCaseAsciiL(RTL_CONSTASCII_STRINGPARAM("uno:"), 0)) |
| throw rtl::MalformedUriException( |
| rtl::OUString(RTL_CONSTASCII_USTRINGPARAM( |
| "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( |
| rtl::OUString(RTL_CONSTASCII_USTRINGPARAM( |
| "UNO URL has too few semicolons"))); |
| std::auto_ptr< UnoUrlDescriptor::Impl > |
| xConnection(new UnoUrlDescriptor::Impl(rUrl.copy(i, j - i))); |
| i = j + 1; |
| j = rUrl.indexOf(0x3B, i); // ';' |
| if (j < 0) |
| throw rtl::MalformedUriException( |
| rtl::OUString(RTL_CONSTASCII_USTRINGPARAM( |
| "UNO URL has too few semicolons"))); |
| std::auto_ptr< UnoUrlDescriptor::Impl > |
| xProtocol(new UnoUrlDescriptor::Impl(rUrl.copy(i, j - i))); |
| i = j + 1; |
| if (i == rUrl.getLength()) |
| throw rtl::MalformedUriException( |
| rtl::OUString(RTL_CONSTASCII_USTRINGPARAM( |
| "UNO URL contains empty ObjectName"))); |
| for (j = i; j < rUrl.getLength(); ++j) |
| { |
| sal_Unicode c = rUrl.getStr()[j]; |
| if (!isAlphanum(c) && c != 0x21 && c != 0x24 // '!', '$' |
| && c != 0x26 && c != 0x27 && c != 0x28 // '&', ''', '(' |
| && c != 0x28 && 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( |
| rtl::OUString(RTL_CONSTASCII_USTRINGPARAM( |
| "UNO URL contains invalid ObjectName"))); |
| } |
| return new Impl(xConnection, xProtocol, rUrl.copy(i)); |
| } |
| |
| UnoUrl::UnoUrl(rtl::OUString const & rUrl): m_xImpl(Impl::create(rUrl)) |
| {} |
| |
| UnoUrl::UnoUrl(UnoUrl const & rOther): m_xImpl(rOther.m_xImpl->clone()) |
| {} |
| |
| UnoUrl::~UnoUrl() |
| {} |
| |
| UnoUrl & UnoUrl::operator =(UnoUrl const & rOther) |
| { |
| m_xImpl.reset(rOther.m_xImpl->clone()); |
| return *this; |
| } |
| |
| UnoUrlDescriptor const & UnoUrl::getConnection() const |
| { |
| return m_xImpl->m_aConnection; |
| } |
| |
| UnoUrlDescriptor const & UnoUrl::getProtocol() const |
| { |
| return m_xImpl->m_aProtocol; |
| } |
| |
| rtl::OUString const & UnoUrl::getObjectName() const |
| { |
| return m_xImpl->m_aObjectName; |
| } |