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_cppuhelper.hxx" 30 31 #include "cppuhelper/unourl.hxx" 32 33 #include "osl/diagnose.h" 34 #include "rtl/malformeduriexception.hxx" 35 #include "rtl/string.h" 36 #include "rtl/textenc.h" 37 #include "rtl/uri.h" 38 #include "rtl/uri.hxx" 39 #include "rtl/ustring.h" 40 #include "rtl/ustring.hxx" 41 #include "sal/types.h" 42 43 #include <map> 44 45 using cppu::UnoUrl; 46 using cppu::UnoUrlDescriptor; 47 48 namespace { 49 50 inline bool isAlphanum(sal_Unicode c) 51 { 52 return (c >= 0x30 && c <= 0x39) // '0'--'9' 53 || (c >= 0x41 && c <= 0x5A) // 'A'--'Z' 54 || (c >= 0x61 && c <= 0x7A); // 'a'--'z' 55 } 56 57 } 58 59 class UnoUrlDescriptor::Impl 60 { 61 public: 62 typedef std::map< rtl::OUString, rtl::OUString > Parameters; 63 64 rtl::OUString m_aDescriptor; 65 rtl::OUString m_aName; 66 Parameters m_aParameters; 67 68 /** @exception rtl::MalformedUriException 69 */ 70 explicit inline Impl(rtl::OUString const & m_aDescriptor); 71 72 inline Impl * clone() const { return new Impl(*this); } 73 }; 74 75 inline UnoUrlDescriptor::Impl::Impl(rtl::OUString const & rDescriptor) 76 { 77 m_aDescriptor = rDescriptor; 78 enum State { STATE_NAME0, STATE_NAME, STATE_KEY0, STATE_KEY, STATE_VALUE }; 79 State eState = STATE_NAME0; 80 sal_Int32 nStart = 0; 81 rtl::OUString aKey; 82 for (sal_Int32 i = 0;; ++i) 83 { 84 bool bEnd = i == rDescriptor.getLength(); 85 sal_Unicode c = bEnd ? 0 : rDescriptor.getStr()[i]; 86 switch (eState) 87 { 88 case STATE_NAME0: 89 if (bEnd || !isAlphanum(c)) 90 throw rtl::MalformedUriException( 91 rtl::OUString(RTL_CONSTASCII_USTRINGPARAM( 92 "UNO URL contains bad descriptor name"))); 93 nStart = i; 94 eState = STATE_NAME; 95 break; 96 97 case STATE_NAME: 98 if (bEnd || c == 0x2C) // ',' 99 { 100 m_aName 101 = rDescriptor.copy(nStart, i - nStart).toAsciiLowerCase(); 102 eState = STATE_KEY0; 103 } 104 else if (!isAlphanum(c)) 105 throw rtl::MalformedUriException( 106 rtl::OUString(RTL_CONSTASCII_USTRINGPARAM( 107 "UNO URL contains bad descriptor name"))); 108 break; 109 110 case STATE_KEY0: 111 if (bEnd || !isAlphanum(c)) 112 throw rtl::MalformedUriException( 113 rtl::OUString(RTL_CONSTASCII_USTRINGPARAM( 114 "UNO URL contains bad parameter key"))); 115 nStart = i; 116 eState = STATE_KEY; 117 break; 118 119 case STATE_KEY: 120 if (c == 0x3D) // '=' 121 { 122 aKey = rDescriptor.copy(nStart, i - nStart).toAsciiLowerCase(); 123 nStart = i + 1; 124 eState = STATE_VALUE; 125 } 126 else if (bEnd || !isAlphanum(c)) 127 throw rtl::MalformedUriException( 128 rtl::OUString(RTL_CONSTASCII_USTRINGPARAM( 129 "UNO URL contains bad parameter key"))); 130 break; 131 132 case STATE_VALUE: 133 if (bEnd || c == 0x2C) // ',' 134 { 135 if (!m_aParameters.insert( 136 Parameters::value_type( 137 aKey, 138 rtl::Uri::decode(rDescriptor.copy(nStart, 139 i - nStart), 140 rtl_UriDecodeWithCharset, 141 RTL_TEXTENCODING_UTF8))).second) 142 throw rtl::MalformedUriException( 143 rtl::OUString( 144 RTL_CONSTASCII_USTRINGPARAM( 145 "UNO URL contains duplicated parameter"))); 146 eState = STATE_KEY0; 147 } 148 break; 149 } 150 if (bEnd) 151 break; 152 } 153 } 154 155 UnoUrlDescriptor::UnoUrlDescriptor(rtl::OUString const & rDescriptor): 156 m_xImpl(new Impl(rDescriptor)) 157 {} 158 159 UnoUrlDescriptor::UnoUrlDescriptor(std::auto_ptr< Impl > & rImpl): 160 m_xImpl(rImpl) 161 {} 162 163 UnoUrlDescriptor::UnoUrlDescriptor(UnoUrlDescriptor const & rOther): 164 m_xImpl(rOther.m_xImpl->clone()) 165 {} 166 167 UnoUrlDescriptor::~UnoUrlDescriptor() 168 {} 169 170 UnoUrlDescriptor & UnoUrlDescriptor::operator =(UnoUrlDescriptor const & rOther) 171 { 172 m_xImpl.reset(rOther.m_xImpl->clone()); 173 return *this; 174 } 175 176 rtl::OUString const & UnoUrlDescriptor::getDescriptor() const 177 { 178 return m_xImpl->m_aDescriptor; 179 } 180 181 rtl::OUString const & UnoUrlDescriptor::getName() const 182 { 183 return m_xImpl->m_aName; 184 } 185 186 bool UnoUrlDescriptor::hasParameter(rtl::OUString const & rKey) const 187 { 188 return m_xImpl->m_aParameters.find(rKey.toAsciiLowerCase()) 189 != m_xImpl->m_aParameters.end(); 190 } 191 192 rtl::OUString UnoUrlDescriptor::getParameter(rtl::OUString const & rKey) const 193 { 194 Impl::Parameters::const_iterator 195 aIt(m_xImpl->m_aParameters.find(rKey.toAsciiLowerCase())); 196 return aIt == m_xImpl->m_aParameters.end() ? rtl::OUString() : aIt->second; 197 } 198 199 class UnoUrl::Impl 200 { 201 public: 202 UnoUrlDescriptor m_aConnection; 203 UnoUrlDescriptor m_aProtocol; 204 rtl::OUString m_aObjectName; 205 206 inline Impl * clone() const { return new Impl(*this); } 207 208 /** @exception rtl::MalformedUriException 209 */ 210 static inline Impl * create(rtl::OUString const & rUrl); 211 212 private: 213 inline Impl(std::auto_ptr< UnoUrlDescriptor::Impl > & rConnection, 214 std::auto_ptr< UnoUrlDescriptor::Impl > & rProtocol, 215 rtl::OUString const & rObjectName); 216 }; 217 218 inline UnoUrl::Impl::Impl(std::auto_ptr< UnoUrlDescriptor::Impl > & rConnection, 219 std::auto_ptr< UnoUrlDescriptor::Impl > & rProtocol, 220 rtl::OUString const & rObjectName): 221 m_aConnection(rConnection), 222 m_aProtocol(rProtocol), 223 m_aObjectName(rObjectName) 224 {} 225 226 inline UnoUrl::Impl * UnoUrl::Impl::create(rtl::OUString const & rUrl) 227 { 228 if (!rUrl.matchIgnoreAsciiCaseAsciiL(RTL_CONSTASCII_STRINGPARAM("uno:"), 0)) 229 throw rtl::MalformedUriException( 230 rtl::OUString(RTL_CONSTASCII_USTRINGPARAM( 231 "UNO URL does not start with \"uno:\""))); 232 sal_Int32 i = RTL_CONSTASCII_LENGTH("uno:"); 233 sal_Int32 j = rUrl.indexOf(';', i); 234 if (j < 0) 235 throw rtl::MalformedUriException( 236 rtl::OUString(RTL_CONSTASCII_USTRINGPARAM( 237 "UNO URL has too few semicolons"))); 238 std::auto_ptr< UnoUrlDescriptor::Impl > 239 xConnection(new UnoUrlDescriptor::Impl(rUrl.copy(i, j - i))); 240 i = j + 1; 241 j = rUrl.indexOf(0x3B, i); // ';' 242 if (j < 0) 243 throw rtl::MalformedUriException( 244 rtl::OUString(RTL_CONSTASCII_USTRINGPARAM( 245 "UNO URL has too few semicolons"))); 246 std::auto_ptr< UnoUrlDescriptor::Impl > 247 xProtocol(new UnoUrlDescriptor::Impl(rUrl.copy(i, j - i))); 248 i = j + 1; 249 if (i == rUrl.getLength()) 250 throw rtl::MalformedUriException( 251 rtl::OUString(RTL_CONSTASCII_USTRINGPARAM( 252 "UNO URL contains empty ObjectName"))); 253 for (j = i; j < rUrl.getLength(); ++j) 254 { 255 sal_Unicode c = rUrl.getStr()[j]; 256 if (!isAlphanum(c) && c != 0x21 && c != 0x24 // '!', '$' 257 && c != 0x26 && c != 0x27 && c != 0x28 // '&', ''', '(' 258 && c != 0x28 && c != 0x2A && c != 0x2B // ')', '*', '+' 259 && c != 0x2C && c != 0x2D && c != 0x2E // ',', '-', '.' 260 && c != 0x2F && c != 0x3A && c != 0x3D // '/', ':', '=' 261 && c != 0x3F && c != 0x40 && c != 0x5F // '?', '@', '_' 262 && c != 0x7E) // '~' 263 throw rtl::MalformedUriException( 264 rtl::OUString(RTL_CONSTASCII_USTRINGPARAM( 265 "UNO URL contains invalid ObjectName"))); 266 } 267 return new Impl(xConnection, xProtocol, rUrl.copy(i)); 268 } 269 270 UnoUrl::UnoUrl(rtl::OUString const & rUrl): m_xImpl(Impl::create(rUrl)) 271 {} 272 273 UnoUrl::UnoUrl(UnoUrl const & rOther): m_xImpl(rOther.m_xImpl->clone()) 274 {} 275 276 UnoUrl::~UnoUrl() 277 {} 278 279 UnoUrl & UnoUrl::operator =(UnoUrl const & rOther) 280 { 281 m_xImpl.reset(rOther.m_xImpl->clone()); 282 return *this; 283 } 284 285 UnoUrlDescriptor const & UnoUrl::getConnection() const 286 { 287 return m_xImpl->m_aConnection; 288 } 289 290 UnoUrlDescriptor const & UnoUrl::getProtocol() const 291 { 292 return m_xImpl->m_aProtocol; 293 } 294 295 rtl::OUString const & UnoUrl::getObjectName() const 296 { 297 return m_xImpl->m_aObjectName; 298 } 299