Skip to content

Commit c986c1a

Browse files
committedAug 7, 2021
Use GDAL API to determine multi-layer extensions on GDAL 3.4+
1 parent bdc5b84 commit c986c1a

File tree

5 files changed

+111
-27
lines changed

5 files changed

+111
-27
lines changed
 

‎src/core/providers/gdal/qgsgdalprovider.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3611,7 +3611,7 @@ QList<QgsProviderSublayerDetails> QgsGdalProviderMetadata::querySublayers( const
36113611
details.setProviderKey( QStringLiteral( "gdal" ) );
36123612
details.setUri( uri );
36133613
details.setName( QgsProviderUtils::suggestLayerNameFromFilePath( path ) );
3614-
if ( QgsGdalUtils::SUPPORTED_DB_LAYERS_EXTENSIONS.contains( suffix ) )
3614+
if ( QgsGdalUtils::multiLayerFileExtensions().contains( suffix ) )
36153615
{
36163616
// uri may contain sublayers, but query flags prevent us from examining them
36173617
details.setSkippedContainerScan( true );

‎src/core/providers/ogr/qgsogrprovidermetadata.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1146,7 +1146,7 @@ QList<QgsProviderSublayerDetails> QgsOgrProviderMetadata::querySublayers( const
11461146
details.setProviderKey( QStringLiteral( "ogr" ) );
11471147
details.setUri( uri );
11481148
details.setName( QgsProviderUtils::suggestLayerNameFromFilePath( path ) );
1149-
if ( QgsGdalUtils::SUPPORTED_DB_LAYERS_EXTENSIONS.contains( suffix ) )
1149+
if ( QgsGdalUtils::multiLayerFileExtensions().contains( suffix ) )
11501150
{
11511151
// uri may contain sublayers, but query flags prevent us from examining them
11521152
details.setSkippedContainerScan( true );

‎src/core/qgsgdalutils.cpp

Lines changed: 86 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -22,32 +22,13 @@
2222
#include "gdal.h"
2323
#include "gdalwarper.h"
2424
#include "cpl_string.h"
25+
#include "qgsapplication.h"
2526

2627
#include <QNetworkProxy>
2728
#include <QString>
2829
#include <QImage>
2930
#include <QFileInfo>
30-
31-
// File extensions for formats supported by GDAL which may contain multiple layers
32-
// and should be treated as a potential layer container
33-
const QStringList QgsGdalUtils::SUPPORTED_DB_LAYERS_EXTENSIONS
34-
{
35-
QStringLiteral( "gpkg" ),
36-
QStringLiteral( "sqlite" ),
37-
QStringLiteral( "db" ),
38-
QStringLiteral( "gdb" ),
39-
QStringLiteral( "kml" ),
40-
QStringLiteral( "kmz" ),
41-
QStringLiteral( "osm" ),
42-
QStringLiteral( "mdb" ),
43-
QStringLiteral( "accdb" ),
44-
QStringLiteral( "xls" ),
45-
QStringLiteral( "xlsx" ),
46-
QStringLiteral( "gpx" ),
47-
QStringLiteral( "pdf" ),
48-
QStringLiteral( "pbf" ),
49-
QStringLiteral( "nc" ),
50-
QStringLiteral( "shp.zip" ) };
31+
#include <mutex>
5132

5233
bool QgsGdalUtils::supportsRasterCreate( GDALDriverH driver )
5334
{
@@ -564,6 +545,90 @@ bool QgsGdalUtils::pathIsCheapToOpen( const QString &path, int smallFileSizeLimi
564545
return false;
565546
}
566547

548+
QStringList QgsGdalUtils::multiLayerFileExtensions()
549+
{
550+
#if GDAL_VERSION_NUM >= GDAL_COMPUTE_VERSION(3,4,0)
551+
// get supported extensions
552+
static std::once_flag initialized;
553+
static QStringList SUPPORTED_DB_LAYERS_EXTENSIONS;
554+
std::call_once( initialized, [ = ]
555+
{
556+
// iterate through all of the supported drivers, adding the corresponding file extensions for
557+
// types which advertise multilayer support
558+
GDALDriverH driver = nullptr;
559+
560+
QSet< QString > extensions;
561+
562+
for ( int i = 0; i < GDALGetDriverCount(); ++i )
563+
{
564+
driver = GDALGetDriver( i );
565+
if ( !driver )
566+
{
567+
QgsLogger::warning( "unable to get driver " + QString::number( i ) );
568+
continue;
569+
}
570+
571+
bool isMultiLayer = false;
572+
if ( QString( GDALGetMetadataItem( driver, GDAL_DCAP_RASTER, nullptr ) ) == QLatin1String( "YES" ) )
573+
{
574+
if ( GDALGetMetadataItem( driver, GDAL_DMD_SUBDATASETS, nullptr ) != nullptr )
575+
{
576+
isMultiLayer = true;
577+
}
578+
}
579+
if ( !isMultiLayer && QString( GDALGetMetadataItem( driver, GDAL_DCAP_VECTOR, nullptr ) ) == QLatin1String( "YES" ) )
580+
{
581+
if ( GDALGetMetadataItem( driver, GDAL_DCAP_MULTIPLE_VECTOR_LAYERS, nullptr ) != nullptr )
582+
{
583+
isMultiLayer = true;
584+
}
585+
}
586+
587+
if ( !isMultiLayer )
588+
continue;
589+
590+
const QString driverExtensions = GDALGetMetadataItem( driver, GDAL_DMD_EXTENSIONS, "" );
591+
if ( driverExtensions.isEmpty() )
592+
continue;
593+
594+
#if QT_VERSION < QT_VERSION_CHECK(5, 14, 0)
595+
const QStringList splitExtensions = driverExtensions.split( ' ', QString::SkipEmptyParts );
596+
#else
597+
const QStringList splitExtensions = driverExtensions.split( ' ', Qt::SkipEmptyParts );
598+
#endif
599+
600+
for ( const QString &ext : splitExtensions )
601+
extensions.insert( ext );
602+
}
603+
604+
SUPPORTED_DB_LAYERS_EXTENSIONS = qgis::setToList( extensions );
605+
} );
606+
return SUPPORTED_DB_LAYERS_EXTENSIONS;
607+
608+
#else
609+
static const QStringList SUPPORTED_DB_LAYERS_EXTENSIONS
610+
{
611+
QStringLiteral( "gpkg" ),
612+
QStringLiteral( "sqlite" ),
613+
QStringLiteral( "db" ),
614+
QStringLiteral( "gdb" ),
615+
QStringLiteral( "kml" ),
616+
QStringLiteral( "kmz" ),
617+
QStringLiteral( "osm" ),
618+
QStringLiteral( "mdb" ),
619+
QStringLiteral( "accdb" ),
620+
QStringLiteral( "xls" ),
621+
QStringLiteral( "xlsx" ),
622+
QStringLiteral( "ods" ),
623+
QStringLiteral( "gpx" ),
624+
QStringLiteral( "pdf" ),
625+
QStringLiteral( "pbf" ),
626+
QStringLiteral( "nc" ),
627+
QStringLiteral( "shp.zip" ) };
628+
return SUPPORTED_DB_LAYERS_EXTENSIONS;
629+
#endif
630+
}
631+
567632
bool QgsGdalUtils::vrtMatchesLayerType( const QString &vrtPath, QgsMapLayerType type )
568633
{
569634
CPLPushErrorHandler( CPLQuietErrorHandler );

‎src/core/qgsgdalutils.h

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -148,13 +148,13 @@ class CORE_EXPORT QgsGdalUtils
148148
*/
149149
static bool pathIsCheapToOpen( const QString &path, int smallFileSizeLimit = 50000 );
150150

151-
152151
/**
153-
* File extensions for formats supported by GDAL which may contain multiple layers
154-
* and should be treated as a potential layer container.
152+
* Returns a list of file extensions which potentially contain multiple layers representing
153+
* GDAL raster or vector layers.
154+
*
155155
* \since QGIS 3.22
156156
*/
157-
static const QStringList SUPPORTED_DB_LAYERS_EXTENSIONS;
157+
static QStringList multiLayerFileExtensions();
158158

159159
/**
160160
* Returns TRUE if the VRT file at the specified path is a VRT matching

‎tests/src/core/testqgsgdalutils.cpp

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ class TestQgsGdalUtils: public QObject
4343
void testResampleImageToImage();
4444
void testPathIsCheapToOpen();
4545
void testVrtMatchesLayerType();
46+
void testMultilayerExtensions();
4647

4748
private:
4849

@@ -294,6 +295,24 @@ void TestQgsGdalUtils::testVrtMatchesLayerType()
294295
QVERIFY( QgsGdalUtils::vrtMatchesLayerType( QStringLiteral( TEST_DATA_DIR ) + "/vector_vrt.vrt", QgsMapLayerType::VectorLayer ) );
295296
}
296297

298+
void TestQgsGdalUtils::testMultilayerExtensions()
299+
{
300+
const QStringList extensions = QgsGdalUtils::multiLayerFileExtensions();
301+
QVERIFY( extensions.contains( QStringLiteral( "gpkg" ) ) );
302+
QVERIFY( extensions.contains( QStringLiteral( "sqlite" ) ) );
303+
QVERIFY( extensions.contains( QStringLiteral( "db" ) ) );
304+
QVERIFY( extensions.contains( QStringLiteral( "kml" ) ) );
305+
QVERIFY( extensions.contains( QStringLiteral( "ods" ) ) );
306+
QVERIFY( extensions.contains( QStringLiteral( "osm" ) ) );
307+
QVERIFY( extensions.contains( QStringLiteral( "mdb" ) ) );
308+
QVERIFY( extensions.contains( QStringLiteral( "xls" ) ) );
309+
QVERIFY( extensions.contains( QStringLiteral( "xlsx" ) ) );
310+
QVERIFY( extensions.contains( QStringLiteral( "gpx" ) ) );
311+
QVERIFY( extensions.contains( QStringLiteral( "pdf" ) ) );
312+
QVERIFY( extensions.contains( QStringLiteral( "nc" ) ) );
313+
QVERIFY( extensions.contains( QStringLiteral( "gdb" ) ) );
314+
}
315+
297316
double TestQgsGdalUtils::identify( GDALDatasetH dataset, int band, int px, int py )
298317
{
299318
GDALRasterBandH hBand = GDALGetRasterBand( dataset, band );

0 commit comments

Comments
 (0)
Please sign in to comment.