24#define CPL_SUPRESS_CPLUSPLUS   
   26#include "gdalwarper.h" 
   27#include "cpl_string.h" 
   29#include <QNetworkProxy> 
   38  if ( node->eType != CXT_Element || !EQUAL( node->pszValue, 
"Option" ) )
 
   41  const QString optionName( CPLGetXMLValue( node, 
"name", 
nullptr ) );
 
   42  if ( optionName.isEmpty() )
 
   46  option.
name = optionName;
 
   48  option.
description = QString( CPLGetXMLValue( node, 
"description", 
nullptr ) );
 
   49  option.
scope = QString( CPLGetXMLValue( node, 
"scope", 
nullptr ) );
 
   53  const char *pszType = CPLGetXMLValue( node, 
"type", 
nullptr );
 
   54  const char *pszDefault = CPLGetXMLValue( node, 
"default", 
nullptr );
 
   55  if ( pszType && EQUAL( pszType, 
"string-select" ) )
 
   58    for ( 
auto psOption = node->psChild; psOption != 
nullptr; psOption = psOption->psNext )
 
   60      if ( psOption->eType != CXT_Element ||
 
   61           !EQUAL( psOption->pszValue, 
"Value" ) ||
 
   66      option.
options << psOption->psChild->pszValue;
 
   71  else if ( pszType && EQUAL( pszType, 
"boolean" ) )
 
   74    option.
defaultValue = pszDefault ? QString( pszDefault ) : QStringLiteral( 
"YES" );
 
   77  else if ( pszType && EQUAL( pszType, 
"string" ) )
 
   84  else if ( pszType && ( EQUAL( pszType, 
"int" ) || EQUAL( pszType, 
"integer" ) ) )
 
   90      const int defaultInt = QString( pszDefault ).toInt( &ok );
 
   95    if ( 
const char *pszMin = CPLGetXMLValue( node, 
"min", 
nullptr ) )
 
   98      const int minInt = QString( pszMin ).toInt( &ok );
 
  102    if ( 
const char *pszMax = CPLGetXMLValue( node, 
"max", 
nullptr ) )
 
  105      const int maxInt = QString( pszMax ).toInt( &ok );
 
  111  else if ( pszType && ( EQUAL( pszType, 
"double" ) || EQUAL( pszType, 
"float" ) ) )
 
  117      const double defaultDouble = QString( pszDefault ).toDouble( &ok );
 
  122    if ( 
const char *pszMin = CPLGetXMLValue( node, 
"min", 
nullptr ) )
 
  125      const double minDouble = QString( pszMin ).toDouble( &ok );
 
  129    if ( 
const char *pszMax = CPLGetXMLValue( node, 
"max", 
nullptr ) )
 
  132      const double maxDouble = QString( pszMax ).toDouble( &ok );
 
  139  QgsDebugError( QStringLiteral( 
"Unhandled GDAL option type: %1" ).arg( pszType ) );
 
 
  145  QList< QgsGdalOption > 
options;
 
  146  for ( 
auto psItem = node->psChild; psItem != 
nullptr; psItem = psItem->psNext )
 
 
  164  const QString driverShortName = GDALGetDriverShortName( driver );
 
  165  if ( driverShortName == QLatin1String( 
"SQLite" ) ||
 
  166       driverShortName == QLatin1String( 
"PDF" ) )
 
  171  return GDALGetMetadataItem( driver, GDAL_DCAP_CREATE, 
nullptr ) &&
 
  172         GDALGetMetadataItem( driver, GDAL_DCAP_RASTER, 
nullptr );
 
 
  182  GDALDriverH hDriverMem = GDALGetDriverByName( 
"MEM" );
 
  190  const double cellSizeX = extent.
width() / width;
 
  191  const double cellSizeY = extent.
height() / height;
 
  192  double geoTransform[6];
 
  193  geoTransform[0] = extent.
xMinimum();
 
  194  geoTransform[1] = cellSizeX;
 
  196  geoTransform[3] = extent.
yMinimum() + ( cellSizeY * height );
 
  198  geoTransform[5] = -cellSizeY;
 
  201  GDALSetGeoTransform( hSrcDS.get(), geoTransform );
 
 
  207  const double cellSizeX = extent.
width() / width;
 
  208  const double cellSizeY = extent.
height() / height;
 
  209  double geoTransform[6];
 
  210  geoTransform[0] = extent.
xMinimum();
 
  211  geoTransform[1] = cellSizeX;
 
  213  geoTransform[3] = extent.
yMinimum() + ( cellSizeY * height );
 
  215  geoTransform[5] = -cellSizeY;
 
  217  GDALDriverH hDriver = GDALGetDriverByName( 
"GTiff" );
 
  224  gdal::dataset_unique_ptr hDstDS( GDALCreate( hDriver, filename.toUtf8().constData(), width, height, 1, dataType, 
nullptr ) );
 
  232  GDALSetGeoTransform( hDstDS.get(), geoTransform );
 
 
  238  if ( image.isNull() )
 
  241  const QRgb *rgb = 
reinterpret_cast<const QRgb *
>( image.constBits() );
 
  242  GDALDriverH hDriverMem = GDALGetDriverByName( 
"MEM" );
 
  247  gdal::dataset_unique_ptr hSrcDS( GDALCreate( hDriverMem, 
"",  image.width(), image.height(), 0, GDT_Byte, 
nullptr ) );
 
  250                        << QStringLiteral( 
"PIXELOFFSET=%1" ).arg( 
sizeof( QRgb ) )
 
  251                        << QStringLiteral( 
"LINEOFFSET=%1" ).arg( image.bytesPerLine() )
 
  252                        << QStringLiteral( 
"DATAPOINTER=%1" ).arg( 
reinterpret_cast< qulonglong 
>( rgb ) + 2 ) );
 
  253  GDALAddBand( hSrcDS.get(), GDT_Byte, papszOptions );
 
  254  CSLDestroy( papszOptions );
 
  257                 << QStringLiteral( 
"PIXELOFFSET=%1" ).arg( 
sizeof( QRgb ) )
 
  258                 << QStringLiteral( 
"LINEOFFSET=%1" ).arg( image.bytesPerLine() )
 
  259                 << QStringLiteral( 
"DATAPOINTER=%1" ).arg( 
reinterpret_cast< qulonglong 
>( rgb ) + 1 ) );
 
  260  GDALAddBand( hSrcDS.get(), GDT_Byte, papszOptions );
 
  261  CSLDestroy( papszOptions );
 
  264                 << QStringLiteral( 
"PIXELOFFSET=%1" ).arg( 
sizeof( QRgb ) )
 
  265                 << QStringLiteral( 
"LINEOFFSET=%1" ).arg( image.bytesPerLine() )
 
  266                 << QStringLiteral( 
"DATAPOINTER=%1" ).arg( 
reinterpret_cast< qulonglong 
>( rgb ) ) );
 
  267  GDALAddBand( hSrcDS.get(), GDT_Byte, papszOptions );
 
  268  CSLDestroy( papszOptions );
 
  271                 << QStringLiteral( 
"PIXELOFFSET=%1" ).arg( 
sizeof( QRgb ) )
 
  272                 << QStringLiteral( 
"LINEOFFSET=%1" ).arg( image.bytesPerLine() )
 
  273                 << QStringLiteral( 
"DATAPOINTER=%1" ).arg( 
reinterpret_cast< qulonglong 
>( rgb ) + 3 ) );
 
  274  GDALAddBand( hSrcDS.get(), GDT_Byte, papszOptions );
 
  275  CSLDestroy( papszOptions );
 
 
  285  GDALDriverH hDriverMem = GDALGetDriverByName( 
"MEM" );
 
  289  const double cellSizeX = extent.
width() / pixelWidth;
 
  290  const double cellSizeY = extent.
height() / pixelHeight;
 
  291  double geoTransform[6];
 
  292  geoTransform[0] = extent.
xMinimum();
 
  293  geoTransform[1] = cellSizeX;
 
  295  geoTransform[3] = extent.
yMinimum() + ( cellSizeY * pixelHeight );
 
  297  geoTransform[5] = -cellSizeY;
 
  301  int dataTypeSize = GDALGetDataTypeSizeBytes( dataType );
 
  303                        << QStringLiteral( 
"PIXELOFFSET=%1" ).arg( dataTypeSize )
 
  304                        << QStringLiteral( 
"LINEOFFSET=%1" ).arg( pixelWidth * dataTypeSize )
 
  305                        << QStringLiteral( 
"DATAPOINTER=%1" ).arg( 
reinterpret_cast< qulonglong 
>( block ) ) );
 
  306  GDALAddBand( hDstDS.get(), dataType, papszOptions );
 
  307  CSLDestroy( papszOptions );
 
  309  GDALSetGeoTransform( hDstDS.get(), geoTransform );
 
 
  322    GDALRasterBandH band = GDALGetRasterBand( ret.get(), 1 );
 
  324      GDALSetRasterNoDataValue( band, block->
noDataValue() );
 
 
  341  GDALDriverH hDriverMem = GDALGetDriverByName( 
"MEM" );
 
  345  const double cellSizeX = gridXSize / block->
width();
 
  346  const double cellSizeY = gridYSize / block->
height();
 
  347  double geoTransform[6];
 
  348  geoTransform[0] = origin.
x();
 
  349  geoTransform[1] = cellSizeX * std::cos( rotation );
 
  350  geoTransform[2] = cellSizeY * std::sin( rotation );
 
  351  geoTransform[3] = origin.
y();
 
  352  geoTransform[4] = cellSizeX * std::sin( rotation );
 
  353  geoTransform[5] = -cellSizeY * std::cos( rotation );
 
  358  int dataTypeSize = GDALGetDataTypeSizeBytes( dataType );
 
  360                        << QStringLiteral( 
"PIXELOFFSET=%1" ).arg( dataTypeSize )
 
  361                        << QStringLiteral( 
"LINEOFFSET=%1" ).arg( block->
width() * dataTypeSize )
 
  362                        << QStringLiteral( 
"DATAPOINTER=%1" ).arg( 
reinterpret_cast< qulonglong 
>( block->
bits() ) ) );
 
  363  GDALAddBand( hDstDS.get(), dataType, papszOptions );
 
  364  CSLDestroy( papszOptions );
 
  366  GDALSetGeoTransform( hDstDS.get(), geoTransform );
 
  368  GDALRasterBandH band = GDALGetRasterBand( hDstDS.get(), 1 );
 
  370    GDALSetRasterNoDataValue( band, block->
noDataValue() );
 
 
  375static bool resampleSingleBandRasterStatic( 
GDALDatasetH hSrcDS, 
GDALDatasetH hDstDS, GDALResampleAlg resampleAlg, 
char **papszOptions )
 
  378  psWarpOptions->hSrcDS = hSrcDS;
 
  379  psWarpOptions->hDstDS = hDstDS;
 
  381  psWarpOptions->nBandCount = 1;
 
  382  psWarpOptions->panSrcBands = 
reinterpret_cast< int * 
>( CPLMalloc( 
sizeof( 
int ) * 1 ) );
 
  383  psWarpOptions->panDstBands = 
reinterpret_cast< int * 
>( CPLMalloc( 
sizeof( 
int ) * 1 ) );
 
  384  psWarpOptions->panSrcBands[0] = 1;
 
  385  psWarpOptions->panDstBands[0] = 1;
 
  386  double noDataValue = GDALGetRasterNoDataValue( GDALGetRasterBand( hDstDS, 1 ), 
nullptr );
 
  387  psWarpOptions->padfDstNoDataReal = 
reinterpret_cast< double * 
>( CPLMalloc( 
sizeof( 
double ) * 1 ) );
 
  388  psWarpOptions->padfDstNoDataReal[0] = noDataValue;
 
  389  psWarpOptions->eResampleAlg = resampleAlg;
 
  392  psWarpOptions->pTransformerArg = GDALCreateGenImgProjTransformer2( hSrcDS, hDstDS, papszOptions );
 
  394  if ( ! psWarpOptions->pTransformerArg )
 
  399  psWarpOptions->pfnTransformer = GDALGenImgProjTransform;
 
  400  psWarpOptions->papszWarpOptions = CSLSetNameValue( psWarpOptions-> papszWarpOptions, 
"INIT_DEST", 
"NO_DATA" );
 
  404  GDALWarpOperation oOperation;
 
  405  CPLErr initResult = oOperation.Initialize( psWarpOptions.get() );
 
  406  if ( initResult != CE_Failure )
 
  407    retVal =  oOperation.ChunkAndWarpImage( 0, 0, GDALGetRasterXSize( hDstDS ), GDALGetRasterYSize( hDstDS ) ) == CE_None;
 
  408  GDALDestroyGenImgProjTransformer( psWarpOptions->pTransformerArg );
 
  414  char **papszOptions = 
nullptr;
 
  415  if ( pszCoordinateOperation )
 
  416    papszOptions = CSLSetNameValue( papszOptions, 
"COORDINATE_OPERATION", pszCoordinateOperation );
 
  418  bool result = resampleSingleBandRasterStatic( hSrcDS, hDstDS, resampleAlg, papszOptions );
 
  419  CSLDestroy( papszOptions );
 
 
  425    GDALResampleAlg resampleAlg,
 
  429  char **papszOptions = 
nullptr;
 
  434  bool result = resampleSingleBandRasterStatic( hSrcDS, hDstDS, resampleAlg, papszOptions );
 
  435  CSLDestroy( papszOptions );
 
 
  445  GDALRasterIOExtraArg extra;
 
  446  INIT_RASTERIO_EXTRA_ARG( extra );
 
  447  extra.eResampleAlg = resampleAlg;
 
  449  QImage res( outputSize, image.format() );
 
  453  GByte *rgb = 
reinterpret_cast<GByte *
>( res.bits() );
 
  455  CPLErr err = GDALRasterIOEx( GDALGetRasterBand( srcDS.get(), 1 ), GF_Read, 0, 0, image.width(), image.height(), rgb + 2, outputSize.width(),
 
  456                               outputSize.height(), GDT_Byte, 
sizeof( QRgb ), res.bytesPerLine(), &extra );
 
  457  if ( err != CE_None )
 
  459    QgsDebugError( QStringLiteral( 
"failed to read red band" ) );
 
  463  err = GDALRasterIOEx( GDALGetRasterBand( srcDS.get(), 2 ), GF_Read, 0, 0, image.width(), image.height(), rgb + 1, outputSize.width(),
 
  464                        outputSize.height(), GDT_Byte, 
sizeof( QRgb ), res.bytesPerLine(), &extra );
 
  465  if ( err != CE_None )
 
  467    QgsDebugError( QStringLiteral( 
"failed to read green band" ) );
 
  471  err = GDALRasterIOEx( GDALGetRasterBand( srcDS.get(), 3 ), GF_Read, 0, 0, image.width(), image.height(), rgb, outputSize.width(),
 
  472                        outputSize.height(), GDT_Byte, 
sizeof( QRgb ), res.bytesPerLine(), &extra );
 
  473  if ( err != CE_None )
 
  475    QgsDebugError( QStringLiteral( 
"failed to read blue band" ) );
 
  479  err = GDALRasterIOEx( GDALGetRasterBand( srcDS.get(), 4 ), GF_Read, 0, 0, image.width(), image.height(), rgb + 3, outputSize.width(),
 
  480                        outputSize.height(), GDT_Byte, 
sizeof( QRgb ), res.bytesPerLine(), &extra );
 
  481  if ( err != CE_None )
 
  483    QgsDebugError( QStringLiteral( 
"failed to read alpha band" ) );
 
 
  493  GDALDriverH myGdalDriver = GDALGetDriverByName( format.toLocal8Bit().constData() );
 
  497    char **GDALmetadata = GDALGetMetadata( myGdalDriver, 
nullptr );
 
  498    message += QLatin1String( 
"Format Details:\n" );
 
  499    message += QStringLiteral( 
"  Extension: %1\n" ).arg( CSLFetchNameValue( GDALmetadata, GDAL_DMD_EXTENSION ) );
 
  500    message += QStringLiteral( 
"  Short Name: %1" ).arg( GDALGetDriverShortName( myGdalDriver ) );
 
  501    message += QStringLiteral( 
"  /  Long Name: %1\n" ).arg( GDALGetDriverLongName( myGdalDriver ) );
 
  503    if ( !helpUrl.isEmpty() )
 
  504      message += QStringLiteral( 
"  Help page:  %1\n\n" ).arg( helpUrl );
 
  508    CPLXMLNode *psCOL = CPLParseXMLString( GDALGetMetadataItem( myGdalDriver,
 
  509                                           GDAL_DMD_CREATIONOPTIONLIST, 
"" ) );
 
  510    char *pszFormattedXML = CPLSerializeXMLTree( psCOL );
 
  511    if ( pszFormattedXML )
 
  512      message += QString( pszFormattedXML );
 
  514      CPLDestroyXMLNode( psCOL );
 
  515    if ( pszFormattedXML )
 
  516      CPLFree( pszFormattedXML );
 
 
  523  char **papszRetList = 
nullptr;
 
  524  const auto constList = list;
 
  525  for ( 
const QString &elem : constList )
 
  527    papszRetList = CSLAddString( papszRetList, elem.toLocal8Bit().constData() );
 
 
  534  GDALDriverH myGdalDriver = GDALGetDriverByName( format.toLocal8Bit().constData() );
 
  535  if ( ! myGdalDriver )
 
  536    return QStringLiteral( 
"invalid GDAL driver" );
 
  540  const int ok = GDALValidateCreationOptions( myGdalDriver, papszOptions );
 
  541  CSLDestroy( papszOptions );
 
  544    return QStringLiteral( 
"Failed GDALValidateCreationOptions() test" );
 
 
  548static void setRPCTransformerOptions( 
GDALDatasetH hSrcDS, 
char  ***opts )
 
  550  if ( GDALGetMetadata( hSrcDS, 
"RPC" ) )
 
  554    const char *heightStr = GDALGetMetadataItem( hSrcDS, 
"HEIGHT_DEFAULT", 
"RPC" );
 
  559      heightStr = GDALGetMetadataItem( hSrcDS, 
"HEIGHT_OFF", 
"RPC" );
 
  562      *opts = CSLAddNameValue( *opts, 
"RPC_HEIGHT", heightStr );
 
  568  const char *pszSrcWKT,
 
  569  const char *pszDstWKT,
 
  570  GDALResampleAlg eResampleAlg,
 
  572  const GDALWarpOptions *psOptionsIn )
 
  574  char **opts = 
nullptr;
 
  575  setRPCTransformerOptions( hSrcDS, &opts );
 
  576  GDALDatasetH hRetDS = GDALAutoCreateWarpedVRTEx( hSrcDS, pszSrcWKT, pszDstWKT, eResampleAlg, dfMaxError, psOptionsIn, opts );
 
 
  583  char **opts = CSLDuplicate( papszOptions );
 
  584  setRPCTransformerOptions( hSrcDS, &opts );
 
  585  void *transformer = GDALCreateGenImgProjTransformer2( hSrcDS, hDstDS, opts );
 
 
  595      return GDALDataType::GDT_Unknown;
 
  598      return GDALDataType::GDT_Byte;
 
  601#if GDAL_VERSION_NUM >= GDAL_COMPUTE_VERSION(3,7,0) 
  602      return GDALDataType::GDT_Int8;
 
  604      return GDALDataType::GDT_Unknown;
 
  608      return GDALDataType::GDT_UInt16;
 
  611      return GDALDataType::GDT_Int16;
 
  614      return GDALDataType::GDT_UInt32;
 
  617      return GDALDataType::GDT_Int32;
 
  620      return GDALDataType::GDT_Float32;
 
  623      return GDALDataType::GDT_Float64;
 
  626      return GDALDataType::GDT_CInt16;
 
  629      return GDALDataType::GDT_CInt32;
 
  632      return GDALDataType::GDT_CFloat32;
 
  635      return GDALDataType::GDT_CFloat64;
 
  639      return GDALDataType::GDT_Unknown;
 
  643  return GDALDataType::GDT_Unknown;
 
 
  648  GDALResampleAlg eResampleAlg = GRA_NearestNeighbour;
 
  653      eResampleAlg = GRA_NearestNeighbour;
 
  657      eResampleAlg = GRA_Bilinear;
 
  661      eResampleAlg = GRA_Cubic;
 
  665      eResampleAlg = GRA_CubicSpline;
 
  669      eResampleAlg = GRA_Lanczos;
 
  673      eResampleAlg = GRA_Average;
 
  677      eResampleAlg = GRA_Mode;
 
 
  684#ifndef QT_NO_NETWORKPROXY 
  694  if ( settings.
value( QStringLiteral( 
"proxy/proxyEnabled" ), 
false ).toBool() )
 
  698    if ( ! proxies.isEmpty() )
 
  700      const QNetworkProxy proxy( proxies.first() );
 
  705      const QString proxyHost( proxy.hostName() );
 
  706      const quint16 proxyPort( proxy.port() );
 
  708      const QString proxyUser( proxy.user() );
 
  709      const QString proxyPassword( proxy.password() );
 
  711      if ( ! proxyHost.isEmpty() )
 
  713        QString connection( proxyHost );
 
  716          connection += 
':' +  QString::number( proxyPort );
 
  718        CPLSetConfigOption( 
"GDAL_HTTP_PROXY", connection.toUtf8() );
 
  719        if ( !  proxyUser.isEmpty( ) )
 
  721          QString credentials( proxyUser );
 
  722          if ( !  proxyPassword.isEmpty( ) )
 
  724            credentials += 
':' + proxyPassword;
 
  726          CPLSetConfigOption( 
"GDAL_HTTP_PROXYUSERPWD", credentials.toUtf8() );
 
 
  735  const QFileInfo info( path );
 
  736  const long long size = info.size();
 
  742  const QString suffix = info.suffix().toLower();
 
  743  static const QStringList sFileSizeDependentExtensions
 
  745    QStringLiteral( 
"xlsx" ),
 
  746    QStringLiteral( 
"ods" ),
 
  747    QStringLiteral( 
"csv" )
 
  749  if ( sFileSizeDependentExtensions.contains( suffix ) )
 
  752    return size < smallFileSizeLimit;
 
 
  762#if GDAL_VERSION_NUM >= GDAL_COMPUTE_VERSION(3,4,0) 
  764  static std::once_flag initialized;
 
  765  static QStringList SUPPORTED_DB_LAYERS_EXTENSIONS;
 
  766  std::call_once( initialized, [ = ]
 
  770    GDALDriverH driver = 
nullptr;
 
  772    QSet< QString > extensions;
 
  774    for ( 
int i = 0; i < GDALGetDriverCount(); ++i )
 
  776      driver = GDALGetDriver( i );
 
  783      bool isMultiLayer = 
false;
 
  784      if ( QString( GDALGetMetadataItem( driver, GDAL_DCAP_RASTER, 
nullptr ) ) == QLatin1String( 
"YES" ) )
 
  786        if ( GDALGetMetadataItem( driver, GDAL_DMD_SUBDATASETS, 
nullptr ) )
 
  791      if ( !isMultiLayer && QString( GDALGetMetadataItem( driver, GDAL_DCAP_VECTOR, 
nullptr ) ) == QLatin1String( 
"YES" ) )
 
  793        if ( GDALGetMetadataItem( driver, GDAL_DCAP_MULTIPLE_VECTOR_LAYERS, 
nullptr ) )
 
  802      const QString driverExtensions = GDALGetMetadataItem( driver, GDAL_DMD_EXTENSIONS, 
"" );
 
  803      if ( driverExtensions.isEmpty() )
 
  806      const QStringList splitExtensions = driverExtensions.split( 
' ', Qt::SkipEmptyParts );
 
  808      for ( 
const QString &ext : splitExtensions )
 
  811        if ( ext == QLatin1String( 
"tif" ) || ext == QLatin1String( 
"tiff" ) )
 
  814        extensions.insert( ext );
 
  818    SUPPORTED_DB_LAYERS_EXTENSIONS = QStringList( extensions.constBegin(), extensions.constEnd() );
 
  820  return SUPPORTED_DB_LAYERS_EXTENSIONS;
 
  823  static const QStringList SUPPORTED_DB_LAYERS_EXTENSIONS
 
  825    QStringLiteral( 
"gpkg" ),
 
  826    QStringLiteral( 
"sqlite" ),
 
  827    QStringLiteral( 
"db" ),
 
  828    QStringLiteral( 
"gdb" ),
 
  829    QStringLiteral( 
"kml" ),
 
  830    QStringLiteral( 
"kmz" ),
 
  831    QStringLiteral( 
"osm" ),
 
  832    QStringLiteral( 
"mdb" ),
 
  833    QStringLiteral( 
"accdb" ),
 
  834    QStringLiteral( 
"xls" ),
 
  835    QStringLiteral( 
"xlsx" ),
 
  836    QStringLiteral( 
"ods" ),
 
  837    QStringLiteral( 
"gpx" ),
 
  838    QStringLiteral( 
"pdf" ),
 
  839    QStringLiteral( 
"pbf" ),
 
  840    QStringLiteral( 
"vrt" ),
 
  841    QStringLiteral( 
"nc" ),
 
  842    QStringLiteral( 
"dxf" ),
 
  843    QStringLiteral( 
"shp.zip" ) };
 
  844  return SUPPORTED_DB_LAYERS_EXTENSIONS;
 
 
  852  const thread_local QRegularExpression vsiRx( QStringLiteral( 
"^(/vsi.+?/)" ), QRegularExpression::PatternOption::CaseInsensitiveOption );
 
  853  const QRegularExpressionMatch vsiMatch = vsiRx.match( path );
 
  854  if ( vsiMatch.hasMatch() )
 
  855    return vsiMatch.captured( 1 );
 
  857  if ( path.endsWith( QLatin1String( 
".shp.zip" ), Qt::CaseInsensitive ) )
 
  860    if ( GDALIdentifyDriverEx( path.toUtf8().constData(), GDAL_OF_VECTOR, 
nullptr, 
nullptr ) )
 
  862    return QStringLiteral( 
"/vsizip/" );
 
  864  else if ( path.endsWith( QLatin1String( 
".zip" ), Qt::CaseInsensitive ) )
 
  867    const char *
const apszAllowedDrivers[] = { 
"GTFS", 
nullptr };
 
  868    if ( GDALIdentifyDriverEx( path.toUtf8().constData(), GDAL_OF_VECTOR, apszAllowedDrivers, 
nullptr ) )
 
  870    return QStringLiteral( 
"/vsizip/" );
 
  872  else if ( path.endsWith( QLatin1String( 
".tar" ), Qt::CaseInsensitive ) ||
 
  873            path.endsWith( QLatin1String( 
".tar.gz" ), Qt::CaseInsensitive ) ||
 
  874            path.endsWith( QLatin1String( 
".tgz" ), Qt::CaseInsensitive ) )
 
  875    return QStringLiteral( 
"/vsitar/" );
 
  876  else if ( path.endsWith( QLatin1String( 
".gz" ), Qt::CaseInsensitive ) )
 
  877    return QStringLiteral( 
"/vsigzip/" );
 
  878#if GDAL_VERSION_NUM >= GDAL_COMPUTE_VERSION(3,7,0) 
  879  else if ( vsiPrefixes.contains( QStringLiteral( 
"/vsi7z/" ) ) &&
 
  880            ( path.endsWith( QLatin1String( 
".7z" ), Qt::CaseInsensitive ) ||
 
  881              path.endsWith( QLatin1String( 
".lpk" ), Qt::CaseInsensitive ) ||
 
  882              path.endsWith( QLatin1String( 
".lpkx" ), Qt::CaseInsensitive ) ||
 
  883              path.endsWith( QLatin1String( 
".mpk" ), Qt::CaseInsensitive ) ||
 
  884              path.endsWith( QLatin1String( 
".mpkx" ), Qt::CaseInsensitive ) ) )
 
  885    return QStringLiteral( 
"/vsi7z/" );
 
  886  else if ( vsiPrefixes.contains( QStringLiteral( 
"/vsirar/" ) ) &&
 
  887            path.endsWith( QLatin1String( 
".rar" ), Qt::CaseInsensitive ) )
 
  888    return QStringLiteral( 
"/vsirar/" );
 
 
  896  QStringList res { QStringLiteral( 
"/vsizip/" ),
 
  897                    QStringLiteral( 
"/vsitar/" ),
 
  898                    QStringLiteral( 
"/vsigzip/" ),
 
  900#if GDAL_VERSION_NUM >= GDAL_COMPUTE_VERSION(3,7,0) 
  901  res.append( QStringLiteral( 
"/vsi7z/" ) );
 
  902  res.append( QStringLiteral( 
"/vsirar/" ) );
 
 
  910  static std::once_flag initialized;
 
  911  static QList<QgsGdalUtils::VsiNetworkFileSystemDetails> VSI_FILE_SYSTEM_DETAILS;
 
  912  std::call_once( initialized, [ = ]
 
  914    if ( 
char **papszPrefixes = VSIGetFileSystemsPrefixes() )
 
  916      for ( 
int i = 0; papszPrefixes[i]; i++ )
 
  919        details.
identifier = QString( papszPrefixes[i] );
 
  925        if ( details.
identifier == QLatin1String( 
"vsicurl" ) )
 
  926          details.
name = QObject::tr( 
"HTTP/HTTPS/FTP" );
 
  927        else if ( details.
identifier == QLatin1String( 
"vsis3" ) )
 
  928          details.
name = QObject::tr( 
"AWS S3" );
 
  929        else if ( details.
identifier == QLatin1String( 
"vsigs" ) )
 
  930          details.
name = QObject::tr( 
"Google Cloud Storage" );
 
  931        else if ( details.
identifier == QLatin1String( 
"vsiaz" ) )
 
  932          details.
name = QObject::tr( 
"Microsoft Azure Blob" );
 
  933        else if ( details.
identifier == QLatin1String( 
"vsiadls" ) )
 
  934          details.
name = QObject::tr( 
"Microsoft Azure Data Lake Storage" );
 
  935        else if ( details.
identifier == QLatin1String( 
"vsioss" ) )
 
  936          details.
name = QObject::tr( 
"Alibaba Cloud OSS" );
 
  937        else if ( details.
identifier == QLatin1String( 
"vsiswift" ) )
 
  938          details.
name = QObject::tr( 
"OpenStack Swift Object Storage" );
 
  939        else if ( details.
identifier == QLatin1String( 
"vsihdfs" ) )
 
  940          details.
name = QObject::tr( 
"Hadoop File System" );
 
  943        VSI_FILE_SYSTEM_DETAILS.append( details );
 
  946      CSLDestroy( papszPrefixes );
 
  950  return VSI_FILE_SYSTEM_DETAILS;
 
 
  956  for ( 
const QString &archivePrefix : prefixes )
 
  959    if ( prefix.contains( archivePrefix ) )
 
 
  967  QStringList res { QStringLiteral( 
".zip" ),
 
  968                    QStringLiteral( 
".tar" ),
 
  969                    QStringLiteral( 
".tar.gz" ),
 
  970                    QStringLiteral( 
".tgz" ),
 
  971                    QStringLiteral( 
".gz" ),
 
  973#if GDAL_VERSION_NUM >= GDAL_COMPUTE_VERSION(3,7,0) 
  974  res.append( { QStringLiteral( 
".7z" ),
 
  975                QStringLiteral( 
".lpk" ),
 
  976                QStringLiteral( 
".lpkx" ),
 
  977                QStringLiteral( 
".mpk" ),
 
  978                QStringLiteral( 
".mpkx" ),
 
  979                QStringLiteral( 
".rar" )
 
 
  987  const QString extWithDot = extension.startsWith( 
'.' ) ? extension : ( 
'.' + extension );
 
 
  993  if ( prefix.isEmpty() )
 
  996  QString vsiPrefix = prefix;
 
  997  if ( vsiPrefix.startsWith( 
'/' ) )
 
  998    vsiPrefix = vsiPrefix.mid( 1 );
 
  999  if ( vsiPrefix.endsWith( 
'/' ) )
 
 1000    vsiPrefix.chop( 1 );
 
 1002  if ( !vsiPrefix.startsWith( QLatin1String( 
"vsi" ) ) )
 
 1005  if ( vsiPrefix == QLatin1String( 
"vsizip" ) ||
 
 1006       vsiPrefix == QLatin1String( 
"vsigzip" ) ||
 
 1007       vsiPrefix == QLatin1String( 
"vsitar" ) ||
 
 1008       vsiPrefix == QLatin1String( 
"vsi7z" ) ||
 
 1009       vsiPrefix == QLatin1String( 
"vsirar" ) )
 
 1012  else if ( vsiPrefix == QLatin1String( 
"vsicurl" ) ||
 
 1013            vsiPrefix == QLatin1String( 
"vsicurl_streaming" ) )
 
 1016  else if ( vsiPrefix == QLatin1String( 
"vsis3" ) ||
 
 1017            vsiPrefix == QLatin1String( 
"vsicurl_streaming" ) ||
 
 1018            vsiPrefix == QLatin1String( 
"vsigs" ) ||
 
 1019            vsiPrefix == QLatin1String( 
"vsigs_streaming" ) ||
 
 1020            vsiPrefix == QLatin1String( 
"vsiaz" ) ||
 
 1021            vsiPrefix == QLatin1String( 
"vsiaz_streaming" ) ||
 
 1022            vsiPrefix == QLatin1String( 
"vsiadls" ) ||
 
 1023            vsiPrefix == QLatin1String( 
"vsioss" ) ||
 
 1024            vsiPrefix == QLatin1String( 
"vsioss_streaming" ) ||
 
 1025            vsiPrefix == QLatin1String( 
"vsiswift" ) ||
 
 1026            vsiPrefix == QLatin1String( 
"vsiswift_streaming" ) ||
 
 1027            vsiPrefix == QLatin1String( 
"vsihdfs" ) ||
 
 1028            vsiPrefix == QLatin1String( 
"vsiwebhdfs" ) )
 
 1031  else if ( vsiPrefix == QLatin1String( 
"vsimem" ) )
 
 
 1039  CPLPushErrorHandler( CPLQuietErrorHandler );
 
 1041  GDALDriverH hDriver = 
nullptr;
 
 1046      hDriver = GDALIdentifyDriverEx( vrtPath.toUtf8().constData(), GDAL_OF_VECTOR, 
nullptr, 
nullptr );
 
 1050      hDriver = GDALIdentifyDriverEx( vrtPath.toUtf8().constData(), GDAL_OF_RASTER, 
nullptr, 
nullptr );
 
 1063  CPLPopErrorHandler();
 
 1064  return static_cast< bool >( hDriver );
 
 
 1071    const QString gdalDriverHelpTopic = GDALGetMetadataItem( hDriver, GDAL_DMD_HELPTOPIC, 
nullptr );  
 
 1072    if ( !gdalDriverHelpTopic.isEmpty() )
 
 1073      return QStringLiteral( 
"https://gdal.org/%1" ).arg( gdalDriverHelpTopic );
 
 
 1080  QString vsiPrefix = prefix;
 
 1081  if ( !vsiPrefix.startsWith( 
'/' ) )
 
 1082    vsiPrefix.prepend( 
'/' );
 
 1083  if ( !vsiPrefix.endsWith( 
'/' ) )
 
 1084    vsiPrefix.append( 
'/' );
 
 1086  QString vsiPath = path;
 
 1087  if ( vsiPath.endsWith( 
'/' ) )
 
 1090  const QString bucket = vsiPrefix + vsiPath;
 
 1092  for ( 
auto it = options.constBegin(); it != options.constEnd(); ++it )
 
 1094#if GDAL_VERSION_NUM >= GDAL_COMPUTE_VERSION(3, 6, 0) 
 1095    VSISetPathSpecificOption( bucket.toUtf8().constData(), it.key().toUtf8().constData(), it.value().toString().toUtf8().constData() );
 
 1096#elif GDAL_VERSION_NUM >= GDAL_COMPUTE_VERSION(3, 5, 0) 
 1097    VSISetCredential( bucket.toUtf8().constData(), it.key().toUtf8().constData(), it.value().toString().toUtf8().constData() );
 
 
VsiHandlerType
GDAL VSI handler types.
 
@ Memory
In-memory types (e.g. vsimem)
 
@ Invalid
Invalid type, i.e. not a valid VSI handler.
 
@ Cloud
Specific cloud provider types (e.g. vsis3)
 
@ Archive
File archive type (e.g. vsizip)
 
@ Network
Generic network types (e.g. vsicurl)
 
RasterResamplingMethod
Resampling method for raster provider-level resampling.
 
@ Lanczos
Lanczos windowed sinc interpolation (6x6 kernel)
 
@ Nearest
Nearest-neighbour resampling.
 
@ Mode
Mode (selects the value which appears most often of all the sampled points)
 
@ Bilinear
Bilinear (2x2 kernel) resampling.
 
@ Average
Average resampling.
 
@ CubicSpline
Cubic B-Spline Approximation (4x4 kernel)
 
@ Cubic
Cubic Convolution Approximation (4x4 kernel) resampling.
 
@ Critical
Critical/error message.
 
DataType
Raster data types.
 
@ Float32
Thirty two bit floating point (float)
 
@ CFloat64
Complex Float64.
 
@ Int16
Sixteen bit signed integer (qint16)
 
@ ARGB32_Premultiplied
Color, alpha, red, green, blue, 4 bytes the same as QImage::Format_ARGB32_Premultiplied.
 
@ Int8
Eight bit signed integer (qint8) (added in QGIS 3.30)
 
@ UInt16
Sixteen bit unsigned integer (quint16)
 
@ Byte
Eight bit unsigned integer (quint8)
 
@ UnknownDataType
Unknown or unspecified type.
 
@ ARGB32
Color, alpha, red, green, blue, 4 bytes the same as QImage::Format_ARGB32.
 
@ Int32
Thirty two bit signed integer (qint32)
 
@ Float64
Sixty four bit floating point (double)
 
@ CFloat32
Complex Float32.
 
@ UInt32
Thirty two bit unsigned integer (quint32)
 
LayerType
Types of layers that can be added to a map.
 
@ Group
Composite group layer. Added in QGIS 3.24.
 
@ Plugin
Plugin based layer.
 
@ TiledScene
Tiled scene layer. Added in QGIS 3.34.
 
@ Annotation
Contains freeform, georeferenced annotations. Added in QGIS 3.16.
 
@ VectorTile
Vector tile layer. Added in QGIS 3.14.
 
@ Mesh
Mesh layer. Added in QGIS 3.2.
 
@ PointCloud
Point cloud layer. Added in QGIS 3.18.
 
@ PreferredGdal
Preferred format for conversion of CRS to WKT for use with the GDAL library.
 
Represents a coordinate reference system (CRS).
 
QString toWkt(Qgis::CrsWktVariant variant=Qgis::CrsWktVariant::Wkt1Gdal, bool multiline=false, int indentationWidth=4) const
Returns a WKT representation of this CRS.
 
Encapsulates the definition of a GDAL configuration option.
 
QVariant defaultValue
Default value.
 
QVariant maximum
Maximum acceptable value.
 
QStringList options
Available choices, for Select options.
 
QVariant minimum
Minimum acceptable value.
 
@ Select
Selection option.
 
QString scope
Option scope.
 
static QList< QgsGdalOption > optionsFromXml(const CPLXMLNode *node)
Returns a list of all GDAL options from an XML node.
 
static QgsGdalOption fromXmlNode(const CPLXMLNode *node)
Creates a QgsGdalOption from an XML node.
 
QString description
Option description.
 
static Qgis::VsiHandlerType vsiHandlerType(const QString &prefix)
Returns the VSI handler type for a given VSI prefix.
 
static bool applyVsiCredentialOptions(const QString &prefix, const QString &path, const QVariantMap &options)
Attempts to apply VSI credential options.
 
static bool pathIsCheapToOpen(const QString &path, int smallFileSizeLimit=50000)
Returns true if the dataset at the specified path is considered "cheap" to open.
 
static QString vsiPrefixForPath(const QString &path)
Returns a the vsi prefix which corresponds to a file path, or an empty string if the path is not asso...
 
static QString helpCreationOptionsFormat(const QString &format)
Gets creation options metadata for a given format.
 
static bool vrtMatchesLayerType(const QString &vrtPath, Qgis::LayerType type)
Returns true if the VRT file at the specified path is a VRT matching the given layer type.
 
static bool resampleSingleBandRaster(GDALDatasetH hSrcDS, GDALDatasetH hDstDS, GDALResampleAlg resampleAlg, const char *pszCoordinateOperation)
Resamples a single band raster to the destination dataset with different resolution (and possibly wit...
 
static GDALDatasetH rpcAwareAutoCreateWarpedVrt(GDALDatasetH hSrcDS, const char *pszSrcWKT, const char *pszDstWKT, GDALResampleAlg eResampleAlg, double dfMaxError, const GDALWarpOptions *psOptionsIn)
This is a copy of GDALAutoCreateWarpedVRT optimized for imagery using RPC georeferencing that also se...
 
static bool supportsRasterCreate(GDALDriverH driver)
Reads whether a driver supports GDALCreate() for raster purposes.
 
static bool isVsiArchiveFileExtension(const QString &extension)
Returns true if a file extension is a supported archive style container (e.g.
 
static GDALResampleAlg gdalResamplingAlgorithm(Qgis::RasterResamplingMethod method)
Returns the GDAL resampling method corresponding to the QGIS resampling method.
 
static gdal::dataset_unique_ptr createSingleBandTiffDataset(const QString &filename, GDALDataType dataType, const QgsRectangle &extent, int width, int height, const QgsCoordinateReferenceSystem &crs)
Creates a new single band TIFF dataset with given parameters.
 
static GDALDataType gdalDataTypeFromQgisDataType(Qgis::DataType dataType)
Returns the GDAL data type corresponding to the QGIS data type dataType.
 
static bool isVsiArchivePrefix(const QString &prefix)
Returns true if prefix is a supported archive style container prefix (e.g.
 
static QString gdalDocumentationUrlForDriver(GDALDriverH hDriver)
Returns the URL for the GDAL documentation for the specified driver.
 
static gdal::dataset_unique_ptr createSingleBandMemoryDataset(GDALDataType dataType, const QgsRectangle &extent, int width, int height, const QgsCoordinateReferenceSystem &crs)
Creates a new single band memory dataset with given parameters.
 
static gdal::dataset_unique_ptr blockToSingleBandMemoryDataset(int pixelWidth, int pixelHeight, const QgsRectangle &extent, void *block, GDALDataType dataType)
Converts a data block to a single band GDAL memory dataset.
 
static QList< VsiNetworkFileSystemDetails > vsiNetworkFileSystems()
Returns a list of available GDAL VSI network file systems.
 
static QString validateCreationOptionsFormat(const QStringList &creationOptions, const QString &format)
Validates creation options for a given format, regardless of layer.
 
static gdal::dataset_unique_ptr imageToMemoryDataset(const QImage &image)
Converts an image to a GDAL memory dataset by borrowing image data.
 
static void * rpcAwareCreateTransformer(GDALDatasetH hSrcDS, GDALDatasetH hDstDS=nullptr, char **papszOptions=nullptr)
This is a wrapper around GDALCreateGenImgProjTransformer2() that takes into account RPC georeferencin...
 
static void setupProxy()
Sets the gdal proxy variables.
 
static QStringList vsiArchiveFileExtensions()
Returns a list of file extensions which correspond to archive style containers supported by GDAL (e....
 
static char ** papszFromStringList(const QStringList &list)
Helper function.
 
static QImage resampleImage(const QImage &image, QSize outputSize, GDALRIOResampleAlg resampleAlg)
Resamples a QImage image using GDAL resampler.
 
static gdal::dataset_unique_ptr createMultiBandMemoryDataset(GDALDataType dataType, int bands, const QgsRectangle &extent, int width, int height, const QgsCoordinateReferenceSystem &crs)
Creates a new multi band memory dataset with given parameters.
 
static QStringList multiLayerFileExtensions()
Returns a list of file extensions which potentially contain multiple layers representing GDAL raster ...
 
static QStringList vsiArchivePrefixes()
Returns a list of vsi prefixes which correspond to archive style containers (eg vsizip).
 
static void warning(const QString &msg)
Goes to qWarning.
 
static void logMessage(const QString &message, const QString &tag=QString(), Qgis::MessageLevel level=Qgis::MessageLevel::Warning, bool notifyUser=true, const char *file=__builtin_FILE(), const char *function=__builtin_FUNCTION(), int line=__builtin_LINE())
Adds a message to the log instance (and creates it if necessary).
 
static QgsNetworkAccessManager * instance(Qt::ConnectionType connectionType=Qt::BlockingQueuedConnection)
Returns a pointer to the active QgsNetworkAccessManager for the current thread.
 
int height() const
Returns the height (number of rows) of the raster block.
 
char * bits(int row, int column)
Returns a pointer to block data.
 
double noDataValue() const
Returns no data value.
 
Qgis::DataType dataType() const
Returns data type.
 
int width() const
Returns the width (number of columns) of the raster block.
 
A rectangle specified with double values.
 
Stores settings for use within QGIS.
 
QVariant value(const QString &key, const QVariant &defaultValue=QVariant(), Section section=NoSection) const
Returns the value for setting key.
 
std::unique_ptr< std::remove_pointer< GDALDatasetH >::type, GDALDatasetCloser > dataset_unique_ptr
Scoped GDAL dataset.
 
std::unique_ptr< GDALWarpOptions, GDALWarpOptionsDeleter > warp_options_unique_ptr
Scoped GDAL warp options.
 
#define QgsDebugError(str)
 
const QgsCoordinateReferenceSystem & crs
 
Encapsulates details for a GDAL VSI network file system.
 
QString name
Translated, user-friendly name.
 
QString identifier
VSI handler identifier, eg "vsis3".