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/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>
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
)
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, 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 OUStringBuffer newPath
;
286 newPath
.append(encodeNameOrParamFragment(name
));
287 newPath
.append(m_base
.m_path
.copy(i
));
288 m_base
.m_path
= newPath
.makeStringAndClear();
291 sal_Bool
UrlReference::hasParameter(OUString
const & key
)
293 osl::MutexGuard
g(m_base
.m_mutex
);
294 return findParameter(key
) >= 0;
297 OUString
UrlReference::getParameter(OUString
const & key
)
299 osl::MutexGuard
g(m_base
.m_mutex
);
300 sal_Int32 i
= findParameter(key
);
301 return i
>= 0 ? parsePart(m_base
.m_path
, false, &i
) : OUString();
304 void UrlReference::setParameter(OUString
const & key
, OUString
const & value
)
307 throw css::lang::IllegalArgumentException(
308 OUString(), *this, 1);
310 osl::MutexGuard
g(m_base
.m_mutex
);
311 sal_Int32 i
= findParameter(key
);
312 bool bExistent
= ( i
>=0 );
314 i
= m_base
.m_path
.getLength();
317 OUStringBuffer newPath
;
318 newPath
.append(m_base
.m_path
.copy(0, i
));
320 newPath
.append( m_base
.m_path
.indexOf('?') < 0 ? '?' : '&' );
321 newPath
.append(encodeNameOrParamFragment(key
));
324 newPath
.append(encodeNameOrParamFragment(value
));
327 parsePart(m_base
.m_path
, false, &i
); // skip key
328 newPath
.append(m_base
.m_path
.copy(i
));
331 m_base
.m_path
= newPath
.makeStringAndClear();
334 sal_Int32
UrlReference::findParameter(OUString
const & key
) const {
336 parsePart(m_base
.m_path
, true, &i
); // skip name
338 if (i
== m_base
.m_path
.getLength()) {
341 ++i
; // skip '?' or '&'
342 OUString k
= parsePart(m_base
.m_path
, false, &i
);
347 parsePart(m_base
.m_path
, false, &i
); // skip value
352 public cppu::WeakImplHelper
<
353 css::lang::XServiceInfo
, css::uri::XUriSchemeParser
>
358 Parser(const Parser
&) = delete;
359 Parser
& operator=(const Parser
&) = delete;
361 virtual OUString SAL_CALL
getImplementationName() override
;
363 virtual sal_Bool SAL_CALL
supportsService(OUString
const & serviceName
) override
;
365 virtual css::uno::Sequence
< OUString
> SAL_CALL
366 getSupportedServiceNames() override
;
368 virtual css::uno::Reference
< css::uri::XUriReference
> SAL_CALL
370 OUString
const & scheme
, OUString
const & schemeSpecificPart
) override
;
373 virtual ~Parser() override
{}
376 OUString
Parser::getImplementationName()
378 return OUString("com.sun.star.comp.uri.UriSchemeParser_vndDOTsunDOTstarDOTscript");
381 sal_Bool
Parser::supportsService(OUString
const & serviceName
)
383 return cppu::supportsService(this, serviceName
);
386 css::uno::Sequence
< OUString
> Parser::getSupportedServiceNames()
388 css::uno::Sequence
< OUString
> s
{ "com.sun.star.uri.UriSchemeParser_vndDOTsunDOTstarDOTscript" };
392 css::uno::Reference
< css::uri::XUriReference
>
394 OUString
const & scheme
, OUString
const & schemeSpecificPart
)
396 if (!parseSchemeSpecificPart(schemeSpecificPart
)) {
399 return new UrlReference(scheme
, schemeSpecificPart
);
404 extern "C" SAL_DLLPUBLIC_EXPORT
css::uno::XInterface
*
405 com_sun_star_comp_uri_UriSchemeParser_vndDOTsunDOTstarDOTscript_get_implementation(css::uno::XComponentContext
*,
406 css::uno::Sequence
<css::uno::Any
> const &)
408 //TODO: single instance
409 return ::cppu::acquire(new Parser());
412 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */