/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* * This file is part of the LibreOffice project. * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * This file incorporates work covered by the following license notice: * * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed * with this work for additional information regarding copyright * ownership. The ASF licenses this file to you under the Apache * License, Version 2.0 (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of * the License at http://www.apache.org/licenses/LICENSE-2.0 . */ #include #include #include #include #include #include #include #include namespace { class URLTransformer : public ::cppu::WeakImplHelper< css::util::XURLTransformer, css::lang::XServiceInfo> { public: URLTransformer() {} virtual OUString SAL_CALL getImplementationName() override { return "com.sun.star.comp.framework.URLTransformer"; } virtual sal_Bool SAL_CALL supportsService(OUString const & ServiceName) override { return cppu::supportsService(this, ServiceName); } virtual css::uno::Sequence SAL_CALL getSupportedServiceNames() override { return {"com.sun.star.util.URLTransformer"}; } virtual sal_Bool SAL_CALL parseStrict( css::util::URL& aURL ) override; virtual sal_Bool SAL_CALL parseSmart( css::util::URL& aURL, const OUString& sSmartProtocol ) override; virtual sal_Bool SAL_CALL assemble( css::util::URL& aURL ) override; virtual OUString SAL_CALL getPresentation( const css::util::URL& aURL, sal_Bool bWithPassword ) override; }; void lcl_ParserHelper(INetURLObject& _rParser, css::util::URL& _rURL) { // Get all information about this URL. _rURL.Protocol = INetURLObject::GetScheme( _rParser.GetProtocol() ); _rURL.User = _rParser.GetUser ( INetURLObject::DecodeMechanism::WithCharset ); _rURL.Password = _rParser.GetPass ( INetURLObject::DecodeMechanism::WithCharset ); _rURL.Server = _rParser.GetHost ( INetURLObject::DecodeMechanism::WithCharset ); _rURL.Port = static_cast(_rParser.GetPort()); sal_Int32 nCount = _rParser.getSegmentCount( false ); if ( nCount > 0 ) { // Don't add last segment as it is the name! --nCount; OUStringBuffer aPath(128); for ( sal_Int32 nIndex = 0; nIndex < nCount; nIndex++ ) { aPath.append( "/" + _rParser.getName( nIndex, false, INetURLObject::DecodeMechanism::NONE )); } if ( nCount > 0 ) aPath.append( '/' ); // final slash! _rURL.Path = aPath.makeStringAndClear(); _rURL.Name = _rParser.getName( INetURLObject::LAST_SEGMENT, false, INetURLObject::DecodeMechanism::NONE ); } else { _rURL.Path = _rParser.GetURLPath( INetURLObject::DecodeMechanism::NONE ); _rURL.Name = _rParser.GetLastName(); } _rURL.Arguments = _rParser.GetParam(); _rURL.Mark = _rParser.GetMark( INetURLObject::DecodeMechanism::WithCharset ); // INetURLObject supports only an intelligent method of parsing URL's. So write // back Complete to have a valid encoded URL in all cases! _rURL.Complete = _rParser.GetMainURL( INetURLObject::DecodeMechanism::NONE ); _rParser.SetMark( u"" ); _rParser.SetParam( u"" ); _rURL.Main = _rParser.GetMainURL( INetURLObject::DecodeMechanism::NONE ); } // XURLTransformer sal_Bool SAL_CALL URLTransformer::parseStrict( css::util::URL& aURL ) { // Safe impossible cases. if ( aURL.Complete.isEmpty() ) { return false; } // Try to extract the protocol sal_Int32 nURLIndex = aURL.Complete.indexOf( ':' ); if ( nURLIndex <= 1 ) return false; std::u16string_view aProtocol = aURL.Complete.subView( 0, nURLIndex+1 ); // If INetURLObject knows this protocol let it parse if ( INetURLObject::CompareProtocolScheme( aProtocol ) != INetProtocol::NotValid ) { // Initialize parser with given URL. INetURLObject aParser( aURL.Complete ); // Get all information about this URL. INetProtocol eINetProt = aParser.GetProtocol(); if ( eINetProt == INetProtocol::NotValid ) { return false; } else if ( !aParser.HasError() ) { lcl_ParserHelper(aParser,aURL); // Return "URL is parsed". return true; } } else { // Minimal support for unknown protocols. This is mandatory to support the "Protocol Handlers" implemented // in framework! aURL.Protocol = aProtocol; aURL.Main = aURL.Complete; aURL.Path = aURL.Complete.copy( nURLIndex+1 ); // Return "URL is parsed". return true; } return false; } // XURLTransformer sal_Bool SAL_CALL URLTransformer::parseSmart( css::util::URL& aURL, const OUString& sSmartProtocol ) { // Safe impossible cases. if ( aURL.Complete.isEmpty() ) { return false; } // Initialize parser with given URL. INetURLObject aParser; aParser.SetSmartProtocol( INetURLObject::CompareProtocolScheme( sSmartProtocol )); bool bOk = aParser.SetSmartURL( aURL.Complete ); if ( bOk ) { lcl_ParserHelper(aParser,aURL); // Return "URL is parsed". return true; } else { // Minimal support for unknown protocols. This is mandatory to support the "Protocol Handlers" implemented // in framework! if ( INetURLObject::CompareProtocolScheme( sSmartProtocol ) == INetProtocol::NotValid ) { // Try to extract the protocol sal_Int32 nIndex = aURL.Complete.indexOf( ':' ); if ( nIndex > 1 ) { OUString aProtocol = aURL.Complete.copy( 0, nIndex+1 ); // If INetURLObject knows this protocol something is wrong as detected before => // give up and return false! if ( INetURLObject::CompareProtocolScheme( aProtocol ) != INetProtocol::NotValid ) return false; else aURL.Protocol = aProtocol; } else return false; aURL.Main = aURL.Complete; aURL.Path = aURL.Complete.copy( nIndex+1 ); return true; } else return false; } } // XURLTransformer sal_Bool SAL_CALL URLTransformer::assemble( css::util::URL& aURL ) { // Initialize parser. INetURLObject aParser; if ( INetURLObject::CompareProtocolScheme( aURL.Protocol ) != INetProtocol::NotValid ) { OUStringBuffer aCompletePath( aURL.Path ); // Concat the name if it is provided, just support a final slash if ( !aURL.Name.isEmpty() ) { sal_Int32 nIndex = aURL.Path.lastIndexOf( '/' ); if ( nIndex == ( aURL.Path.getLength() -1 )) aCompletePath.append( aURL.Name ); else { aCompletePath.append( "/" + aURL.Name ); } } bool bResult = aParser.ConcatData( INetURLObject::CompareProtocolScheme( aURL.Protocol ) , aURL.User , aURL.Password , aURL.Server , aURL.Port , aCompletePath); if ( !bResult ) return false; // First parse URL WITHOUT ... aURL.Main = aParser.GetMainURL( INetURLObject::DecodeMechanism::NONE ); // ...and then WITH parameter and mark. aParser.SetParam( aURL.Arguments); aParser.SetMark ( aURL.Mark, INetURLObject::EncodeMechanism::All ); aURL.Complete = aParser.GetMainURL( INetURLObject::DecodeMechanism::NONE ); // Return "URL is assembled". return true; } else if ( !aURL.Protocol.isEmpty() ) { // Minimal support for unknown protocols aURL.Complete = aURL.Protocol + aURL.Path; aURL.Main = aURL.Complete; return true; } return false; } // XURLTransformer OUString SAL_CALL URLTransformer::getPresentation( const css::util::URL& aURL, sal_Bool bWithPassword ) { // Safe impossible cases. if ( aURL.Complete.isEmpty() ) { return OUString(); } // Check given URL css::util::URL aTestURL = aURL; bool bParseResult = parseSmart( aTestURL, aTestURL.Protocol ); if ( bParseResult ) { if ( !bWithPassword && !aTestURL.Password.isEmpty() ) { // Exchange password text with other placeholder string aTestURL.Password = "<******>"; assemble( aTestURL ); } // Convert internal URLs to "praesentation"-URLs! OUString sPraesentationURL; INetURLObject::translateToExternal( aTestURL.Complete, sPraesentationURL, INetURLObject::DecodeMechanism::Unambiguous ); return sPraesentationURL; } else return OUString(); } } extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface * com_sun_star_comp_framework_URLTransformer_get_implementation( css::uno::XComponentContext *, css::uno::Sequence const &) { return cppu::acquire(new URLTransformer()); } /* vim:set shiftwidth=4 softtabstop=4 expandtab: */