1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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
; }
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)
53 int parseEscaped(OUString
const & part
, sal_Int32
* index
) {
54 if (part
.getLength() - *index
< 3 || part
[*index
] != '%') {
57 int n1
= getHexWeight(part
[*index
+ 1]);
58 int n2
= getHexWeight(part
[*index
+ 2]);
59 if (n1
< 0 || n2
< 0) {
63 return (n1
<< 4) | n2
;
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
== '=') {
74 } else if (c
== '%') {
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) {
84 encoded
= (n
& 0x1F) << 6;
87 } else if (n
<= 0xEF) {
88 encoded
= (n
& 0x0F) << 12;
91 } else if (n
<= 0xF7) {
92 encoded
= (n
& 0x07) << 18;
95 } else if (n
<= 0xFB) {
96 encoded
= (n
& 0x03) << 24;
105 for (; shift
>= 0; shift
-= 6) {
106 n
= parseEscaped(part
, &i
);
107 if (n
< 0x80 || n
> 0xBF) {
111 encoded
|= (n
& 0x3F) << shift
;
113 if (!utf8
|| !rtl::isUnicodeScalarValue(encoded
)
118 if (encoded
<= 0xFFFF) {
119 buf
.append(static_cast< sal_Unicode
>(encoded
));
121 buf
.append(static_cast< sal_Unicode
>(
122 (encoded
>> 10) | 0xD800));
123 buf
.append(static_cast< sal_Unicode
>(
124 (encoded
& 0x3FF) | 0xDC00));
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();
164 if (parsePart(part
, true, &i
).isEmpty() || part
[0] == '/') {
171 ++i
; // skip '?' or '&'
172 if (parsePart(part
, false, &i
).isEmpty() || i
== len
178 parsePart(part
, false, &i
);
182 if (part
[i
] != '&') {
189 public cppu::WeakImplHelper
<css::uri::XVndSunStarScriptUrlReference
>
192 UrlReference(OUString
const & scheme
, OUString
const & path
):
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
;
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
);
272 return parsePart(m_base
.m_path
, true, &i
);
275 void SAL_CALL
UrlReference::setName(OUString
const & name
)
278 throw css::lang::IllegalArgumentException(
279 OUString(), *this, 1);
281 osl::MutexGuard
g(m_base
.m_mutex
);
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
)
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 );
313 i
= m_base
.m_path
.getLength();
316 OUStringBuffer
newPath(128);
317 newPath
.append(std::u16string_view(m_base
.m_path
).substr(0, i
));
319 newPath
.append( m_base
.m_path
.indexOf('?') < 0 ? '?' : '&' );
320 newPath
.append(encodeNameOrParamFragment(key
));
323 newPath
.append(encodeNameOrParamFragment(value
));
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 {
335 parsePart(m_base
.m_path
, true, &i
); // skip name
337 if (i
== m_base
.m_path
.getLength()) {
340 ++i
; // skip '?' or '&'
341 OUString k
= parsePart(m_base
.m_path
, false, &i
);
346 parsePart(m_base
.m_path
, false, &i
); // skip value
351 public cppu::WeakImplHelper
<
352 css::lang::XServiceInfo
, css::uri::XUriSchemeParser
>
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
369 OUString
const & scheme
, OUString
const & schemeSpecificPart
) override
;
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
>
392 OUString
const & scheme
, OUString
const & schemeSpecificPart
)
394 if (!parseSchemeSpecificPart(schemeSpecificPart
)) {
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: */