Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This file is part of the LibreOffice project.
4 : *
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/.
8 : *
9 : * This file incorporates work covered by the following license notice:
10 : *
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 .
18 : */
19 :
20 : #include "UriReference.hxx"
21 :
22 : #include <boost/noncopyable.hpp>
23 : #include <com/sun/star/lang/IllegalArgumentException.hpp>
24 : #include <com/sun/star/lang/XServiceInfo.hpp>
25 : #include <com/sun/star/uno/Reference.hxx>
26 : #include <com/sun/star/uno/RuntimeException.hpp>
27 : #include <com/sun/star/uno/Sequence.hxx>
28 : #include <com/sun/star/uno/XComponentContext.hpp>
29 : #include <com/sun/star/uno/XInterface.hpp>
30 : #include <com/sun/star/uri/XUriReference.hpp>
31 : #include <com/sun/star/uri/XUriSchemeParser.hpp>
32 : #include <com/sun/star/uri/XVndSunStarScriptUrlReference.hpp>
33 : #include <cppuhelper/implbase1.hxx>
34 : #include <cppuhelper/implbase2.hxx>
35 : #include <cppuhelper/supportsservice.hxx>
36 : #include <cppuhelper/weak.hxx>
37 : #include <osl/mutex.hxx>
38 : #include <rtl/uri.hxx>
39 : #include <rtl/ustrbuf.hxx>
40 : #include <rtl/ustring.hxx>
41 : #include <sal/types.h>
42 :
43 : #include <exception>
44 :
45 : namespace {
46 :
47 0 : int getHexWeight(sal_Unicode c) {
48 0 : return c >= '0' && c <= '9' ? static_cast< int >(c - '0')
49 0 : : c >= 'A' && c <= 'F' ? static_cast< int >(c - 'A' + 10)
50 0 : : c >= 'a' && c <= 'f' ? static_cast< int >(c - 'a' + 10)
51 0 : : -1;
52 : }
53 :
54 0 : int parseEscaped(OUString const & part, sal_Int32 * index) {
55 0 : if (part.getLength() - *index < 3 || part[*index] != '%') {
56 0 : return -1;
57 : }
58 0 : int n1 = getHexWeight(part[*index + 1]);
59 0 : int n2 = getHexWeight(part[*index + 2]);
60 0 : if (n1 < 0 || n2 < 0) {
61 0 : return -1;
62 : }
63 0 : *index += 3;
64 0 : return (n1 << 4) | n2;
65 : }
66 :
67 37164 : OUString parsePart(
68 : OUString const & part, bool namePart, sal_Int32 * index)
69 : {
70 37164 : OUStringBuffer buf;
71 508934 : while (*index < part.getLength()) {
72 464512 : sal_Unicode c = part[*index];
73 464512 : if (namePart ? c == '?' : c == '&' || c == '=') {
74 29906 : break;
75 434606 : } else if (c == '%') {
76 0 : sal_Int32 i = *index;
77 0 : int n = parseEscaped(part, &i);
78 0 : if (n >= 0 && n <= 0x7F) {
79 0 : buf.append(static_cast< sal_Unicode >(n));
80 0 : } else if (n >= 0xC0 && n <= 0xFC) {
81 : sal_Int32 encoded;
82 : int shift;
83 : sal_Int32 min;
84 0 : if (n <= 0xDF) {
85 0 : encoded = (n & 0x1F) << 6;
86 0 : shift = 0;
87 0 : min = 0x80;
88 0 : } else if (n <= 0xEF) {
89 0 : encoded = (n & 0x0F) << 12;
90 0 : shift = 6;
91 0 : min = 0x800;
92 0 : } else if (n <= 0xF7) {
93 0 : encoded = (n & 0x07) << 18;
94 0 : shift = 12;
95 0 : min = 0x10000;
96 0 : } else if (n <= 0xFB) {
97 0 : encoded = (n & 0x03) << 24;
98 0 : shift = 18;
99 0 : min = 0x200000;
100 : } else {
101 0 : encoded = 0;
102 0 : shift = 24;
103 0 : min = 0x4000000;
104 : }
105 0 : bool utf8 = true;
106 0 : for (; shift >= 0; shift -= 6) {
107 0 : n = parseEscaped(part, &i);
108 0 : if (n < 0x80 || n > 0xBF) {
109 0 : utf8 = false;
110 0 : break;
111 : }
112 0 : encoded |= (n & 0x3F) << shift;
113 : }
114 0 : if (!utf8 || encoded < min
115 0 : || (encoded >= 0xD800 && encoded <= 0xDFFF)
116 0 : || encoded > 0x10FFFF)
117 : {
118 : break;
119 : }
120 0 : if (encoded <= 0xFFFF) {
121 0 : buf.append(static_cast< sal_Unicode >(encoded));
122 : } else {
123 : buf.append(static_cast< sal_Unicode >(
124 0 : (encoded >> 10) | 0xD800));
125 : buf.append(static_cast< sal_Unicode >(
126 0 : (encoded & 0x3FF) | 0xDC00));
127 : }
128 : } else {
129 : break;
130 : }
131 0 : *index = i;
132 : } else {
133 434606 : buf.append(c);
134 434606 : ++*index;
135 : }
136 : }
137 37164 : return buf.makeStringAndClear();
138 : }
139 :
140 : namespace
141 : {
142 0 : static OUString encodeNameOrParamFragment( OUString const & fragment )
143 : {
144 : static sal_Bool const aCharClass[] =
145 : { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* NameOrParamFragment */
146 : 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
147 : 0, 1, 0, 0, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, /* !"#$%&'()*+,-./*/
148 : 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, /*0123456789:;<=>?*/
149 : 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /*@ABCDEFGHIJKLMNO*/
150 : 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, /*PQRSTUVWXYZ[\]^_*/
151 : 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /*`abcdefghijklmno*/
152 : 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0 /*pqrstuvwxyz{|}~ */
153 : };
154 :
155 : return rtl::Uri::encode(
156 : fragment,
157 : aCharClass,
158 : rtl_UriEncodeIgnoreEscapes,
159 : RTL_TEXTENCODING_UTF8
160 0 : );
161 : }
162 : }
163 :
164 7096 : bool parseSchemeSpecificPart(OUString const & part) {
165 7096 : sal_Int32 len = part.getLength();
166 7096 : sal_Int32 i = 0;
167 7096 : if (parsePart(part, true, &i).isEmpty() || part[0] == '/') {
168 0 : return false;
169 : }
170 7096 : if (i == len) {
171 0 : return true;
172 : }
173 : for (;;) {
174 14190 : ++i; // skip '?' or '&'
175 56760 : if (parsePart(part, false, &i).isEmpty() || i == len
176 56760 : || part[i] != '=')
177 : {
178 0 : return false;
179 : }
180 14190 : ++i;
181 14190 : parsePart(part, false, &i);
182 14190 : if (i == len) {
183 7096 : return true;
184 : }
185 7094 : if (part[i] != '&') {
186 0 : return false;
187 : }
188 7094 : }
189 : }
190 :
191 : class UrlReference:
192 : public cppu::WeakImplHelper1<css::uri::XVndSunStarScriptUrlReference>,
193 : private boost::noncopyable
194 : {
195 : public:
196 7096 : UrlReference(OUString const & scheme, OUString const & path):
197 : m_base(
198 7096 : scheme, false, false, OUString(), path, false, OUString())
199 7096 : {}
200 :
201 0 : virtual OUString SAL_CALL getUriReference()
202 : throw (css::uno::RuntimeException, std::exception) SAL_OVERRIDE
203 0 : { return m_base.getUriReference(); }
204 :
205 0 : virtual sal_Bool SAL_CALL isAbsolute()
206 : throw (css::uno::RuntimeException, std::exception) SAL_OVERRIDE
207 0 : { return m_base.isAbsolute(); }
208 :
209 6934 : virtual OUString SAL_CALL getScheme()
210 : throw (css::uno::RuntimeException, std::exception) SAL_OVERRIDE
211 6934 : { return m_base.getScheme(); }
212 :
213 0 : virtual OUString SAL_CALL getSchemeSpecificPart()
214 : throw (css::uno::RuntimeException, std::exception) SAL_OVERRIDE
215 0 : { return m_base.getSchemeSpecificPart(); }
216 :
217 0 : virtual sal_Bool SAL_CALL isHierarchical()
218 : throw (css::uno::RuntimeException, std::exception) SAL_OVERRIDE
219 0 : { return m_base.isHierarchical(); }
220 :
221 0 : virtual sal_Bool SAL_CALL hasAuthority()
222 : throw (css::uno::RuntimeException, std::exception) SAL_OVERRIDE
223 0 : { return m_base.hasAuthority(); }
224 :
225 0 : virtual OUString SAL_CALL getAuthority()
226 : throw (css::uno::RuntimeException, std::exception) SAL_OVERRIDE
227 0 : { return m_base.getAuthority(); }
228 :
229 0 : virtual OUString SAL_CALL getPath()
230 : throw (css::uno::RuntimeException, std::exception) SAL_OVERRIDE
231 0 : { return m_base.getPath(); }
232 :
233 0 : virtual sal_Bool SAL_CALL hasRelativePath()
234 : throw (css::uno::RuntimeException, std::exception) SAL_OVERRIDE
235 0 : { return m_base.hasRelativePath(); }
236 :
237 0 : virtual sal_Int32 SAL_CALL getPathSegmentCount()
238 : throw (css::uno::RuntimeException, std::exception) SAL_OVERRIDE
239 0 : { return m_base.getPathSegmentCount(); }
240 :
241 0 : virtual OUString SAL_CALL getPathSegment(sal_Int32 index)
242 : throw (css::uno::RuntimeException, std::exception) SAL_OVERRIDE
243 0 : { return m_base.getPathSegment(index); }
244 :
245 0 : virtual sal_Bool SAL_CALL hasQuery()
246 : throw (css::uno::RuntimeException, std::exception) SAL_OVERRIDE
247 0 : { return m_base.hasQuery(); }
248 :
249 0 : virtual OUString SAL_CALL getQuery()
250 : throw (css::uno::RuntimeException, std::exception) SAL_OVERRIDE
251 0 : { return m_base.getQuery(); }
252 :
253 0 : virtual sal_Bool SAL_CALL hasFragment()
254 : throw (css::uno::RuntimeException, std::exception) SAL_OVERRIDE
255 0 : { return m_base.hasFragment(); }
256 :
257 0 : virtual OUString SAL_CALL getFragment()
258 : throw (css::uno::RuntimeException, std::exception) SAL_OVERRIDE
259 0 : { return m_base.getFragment(); }
260 :
261 0 : virtual void SAL_CALL setFragment(OUString const & fragment)
262 : throw (css::uno::RuntimeException, std::exception) SAL_OVERRIDE
263 0 : { m_base.setFragment(fragment); }
264 :
265 0 : virtual void SAL_CALL clearFragment()
266 : throw (css::uno::RuntimeException, std::exception) SAL_OVERRIDE
267 0 : { m_base.clearFragment(); }
268 :
269 : virtual OUString SAL_CALL getName() throw (css::uno::RuntimeException, std::exception) SAL_OVERRIDE;
270 :
271 : virtual void SAL_CALL setName(OUString const & name)
272 : throw (css::uno::RuntimeException, css::lang::IllegalArgumentException, std::exception) SAL_OVERRIDE;
273 :
274 : virtual sal_Bool SAL_CALL hasParameter(OUString const & key)
275 : throw (css::uno::RuntimeException, std::exception) SAL_OVERRIDE;
276 :
277 : virtual OUString SAL_CALL getParameter(OUString const & key)
278 : throw (css::uno::RuntimeException, std::exception) SAL_OVERRIDE;
279 :
280 : virtual void SAL_CALL setParameter(OUString const & key, OUString const & value)
281 : throw (css::uno::RuntimeException, css::lang::IllegalArgumentException, std::exception) SAL_OVERRIDE;
282 :
283 : private:
284 14192 : virtual ~UrlReference() {}
285 :
286 : sal_Int32 findParameter(OUString const & key);
287 :
288 : stoc::uriproc::UriReference m_base;
289 : };
290 :
291 162 : OUString UrlReference::getName() throw (css::uno::RuntimeException, std::exception) {
292 162 : osl::MutexGuard g(m_base.m_mutex);
293 162 : sal_Int32 i = 0;
294 162 : return parsePart(m_base.m_path, true, &i);
295 : }
296 :
297 0 : void SAL_CALL UrlReference::setName(OUString const & name) throw (css::uno::RuntimeException, css::lang::IllegalArgumentException, std::exception)
298 : {
299 0 : if (name.isEmpty())
300 : throw css::lang::IllegalArgumentException(
301 0 : OUString(), *this, 1);
302 :
303 0 : osl::MutexGuard g(m_base.m_mutex);
304 0 : sal_Int32 i = 0;
305 0 : parsePart(m_base.m_path, true, &i);
306 :
307 0 : OUStringBuffer newPath;
308 0 : newPath.append(encodeNameOrParamFragment(name));
309 0 : newPath.append(m_base.m_path.copy(i));
310 0 : m_base.m_path = newPath.makeStringAndClear();
311 0 : }
312 :
313 160 : sal_Bool UrlReference::hasParameter(OUString const & key)
314 : throw (css::uno::RuntimeException, std::exception)
315 : {
316 160 : osl::MutexGuard g(m_base.m_mutex);
317 160 : return findParameter(key) >= 0;
318 : }
319 :
320 242 : OUString UrlReference::getParameter(OUString const & key)
321 : throw (css::uno::RuntimeException, std::exception)
322 : {
323 242 : osl::MutexGuard g(m_base.m_mutex);
324 242 : sal_Int32 i = findParameter(key);
325 242 : return i >= 0 ? parsePart(m_base.m_path, false, &i) : OUString();
326 : }
327 :
328 0 : void UrlReference::setParameter(OUString const & key, OUString const & value)
329 : throw (css::uno::RuntimeException, css::lang::IllegalArgumentException, std::exception)
330 : {
331 0 : if (key.isEmpty())
332 : throw css::lang::IllegalArgumentException(
333 0 : OUString(), *this, 1);
334 :
335 0 : osl::MutexGuard g(m_base.m_mutex);
336 0 : sal_Int32 i = findParameter(key);
337 0 : bool bExistent = ( i>=0 );
338 0 : if (!bExistent) {
339 0 : i = m_base.m_path.getLength();
340 : }
341 :
342 0 : OUStringBuffer newPath;
343 0 : newPath.append(m_base.m_path.copy(0, i));
344 0 : if (!bExistent) {
345 0 : newPath.append( m_base.m_path.indexOf('?') < 0 ? '?' : '&' );
346 0 : newPath.append(encodeNameOrParamFragment(key));
347 0 : newPath.append('=');
348 : }
349 0 : newPath.append(encodeNameOrParamFragment(value));
350 0 : if (bExistent) {
351 : /*oldValue = */
352 0 : parsePart(m_base.m_path, false, &i); // skip key
353 0 : newPath.append(m_base.m_path.copy(i));
354 : }
355 :
356 0 : m_base.m_path = newPath.makeStringAndClear();
357 0 : }
358 :
359 402 : sal_Int32 UrlReference::findParameter(OUString const & key) {
360 402 : sal_Int32 i = 0;
361 402 : parsePart(m_base.m_path, true, &i); // skip name
362 : for (;;) {
363 642 : if (i == m_base.m_path.getLength()) {
364 402 : return -1;
365 : }
366 642 : ++i; // skip '?' or '&'
367 642 : OUString k = parsePart(m_base.m_path, false, &i);
368 642 : ++i; // skip '='
369 642 : if (k == key) {
370 402 : return i;
371 : }
372 240 : parsePart(m_base.m_path, false, &i); // skip value
373 240 : }
374 : }
375 :
376 : class Parser:
377 : public cppu::WeakImplHelper2<
378 : css::lang::XServiceInfo, css::uri::XUriSchemeParser>,
379 : private boost::noncopyable
380 : {
381 : public:
382 7096 : Parser() {}
383 :
384 : virtual OUString SAL_CALL getImplementationName()
385 : throw (css::uno::RuntimeException, std::exception) SAL_OVERRIDE;
386 :
387 : virtual sal_Bool SAL_CALL supportsService(OUString const & serviceName)
388 : throw (css::uno::RuntimeException, std::exception) SAL_OVERRIDE;
389 :
390 : virtual css::uno::Sequence< OUString > SAL_CALL
391 : getSupportedServiceNames() throw (css::uno::RuntimeException, std::exception) SAL_OVERRIDE;
392 :
393 : virtual css::uno::Reference< css::uri::XUriReference > SAL_CALL
394 : parse(
395 : OUString const & scheme, OUString const & schemeSpecificPart)
396 : throw (css::uno::RuntimeException, std::exception) SAL_OVERRIDE;
397 :
398 : private:
399 14192 : virtual ~Parser() {}
400 : };
401 :
402 0 : OUString Parser::getImplementationName()
403 : throw (css::uno::RuntimeException, std::exception)
404 : {
405 0 : return OUString("com.sun.star.comp.uri.UriSchemeParser_vndDOTsunDOTstarDOTscript");
406 : }
407 :
408 0 : sal_Bool Parser::supportsService(OUString const & serviceName)
409 : throw (css::uno::RuntimeException, std::exception)
410 : {
411 0 : return cppu::supportsService(this, serviceName);
412 : }
413 :
414 0 : css::uno::Sequence< OUString > Parser::getSupportedServiceNames()
415 : throw (css::uno::RuntimeException, std::exception)
416 : {
417 0 : css::uno::Sequence< OUString > s(1);
418 0 : s[0] = "com.sun.star.uri.UriSchemeParser_vndDOTsunDOTstarDOTscript";
419 0 : return s;
420 : }
421 :
422 : css::uno::Reference< css::uri::XUriReference >
423 7096 : Parser::parse(
424 : OUString const & scheme, OUString const & schemeSpecificPart)
425 : throw (css::uno::RuntimeException, std::exception)
426 : {
427 7096 : if (!parseSchemeSpecificPart(schemeSpecificPart)) {
428 0 : return 0;
429 : }
430 7096 : return new UrlReference(scheme, schemeSpecificPart);
431 : }
432 :
433 : }
434 :
435 : extern "C" SAL_DLLPUBLIC_EXPORT ::com::sun::star::uno::XInterface* SAL_CALL
436 7096 : com_sun_star_comp_uri_UriSchemeParser_vndDOTsunDOTstarDOTscript_get_implementation(::com::sun::star::uno::XComponentContext*,
437 : ::com::sun::star::uno::Sequence<css::uno::Any> const &)
438 : {
439 : //TODO: single instance
440 7096 : return ::cppu::acquire(new Parser());
441 : }
442 :
443 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|