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