Avoid potential negative array index access to cached text.
[LibreOffice.git] / cppuhelper / source / unourl.cxx
blob9656dd078ba127749368de3ca5900c2c325fdded
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>
34 #include <utility>
36 using cppu::UnoUrl;
37 using cppu::UnoUrlDescriptor;
39 class UnoUrlDescriptor::Impl
41 public:
42 typedef std::map< OUString, OUString > Parameters;
44 OUString m_aDescriptor;
45 OUString m_aName;
46 Parameters m_aParameters;
48 /** @exception rtl::MalformedUriException
50 explicit inline Impl(OUString const & m_aDescriptor);
52 Impl * clone() const { return new Impl(*this); }
55 inline UnoUrlDescriptor::Impl::Impl(OUString const & rDescriptor)
57 m_aDescriptor = rDescriptor;
58 enum State { STATE_NAME0, STATE_NAME, STATE_KEY0, STATE_KEY, STATE_VALUE };
59 State eState = STATE_NAME0;
60 sal_Int32 nStart = 0;
61 OUString aKey;
62 for (sal_Int32 i = 0;; ++i)
64 bool bEnd = i == rDescriptor.getLength();
65 sal_Unicode c = bEnd ? 0 : rDescriptor[i];
66 switch (eState)
68 case STATE_NAME0:
69 if (bEnd || !rtl::isAsciiAlphanumeric(c))
70 throw rtl::MalformedUriException(
71 "UNO URL contains bad descriptor name");
72 nStart = i;
73 eState = STATE_NAME;
74 break;
76 case STATE_NAME:
77 if (bEnd || c == 0x2C) // ','
79 m_aName
80 = rDescriptor.copy(nStart, i - nStart).toAsciiLowerCase();
81 eState = STATE_KEY0;
83 else if (!rtl::isAsciiAlphanumeric(c))
84 throw rtl::MalformedUriException(
85 "UNO URL contains bad descriptor name");
86 break;
88 case STATE_KEY0:
89 if (bEnd || !rtl::isAsciiAlphanumeric(c))
90 throw rtl::MalformedUriException(
91 "UNO URL contains bad parameter key");
92 nStart = i;
93 eState = STATE_KEY;
94 break;
96 case STATE_KEY:
97 if (c == 0x3D) // '='
99 aKey = rDescriptor.copy(nStart, i - nStart).toAsciiLowerCase();
100 nStart = i + 1;
101 eState = STATE_VALUE;
103 else if (bEnd || !rtl::isAsciiAlphanumeric(c))
104 throw rtl::MalformedUriException(
105 "UNO URL contains bad parameter key");
106 break;
108 case STATE_VALUE:
109 if (bEnd || c == 0x2C) // ','
111 if (!m_aParameters.emplace(
112 aKey,
113 rtl::Uri::decode(rDescriptor.copy(nStart,
114 i - nStart),
115 rtl_UriDecodeWithCharset,
116 RTL_TEXTENCODING_UTF8)).second)
117 throw rtl::MalformedUriException(
118 "UNO URL contains duplicated parameter");
119 eState = STATE_KEY0;
121 break;
123 if (bEnd)
124 break;
128 UnoUrlDescriptor::UnoUrlDescriptor(OUString const & rDescriptor):
129 m_pImpl(new Impl(rDescriptor))
132 UnoUrlDescriptor::UnoUrlDescriptor(UnoUrlDescriptor const & rOther):
133 m_pImpl(rOther.m_pImpl->clone())
136 UnoUrlDescriptor::~UnoUrlDescriptor()
138 delete m_pImpl;
141 UnoUrlDescriptor & UnoUrlDescriptor::operator =(UnoUrlDescriptor const & rOther)
143 if (this != &rOther)
145 std::unique_ptr<Impl> newImpl(rOther.m_pImpl->clone());
146 delete m_pImpl;
147 m_pImpl = newImpl.release();
149 return *this;
152 OUString const & UnoUrlDescriptor::getDescriptor() const
154 return m_pImpl->m_aDescriptor;
157 OUString const & UnoUrlDescriptor::getName() const
159 return m_pImpl->m_aName;
162 bool UnoUrlDescriptor::hasParameter(OUString const & rKey) const
164 return m_pImpl->m_aParameters.find(rKey.toAsciiLowerCase())
165 != m_pImpl->m_aParameters.end();
168 OUString UnoUrlDescriptor::getParameter(OUString const & rKey) const
170 Impl::Parameters::const_iterator
171 aIt(m_pImpl->m_aParameters.find(rKey.toAsciiLowerCase()));
172 return aIt == m_pImpl->m_aParameters.end() ? OUString() : aIt->second;
175 class UnoUrl::Impl
177 public:
178 UnoUrlDescriptor m_aConnection;
179 UnoUrlDescriptor m_aProtocol;
180 OUString m_aObjectName;
182 Impl * clone() const { return new Impl(*this); }
184 /** @exception rtl::MalformedUriException
186 static inline Impl * create(OUString const & rUrl);
188 private:
189 Impl(OUString const & rConnectionDescriptor,
190 OUString const & rProtocolDescriptor,
191 OUString aObjectName):
192 m_aConnection(rConnectionDescriptor),
193 m_aProtocol(rProtocolDescriptor),
194 m_aObjectName(std::move(aObjectName))
198 inline UnoUrl::Impl * UnoUrl::Impl::create(OUString const & rUrl)
200 if (!rUrl.startsWithIgnoreAsciiCase("uno:"))
201 throw rtl::MalformedUriException("UNO URL does not start with \"uno:\"");
202 sal_Int32 i = RTL_CONSTASCII_LENGTH("uno:");
203 sal_Int32 j = rUrl.indexOf(';', i);
204 if (j < 0)
205 throw rtl::MalformedUriException("UNO URL has too few semicolons");
206 OUString aConnection(rUrl.copy(i, j - i));
207 i = j + 1;
208 j = rUrl.indexOf(0x3B, i); // ';'
209 if (j < 0)
210 throw rtl::MalformedUriException("UNO URL has too few semicolons");
211 OUString aProtocol(rUrl.copy(i, j - i));
212 i = j + 1;
213 if (i == rUrl.getLength())
214 throw rtl::MalformedUriException("UNO URL contains empty ObjectName");
215 for (j = i; j < rUrl.getLength(); ++j)
217 sal_Unicode c = rUrl[j];
218 if (!rtl::isAsciiAlphanumeric(c) && c != 0x21 && c != 0x24 // '!', '$'
219 && c != 0x26 && c != 0x27 && c != 0x28 // '&', ''', '('
220 && c != 0x29 && c != 0x2A && c != 0x2B // ')', '*', '+'
221 && c != 0x2C && c != 0x2D && c != 0x2E // ',', '-', '.'
222 && c != 0x2F && c != 0x3A && c != 0x3D // '/', ':', '='
223 && c != 0x3F && c != 0x40 && c != 0x5F // '?', '@', '_'
224 && c != 0x7E) // '~'
225 throw rtl::MalformedUriException("UNO URL contains invalid ObjectName");
227 return new Impl(aConnection, aProtocol, rUrl.copy(i));
230 UnoUrl::UnoUrl(OUString const & rUrl): m_pImpl(Impl::create(rUrl))
233 UnoUrl::UnoUrl(UnoUrl const & rOther): m_pImpl(rOther.m_pImpl->clone())
236 UnoUrl::~UnoUrl()
238 delete m_pImpl;
241 UnoUrl & UnoUrl::operator =(UnoUrl const & rOther)
243 if (this != &rOther)
245 std::unique_ptr<Impl> newImpl(rOther.m_pImpl->clone());
246 delete m_pImpl;
247 m_pImpl = newImpl.release();
249 return *this;
252 UnoUrlDescriptor const & UnoUrl::getConnection() const
254 return m_pImpl->m_aConnection;
257 UnoUrlDescriptor const & UnoUrl::getProtocol() const
259 return m_pImpl->m_aProtocol;
262 OUString const & UnoUrl::getObjectName() const
264 return m_pImpl->m_aObjectName;
267 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */