Version 5.4.3.2, tag libreoffice-5.4.3.2
[LibreOffice.git] / stoc / source / uriproc / UriSchemeParser_vndDOTsunDOTstarDOTscript.cxx
blobc57670e27f20d8995a959beb09fd280fd5a9041d
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/RuntimeException.hpp>
26 #include <com/sun/star/uno/Sequence.hxx>
27 #include <com/sun/star/uno/XComponentContext.hpp>
28 #include <com/sun/star/uno/XInterface.hpp>
29 #include <com/sun/star/uri/XUriReference.hpp>
30 #include <com/sun/star/uri/XUriSchemeParser.hpp>
31 #include <com/sun/star/uri/XVndSunStarScriptUrlReference.hpp>
32 #include <cppuhelper/implbase.hxx>
33 #include <cppuhelper/supportsservice.hxx>
34 #include <cppuhelper/weak.hxx>
35 #include <osl/mutex.hxx>
36 #include <rtl/character.hxx>
37 #include <rtl/uri.hxx>
38 #include <rtl/ustrbuf.hxx>
39 #include <rtl/ustring.hxx>
40 #include <sal/types.h>
42 #include <exception>
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;
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::isUnicodeCodePoint(encoded) || encoded < min
114 || (encoded >= 0xD800 && encoded <= 0xDFFF))
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 namespace {
140 OUString encodeNameOrParamFragment(OUString const & fragment) {
141 static sal_Bool const nameOrParamFragment[] = {
142 false, false, false, false, false, false, false, false,
143 false, false, false, false, false, false, false, false,
144 false, false, false, false, false, false, false, false,
145 false, false, false, false, false, false, false, false,
146 false, true, false, false, true, false, false, true, // !"#$%&'
147 true, true, true, true, true, true, true, false, // ()*+,-./
148 true, true, true, true, true, true, true, true, // 01234567
149 true, true, true, true, false, false, false, false, // 89:;<=>?
150 true, true, true, true, true, true, true, true, // @ABCDEFG
151 true, true, true, true, true, true, true, true, // HIJKLMNO
152 true, true, true, true, true, true, true, true, // PQRSTUVW
153 true, true, true, true, false, true, false, true, // XYZ[\]^_
154 false, true, true, true, true, true, true, true, // `abcdefg
155 true, true, true, true, true, true, true, true, // hijklmno
156 true, true, true, true, true, true, true, true, // pqrstuvw
157 true, true, true, false, false, false, true, false}; // xyz{|}~
158 return rtl::Uri::encode(
159 fragment, nameOrParamFragment, rtl_UriEncodeIgnoreEscapes,
160 RTL_TEXTENCODING_UTF8);
165 bool parseSchemeSpecificPart(OUString const & part) {
166 sal_Int32 len = part.getLength();
167 sal_Int32 i = 0;
168 if (parsePart(part, true, &i).isEmpty() || part[0] == '/') {
169 return false;
171 if (i == len) {
172 return true;
174 for (;;) {
175 ++i; // skip '?' or '&'
176 if (parsePart(part, false, &i).isEmpty() || i == len
177 || part[i] != '=')
179 return false;
181 ++i;
182 parsePart(part, false, &i);
183 if (i == len) {
184 return true;
186 if (part[i] != '&') {
187 return false;
192 class UrlReference:
193 public cppu::WeakImplHelper<css::uri::XVndSunStarScriptUrlReference>
195 public:
196 UrlReference(OUString const & scheme, OUString const & path):
197 m_base(
198 scheme, false, false, OUString(), path, false, OUString())
201 UrlReference(const UrlReference&) = delete;
202 UrlReference& operator=(const UrlReference&) = delete;
204 virtual OUString SAL_CALL getUriReference() override
205 { return m_base.getUriReference(); }
207 virtual sal_Bool SAL_CALL isAbsolute() override
208 { return m_base.isAbsolute(); }
210 virtual OUString SAL_CALL getScheme() override
211 { return m_base.getScheme(); }
213 virtual OUString SAL_CALL getSchemeSpecificPart() override
214 { return m_base.getSchemeSpecificPart(); }
216 virtual sal_Bool SAL_CALL isHierarchical() override
217 { return m_base.isHierarchical(); }
219 virtual sal_Bool SAL_CALL hasAuthority() override
220 { return m_base.hasAuthority(); }
222 virtual OUString SAL_CALL getAuthority() override
223 { return m_base.getAuthority(); }
225 virtual OUString SAL_CALL getPath() override
226 { return m_base.getPath(); }
228 virtual sal_Bool SAL_CALL hasRelativePath() override
229 { return m_base.hasRelativePath(); }
231 virtual sal_Int32 SAL_CALL getPathSegmentCount() override
232 { return m_base.getPathSegmentCount(); }
234 virtual OUString SAL_CALL getPathSegment(sal_Int32 index) override
235 { return m_base.getPathSegment(index); }
237 virtual sal_Bool SAL_CALL hasQuery() override
238 { return m_base.hasQuery(); }
240 virtual OUString SAL_CALL getQuery() override
241 { return m_base.getQuery(); }
243 virtual sal_Bool SAL_CALL hasFragment() override
244 { return m_base.hasFragment(); }
246 virtual OUString SAL_CALL getFragment() override
247 { return m_base.getFragment(); }
249 virtual void SAL_CALL setFragment(OUString const & fragment) override
250 { m_base.setFragment(fragment); }
252 virtual void SAL_CALL clearFragment() override
253 { m_base.clearFragment(); }
255 virtual OUString SAL_CALL getName() override;
257 virtual void SAL_CALL setName(OUString const & name) override;
259 virtual sal_Bool SAL_CALL hasParameter(OUString const & key) override;
261 virtual OUString SAL_CALL getParameter(OUString const & key) override;
263 virtual void SAL_CALL setParameter(OUString const & key, OUString const & value) override;
265 private:
266 virtual ~UrlReference() override {}
268 sal_Int32 findParameter(OUString const & key);
270 stoc::uriproc::UriReference m_base;
273 OUString UrlReference::getName() {
274 osl::MutexGuard g(m_base.m_mutex);
275 sal_Int32 i = 0;
276 return parsePart(m_base.m_path, true, &i);
279 void SAL_CALL UrlReference::setName(OUString const & name)
281 if (name.isEmpty())
282 throw css::lang::IllegalArgumentException(
283 OUString(), *this, 1);
285 osl::MutexGuard g(m_base.m_mutex);
286 sal_Int32 i = 0;
287 parsePart(m_base.m_path, true, &i);
289 OUStringBuffer newPath;
290 newPath.append(encodeNameOrParamFragment(name));
291 newPath.append(m_base.m_path.copy(i));
292 m_base.m_path = newPath.makeStringAndClear();
295 sal_Bool UrlReference::hasParameter(OUString const & key)
297 osl::MutexGuard g(m_base.m_mutex);
298 return findParameter(key) >= 0;
301 OUString UrlReference::getParameter(OUString const & key)
303 osl::MutexGuard g(m_base.m_mutex);
304 sal_Int32 i = findParameter(key);
305 return i >= 0 ? parsePart(m_base.m_path, false, &i) : OUString();
308 void UrlReference::setParameter(OUString const & key, OUString const & value)
310 if (key.isEmpty())
311 throw css::lang::IllegalArgumentException(
312 OUString(), *this, 1);
314 osl::MutexGuard g(m_base.m_mutex);
315 sal_Int32 i = findParameter(key);
316 bool bExistent = ( i>=0 );
317 if (!bExistent) {
318 i = m_base.m_path.getLength();
321 OUStringBuffer newPath;
322 newPath.append(m_base.m_path.copy(0, i));
323 if (!bExistent) {
324 newPath.append( m_base.m_path.indexOf('?') < 0 ? '?' : '&' );
325 newPath.append(encodeNameOrParamFragment(key));
326 newPath.append('=');
328 newPath.append(encodeNameOrParamFragment(value));
329 if (bExistent) {
330 /*oldValue = */
331 parsePart(m_base.m_path, false, &i); // skip key
332 newPath.append(m_base.m_path.copy(i));
335 m_base.m_path = newPath.makeStringAndClear();
338 sal_Int32 UrlReference::findParameter(OUString const & key) {
339 sal_Int32 i = 0;
340 parsePart(m_base.m_path, true, &i); // skip name
341 for (;;) {
342 if (i == m_base.m_path.getLength()) {
343 return -1;
345 ++i; // skip '?' or '&'
346 OUString k = parsePart(m_base.m_path, false, &i);
347 ++i; // skip '='
348 if (k == key) {
349 return i;
351 parsePart(m_base.m_path, false, &i); // skip value
355 class Parser:
356 public cppu::WeakImplHelper<
357 css::lang::XServiceInfo, css::uri::XUriSchemeParser>
359 public:
360 Parser() {}
362 Parser(const Parser&) = delete;
363 Parser& operator=(const Parser&) = delete;
365 virtual OUString SAL_CALL getImplementationName() override;
367 virtual sal_Bool SAL_CALL supportsService(OUString const & serviceName) override;
369 virtual css::uno::Sequence< OUString > SAL_CALL
370 getSupportedServiceNames() override;
372 virtual css::uno::Reference< css::uri::XUriReference > SAL_CALL
373 parse(
374 OUString const & scheme, OUString const & schemeSpecificPart) override;
376 private:
377 virtual ~Parser() override {}
380 OUString Parser::getImplementationName()
382 return OUString("com.sun.star.comp.uri.UriSchemeParser_vndDOTsunDOTstarDOTscript");
385 sal_Bool Parser::supportsService(OUString const & serviceName)
387 return cppu::supportsService(this, serviceName);
390 css::uno::Sequence< OUString > Parser::getSupportedServiceNames()
392 css::uno::Sequence< OUString > s { "com.sun.star.uri.UriSchemeParser_vndDOTsunDOTstarDOTscript" };
393 return s;
396 css::uno::Reference< css::uri::XUriReference >
397 Parser::parse(
398 OUString const & scheme, OUString const & schemeSpecificPart)
400 if (!parseSchemeSpecificPart(schemeSpecificPart)) {
401 return nullptr;
403 return new UrlReference(scheme, schemeSpecificPart);
408 extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface* SAL_CALL
409 com_sun_star_comp_uri_UriSchemeParser_vndDOTsunDOTstarDOTscript_get_implementation(css::uno::XComponentContext*,
410 css::uno::Sequence<css::uno::Any> const &)
412 //TODO: single instance
413 return ::cppu::acquire(new Parser());
416 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */