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