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::isUnicodeCodePoint(encoded
) || encoded
< min
114 || (encoded
>= 0xD800 && encoded
<= 0xDFFF))
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();
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();
168 if (parsePart(part
, true, &i
).isEmpty() || part
[0] == '/') {
175 ++i
; // skip '?' or '&'
176 if (parsePart(part
, false, &i
).isEmpty() || i
== len
182 parsePart(part
, false, &i
);
186 if (part
[i
] != '&') {
193 public cppu::WeakImplHelper
<css::uri::XVndSunStarScriptUrlReference
>
196 UrlReference(OUString
const & scheme
, OUString
const & path
):
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
;
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
);
276 return parsePart(m_base
.m_path
, true, &i
);
279 void SAL_CALL
UrlReference::setName(OUString
const & name
)
282 throw css::lang::IllegalArgumentException(
283 OUString(), *this, 1);
285 osl::MutexGuard
g(m_base
.m_mutex
);
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
)
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 );
318 i
= m_base
.m_path
.getLength();
321 OUStringBuffer newPath
;
322 newPath
.append(m_base
.m_path
.copy(0, i
));
324 newPath
.append( m_base
.m_path
.indexOf('?') < 0 ? '?' : '&' );
325 newPath
.append(encodeNameOrParamFragment(key
));
328 newPath
.append(encodeNameOrParamFragment(value
));
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
) {
340 parsePart(m_base
.m_path
, true, &i
); // skip name
342 if (i
== m_base
.m_path
.getLength()) {
345 ++i
; // skip '?' or '&'
346 OUString k
= parsePart(m_base
.m_path
, false, &i
);
351 parsePart(m_base
.m_path
, false, &i
); // skip value
356 public cppu::WeakImplHelper
<
357 css::lang::XServiceInfo
, css::uri::XUriSchemeParser
>
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
374 OUString
const & scheme
, OUString
const & schemeSpecificPart
) override
;
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" };
396 css::uno::Reference
< css::uri::XUriReference
>
398 OUString
const & scheme
, OUString
const & schemeSpecificPart
)
400 if (!parseSchemeSpecificPart(schemeSpecificPart
)) {
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: */