Version 6.4.0.0.beta1, tag libreoffice-6.4.0.0.beta1
[LibreOffice.git] / cppuhelper / source / unourl.cxx
blob8ee7e593ad2099884139fece07969595c18450b7
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
21 #include <cppuhelper/unourl.hxx>
23 #include <rtl/malformeduriexception.hxx>
24 #include <rtl/string.h>
25 #include <rtl/textenc.h>
26 #include <rtl/uri.h>
27 #include <rtl/uri.hxx>
28 #include <rtl/ustring.hxx>
29 #include <rtl/character.hxx>
30 #include <sal/types.h>
32 #include <map>
33 #include <memory>
35 using cppu::UnoUrl;
36 using cppu::UnoUrlDescriptor;
38 class UnoUrlDescriptor::Impl
40 public:
41 typedef std::map< OUString, OUString > Parameters;
43 OUString m_aDescriptor;
44 OUString m_aName;
45 Parameters m_aParameters;
47 /** @exception rtl::MalformedUriException
49 explicit inline Impl(OUString const & m_aDescriptor);
51 Impl * clone() const { return new Impl(*this); }
54 inline UnoUrlDescriptor::Impl::Impl(OUString const & rDescriptor)
56 m_aDescriptor = rDescriptor;
57 enum State { STATE_NAME0, STATE_NAME, STATE_KEY0, STATE_KEY, STATE_VALUE };
58 State eState = STATE_NAME0;
59 sal_Int32 nStart = 0;
60 OUString aKey;
61 for (sal_Int32 i = 0;; ++i)
63 bool bEnd = i == rDescriptor.getLength();
64 sal_Unicode c = bEnd ? 0 : rDescriptor[i];
65 switch (eState)
67 case STATE_NAME0:
68 if (bEnd || !rtl::isAsciiAlphanumeric(c))
69 throw rtl::MalformedUriException(
70 "UNO URL contains bad descriptor name");
71 nStart = i;
72 eState = STATE_NAME;
73 break;
75 case STATE_NAME:
76 if (bEnd || c == 0x2C) // ','
78 m_aName
79 = rDescriptor.copy(nStart, i - nStart).toAsciiLowerCase();
80 eState = STATE_KEY0;
82 else if (!rtl::isAsciiAlphanumeric(c))
83 throw rtl::MalformedUriException(
84 "UNO URL contains bad descriptor name");
85 break;
87 case STATE_KEY0:
88 if (bEnd || !rtl::isAsciiAlphanumeric(c))
89 throw rtl::MalformedUriException(
90 "UNO URL contains bad parameter key");
91 nStart = i;
92 eState = STATE_KEY;
93 break;
95 case STATE_KEY:
96 if (c == 0x3D) // '='
98 aKey = rDescriptor.copy(nStart, i - nStart).toAsciiLowerCase();
99 nStart = i + 1;
100 eState = STATE_VALUE;
102 else if (bEnd || !rtl::isAsciiAlphanumeric(c))
103 throw rtl::MalformedUriException(
104 "UNO URL contains bad parameter key");
105 break;
107 case STATE_VALUE:
108 if (bEnd || c == 0x2C) // ','
110 if (!m_aParameters.emplace(
111 aKey,
112 rtl::Uri::decode(rDescriptor.copy(nStart,
113 i - nStart),
114 rtl_UriDecodeWithCharset,
115 RTL_TEXTENCODING_UTF8)).second)
116 throw rtl::MalformedUriException(
117 "UNO URL contains duplicated parameter");
118 eState = STATE_KEY0;
120 break;
122 if (bEnd)
123 break;
127 UnoUrlDescriptor::UnoUrlDescriptor(OUString const & rDescriptor):
128 m_pImpl(new Impl(rDescriptor))
131 UnoUrlDescriptor::UnoUrlDescriptor(UnoUrlDescriptor const & rOther):
132 m_pImpl(rOther.m_pImpl->clone())
135 UnoUrlDescriptor::~UnoUrlDescriptor()
137 delete m_pImpl;
140 UnoUrlDescriptor & UnoUrlDescriptor::operator =(UnoUrlDescriptor const & rOther)
142 if (this != &rOther)
144 std::unique_ptr<Impl> newImpl(rOther.m_pImpl->clone());
145 delete m_pImpl;
146 m_pImpl = newImpl.release();
148 return *this;
151 OUString const & UnoUrlDescriptor::getDescriptor() const
153 return m_pImpl->m_aDescriptor;
156 OUString const & UnoUrlDescriptor::getName() const
158 return m_pImpl->m_aName;
161 bool UnoUrlDescriptor::hasParameter(OUString const & rKey) const
163 return m_pImpl->m_aParameters.find(rKey.toAsciiLowerCase())
164 != m_pImpl->m_aParameters.end();
167 OUString UnoUrlDescriptor::getParameter(OUString const & rKey) const
169 Impl::Parameters::const_iterator
170 aIt(m_pImpl->m_aParameters.find(rKey.toAsciiLowerCase()));
171 return aIt == m_pImpl->m_aParameters.end() ? OUString() : aIt->second;
174 class UnoUrl::Impl
176 public:
177 UnoUrlDescriptor m_aConnection;
178 UnoUrlDescriptor m_aProtocol;
179 OUString m_aObjectName;
181 Impl * clone() const { return new Impl(*this); }
183 /** @exception rtl::MalformedUriException
185 static inline Impl * create(OUString const & rUrl);
187 private:
188 Impl(OUString const & rConnectionDescriptor,
189 OUString const & rProtocolDescriptor,
190 OUString const & rObjectName):
191 m_aConnection(rConnectionDescriptor),
192 m_aProtocol(rProtocolDescriptor),
193 m_aObjectName(rObjectName)
197 inline UnoUrl::Impl * UnoUrl::Impl::create(OUString const & rUrl)
199 if (!rUrl.startsWithIgnoreAsciiCase("uno:"))
200 throw rtl::MalformedUriException("UNO URL does not start with \"uno:\"");
201 sal_Int32 i = RTL_CONSTASCII_LENGTH("uno:");
202 sal_Int32 j = rUrl.indexOf(';', i);
203 if (j < 0)
204 throw rtl::MalformedUriException("UNO URL has too few semicolons");
205 OUString aConnection(rUrl.copy(i, j - i));
206 i = j + 1;
207 j = rUrl.indexOf(0x3B, i); // ';'
208 if (j < 0)
209 throw rtl::MalformedUriException("UNO URL has too few semicolons");
210 OUString aProtocol(rUrl.copy(i, j - i));
211 i = j + 1;
212 if (i == rUrl.getLength())
213 throw rtl::MalformedUriException("UNO URL contains empty ObjectName");
214 for (j = i; j < rUrl.getLength(); ++j)
216 sal_Unicode c = rUrl[j];
217 if (!rtl::isAsciiAlphanumeric(c) && c != 0x21 && c != 0x24 // '!', '$'
218 && c != 0x26 && c != 0x27 && c != 0x28 // '&', ''', '('
219 && c != 0x29 && c != 0x2A && c != 0x2B // ')', '*', '+'
220 && c != 0x2C && c != 0x2D && c != 0x2E // ',', '-', '.'
221 && c != 0x2F && c != 0x3A && c != 0x3D // '/', ':', '='
222 && c != 0x3F && c != 0x40 && c != 0x5F // '?', '@', '_'
223 && c != 0x7E) // '~'
224 throw rtl::MalformedUriException("UNO URL contains invalid ObjectName");
226 return new Impl(aConnection, aProtocol, rUrl.copy(i));
229 UnoUrl::UnoUrl(OUString const & rUrl): m_pImpl(Impl::create(rUrl))
232 UnoUrl::UnoUrl(UnoUrl const & rOther): m_pImpl(rOther.m_pImpl->clone())
235 UnoUrl::~UnoUrl()
237 delete m_pImpl;
240 UnoUrl & UnoUrl::operator =(UnoUrl const & rOther)
242 if (this != &rOther)
244 std::unique_ptr<Impl> newImpl(rOther.m_pImpl->clone());
245 delete m_pImpl;
246 m_pImpl = newImpl.release();
248 return *this;
251 UnoUrlDescriptor const & UnoUrl::getConnection() const
253 return m_pImpl->m_aConnection;
256 UnoUrlDescriptor const & UnoUrl::getProtocol() const
258 return m_pImpl->m_aProtocol;
261 OUString const & UnoUrl::getObjectName() const
263 return m_pImpl->m_aObjectName;
266 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */