From a4843be25b08243173fdbf241c80213d63fa7a10 Mon Sep 17 00:00:00 2001 From: Nyall Dawson Date: Tue, 20 Jun 2023 10:55:42 +1000 Subject: [PATCH] Move qgsVsiPrefix to QgsGdalUtils::vsiPrefixForPath --- .../auto_generated/browser/qgszipitem.sip.in | 7 +++- src/app/layers/qgsapplayerhandling.cpp | 7 ++-- .../browser/qgsfilebaseddataitemprovider.cpp | 4 +- src/core/browser/qgszipitem.cpp | 6 +++ src/core/browser/qgszipitem.h | 5 ++- src/core/providers/gdal/qgsgdalprovider.cpp | 6 +-- .../providers/gdal/qgsgdalproviderbase.cpp | 3 +- src/core/providers/ogr/qgsogrprovider.cpp | 2 +- .../providers/ogr/qgsogrprovidermetadata.cpp | 4 +- src/core/qgis.cpp | 23 +---------- src/core/qgsgdalutils.cpp | 41 +++++++++++++++++++ src/core/qgsgdalutils.h | 8 ++++ src/core/qgspathresolver.cpp | 5 ++- .../providers/gdal/qgsgdalsourceselect.cpp | 3 +- 14 files changed, 85 insertions(+), 39 deletions(-) diff --git a/python/core/auto_generated/browser/qgszipitem.sip.in b/python/core/auto_generated/browser/qgszipitem.sip.in index 26437691e93..8e0dba77600 100644 --- a/python/core/auto_generated/browser/qgszipitem.sip.in +++ b/python/core/auto_generated/browser/qgszipitem.sip.in @@ -47,7 +47,12 @@ Constructor static QStringList sProviderNames; - static QString vsiPrefix( const QString &uri ); + static QString vsiPrefix( const QString &uri ) /Deprecated/; +%Docstring + +.. deprecated:: + Will be removed in QGIS 4.0 +%End static QgsDataItem *itemFromPath( QgsDataItem *parent, const QString &path, const QString &name ) /Factory/; %Docstring diff --git a/src/app/layers/qgsapplayerhandling.cpp b/src/app/layers/qgsapplayerhandling.cpp index 67a24bd2917..162c3acee42 100644 --- a/src/app/layers/qgsapplayerhandling.cpp +++ b/src/app/layers/qgsapplayerhandling.cpp @@ -59,6 +59,7 @@ #include "qgsfieldformatter.h" #include "qgsabstractdatabaseproviderconnection.h" #include "qgsrasterlayerelevationproperties.h" +#include "qgsgdalutils.h" #include #include @@ -283,7 +284,7 @@ QList< QgsMapLayer * > QgsAppLayerHandling::addOgrVectorLayers( const QStringLis baseName = QgsProviderUtils::suggestLayerNameFromFilePath( srcWithoutLayername ); // if needed prompt for zipitem layers - QString vsiPrefix = qgsVsiPrefix( uri ); + const QString vsiPrefix = QgsGdalUtils::vsiPrefixForPath( uri ); if ( ! uri.startsWith( QLatin1String( "/vsi" ), Qt::CaseInsensitive ) && ( vsiPrefix == QLatin1String( "/vsizip/" ) || vsiPrefix == QLatin1String( "/vsitar/" ) ) ) { @@ -871,7 +872,7 @@ QList< QgsMapLayer * > QgsAppLayerHandling::openLayer( const QString &fileName, CPLPushErrorHandler( CPLQuietErrorHandler ); // if needed prompt for zipitem layers - QString vsiPrefix = qgsVsiPrefix( fileName ); + const QString vsiPrefix = QgsGdalUtils::vsiPrefixForPath( fileName ); if ( vsiPrefix == QLatin1String( "/vsizip/" ) || vsiPrefix == QLatin1String( "/vsitar/" ) ) { if ( askUserForZipItemLayers( fileName, {} ) ) @@ -1055,7 +1056,7 @@ QList QgsAppLayerHandling::addGdalRasterLayers( const QStringList QString errMsg; // if needed prompt for zipitem layers - QString vsiPrefix = qgsVsiPrefix( uri ); + const QString vsiPrefix = QgsGdalUtils::vsiPrefixForPath( uri ); if ( ( !uri.startsWith( QLatin1String( "/vsi" ), Qt::CaseInsensitive ) || uri.endsWith( QLatin1String( ".zip" ) ) || uri.endsWith( QLatin1String( ".tar" ) ) ) && ( vsiPrefix == QLatin1String( "/vsizip/" ) || vsiPrefix == QLatin1String( "/vsitar/" ) ) ) { diff --git a/src/core/browser/qgsfilebaseddataitemprovider.cpp b/src/core/browser/qgsfilebaseddataitemprovider.cpp index c3c3ba04495..fdac6ebb202 100644 --- a/src/core/browser/qgsfilebaseddataitemprovider.cpp +++ b/src/core/browser/qgsfilebaseddataitemprovider.cpp @@ -27,9 +27,7 @@ #include "qgsrelationshipsitem.h" #include "qgsproviderutils.h" #include "qgsprovidermetadata.h" -#if GDAL_VERSION_NUM < GDAL_COMPUTE_VERSION(3,4,0) #include "qgsgdalutils.h" -#endif #include // @@ -221,7 +219,7 @@ QgsFileDataCollectionItem::QgsFileDataCollectionItem( QgsDataItem *parent, const else setCapabilities( Qgis::BrowserItemCapability::Fast | Qgis::BrowserItemCapability::Fertile ); - if ( !qgsVsiPrefix( path ).isEmpty() ) + if ( !QgsGdalUtils::vsiPrefixForPath( path ).isEmpty() ) { mIconName = QStringLiteral( "/mIconZip.svg" ); } diff --git a/src/core/browser/qgszipitem.cpp b/src/core/browser/qgszipitem.cpp index 4ef716a2576..6ce8e9a10ef 100644 --- a/src/core/browser/qgszipitem.cpp +++ b/src/core/browser/qgszipitem.cpp @@ -20,6 +20,7 @@ #include "qgsdataitemprovider.h" #include "qgsdataitemproviderregistry.h" #include "qgssettings.h" +#include "qgsgdalutils.h" #include @@ -82,6 +83,11 @@ QgsMimeDataUtils::UriList QgsZipItem::mimeUris() const return { u }; } +QString QgsZipItem::vsiPrefix( const QString &uri ) +{ + return QgsGdalUtils::vsiPrefixForPath( uri ); +} + QVector QgsZipItem::createChildren() { QVector children; diff --git a/src/core/browser/qgszipitem.h b/src/core/browser/qgszipitem.h index eef251df33a..1f3fad63590 100644 --- a/src/core/browser/qgszipitem.h +++ b/src/core/browser/qgszipitem.h @@ -60,7 +60,10 @@ class CORE_EXPORT QgsZipItem : public QgsDataCollectionItem static QVector sDataItemPtr SIP_SKIP; static QStringList sProviderNames; - static QString vsiPrefix( const QString &uri ) { return qgsVsiPrefix( uri ); } + /** + * \deprecated Will be removed in QGIS 4.0 + */ + Q_DECL_DEPRECATED static QString vsiPrefix( const QString &uri ) SIP_DEPRECATED; /** * Creates a new data item from the specified path. diff --git a/src/core/providers/gdal/qgsgdalprovider.cpp b/src/core/providers/gdal/qgsgdalprovider.cpp index d349a764f5e..b99d18553bd 100644 --- a/src/core/providers/gdal/qgsgdalprovider.cpp +++ b/src/core/providers/gdal/qgsgdalprovider.cpp @@ -2874,7 +2874,7 @@ bool QgsGdalProvider::isValidRasterFileName( QString const &fileNameQString, QSt // Try to open using VSIFileHandler (see qgsogrprovider.cpp) // TODO suppress error messages and report in debug, like in OGR provider - QString vsiPrefix = qgsVsiPrefix( fileName ); + const QString vsiPrefix = QgsGdalUtils::vsiPrefixForPath( fileName ); if ( !vsiPrefix.isEmpty() ) { if ( !fileName.startsWith( vsiPrefix ) ) @@ -3216,7 +3216,7 @@ bool QgsGdalProvider::initIfNeeded() QString gdalUri = dataSourceUri( true ); // Try to open using VSIFileHandler (see qgsogrprovider.cpp) - QString vsiPrefix = qgsVsiPrefix( gdalUri ); + const QString vsiPrefix = QgsGdalUtils::vsiPrefixForPath( gdalUri ); if ( !vsiPrefix.isEmpty() ) { if ( !gdalUri.startsWith( vsiPrefix ) ) @@ -4228,7 +4228,7 @@ QList QgsGdalProviderMetadata::querySublayers( const QVariantMap uriParts = decodeUri( gdalUri ); // Try to open using VSIFileHandler - QString vsiPrefix = qgsVsiPrefix( gdalUri ); + const QString vsiPrefix = QgsGdalUtils::vsiPrefixForPath( gdalUri ); if ( !vsiPrefix.isEmpty() ) { if ( !gdalUri.startsWith( vsiPrefix ) ) diff --git a/src/core/providers/gdal/qgsgdalproviderbase.cpp b/src/core/providers/gdal/qgsgdalproviderbase.cpp index 8409718912c..d17e9709428 100644 --- a/src/core/providers/gdal/qgsgdalproviderbase.cpp +++ b/src/core/providers/gdal/qgsgdalproviderbase.cpp @@ -25,6 +25,7 @@ #include "qgsapplication.h" #include "qgslogger.h" #include "qgsgdalproviderbase.h" +#include "qgsgdalutils.h" #include "qgssettings.h" #include @@ -401,7 +402,7 @@ QVariantMap QgsGdalProviderBase::decodeGdalUri( const QString &uri ) authcfg = match.captured( 1 ); } - QString vsiPrefix = qgsVsiPrefix( path ); + QString vsiPrefix = QgsGdalUtils::vsiPrefixForPath( path ); QString vsiSuffix; if ( path.startsWith( vsiPrefix, Qt::CaseInsensitive ) ) { diff --git a/src/core/providers/ogr/qgsogrprovider.cpp b/src/core/providers/ogr/qgsogrprovider.cpp index 0b8687727d8..1b419c212d4 100644 --- a/src/core/providers/ogr/qgsogrprovider.cpp +++ b/src/core/providers/ogr/qgsogrprovider.cpp @@ -3592,7 +3592,7 @@ void QgsOgrProvider::open( OpenMode mode ) // Try to open using VSIFileHandler // see http://trac.osgeo.org/gdal/wiki/UserDocs/ReadInZip - QString vsiPrefix = qgsVsiPrefix( dataSourceUri( true ) ); + const QString vsiPrefix = QgsGdalUtils::vsiPrefixForPath( dataSourceUri( true ) ); if ( !vsiPrefix.isEmpty() || mFilePath.startsWith( QLatin1String( "/vsicurl/" ) ) ) { // GDAL>=1.8.0 has write support for zip, but read and write operations diff --git a/src/core/providers/ogr/qgsogrprovidermetadata.cpp b/src/core/providers/ogr/qgsogrprovidermetadata.cpp index 447826a2a65..f33c3249999 100644 --- a/src/core/providers/ogr/qgsogrprovidermetadata.cpp +++ b/src/core/providers/ogr/qgsogrprovidermetadata.cpp @@ -152,7 +152,7 @@ QVariantMap QgsOgrProviderMetadata::decodeUri( const QString &uri ) const authcfg = match.captured( 1 ); } - QString vsiPrefix = qgsVsiPrefix( path ); + QString vsiPrefix = QgsGdalUtils::vsiPrefixForPath( path ); QString vsiSuffix; if ( path.startsWith( vsiPrefix, Qt::CaseInsensitive ) ) { @@ -1185,7 +1185,7 @@ QList QgsOgrProviderMetadata::querySublayers( const QVariantMap uriParts = decodeUri( uri ); // Try to open using VSIFileHandler - QString vsiPrefix = qgsVsiPrefix( uriParts.value( QStringLiteral( "path" ) ).toString() ); + const QString vsiPrefix = QgsGdalUtils::vsiPrefixForPath( uriParts.value( QStringLiteral( "path" ) ).toString() ); if ( !vsiPrefix.isEmpty() && uriParts.value( QStringLiteral( "vsiPrefix" ) ).toString().isEmpty() ) { if ( !uri.startsWith( vsiPrefix ) ) diff --git a/src/core/qgis.cpp b/src/core/qgis.cpp index 5f50cc1afc8..86885c515c4 100644 --- a/src/core/qgis.cpp +++ b/src/core/qgis.cpp @@ -27,6 +27,7 @@ #include #include "qgsconfig.h" #include "qgslogger.h" +#include "qgsgdalutils.h" #include "qgswkbtypes.h" #include @@ -191,27 +192,7 @@ bool qgsVariantGreaterThan( const QVariant &lhs, const QVariant &rhs ) QString qgsVsiPrefix( const QString &path ) { - if ( path.startsWith( QLatin1String( "/vsizip/" ), Qt::CaseInsensitive ) ) - return QStringLiteral( "/vsizip/" ); - else if ( path.endsWith( QLatin1String( ".shp.zip" ), Qt::CaseInsensitive ) ) - { - // GDAL 3.1 Shapefile driver directly handles .shp.zip files - if ( GDALIdentifyDriverEx( path.toUtf8().constData(), GDAL_OF_VECTOR, nullptr, nullptr ) ) - return QString(); - return QStringLiteral( "/vsizip/" ); - } - else if ( path.endsWith( QLatin1String( ".zip" ), Qt::CaseInsensitive ) ) - return QStringLiteral( "/vsizip/" ); - else if ( path.startsWith( QLatin1String( "/vsitar/" ), Qt::CaseInsensitive ) || - path.endsWith( QLatin1String( ".tar" ), Qt::CaseInsensitive ) || - path.endsWith( QLatin1String( ".tar.gz" ), Qt::CaseInsensitive ) || - path.endsWith( QLatin1String( ".tgz" ), Qt::CaseInsensitive ) ) - return QStringLiteral( "/vsitar/" ); - else if ( path.startsWith( QLatin1String( "/vsigzip/" ), Qt::CaseInsensitive ) || - path.endsWith( QLatin1String( ".gz" ), Qt::CaseInsensitive ) ) - return QStringLiteral( "/vsigzip/" ); - else - return QString(); + return QgsGdalUtils::vsiPrefixForPath( path ); } uint qHash( const QVariant &variant ) diff --git a/src/core/qgsgdalutils.cpp b/src/core/qgsgdalutils.cpp index eed4a2aa758..cdbadfbeeed 100644 --- a/src/core/qgsgdalutils.cpp +++ b/src/core/qgsgdalutils.cpp @@ -708,6 +708,47 @@ QStringList QgsGdalUtils::multiLayerFileExtensions() #endif } +QString QgsGdalUtils::vsiPrefixForPath( const QString &path ) +{ + const QStringList vsiPrefixes = QgsGdalUtils::vsiArchivePrefixes(); + + for ( const QString &vsiPrefix : vsiPrefixes ) + { + if ( path.startsWith( vsiPrefix, Qt::CaseInsensitive ) ) + return vsiPrefix; + } + + if ( path.endsWith( QLatin1String( ".shp.zip" ), Qt::CaseInsensitive ) ) + { + // GDAL 3.1 Shapefile driver directly handles .shp.zip files + if ( GDALIdentifyDriverEx( path.toUtf8().constData(), GDAL_OF_VECTOR, nullptr, nullptr ) ) + return QString(); + return QStringLiteral( "/vsizip/" ); + } + else if ( path.endsWith( QLatin1String( ".zip" ), Qt::CaseInsensitive ) ) + return QStringLiteral( "/vsizip/" ); + else if ( path.endsWith( QLatin1String( ".tar" ), Qt::CaseInsensitive ) || + path.endsWith( QLatin1String( ".tar.gz" ), Qt::CaseInsensitive ) || + path.endsWith( QLatin1String( ".tgz" ), Qt::CaseInsensitive ) ) + return QStringLiteral( "/vsitar/" ); + else if ( path.endsWith( QLatin1String( ".gz" ), Qt::CaseInsensitive ) ) + return QStringLiteral( "/vsigzip/" ); +#if GDAL_VERSION_NUM >= GDAL_COMPUTE_VERSION(3,7,0) + else if ( vsiPrefixes.contains( QStringLiteral( "/vsi7z/" ) ) && + ( path.endsWith( QLatin1String( ".7z" ), Qt::CaseInsensitive ) || + path.endsWith( QLatin1String( ".lpk" ), Qt::CaseInsensitive ) || + path.endsWith( QLatin1String( ".lpkx" ), Qt::CaseInsensitive ) || + path.endsWith( QLatin1String( ".mpk" ), Qt::CaseInsensitive ) || + path.endsWith( QLatin1String( ".mpkx" ), Qt::CaseInsensitive ) ) ) + return QStringLiteral( "/vsi7z/" ); + else if ( vsiPrefixes.contains( QStringLiteral( "/vsirar/" ) ) && + path.endsWith( QLatin1String( ".rar" ), Qt::CaseInsensitive ) ) + return QStringLiteral( "/vsirar/" ); +#endif + + return QString(); +} + bool QgsGdalUtils::vrtMatchesLayerType( const QString &vrtPath, Qgis::LayerType type ) { CPLPushErrorHandler( CPLQuietErrorHandler ); diff --git a/src/core/qgsgdalutils.h b/src/core/qgsgdalutils.h index 4c04205a363..3dd92c5b656 100644 --- a/src/core/qgsgdalutils.h +++ b/src/core/qgsgdalutils.h @@ -220,6 +220,14 @@ class CORE_EXPORT QgsGdalUtils */ static QStringList multiLayerFileExtensions(); + /** + * Returns a the vsi prefix which corresponds to a file \a path, or an empty + * string if the path is not associated with a vsi prefix. + * + * \since QGIS 3.32 + */ + static QString vsiPrefixForPath( const QString &path ); + /** * Returns TRUE if the VRT file at the specified path is a VRT matching * the given layer \a type. diff --git a/src/core/qgspathresolver.cpp b/src/core/qgspathresolver.cpp index 7e84d2debbe..0d3cdeebe18 100644 --- a/src/core/qgspathresolver.cpp +++ b/src/core/qgspathresolver.cpp @@ -18,6 +18,7 @@ #include "qgis.h" #include "qgsapplication.h" +#include "qgsgdalutils.h" #include #include #include @@ -81,7 +82,7 @@ QString QgsPathResolver::readPath( const QString &f ) const } // if this is a VSIFILE, remove the VSI prefix and append to final result - QString vsiPrefix = qgsVsiPrefix( src ); + QString vsiPrefix = QgsGdalUtils::vsiPrefixForPath( src ); if ( ! vsiPrefix.isEmpty() ) { // unfortunately qgsVsiPrefix returns prefix also for files like "/x/y/z.gz" @@ -298,7 +299,7 @@ QString QgsPathResolver::writePath( const QString &s ) const srcPath = srcFileInfo.canonicalFilePath(); // if this is a VSIFILE, remove the VSI prefix and append to final result - const QString vsiPrefix = qgsVsiPrefix( src ); + const QString vsiPrefix = QgsGdalUtils::vsiPrefixForPath( src ); if ( ! vsiPrefix.isEmpty() ) { srcPath.remove( 0, vsiPrefix.size() ); diff --git a/src/gui/providers/gdal/qgsgdalsourceselect.cpp b/src/gui/providers/gdal/qgsgdalsourceselect.cpp index d484ee56754..0b675426866 100644 --- a/src/gui/providers/gdal/qgsgdalsourceselect.cpp +++ b/src/gui/providers/gdal/qgsgdalsourceselect.cpp @@ -22,6 +22,7 @@ #include "qgsproviderregistry.h" #include "ogr/qgsogrhelperfunctions.h" +#include "qgsgdalutils.h" #include #include @@ -329,7 +330,7 @@ void QgsGdalSourceSelect::fillOpenOptions() return; const QString firstDataSource = mDataSources.at( 0 ); - const QString vsiPrefix = qgsVsiPrefix( firstDataSource ); + const QString vsiPrefix = QgsGdalUtils::vsiPrefixForPath( firstDataSource ); const QString scheme = QUrl( firstDataSource ).scheme(); const bool isRemoteNonVsiCurlUrl = vsiPrefix.isEmpty() && ( scheme.startsWith( QLatin1String( "http" ) ) || scheme == QLatin1String( "ftp" ) ); if ( isRemoteNonVsiCurlUrl )