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