diff options
Diffstat (limited to '')
-rw-r--r-- | ucb/source/ucp/package/pkguri.cxx | 234 |
1 files changed, 234 insertions, 0 deletions
diff --git a/ucb/source/ucp/package/pkguri.cxx b/ucb/source/ucp/package/pkguri.cxx new file mode 100644 index 000000000..b1de54aa4 --- /dev/null +++ b/ucb/source/ucp/package/pkguri.cxx @@ -0,0 +1,234 @@ +/* -*- 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 . + */ + + +/************************************************************************** + TODO + ************************************************************************** + + *************************************************************************/ + +#include <sal/config.h> + +#include <string_view> + +#include <comphelper/storagehelper.hxx> + +#include "../inc/urihelper.hxx" + +#include "pkguri.hxx" + +using namespace package_ucp; + + +// PackageUri Implementation. + + +static void normalize( OUString& rURL ) +{ + sal_Int32 nPos = 0; + do + { + nPos = rURL.indexOf( '%', nPos ); + if ( nPos != -1 ) + { + if ( nPos < ( rURL.getLength() - 2 ) ) + { + OUString aTmp = rURL.copy( nPos + 1, 2 ); + rURL = rURL.replaceAt( nPos + 1, 2, aTmp.toAsciiUpperCase() ); + nPos++; + } + } + } + while ( nPos != -1 ); +} + + +void PackageUri::init() const +{ + // Already inited? + if ( m_aUri.isEmpty() || !m_aPath.isEmpty() ) + return; + + // Note: Maybe it's a re-init, setUri only resets m_aPath! + m_aPackage.clear(); + m_aParentUri.clear(); + m_aName.clear(); + m_aParam.clear(); + m_aScheme.clear(); + + // URI must match at least: <scheme>://<non_empty_url_to_file> + if ( m_aUri.getLength() < PACKAGE_URL_SCHEME_LENGTH + 4 ) + { + // error, but remember that we did an init(). + m_aPath = "/"; + return; + } + + // Scheme must be followed by '://' + if ( ( m_aUri[ PACKAGE_URL_SCHEME_LENGTH ] != ':' ) + || + ( m_aUri[ PACKAGE_URL_SCHEME_LENGTH + 1 ] != '/' ) + || + ( m_aUri[ PACKAGE_URL_SCHEME_LENGTH + 2 ] != '/' ) ) + { + // error, but remember that we did an init(). + m_aPath = "/"; + return; + } + + OUString aPureUri; + sal_Int32 nParam = m_aUri.indexOf( '?' ); + if( nParam >= 0 ) + { + m_aParam = m_aUri.copy( nParam ); + aPureUri = m_aUri.copy( 0, nParam ); + } + else + aPureUri = m_aUri; + + // Scheme is case insensitive. + m_aScheme = aPureUri.copy( + 0, PACKAGE_URL_SCHEME_LENGTH ).toAsciiLowerCase(); + + if ( m_aScheme == PACKAGE_URL_SCHEME || m_aScheme == PACKAGE_ZIP_URL_SCHEME ) + { + if ( m_aScheme == PACKAGE_ZIP_URL_SCHEME ) + { + m_aParam += + ( !m_aParam.isEmpty() + ? std::u16string_view( u"&purezip" ) + : std::u16string_view( u"?purezip" ) ); + } + + aPureUri = aPureUri.replaceAt( 0, + m_aScheme.getLength(), + m_aScheme ); + + sal_Int32 nStart = PACKAGE_URL_SCHEME_LENGTH + 3; + sal_Int32 nEnd = aPureUri.lastIndexOf( '/' ); + if ( nEnd == PACKAGE_URL_SCHEME_LENGTH + 3 ) + { + // Only <scheme>:/// - Empty authority + + // error, but remember that we did an init(). + m_aPath = "/"; + return; + } + else if ( nEnd == ( aPureUri.getLength() - 1 ) ) + { + if ( aPureUri[ aPureUri.getLength() - 2 ] == '/' ) + { + // Only <scheme>://// or <scheme>://<something> + + // error, but remember that we did an init(). + m_aPath = "/"; + return; + } + + // Remove trailing slash. + aPureUri = aPureUri.copy( 0, nEnd ); + } + + + nEnd = aPureUri.indexOf( '/', nStart ); + if ( nEnd == -1 ) + { + // root folder. + + OUString aNormPackage = aPureUri.copy( nStart ); + normalize( aNormPackage ); + + aPureUri = aPureUri.replaceAt( + nStart, aPureUri.getLength() - nStart, aNormPackage ); + m_aPackage + = ::ucb_impl::urihelper::decodeSegment( aNormPackage ); + m_aPath = "/"; + m_aUri = m_aUri.replaceAt( 0, + ( nParam >= 0 ) + ? nParam + : m_aUri.getLength(), aPureUri ); + + sal_Int32 nLastSlash = m_aPackage.lastIndexOf( '/' ); + if ( nLastSlash != -1 ) + m_aName = ::ucb_impl::urihelper::decodeSegment( + m_aPackage.copy( nLastSlash + 1 ) ); + else + m_aName + = ::ucb_impl::urihelper::decodeSegment( m_aPackage ); + } + else + { + m_aPath = aPureUri.copy( nEnd + 1 ); + + // Unexpected sequences of characters: + // - empty path segments + // - encoded slashes + // - parent folder segments ".." + // - current folder segments "." + if ( m_aPath.indexOf( "//" ) != -1 + || m_aPath.indexOf( "%2F" ) != -1 + || m_aPath.indexOf( "%2f" ) != -1 + || ::comphelper::OStorageHelper::PathHasSegment( m_aPath, u".." ) + || ::comphelper::OStorageHelper::PathHasSegment( m_aPath, u"." ) ) + { + // error, but remember that we did an init(). + m_aPath = "/"; + return; + } + + OUString aNormPackage = aPureUri.copy( nStart, nEnd - nStart ); + normalize( aNormPackage ); + + aPureUri = aPureUri.replaceAt( + nStart, nEnd - nStart, aNormPackage ); + aPureUri = aPureUri.replaceAt( + nEnd + 1, + aPureUri.getLength() - nEnd - 1, + ::ucb_impl::urihelper::encodeURI( m_aPath ) ); + + m_aPackage + = ::ucb_impl::urihelper::decodeSegment( aNormPackage ); + m_aPath = ::ucb_impl::urihelper::decodeSegment( m_aPath ); + m_aUri = m_aUri.replaceAt( 0, + ( nParam >= 0 ) + ? nParam + : m_aUri.getLength(), aPureUri ); + + sal_Int32 nLastSlash = aPureUri.lastIndexOf( '/' ); + if ( nLastSlash != -1 ) + { + m_aParentUri = aPureUri.copy( 0, nLastSlash ); + m_aName = ::ucb_impl::urihelper::decodeSegment( + aPureUri.copy( nLastSlash + 1 ) ); + } + } + + // success + m_bValid = true; + } + else + { + // error, but remember that we did an init(). + m_aPath = "/"; + } + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |