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 <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>
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(std::u16string_view part
, sal_Int32
* index
) {
54 if (part
.size() - *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 std::u16string_view part
, bool namePart
, sal_Int32
* index
)
69 OUStringBuffer
buf(64);
70 while (o3tl::make_unsigned(*index
) < part
.size()) {
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 buf
.appendUtf32(encoded
);
128 return buf
.makeStringAndClear();
131 OUString
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
);
139 bool parseSchemeSpecificPart(std::u16string_view part
) {
140 size_t len
= part
.size();
142 if (parsePart(part
, true, &i
).isEmpty() || part
[0] == '/') {
145 if (o3tl::make_unsigned(i
) == len
) {
149 ++i
; // skip '?' or '&'
150 if (parsePart(part
, false, &i
).isEmpty() || o3tl::make_unsigned(i
) == len
156 parsePart(part
, false, &i
);
157 if (o3tl::make_unsigned(i
) == len
) {
160 if (part
[i
] != '&') {
167 public cppu::WeakImplHelper
<css::uri::XVndSunStarScriptUrlReference
>
170 UrlReference(OUString
const & scheme
, OUString
const & path
):
172 scheme
, false, OUString(), path
, false, OUString())
175 UrlReference(const UrlReference
&) = delete;
176 UrlReference
& operator=(const UrlReference
&) = delete;
178 virtual OUString SAL_CALL
getUriReference() override
179 { return m_base
.getUriReference(); }
181 virtual sal_Bool SAL_CALL
isAbsolute() override
182 { return m_base
.isAbsolute(); }
184 virtual OUString SAL_CALL
getScheme() override
185 { return m_base
.getScheme(); }
187 virtual OUString SAL_CALL
getSchemeSpecificPart() override
188 { return m_base
.getSchemeSpecificPart(); }
190 virtual sal_Bool SAL_CALL
isHierarchical() override
191 { return m_base
.isHierarchical(); }
193 virtual sal_Bool SAL_CALL
hasAuthority() override
194 { return m_base
.hasAuthority(); }
196 virtual OUString SAL_CALL
getAuthority() override
197 { return m_base
.getAuthority(); }
199 virtual OUString SAL_CALL
getPath() override
200 { return m_base
.getPath(); }
202 virtual sal_Bool SAL_CALL
hasRelativePath() override
203 { return m_base
.hasRelativePath(); }
205 virtual sal_Int32 SAL_CALL
getPathSegmentCount() override
206 { return m_base
.getPathSegmentCount(); }
208 virtual OUString SAL_CALL
getPathSegment(sal_Int32 index
) override
209 { return m_base
.getPathSegment(index
); }
211 virtual sal_Bool SAL_CALL
hasQuery() override
212 { return m_base
.hasQuery(); }
214 virtual OUString SAL_CALL
getQuery() override
215 { return m_base
.getQuery(); }
217 virtual sal_Bool SAL_CALL
hasFragment() override
218 { return m_base
.hasFragment(); }
220 virtual OUString SAL_CALL
getFragment() override
221 { return m_base
.getFragment(); }
223 virtual void SAL_CALL
setFragment(OUString
const & fragment
) override
224 { m_base
.setFragment(fragment
); }
226 virtual void SAL_CALL
clearFragment() override
227 { m_base
.clearFragment(); }
229 virtual OUString SAL_CALL
getName() override
;
231 virtual void SAL_CALL
setName(OUString
const & name
) override
;
233 virtual sal_Bool SAL_CALL
hasParameter(OUString
const & key
) override
;
235 virtual OUString SAL_CALL
getParameter(OUString
const & key
) override
;
237 virtual void SAL_CALL
setParameter(OUString
const & key
, OUString
const & value
) override
;
240 virtual ~UrlReference() override
{}
242 sal_Int32
findParameter(std::u16string_view key
) const;
244 stoc::uriproc::UriReference m_base
;
247 OUString
UrlReference::getName() {
248 std::lock_guard
g(m_base
.m_mutex
);
250 return parsePart(m_base
.m_path
, true, &i
);
253 void SAL_CALL
UrlReference::setName(OUString
const & name
)
256 throw css::lang::IllegalArgumentException(
257 OUString(), *this, 1);
259 std::lock_guard
g(m_base
.m_mutex
);
261 parsePart(m_base
.m_path
, true, &i
);
263 m_base
.m_path
= encodeNameOrParamFragment(name
) + m_base
.m_path
.subView(i
);
266 sal_Bool
UrlReference::hasParameter(OUString
const & key
)
268 std::lock_guard
g(m_base
.m_mutex
);
269 return findParameter(key
) >= 0;
272 OUString
UrlReference::getParameter(OUString
const & key
)
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();
279 void UrlReference::setParameter(OUString
const & key
, OUString
const & value
)
282 throw css::lang::IllegalArgumentException(
283 OUString(), *this, 1);
285 std::lock_guard
g(m_base
.m_mutex
);
286 sal_Int32 i
= findParameter(key
);
287 bool bExistent
= ( i
>=0 );
289 i
= m_base
.m_path
.getLength();
292 OUStringBuffer
newPath(128);
293 newPath
.append(m_base
.m_path
.subView(0, i
));
295 newPath
.append( m_base
.m_path
.indexOf('?') < 0 ? '?' : '&' );
296 newPath
.append(encodeNameOrParamFragment(key
) + "=");
298 newPath
.append(encodeNameOrParamFragment(value
));
301 parsePart(m_base
.m_path
, false, &i
); // skip key
302 newPath
.append(m_base
.m_path
.subView(i
));
305 m_base
.m_path
= newPath
.makeStringAndClear();
308 sal_Int32
UrlReference::findParameter(std::u16string_view key
) const {
310 parsePart(m_base
.m_path
, true, &i
); // skip name
312 if (i
== m_base
.m_path
.getLength()) {
315 ++i
; // skip '?' or '&'
316 OUString k
= parsePart(m_base
.m_path
, false, &i
);
321 parsePart(m_base
.m_path
, false, &i
); // skip value
326 public cppu::WeakImplHelper
<
327 css::lang::XServiceInfo
, css::uri::XUriSchemeParser
>
332 Parser(const Parser
&) = delete;
333 Parser
& operator=(const Parser
&) = delete;
335 virtual OUString SAL_CALL
getImplementationName() override
;
337 virtual sal_Bool SAL_CALL
supportsService(OUString
const & serviceName
) override
;
339 virtual css::uno::Sequence
< OUString
> SAL_CALL
340 getSupportedServiceNames() override
;
342 virtual css::uno::Reference
< css::uri::XUriReference
> SAL_CALL
344 OUString
const & scheme
, OUString
const & schemeSpecificPart
) override
;
347 virtual ~Parser() override
{}
350 OUString
Parser::getImplementationName()
352 return u
"com.sun.star.comp.uri.UriSchemeParser_vndDOTsunDOTstarDOTscript"_ustr
;
355 sal_Bool
Parser::supportsService(OUString
const & serviceName
)
357 return cppu::supportsService(this, serviceName
);
360 css::uno::Sequence
< OUString
> Parser::getSupportedServiceNames()
362 return { u
"com.sun.star.uri.UriSchemeParser_vndDOTsunDOTstarDOTscript"_ustr
};
365 css::uno::Reference
< css::uri::XUriReference
>
367 OUString
const & scheme
, OUString
const & schemeSpecificPart
)
369 if (!parseSchemeSpecificPart(schemeSpecificPart
)) {
372 return new UrlReference(scheme
, schemeSpecificPart
);
377 extern "C" SAL_DLLPUBLIC_EXPORT
css::uno::XInterface
*
378 com_sun_star_comp_uri_UriSchemeParser_vndDOTsunDOTstarDOTscript_get_implementation(css::uno::XComponentContext
*,
379 css::uno::Sequence
<css::uno::Any
> const &)
381 //TODO: single instance
382 return ::cppu::acquire(new Parser());
385 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */