LibreOffice Module stoc (master) 1
UriSchemeParser_vndDOTsunDOTstarDOTscript.cxx
Go to the documentation of this file.
1/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2/*
3 * This file is part of the LibreOffice project.
4 *
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/.
8 *
9 * This file incorporates work covered by the following license notice:
10 *
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 .
18 */
19
20#include "UriReference.hxx"
21
22#include <com/sun/star/lang/IllegalArgumentException.hpp>
23#include <com/sun/star/lang/XServiceInfo.hpp>
24#include <com/sun/star/uno/Reference.hxx>
25#include <com/sun/star/uno/Sequence.hxx>
26#include <com/sun/star/uri/XUriSchemeParser.hpp>
27#include <com/sun/star/uri/XVndSunStarScriptUrlReference.hpp>
30#include <cppuhelper/weak.hxx>
31#include <rtl/character.hxx>
32#include <rtl/uri.hxx>
33#include <rtl/ustrbuf.hxx>
34#include <rtl/ustring.hxx>
35#include <sal/types.h>
36#include <o3tl/safeint.hxx>
37
38#include <string_view>
39
40namespace com::sun::star::uno { class XComponentContext; }
41namespace com::sun::star::uno { class XInterface; }
42namespace com::sun::star::uri { class XUriReference; }
43
44namespace {
45
46int getHexWeight(sal_Unicode c) {
47 return c >= '0' && c <= '9' ? static_cast< int >(c - '0')
48 : c >= 'A' && c <= 'F' ? static_cast< int >(c - 'A' + 10)
49 : c >= 'a' && c <= 'f' ? static_cast< int >(c - 'a' + 10)
50 : -1;
51}
52
53int parseEscaped(std::u16string_view part, sal_Int32 * index) {
54 if (part.size() - *index < 3 || part[*index] != '%') {
55 return -1;
56 }
57 int n1 = getHexWeight(part[*index + 1]);
58 int n2 = getHexWeight(part[*index + 2]);
59 if (n1 < 0 || n2 < 0) {
60 return -1;
61 }
62 *index += 3;
63 return (n1 << 4) | n2;
64}
65
66OUString parsePart(
67 std::u16string_view part, bool namePart, sal_Int32 * index)
68{
69 OUStringBuffer buf(64);
70 while (o3tl::make_unsigned(*index) < part.size()) {
71 sal_Unicode c = part[*index];
72 if (namePart ? c == '?' : c == '&' || c == '=') {
73 break;
74 } else if (c == '%') {
75 sal_Int32 i = *index;
76 int n = parseEscaped(part, &i);
77 if (n >= 0 && n <= 0x7F) {
78 buf.append(static_cast< sal_Unicode >(n));
79 } else if (n >= 0xC0 && n <= 0xFC) {
80 sal_Int32 encoded;
81 int shift;
82 sal_Int32 min;
83 if (n <= 0xDF) {
84 encoded = (n & 0x1F) << 6;
85 shift = 0;
86 min = 0x80;
87 } else if (n <= 0xEF) {
88 encoded = (n & 0x0F) << 12;
89 shift = 6;
90 min = 0x800;
91 } else if (n <= 0xF7) {
92 encoded = (n & 0x07) << 18;
93 shift = 12;
94 min = 0x10000;
95 } else if (n <= 0xFB) {
96 encoded = (n & 0x03) << 24;
97 shift = 18;
98 min = 0x200000;
99 } else {
100 encoded = 0;
101 shift = 24;
102 min = 0x4000000;
103 }
104 bool utf8 = true;
105 for (; shift >= 0; shift -= 6) {
106 n = parseEscaped(part, &i);
107 if (n < 0x80 || n > 0xBF) {
108 utf8 = false;
109 break;
110 }
111 encoded |= (n & 0x3F) << shift;
112 }
113 if (!utf8 || !rtl::isUnicodeScalarValue(encoded)
114 || encoded < min)
115 {
116 break;
117 }
118 buf.appendUtf32(encoded);
119 } else {
120 break;
121 }
122 *index = i;
123 } else {
124 buf.append(c);
125 ++*index;
126 }
127 }
128 return buf.makeStringAndClear();
129}
130
131OUString encodeNameOrParamFragment(OUString const & fragment) {
132 static constexpr auto nameOrParamFragment = rtl::createUriCharClass(
133 u8"!$'()*+,-.0123456789:;@ABCDEFGHIJKLMNOPQRSTUVWXYZ[]_abcdefghijklmnopqrstuvwxyz~");
134 return rtl::Uri::encode(
135 fragment, nameOrParamFragment.data(), rtl_UriEncodeIgnoreEscapes,
136 RTL_TEXTENCODING_UTF8);
137}
138
139bool parseSchemeSpecificPart(std::u16string_view part) {
140 size_t len = part.size();
141 sal_Int32 i = 0;
142 if (parsePart(part, true, &i).isEmpty() || part[0] == '/') {
143 return false;
144 }
145 if (o3tl::make_unsigned(i) == len) {
146 return true;
147 }
148 for (;;) {
149 ++i; // skip '?' or '&'
150 if (parsePart(part, false, &i).isEmpty() || o3tl::make_unsigned(i) == len
151 || part[i] != '=')
152 {
153 return false;
154 }
155 ++i;
156 parsePart(part, false, &i);
157 if (o3tl::make_unsigned(i) == len) {
158 return true;
159 }
160 if (part[i] != '&') {
161 return false;
162 }
163 }
164}
165
166class UrlReference:
167 public cppu::WeakImplHelper<css::uri::XVndSunStarScriptUrlReference>
168{
169public:
170 UrlReference(OUString const & scheme, OUString const & path):
171 m_base(
172 scheme, false, OUString(), path, false, OUString())
173 {}
174
175 UrlReference(const UrlReference&) = delete;
176 UrlReference& operator=(const UrlReference&) = delete;
177
178 virtual OUString SAL_CALL getUriReference() override
179 { return m_base.getUriReference(); }
180
181 virtual sal_Bool SAL_CALL isAbsolute() override
182 { return m_base.isAbsolute(); }
183
184 virtual OUString SAL_CALL getScheme() override
185 { return m_base.getScheme(); }
186
187 virtual OUString SAL_CALL getSchemeSpecificPart() override
188 { return m_base.getSchemeSpecificPart(); }
189
190 virtual sal_Bool SAL_CALL isHierarchical() override
191 { return m_base.isHierarchical(); }
192
193 virtual sal_Bool SAL_CALL hasAuthority() override
194 { return m_base.hasAuthority(); }
195
196 virtual OUString SAL_CALL getAuthority() override
197 { return m_base.getAuthority(); }
198
199 virtual OUString SAL_CALL getPath() override
200 { return m_base.getPath(); }
201
202 virtual sal_Bool SAL_CALL hasRelativePath() override
203 { return m_base.hasRelativePath(); }
204
205 virtual sal_Int32 SAL_CALL getPathSegmentCount() override
206 { return m_base.getPathSegmentCount(); }
207
208 virtual OUString SAL_CALL getPathSegment(sal_Int32 index) override
209 { return m_base.getPathSegment(index); }
210
211 virtual sal_Bool SAL_CALL hasQuery() override
212 { return m_base.hasQuery(); }
213
214 virtual OUString SAL_CALL getQuery() override
215 { return m_base.getQuery(); }
216
217 virtual sal_Bool SAL_CALL hasFragment() override
218 { return m_base.hasFragment(); }
219
220 virtual OUString SAL_CALL getFragment() override
221 { return m_base.getFragment(); }
222
223 virtual void SAL_CALL setFragment(OUString const & fragment) override
224 { m_base.setFragment(fragment); }
225
226 virtual void SAL_CALL clearFragment() override
227 { m_base.clearFragment(); }
228
229 virtual OUString SAL_CALL getName() override;
230
231 virtual void SAL_CALL setName(OUString const & name) override;
232
233 virtual sal_Bool SAL_CALL hasParameter(OUString const & key) override;
234
235 virtual OUString SAL_CALL getParameter(OUString const & key) override;
236
237 virtual void SAL_CALL setParameter(OUString const & key, OUString const & value) override;
238
239private:
240 virtual ~UrlReference() override {}
241
242 sal_Int32 findParameter(std::u16string_view key) const;
243
245};
246
247OUString UrlReference::getName() {
248 std::lock_guard g(m_base.m_mutex);
249 sal_Int32 i = 0;
250 return parsePart(m_base.m_path, true, &i);
251}
252
253void SAL_CALL UrlReference::setName(OUString const & name)
254{
255 if (name.isEmpty())
256 throw css::lang::IllegalArgumentException(
257 OUString(), *this, 1);
258
259 std::lock_guard g(m_base.m_mutex);
260 sal_Int32 i = 0;
261 parsePart(m_base.m_path, true, &i);
262
263 m_base.m_path = encodeNameOrParamFragment(name) + m_base.m_path.subView(i);
264}
265
266sal_Bool UrlReference::hasParameter(OUString const & key)
267{
268 std::lock_guard g(m_base.m_mutex);
269 return findParameter(key) >= 0;
270}
271
272OUString UrlReference::getParameter(OUString const & key)
273{
274 std::lock_guard g(m_base.m_mutex);
275 sal_Int32 i = findParameter(key);
276 return i >= 0 ? parsePart(m_base.m_path, false, &i) : OUString();
277}
278
279void UrlReference::setParameter(OUString const & key, OUString const & value)
280{
281 if (key.isEmpty())
282 throw css::lang::IllegalArgumentException(
283 OUString(), *this, 1);
284
285 std::lock_guard g(m_base.m_mutex);
286 sal_Int32 i = findParameter(key);
287 bool bExistent = ( i>=0 );
288 if (!bExistent) {
289 i = m_base.m_path.getLength();
290 }
291
292 OUStringBuffer newPath(128);
293 newPath.append(m_base.m_path.subView(0, i));
294 if (!bExistent) {
295 newPath.append( m_base.m_path.indexOf('?') < 0 ? '?' : '&' );
296 newPath.append(encodeNameOrParamFragment(key) + "=");
297 }
298 newPath.append(encodeNameOrParamFragment(value));
299 if (bExistent) {
300 /*oldValue = */
301 parsePart(m_base.m_path, false, &i); // skip key
302 newPath.append(m_base.m_path.subView(i));
303 }
304
305 m_base.m_path = newPath.makeStringAndClear();
306}
307
308sal_Int32 UrlReference::findParameter(std::u16string_view key) const {
309 sal_Int32 i = 0;
310 parsePart(m_base.m_path, true, &i); // skip name
311 for (;;) {
312 if (i == m_base.m_path.getLength()) {
313 return -1;
314 }
315 ++i; // skip '?' or '&'
316 OUString k = parsePart(m_base.m_path, false, &i);
317 ++i; // skip '='
318 if (k == key) {
319 return i;
320 }
321 parsePart(m_base.m_path, false, &i); // skip value
322 }
323}
324
325class Parser:
326 public cppu::WeakImplHelper<
327 css::lang::XServiceInfo, css::uri::XUriSchemeParser>
328{
329public:
330 Parser() {}
331
332 Parser(const Parser&) = delete;
333 Parser& operator=(const Parser&) = delete;
334
335 virtual OUString SAL_CALL getImplementationName() override;
336
337 virtual sal_Bool SAL_CALL supportsService(OUString const & serviceName) override;
338
339 virtual css::uno::Sequence< OUString > SAL_CALL
340 getSupportedServiceNames() override;
341
342 virtual css::uno::Reference< css::uri::XUriReference > SAL_CALL
343 parse(
344 OUString const & scheme, OUString const & schemeSpecificPart) override;
345
346private:
347 virtual ~Parser() override {}
348};
349
350OUString Parser::getImplementationName()
351{
352 return "com.sun.star.comp.uri.UriSchemeParser_vndDOTsunDOTstarDOTscript";
353}
354
355sal_Bool Parser::supportsService(OUString const & serviceName)
356{
357 return cppu::supportsService(this, serviceName);
358}
359
360css::uno::Sequence< OUString > Parser::getSupportedServiceNames()
361{
362 return { "com.sun.star.uri.UriSchemeParser_vndDOTsunDOTstarDOTscript" };
363}
364
365css::uno::Reference< css::uri::XUriReference >
366Parser::parse(
367 OUString const & scheme, OUString const & schemeSpecificPart)
368{
369 if (!parseSchemeSpecificPart(schemeSpecificPart)) {
370 return nullptr;
371 }
372 return new UrlReference(scheme, schemeSpecificPart);
373}
374
375}
376
377extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
379 css::uno::Sequence<css::uno::Any> const &)
380{
381 //TODO: single instance
382 return ::cppu::acquire(new Parser());
383}
384
385/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
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 &)
const char * name
sal_Int64 n
int n2
int n1
css::uno::Sequence< OUString > getSupportedServiceNames()
OUString getImplementationName()
bool CPPUHELPER_DLLPUBLIC supportsService(css::lang::XServiceInfo *implementation, rtl::OUString const &name)
int i
index
int shift
constexpr std::enable_if_t< std::is_signed_v< T >, std::make_unsigned_t< T > > make_unsigned(T value)
bool parse(OUString const &uri, SourceProviderScannerData *data)
SwNodeOffset min(const SwNodeOffset &a, const SwNodeOffset &b)
const wchar_t *typedef int(__stdcall *DllNativeUnregProc)(int
unsigned char sal_Bool
sal_uInt16 sal_Unicode