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 #include <services.h> 21 22 #include <cppuhelper/implbase.hxx> 23 #include <cppuhelper/supportsservice.hxx> 24 #include <tools/urlobj.hxx> 25 #include <rtl/ref.hxx> 26 #include <rtl/ustrbuf.hxx> 27 28 #include <com/sun/star/util/XURLTransformer.hpp> 29 #include <com/sun/star/util/URL.hpp> 30 #include <com/sun/star/lang/XServiceInfo.hpp> 31 #include <com/sun/star/uno/XComponentContext.hpp> 32 33 namespace { 34 35 class URLTransformer : public ::cppu::WeakImplHelper< css::util::XURLTransformer, css::lang::XServiceInfo> 36 { 37 public: 38 URLTransformer() {} 39 40 virtual OUString SAL_CALL getImplementationName() override 41 { 42 return "com.sun.star.comp.framework.URLTransformer"; 43 } 44 45 virtual sal_Bool SAL_CALL supportsService(OUString const & ServiceName) override 46 { 47 return cppu::supportsService(this, ServiceName); 48 } 49 50 virtual css::uno::Sequence<OUString> SAL_CALL getSupportedServiceNames() override 51 { 52 return {"com.sun.star.util.URLTransformer"}; 53 } 54 55 virtual sal_Bool SAL_CALL parseStrict( css::util::URL& aURL ) override; 56 57 virtual sal_Bool SAL_CALL parseSmart( css::util::URL& aURL, const OUString& sSmartProtocol ) override; 58 59 virtual sal_Bool SAL_CALL assemble( css::util::URL& aURL ) override; 60 61 virtual OUString SAL_CALL getPresentation( const css::util::URL& aURL, sal_Bool bWithPassword ) override; 62 }; 63 64 void lcl_ParserHelper(INetURLObject& _rParser, css::util::URL& _rURL,bool _bUseIntern) 65 { 66 // Get all information about this URL. 67 _rURL.Protocol = INetURLObject::GetScheme( _rParser.GetProtocol() ); 68 _rURL.User = _rParser.GetUser ( INetURLObject::DecodeMechanism::WithCharset ); 69 _rURL.Password = _rParser.GetPass ( INetURLObject::DecodeMechanism::WithCharset ); 70 _rURL.Server = _rParser.GetHost ( INetURLObject::DecodeMechanism::WithCharset ); 71 _rURL.Port = static_cast<sal_Int16>(_rParser.GetPort()); 72 73 sal_Int32 nCount = _rParser.getSegmentCount( false ); 74 if ( nCount > 0 ) 75 { 76 // Don't add last segment as it is the name! 77 --nCount; 78 79 OUStringBuffer aPath; 80 for ( sal_Int32 nIndex = 0; nIndex < nCount; nIndex++ ) 81 { 82 aPath.append( '/'); 83 aPath.append( _rParser.getName( nIndex, false, INetURLObject::DecodeMechanism::NONE )); 84 } 85 86 if ( nCount > 0 ) 87 aPath.append( '/' ); // final slash! 88 89 _rURL.Path = aPath.makeStringAndClear(); 90 _rURL.Name = _rParser.getName( INetURLObject::LAST_SEGMENT, false, INetURLObject::DecodeMechanism::NONE ); 91 } 92 else 93 { 94 _rURL.Path = _rParser.GetURLPath( INetURLObject::DecodeMechanism::NONE ); 95 _rURL.Name = _rParser.GetLastName(); 96 } 97 98 _rURL.Arguments = _rParser.GetParam(); 99 _rURL.Mark = _rParser.GetMark( INetURLObject::DecodeMechanism::WithCharset ); 100 101 // INetURLObject supports only an intelligent method of parsing URL's. So write 102 // back Complete to have a valid encoded URL in all cases! 103 _rURL.Complete = _rParser.GetMainURL( INetURLObject::DecodeMechanism::NONE ); 104 if ( _bUseIntern ) 105 _rURL.Complete = _rURL.Complete.intern(); 106 107 _rParser.SetMark ( OUString() ); 108 _rParser.SetParam( OUString() ); 109 110 _rURL.Main = _rParser.GetMainURL( INetURLObject::DecodeMechanism::NONE ); 111 } 112 113 // XURLTransformer 114 sal_Bool SAL_CALL URLTransformer::parseStrict( css::util::URL& aURL ) 115 { 116 // Safe impossible cases. 117 if ( aURL.Complete.isEmpty() ) 118 { 119 return false; 120 } 121 // Try to extract the protocol 122 sal_Int32 nURLIndex = aURL.Complete.indexOf( ':' ); 123 OUString aProtocol; 124 if ( nURLIndex > 1 ) 125 { 126 aProtocol = aURL.Complete.copy( 0, nURLIndex+1 ); 127 128 // If INetURLObject knows this protocol let it parse 129 if ( INetURLObject::CompareProtocolScheme( aProtocol ) != INetProtocol::NotValid ) 130 { 131 // Initialize parser with given URL. 132 INetURLObject aParser( aURL.Complete ); 133 134 // Get all information about this URL. 135 INetProtocol eINetProt = aParser.GetProtocol(); 136 if ( eINetProt == INetProtocol::NotValid ) 137 { 138 return false; 139 } 140 else if ( !aParser.HasError() ) 141 { 142 lcl_ParserHelper(aParser,aURL,false); 143 // Return "URL is parsed". 144 return true; 145 } 146 } 147 else 148 { 149 // Minimal support for unknown protocols. This is mandatory to support the "Protocol Handlers" implemented 150 // in framework! 151 aURL.Protocol = aProtocol; 152 aURL.Main = aURL.Complete; 153 aURL.Path = aURL.Complete.copy( nURLIndex+1 ); 154 155 // Return "URL is parsed". 156 return true; 157 } 158 } 159 160 return false; 161 } 162 163 // XURLTransformer 164 165 sal_Bool SAL_CALL URLTransformer::parseSmart( css::util::URL& aURL, 166 const OUString& sSmartProtocol ) 167 { 168 // Safe impossible cases. 169 if ( aURL.Complete.isEmpty() ) 170 { 171 return false; 172 } 173 174 // Initialize parser with given URL. 175 INetURLObject aParser; 176 177 aParser.SetSmartProtocol( INetURLObject::CompareProtocolScheme( sSmartProtocol )); 178 bool bOk = aParser.SetSmartURL( aURL.Complete ); 179 if ( bOk ) 180 { 181 lcl_ParserHelper(aParser,aURL,true); 182 // Return "URL is parsed". 183 return true; 184 } 185 else 186 { 187 // Minimal support for unknown protocols. This is mandatory to support the "Protocol Handlers" implemented 188 // in framework! 189 if ( INetURLObject::CompareProtocolScheme( sSmartProtocol ) == INetProtocol::NotValid ) 190 { 191 // Try to extract the protocol 192 sal_Int32 nIndex = aURL.Complete.indexOf( ':' ); 193 OUString aProtocol; 194 if ( nIndex > 1 ) 195 { 196 aProtocol = aURL.Complete.copy( 0, nIndex+1 ); 197 198 // If INetURLObject knows this protocol something is wrong as detected before => 199 // give up and return false! 200 if ( INetURLObject::CompareProtocolScheme( aProtocol ) != INetProtocol::NotValid ) 201 return false; 202 else 203 aURL.Protocol = aProtocol; 204 } 205 else 206 return false; 207 208 aURL.Main = aURL.Complete; 209 aURL.Path = aURL.Complete.copy( nIndex+1 ); 210 return true; 211 } 212 else 213 return false; 214 } 215 } 216 217 // XURLTransformer 218 sal_Bool SAL_CALL URLTransformer::assemble( css::util::URL& aURL ) 219 { 220 // Initialize parser. 221 INetURLObject aParser; 222 223 if ( INetURLObject::CompareProtocolScheme( aURL.Protocol ) != INetProtocol::NotValid ) 224 { 225 OUStringBuffer aCompletePath( aURL.Path ); 226 227 // Concat the name if it is provided, just support a final slash 228 if ( !aURL.Name.isEmpty() ) 229 { 230 sal_Int32 nIndex = aURL.Path.lastIndexOf( '/' ); 231 if ( nIndex == ( aURL.Path.getLength() -1 )) 232 aCompletePath.append( aURL.Name ); 233 else 234 { 235 aCompletePath.append( '/' ); 236 aCompletePath.append( aURL.Name ); 237 } 238 } 239 240 bool bResult = aParser.ConcatData( 241 INetURLObject::CompareProtocolScheme( aURL.Protocol ) , 242 aURL.User , 243 aURL.Password , 244 aURL.Server , 245 aURL.Port , 246 aCompletePath.makeStringAndClear() ); 247 248 if ( !bResult ) 249 return false; 250 251 // First parse URL WITHOUT ... 252 aURL.Main = aParser.GetMainURL( INetURLObject::DecodeMechanism::NONE ); 253 // ...and then WITH parameter and mark. 254 aParser.SetParam( aURL.Arguments); 255 aParser.SetMark ( aURL.Mark, INetURLObject::EncodeMechanism::All ); 256 aURL.Complete = aParser.GetMainURL( INetURLObject::DecodeMechanism::NONE ); 257 258 // Return "URL is assembled". 259 return true; 260 } 261 else if ( !aURL.Protocol.isEmpty() ) 262 { 263 // Minimal support for unknown protocols 264 OUStringBuffer aBuffer( aURL.Protocol ); 265 aBuffer.append( aURL.Path ); 266 aURL.Complete = aBuffer.makeStringAndClear(); 267 aURL.Main = aURL.Complete; 268 return true; 269 } 270 271 return false; 272 } 273 274 // XURLTransformer 275 276 OUString SAL_CALL URLTransformer::getPresentation( const css::util::URL& aURL, 277 sal_Bool bWithPassword ) 278 { 279 // Safe impossible cases. 280 if ( aURL.Complete.isEmpty() ) 281 { 282 return OUString(); 283 } 284 285 // Check given URL 286 css::util::URL aTestURL = aURL; 287 bool bParseResult = parseSmart( aTestURL, aTestURL.Protocol ); 288 if ( bParseResult ) 289 { 290 if ( !bWithPassword && !aTestURL.Password.isEmpty() ) 291 { 292 // Exchange password text with other placeholder string 293 aTestURL.Password = "<******>"; 294 assemble( aTestURL ); 295 } 296 297 // Convert internal URLs to "praesentation"-URLs! 298 OUString sPraesentationURL; 299 INetURLObject::translateToExternal( aTestURL.Complete, sPraesentationURL, INetURLObject::DecodeMechanism::Unambiguous ); 300 301 return sPraesentationURL; 302 } 303 else 304 return OUString(); 305 } 306 307 } 308 309 extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface * 310 com_sun_star_comp_framework_URLTransformer_get_implementation( 311 css::uno::XComponentContext *, 312 css::uno::Sequence<css::uno::Any> const &) 313 { 314 return cppu::acquire(new URLTransformer()); 315 } 316 317 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ 318
