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 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 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 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 { 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 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: 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 209 virtual rtl::OUString SAL_CALL getUriReference() 210 throw (com::sun::star::uno::RuntimeException) 211 { return m_base.getUriReference(); } 212 213 virtual sal_Bool SAL_CALL isAbsolute() 214 throw (com::sun::star::uno::RuntimeException) 215 { return m_base.isAbsolute(); } 216 217 virtual rtl::OUString SAL_CALL getScheme() 218 throw (com::sun::star::uno::RuntimeException) 219 { return m_base.getScheme(); } 220 221 virtual rtl::OUString SAL_CALL getSchemeSpecificPart() 222 throw (com::sun::star::uno::RuntimeException) 223 { return m_base.getSchemeSpecificPart(); } 224 225 virtual sal_Bool SAL_CALL isHierarchical() 226 throw (com::sun::star::uno::RuntimeException) 227 { return m_base.isHierarchical(); } 228 229 virtual sal_Bool SAL_CALL hasAuthority() 230 throw (com::sun::star::uno::RuntimeException) 231 { return m_base.hasAuthority(); } 232 233 virtual rtl::OUString SAL_CALL getAuthority() 234 throw (com::sun::star::uno::RuntimeException) 235 { return m_base.getAuthority(); } 236 237 virtual rtl::OUString SAL_CALL getPath() 238 throw (com::sun::star::uno::RuntimeException) 239 { return m_base.getPath(); } 240 241 virtual sal_Bool SAL_CALL hasRelativePath() 242 throw (com::sun::star::uno::RuntimeException) 243 { return m_base.hasRelativePath(); } 244 245 virtual sal_Int32 SAL_CALL getPathSegmentCount() 246 throw (com::sun::star::uno::RuntimeException) 247 { return m_base.getPathSegmentCount(); } 248 249 virtual rtl::OUString SAL_CALL getPathSegment(sal_Int32 index) 250 throw (com::sun::star::uno::RuntimeException) 251 { return m_base.getPathSegment(index); } 252 253 virtual sal_Bool SAL_CALL hasQuery() 254 throw (com::sun::star::uno::RuntimeException) 255 { return m_base.hasQuery(); } 256 257 virtual rtl::OUString SAL_CALL getQuery() 258 throw (com::sun::star::uno::RuntimeException) 259 { return m_base.getQuery(); } 260 261 virtual sal_Bool SAL_CALL hasFragment() 262 throw (com::sun::star::uno::RuntimeException) 263 { return m_base.hasFragment(); } 264 265 virtual rtl::OUString SAL_CALL getFragment() 266 throw (com::sun::star::uno::RuntimeException) 267 { return m_base.getFragment(); } 268 269 virtual void SAL_CALL setFragment(rtl::OUString const & fragment) 270 throw (com::sun::star::uno::RuntimeException) 271 { m_base.setFragment(fragment); } 272 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 295 virtual ~UrlReference() {} 296 297 sal_Int32 findParameter(rtl::OUString const & key); 298 299 stoc::uriproc::UriReference m_base; 300 }; 301 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 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 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 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 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 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: 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 411 virtual ~Parser() {} 412 }; 413 414 rtl::OUString Parser::getImplementationName() 415 throw (css::uno::RuntimeException) 416 { 417 return stoc_services::UriSchemeParser_vndDOTsunDOTstarDOTscript:: 418 getImplementationName(); 419 } 420 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 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 > 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 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 469 rtl::OUString getImplementationName() { 470 return rtl::OUString::createFromAscii( 471 "com.sun.star.comp.uri.UriSchemeParser_vndDOTsunDOTstarDOTscript"); 472 } 473 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