Bump version to 21.06.18.1
[LibreOffice.git] / stoc / source / uriproc / UriSchemeParser_vndDOTsunDOTstarDOTscript.cxx
blob960ecbcd16a8ca547431822705732c56aa4afcb0
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 .
20 #include "UriReference.hxx"
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>
28 #include <cppuhelper/implbase.hxx>
29 #include <cppuhelper/supportsservice.hxx>
30 #include <cppuhelper/weak.hxx>
31 #include <osl/mutex.hxx>
32 #include <rtl/character.hxx>
33 #include <rtl/uri.hxx>
34 #include <rtl/ustrbuf.hxx>
35 #include <rtl/ustring.hxx>
36 #include <sal/types.h>
38 #include <string_view>
40 namespace com::sun::star::uno { class XComponentContext; }
41 namespace com::sun::star::uno { class XInterface; }
42 namespace com::sun::star::uri { class XUriReference; }
44 namespace {
46 int 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;
53 int parseEscaped(OUString const & part, sal_Int32 * index) {
54 if (part.getLength() - *index < 3 || part[*index] != '%') {
55 return -1;
57 int n1 = getHexWeight(part[*index + 1]);
58 int n2 = getHexWeight(part[*index + 2]);
59 if (n1 < 0 || n2 < 0) {
60 return -1;
62 *index += 3;
63 return (n1 << 4) | n2;
66 OUString parsePart(
67 OUString const & part, bool namePart, sal_Int32 * index)
69 OUStringBuffer buf(64);
70 while (*index < part.getLength()) {
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;
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;
111 encoded |= (n & 0x3F) << shift;
113 if (!utf8 || !rtl::isUnicodeScalarValue(encoded)
114 || encoded < min)
116 break;
118 if (encoded <= 0xFFFF) {
119 buf.append(static_cast< sal_Unicode >(encoded));
120 } else {
121 buf.append(static_cast< sal_Unicode >(
122 (encoded >> 10) | 0xD800));
123 buf.append(static_cast< sal_Unicode >(
124 (encoded & 0x3FF) | 0xDC00));
126 } else {
127 break;
129 *index = i;
130 } else {
131 buf.append(c);
132 ++*index;
135 return buf.makeStringAndClear();
138 OUString encodeNameOrParamFragment(OUString const & fragment) {
139 static sal_Bool const nameOrParamFragment[] = {
140 false, false, false, false, false, false, false, false,
141 false, false, false, false, false, false, false, false,
142 false, false, false, false, false, false, false, false,
143 false, false, false, false, false, false, false, false,
144 false, true, false, false, true, false, false, true, // !"#$%&'
145 true, true, true, true, true, true, true, false, // ()*+,-./
146 true, true, true, true, true, true, true, true, // 01234567
147 true, true, true, true, false, false, false, false, // 89:;<=>?
148 true, true, true, true, true, true, true, true, // @ABCDEFG
149 true, true, true, true, true, true, true, true, // HIJKLMNO
150 true, true, true, true, true, true, true, true, // PQRSTUVW
151 true, true, true, true, false, true, false, true, // XYZ[\]^_
152 false, true, true, true, true, true, true, true, // `abcdefg
153 true, true, true, true, true, true, true, true, // hijklmno
154 true, true, true, true, true, true, true, true, // pqrstuvw
155 true, true, true, false, false, false, true, false}; // xyz{|}~
156 return rtl::Uri::encode(
157 fragment, nameOrParamFragment, rtl_UriEncodeIgnoreEscapes,
158 RTL_TEXTENCODING_UTF8);
161 bool parseSchemeSpecificPart(OUString const & part) {
162 sal_Int32 len = part.getLength();
163 sal_Int32 i = 0;
164 if (parsePart(part, true, &i).isEmpty() || part[0] == '/') {
165 return false;
167 if (i == len) {
168 return true;
170 for (;;) {
171 ++i; // skip '?' or '&'
172 if (parsePart(part, false, &i).isEmpty() || i == len
173 || part[i] != '=')
175 return false;
177 ++i;
178 parsePart(part, false, &i);
179 if (i == len) {
180 return true;
182 if (part[i] != '&') {
183 return false;
188 class UrlReference:
189 public cppu::WeakImplHelper<css::uri::XVndSunStarScriptUrlReference>
191 public:
192 UrlReference(OUString const & scheme, OUString const & path):
193 m_base(
194 scheme, false, OUString(), path, false, OUString())
197 UrlReference(const UrlReference&) = delete;
198 UrlReference& operator=(const UrlReference&) = delete;
200 virtual OUString SAL_CALL getUriReference() override
201 { return m_base.getUriReference(); }
203 virtual sal_Bool SAL_CALL isAbsolute() override
204 { return m_base.isAbsolute(); }
206 virtual OUString SAL_CALL getScheme() override
207 { return m_base.getScheme(); }
209 virtual OUString SAL_CALL getSchemeSpecificPart() override
210 { return m_base.getSchemeSpecificPart(); }
212 virtual sal_Bool SAL_CALL isHierarchical() override
213 { return m_base.isHierarchical(); }
215 virtual sal_Bool SAL_CALL hasAuthority() override
216 { return m_base.hasAuthority(); }
218 virtual OUString SAL_CALL getAuthority() override
219 { return m_base.getAuthority(); }
221 virtual OUString SAL_CALL getPath() override
222 { return m_base.getPath(); }
224 virtual sal_Bool SAL_CALL hasRelativePath() override
225 { return m_base.hasRelativePath(); }
227 virtual sal_Int32 SAL_CALL getPathSegmentCount() override
228 { return m_base.getPathSegmentCount(); }
230 virtual OUString SAL_CALL getPathSegment(sal_Int32 index) override
231 { return m_base.getPathSegment(index); }
233 virtual sal_Bool SAL_CALL hasQuery() override
234 { return m_base.hasQuery(); }
236 virtual OUString SAL_CALL getQuery() override
237 { return m_base.getQuery(); }
239 virtual sal_Bool SAL_CALL hasFragment() override
240 { return m_base.hasFragment(); }
242 virtual OUString SAL_CALL getFragment() override
243 { return m_base.getFragment(); }
245 virtual void SAL_CALL setFragment(OUString const & fragment) override
246 { m_base.setFragment(fragment); }
248 virtual void SAL_CALL clearFragment() override
249 { m_base.clearFragment(); }
251 virtual OUString SAL_CALL getName() override;
253 virtual void SAL_CALL setName(OUString const & name) override;
255 virtual sal_Bool SAL_CALL hasParameter(OUString const & key) override;
257 virtual OUString SAL_CALL getParameter(OUString const & key) override;
259 virtual void SAL_CALL setParameter(OUString const & key, OUString const & value) override;
261 private:
262 virtual ~UrlReference() override {}
264 sal_Int32 findParameter(OUString const & key) const;
266 stoc::uriproc::UriReference m_base;
269 OUString UrlReference::getName() {
270 osl::MutexGuard g(m_base.m_mutex);
271 sal_Int32 i = 0;
272 return parsePart(m_base.m_path, true, &i);
275 void SAL_CALL UrlReference::setName(OUString const & name)
277 if (name.isEmpty())
278 throw css::lang::IllegalArgumentException(
279 OUString(), *this, 1);
281 osl::MutexGuard g(m_base.m_mutex);
282 sal_Int32 i = 0;
283 parsePart(m_base.m_path, true, &i);
285 auto tmp = std::u16string_view(m_base.m_path).substr(i);
286 m_base.m_path = encodeNameOrParamFragment(name) +
287 std::u16string_view(tmp.data(), tmp.length());
290 sal_Bool UrlReference::hasParameter(OUString const & key)
292 osl::MutexGuard g(m_base.m_mutex);
293 return findParameter(key) >= 0;
296 OUString UrlReference::getParameter(OUString const & key)
298 osl::MutexGuard g(m_base.m_mutex);
299 sal_Int32 i = findParameter(key);
300 return i >= 0 ? parsePart(m_base.m_path, false, &i) : OUString();
303 void UrlReference::setParameter(OUString const & key, OUString const & value)
305 if (key.isEmpty())
306 throw css::lang::IllegalArgumentException(
307 OUString(), *this, 1);
309 osl::MutexGuard g(m_base.m_mutex);
310 sal_Int32 i = findParameter(key);
311 bool bExistent = ( i>=0 );
312 if (!bExistent) {
313 i = m_base.m_path.getLength();
316 OUStringBuffer newPath(128);
317 newPath.append(std::u16string_view(m_base.m_path).substr(0, i));
318 if (!bExistent) {
319 newPath.append( m_base.m_path.indexOf('?') < 0 ? '?' : '&' );
320 newPath.append(encodeNameOrParamFragment(key));
321 newPath.append('=');
323 newPath.append(encodeNameOrParamFragment(value));
324 if (bExistent) {
325 /*oldValue = */
326 parsePart(m_base.m_path, false, &i); // skip key
327 newPath.append(std::u16string_view(m_base.m_path).substr(i));
330 m_base.m_path = newPath.makeStringAndClear();
333 sal_Int32 UrlReference::findParameter(OUString const & key) const {
334 sal_Int32 i = 0;
335 parsePart(m_base.m_path, true, &i); // skip name
336 for (;;) {
337 if (i == m_base.m_path.getLength()) {
338 return -1;
340 ++i; // skip '?' or '&'
341 OUString k = parsePart(m_base.m_path, false, &i);
342 ++i; // skip '='
343 if (k == key) {
344 return i;
346 parsePart(m_base.m_path, false, &i); // skip value
350 class Parser:
351 public cppu::WeakImplHelper<
352 css::lang::XServiceInfo, css::uri::XUriSchemeParser>
354 public:
355 Parser() {}
357 Parser(const Parser&) = delete;
358 Parser& operator=(const Parser&) = delete;
360 virtual OUString SAL_CALL getImplementationName() override;
362 virtual sal_Bool SAL_CALL supportsService(OUString const & serviceName) override;
364 virtual css::uno::Sequence< OUString > SAL_CALL
365 getSupportedServiceNames() override;
367 virtual css::uno::Reference< css::uri::XUriReference > SAL_CALL
368 parse(
369 OUString const & scheme, OUString const & schemeSpecificPart) override;
371 private:
372 virtual ~Parser() override {}
375 OUString Parser::getImplementationName()
377 return "com.sun.star.comp.uri.UriSchemeParser_vndDOTsunDOTstarDOTscript";
380 sal_Bool Parser::supportsService(OUString const & serviceName)
382 return cppu::supportsService(this, serviceName);
385 css::uno::Sequence< OUString > Parser::getSupportedServiceNames()
387 return { "com.sun.star.uri.UriSchemeParser_vndDOTsunDOTstarDOTscript" };
390 css::uno::Reference< css::uri::XUriReference >
391 Parser::parse(
392 OUString const & scheme, OUString const & schemeSpecificPart)
394 if (!parseSchemeSpecificPart(schemeSpecificPart)) {
395 return nullptr;
397 return new UrlReference(scheme, schemeSpecificPart);
402 extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
403 com_sun_star_comp_uri_UriSchemeParser_vndDOTsunDOTstarDOTscript_get_implementation(css::uno::XComponentContext*,
404 css::uno::Sequence<css::uno::Any> const &)
406 //TODO: single instance
407 return ::cppu::acquire(new Parser());
410 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */