LCOV - code coverage report
Current view: top level - gcore - gdaldataset.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 3027 3528 85.8 %
Date: 2025-12-21 22:14:19 Functions: 304 334 91.0 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Project:  GDAL Core
       4             :  * Purpose:  Base class for raster file formats.
       5             :  * Author:   Frank Warmerdam, warmerdam@pobox.com
       6             :  *
       7             :  ******************************************************************************
       8             :  * Copyright (c) 1998, 2003, Frank Warmerdam
       9             :  * Copyright (c) 2008-2013, Even Rouault <even dot rouault at spatialys.com>
      10             :  *
      11             :  * SPDX-License-Identifier: MIT
      12             :  ****************************************************************************/
      13             : 
      14             : #include "cpl_port.h"
      15             : 
      16             : #include <array>
      17             : #include <cassert>
      18             : #include <climits>
      19             : #include <cmath>
      20             : #include <cstdarg>
      21             : #include <cstdio>
      22             : #include <cstdlib>
      23             : #include <cstring>
      24             : #include <algorithm>
      25             : #include <limits>
      26             : #include <map>
      27             : #include <mutex>
      28             : #include <new>
      29             : #include <set>
      30             : #include <string>
      31             : #include <type_traits>
      32             : #include <utility>
      33             : 
      34             : #include "cpl_conv.h"
      35             : #include "cpl_cpu_features.h"
      36             : #include "cpl_error.h"
      37             : #include "cpl_hash_set.h"
      38             : #include "cpl_multiproc.h"
      39             : #include "cpl_progress.h"
      40             : #include "cpl_string.h"
      41             : #include "cpl_vsi.h"
      42             : #include "cpl_vsi_error.h"
      43             : 
      44             : #include "gdal.h"
      45             : #include "gdal_alg.h"
      46             : #include "gdal_abstractbandblockcache.h"
      47             : #include "gdalantirecursion.h"
      48             : #include "gdal_dataset.h"
      49             : #include "gdal_matrix.hpp"
      50             : 
      51             : #ifdef CAN_DETECT_AVX2_FMA_AT_RUNTIME
      52             : #include "gdal_matrix_avx2_fma.h"
      53             : #endif
      54             : 
      55             : #include "gdalsubdatasetinfo.h"
      56             : #include "gdal_typetraits.h"
      57             : 
      58             : #include "ogr_api.h"
      59             : #include "ogr_attrind.h"
      60             : #include "ogr_core.h"
      61             : #include "ogr_feature.h"
      62             : #include "ogr_featurestyle.h"
      63             : #include "ogr_gensql.h"
      64             : #include "ogr_geometry.h"
      65             : #include "ogr_p.h"
      66             : #include "ogr_spatialref.h"
      67             : #include "ogr_srs_api.h"
      68             : #include "ograpispy.h"
      69             : #include "ogrsf_frmts.h"
      70             : #include "ogrunionlayer.h"
      71             : #include "ogr_swq.h"
      72             : #include "memmultidim.h"
      73             : #include "gdalmultidim_priv.h"
      74             : 
      75             : #include "../frmts/derived/derivedlist.h"
      76             : 
      77             : #ifdef SQLITE_ENABLED
      78             : #include "../sqlite/ogrsqliteexecutesql.h"
      79             : #endif
      80             : 
      81             : #ifdef HAVE_OPENMP
      82             : #include <omp.h>
      83             : #endif
      84             : 
      85             : extern const swq_field_type SpecialFieldTypes[SPECIAL_FIELD_COUNT];
      86             : 
      87             : CPL_C_START
      88             : GDALAsyncReader *GDALGetDefaultAsyncReader(GDALDataset *poDS, int nXOff,
      89             :                                            int nYOff, int nXSize, int nYSize,
      90             :                                            void *pBuf, int nBufXSize,
      91             :                                            int nBufYSize, GDALDataType eBufType,
      92             :                                            int nBandCount, int *panBandMap,
      93             :                                            int nPixelSpace, int nLineSpace,
      94             :                                            int nBandSpace, char **papszOptions);
      95             : CPL_C_END
      96             : 
      97             : enum class GDALAllowReadWriteMutexState
      98             : {
      99             :     RW_MUTEX_STATE_UNKNOWN,
     100             :     RW_MUTEX_STATE_ALLOWED,
     101             :     RW_MUTEX_STATE_DISABLED
     102             : };
     103             : 
     104             : const GIntBig TOTAL_FEATURES_NOT_INIT = -2;
     105             : const GIntBig TOTAL_FEATURES_UNKNOWN = -1;
     106             : 
     107             : class GDALDataset::Private
     108             : {
     109             :     CPL_DISALLOW_COPY_ASSIGN(Private)
     110             : 
     111             :   public:
     112             :     CPLMutex *hMutex = nullptr;
     113             :     std::map<GIntBig, int> oMapThreadToMutexTakenCount{};
     114             : #ifdef DEBUG_EXTRA
     115             :     std::map<GIntBig, int> oMapThreadToMutexTakenCountSaved{};
     116             : #endif
     117             :     GDALAllowReadWriteMutexState eStateReadWriteMutex =
     118             :         GDALAllowReadWriteMutexState::RW_MUTEX_STATE_UNKNOWN;
     119             :     int nCurrentLayerIdx = 0;
     120             :     int nLayerCount = -1;
     121             :     GIntBig nFeatureReadInLayer = 0;
     122             :     GIntBig nFeatureReadInDataset = 0;
     123             :     GIntBig nTotalFeaturesInLayer = TOTAL_FEATURES_NOT_INIT;
     124             :     GIntBig nTotalFeatures = TOTAL_FEATURES_NOT_INIT;
     125             :     OGRLayer *poCurrentLayer = nullptr;
     126             : 
     127             :     std::mutex m_oMutexWKT{};
     128             : 
     129             :     char *m_pszWKTCached = nullptr;
     130             :     OGRSpatialReference *m_poSRSCached = nullptr;
     131             :     char *m_pszWKTGCPCached = nullptr;
     132             :     OGRSpatialReference *m_poSRSGCPCached = nullptr;
     133             : 
     134             :     GDALDataset *poParentDataset = nullptr;
     135             : 
     136             :     bool m_bOverviewsEnabled = true;
     137             : 
     138             :     std::vector<int>
     139             :         m_anBandMap{};  // used by RasterIO(). Values are 1, 2, etc.
     140             : 
     141      181131 :     Private() = default;
     142             : };
     143             : 
     144             : struct SharedDatasetCtxt
     145             : {
     146             :     // PID of the thread that mark the dataset as shared
     147             :     // This may not be the actual PID, but the responsiblePID.
     148             :     GIntBig nPID;
     149             :     char *pszDescription;
     150             :     char *pszConcatenatedOpenOptions;
     151             :     int nOpenFlags;
     152             : 
     153             :     GDALDataset *poDS;
     154             : };
     155             : 
     156             : // Set of datasets opened as shared datasets (with GDALOpenShared)
     157             : // The values in the set are of type SharedDatasetCtxt.
     158             : static CPLHashSet *phSharedDatasetSet = nullptr;
     159             : 
     160             : // Set of all datasets created in the constructor of GDALDataset.
     161             : // In the case of a shared dataset, memorize the PID of the thread
     162             : // that marked the dataset as shared, so that we can remove it from
     163             : // the phSharedDatasetSet in the destructor of the dataset, even
     164             : // if GDALClose is called from a different thread.
     165             : static std::map<GDALDataset *, GIntBig> *poAllDatasetMap = nullptr;
     166             : 
     167             : static CPLMutex *hDLMutex = nullptr;
     168             : 
     169             : // Static array of all datasets. Used by GDALGetOpenDatasets.
     170             : // Not thread-safe. See GDALGetOpenDatasets.
     171             : static GDALDataset **ppDatasets = nullptr;
     172             : 
     173        8438 : static unsigned long GDALSharedDatasetHashFunc(const void *elt)
     174             : {
     175        8438 :     const SharedDatasetCtxt *psStruct =
     176             :         static_cast<const SharedDatasetCtxt *>(elt);
     177             :     return static_cast<unsigned long>(
     178        8438 :         CPLHashSetHashStr(psStruct->pszDescription) ^
     179        8438 :         CPLHashSetHashStr(psStruct->pszConcatenatedOpenOptions) ^
     180        8438 :         psStruct->nOpenFlags ^ psStruct->nPID);
     181             : }
     182             : 
     183        7025 : static int GDALSharedDatasetEqualFunc(const void *elt1, const void *elt2)
     184             : {
     185        7025 :     const SharedDatasetCtxt *psStruct1 =
     186             :         static_cast<const SharedDatasetCtxt *>(elt1);
     187        7025 :     const SharedDatasetCtxt *psStruct2 =
     188             :         static_cast<const SharedDatasetCtxt *>(elt2);
     189       13952 :     return strcmp(psStruct1->pszDescription, psStruct2->pszDescription) == 0 &&
     190        6927 :            strcmp(psStruct1->pszConcatenatedOpenOptions,
     191        6927 :                   psStruct2->pszConcatenatedOpenOptions) == 0 &&
     192       20879 :            psStruct1->nPID == psStruct2->nPID &&
     193       13952 :            psStruct1->nOpenFlags == psStruct2->nOpenFlags;
     194             : }
     195             : 
     196         411 : static void GDALSharedDatasetFreeFunc(void *elt)
     197             : {
     198         411 :     SharedDatasetCtxt *psStruct = static_cast<SharedDatasetCtxt *>(elt);
     199         411 :     CPLFree(psStruct->pszDescription);
     200         411 :     CPLFree(psStruct->pszConcatenatedOpenOptions);
     201         411 :     CPLFree(psStruct);
     202         411 : }
     203             : 
     204             : static std::string
     205        7067 : GDALSharedDatasetConcatenateOpenOptions(CSLConstList papszOpenOptions)
     206             : {
     207        7067 :     std::string osStr;
     208        7080 :     for (const char *pszOption : cpl::Iterate(papszOpenOptions))
     209          13 :         osStr += pszOption;
     210        7067 :     return osStr;
     211             : }
     212             : 
     213             : /************************************************************************/
     214             : /* Functions shared between gdalproxypool.cpp and gdaldataset.cpp */
     215             : /************************************************************************/
     216             : 
     217             : // The open-shared mutex must be used by the ProxyPool too.
     218      483423 : CPLMutex **GDALGetphDLMutex()
     219             : {
     220      483423 :     return &hDLMutex;
     221             : }
     222             : 
     223             : // The current thread will act in the behalf of the thread of PID
     224             : // responsiblePID.
     225      472840 : void GDALSetResponsiblePIDForCurrentThread(GIntBig responsiblePID)
     226             : {
     227             :     GIntBig *pResponsiblePID =
     228      472840 :         static_cast<GIntBig *>(CPLGetTLS(CTLS_RESPONSIBLEPID));
     229      472840 :     if (pResponsiblePID == nullptr)
     230             :     {
     231         228 :         pResponsiblePID = static_cast<GIntBig *>(CPLMalloc(sizeof(GIntBig)));
     232         228 :         CPLSetTLS(CTLS_RESPONSIBLEPID, pResponsiblePID, TRUE);
     233             :     }
     234      472840 :     *pResponsiblePID = responsiblePID;
     235      472840 : }
     236             : 
     237             : // Get the PID of the thread that the current thread will act in the behalf of
     238             : // By default : the current thread acts in the behalf of itself.
     239      602229 : GIntBig GDALGetResponsiblePIDForCurrentThread()
     240             : {
     241             :     GIntBig *pResponsiblePID =
     242      602229 :         static_cast<GIntBig *>(CPLGetTLS(CTLS_RESPONSIBLEPID));
     243      602229 :     if (pResponsiblePID == nullptr)
     244       44633 :         return CPLGetPID();
     245      557596 :     return *pResponsiblePID;
     246             : }
     247             : 
     248             : /************************************************************************/
     249             : /* ==================================================================== */
     250             : /*                             GDALDataset                              */
     251             : /* ==================================================================== */
     252             : /************************************************************************/
     253             : 
     254             : /**
     255             :  * \class GDALDataset "gdal_priv.h"
     256             :  *
     257             :  * A dataset encapsulating one or more raster bands.  Details are further
     258             :  * discussed in the <a href="https://gdal.org/user/raster_data_model.html">GDAL
     259             :  * Raster Data Model</a>.
     260             :  *
     261             :  * Use GDALOpen() or GDALOpenShared() to create a GDALDataset for a named file,
     262             :  * or GDALDriver::Create() or GDALDriver::CreateCopy() to create a new
     263             :  * dataset.
     264             :  */
     265             : 
     266             : /************************************************************************/
     267             : /*                            GDALDataset()                             */
     268             : /************************************************************************/
     269             : 
     270             : //! @cond Doxygen_Suppress
     271      160144 : GDALDataset::GDALDataset()
     272      160144 :     : GDALDataset(CPLTestBool(CPLGetConfigOption("GDAL_FORCE_CACHING", "NO")))
     273             : {
     274      160144 : }
     275             : 
     276      181131 : GDALDataset::GDALDataset(int bForceCachedIOIn)
     277      181131 :     : bForceCachedIO(CPL_TO_BOOL(bForceCachedIOIn)),
     278      181131 :       m_poPrivate(new(std::nothrow) GDALDataset::Private)
     279             : {
     280      181131 : }
     281             : 
     282             : //! @endcond
     283             : 
     284             : /************************************************************************/
     285             : /*                            ~GDALDataset()                            */
     286             : /************************************************************************/
     287             : 
     288             : /**
     289             :  * \brief Destroy an open GDALDataset.
     290             :  *
     291             :  * This is the accepted method of closing a GDAL dataset and deallocating
     292             :  * all resources associated with it.
     293             :  *
     294             :  * Equivalent of the C callable GDALClose().  Except that GDALClose() first
     295             :  * decrements the reference count, and then closes only if it has dropped to
     296             :  * zero.
     297             :  *
     298             :  * For Windows users, it is not recommended to use the delete operator on the
     299             :  * dataset object because of known issues when allocating and freeing memory
     300             :  * across module boundaries. Calling GDALClose() is then a better option.
     301             :  */
     302             : 
     303      181112 : GDALDataset::~GDALDataset()
     304             : 
     305             : {
     306             :     // we don't want to report destruction of datasets that
     307             :     // were never really open or meant as internal
     308      181112 :     if (!bIsInternal && (nBands != 0 || !EQUAL(GetDescription(), "")))
     309             :     {
     310       72528 :         if (CPLGetPID() != GDALGetResponsiblePIDForCurrentThread())
     311         209 :             CPLDebug("GDAL",
     312             :                      "GDALClose(%s, this=%p) (pid=%d, responsiblePID=%d)",
     313         209 :                      GetDescription(), this, static_cast<int>(CPLGetPID()),
     314         209 :                      static_cast<int>(GDALGetResponsiblePIDForCurrentThread()));
     315             :         else
     316       72319 :             CPLDebug("GDAL", "GDALClose(%s, this=%p)", GetDescription(), this);
     317             :     }
     318             : 
     319      181112 :     GDALDataset::Close();
     320             : 
     321             :     /* -------------------------------------------------------------------- */
     322             :     /*      Remove dataset from the "open" dataset list.                    */
     323             :     /* -------------------------------------------------------------------- */
     324      181112 :     if (!bIsInternal)
     325             :     {
     326      147882 :         CPLMutexHolderD(&hDLMutex);
     327       73941 :         if (poAllDatasetMap)
     328             :         {
     329             :             std::map<GDALDataset *, GIntBig>::iterator oIter =
     330       73941 :                 poAllDatasetMap->find(this);
     331       73941 :             CPLAssert(oIter != poAllDatasetMap->end());
     332             : 
     333       73941 :             UnregisterFromSharedDataset();
     334             : 
     335       73941 :             poAllDatasetMap->erase(oIter);
     336             : 
     337       73941 :             if (poAllDatasetMap->empty())
     338             :             {
     339       30693 :                 delete poAllDatasetMap;
     340       30693 :                 poAllDatasetMap = nullptr;
     341       30693 :                 if (phSharedDatasetSet)
     342             :                 {
     343         275 :                     CPLHashSetDestroy(phSharedDatasetSet);
     344             :                 }
     345       30693 :                 phSharedDatasetSet = nullptr;
     346       30693 :                 CPLFree(ppDatasets);
     347       30693 :                 ppDatasets = nullptr;
     348             :             }
     349             :         }
     350             :     }
     351             : 
     352             :     /* -------------------------------------------------------------------- */
     353             :     /*      Destroy the raster bands if they exist.                         */
     354             :     /* -------------------------------------------------------------------- */
     355     1716030 :     for (int i = 0; i < nBands && papoBands != nullptr; ++i)
     356             :     {
     357     1534920 :         if (papoBands[i] != nullptr)
     358     1534920 :             delete papoBands[i];
     359     1534920 :         papoBands[i] = nullptr;
     360             :     }
     361             : 
     362      181112 :     CPLFree(papoBands);
     363             : 
     364      181112 :     if (m_poStyleTable)
     365             :     {
     366          23 :         delete m_poStyleTable;
     367          23 :         m_poStyleTable = nullptr;
     368             :     }
     369             : 
     370      181112 :     if (m_poPrivate != nullptr)
     371             :     {
     372      181112 :         if (m_poPrivate->hMutex != nullptr)
     373       21293 :             CPLDestroyMutex(m_poPrivate->hMutex);
     374             : 
     375             : #if defined(__COVERITY__) || defined(DEBUG)
     376             :         // Not needed since at destruction there is no risk of concurrent use.
     377      362224 :         std::lock_guard oLock(m_poPrivate->m_oMutexWKT);
     378             : #endif
     379      181112 :         CPLFree(m_poPrivate->m_pszWKTCached);
     380      181112 :         if (m_poPrivate->m_poSRSCached)
     381             :         {
     382           0 :             m_poPrivate->m_poSRSCached->Release();
     383             :         }
     384      181112 :         CPLFree(m_poPrivate->m_pszWKTGCPCached);
     385      181112 :         if (m_poPrivate->m_poSRSGCPCached)
     386             :         {
     387           0 :             m_poPrivate->m_poSRSGCPCached->Release();
     388             :         }
     389             :     }
     390             : 
     391      181112 :     delete m_poPrivate;
     392             : 
     393      181112 :     CSLDestroy(papszOpenOptions);
     394      181112 : }
     395             : 
     396             : /************************************************************************/
     397             : /*                             Close()                                  */
     398             : /************************************************************************/
     399             : 
     400             : /** Do final cleanup before a dataset is destroyed.
     401             :  *
     402             :  * This method is typically called by GDALClose() or the destructor of a
     403             :  * GDALDataset subclass. It might also be called by C++ users before
     404             :  * destroying a dataset. It should not be called on a shared dataset whose
     405             :  * reference count is greater than one.
     406             :  *
     407             :  * It gives a last chance to the closing process to return an error code if
     408             :  * something goes wrong, in particular in creation / update scenarios where
     409             :  * file write or network communication might occur when finalizing the dataset.
     410             :  *
     411             :  * Implementations should be robust to this method to be called several times
     412             :  * (on subsequent calls, it should do nothing and return CE_None).
     413             :  * Once it has been called, no other method than Close() or the dataset
     414             :  * destructor should be called. RasterBand or OGRLayer owned by the dataset
     415             :  * should be assumed as no longer being valid.
     416             :  *
     417             :  * If a driver implements this method, it must also call it from its
     418             :  * dataset destructor.
     419             :  *
     420             :  * Starting with GDAL 3.13, this function may report progress if a progress
     421             :  * callback if provided in the pfnProgress argument and if the dataset returns
     422             :  * true for GDALDataset::GetCloseReportsProgress()
     423             :  *
     424             :  * This is the equivalent of C function GDALDatasetRunCloseWithoutDestroying()
     425             :  * or GDALDatasetRunCloseWithoutDestroyingEx()
     426             :  *
     427             :  * A typical implementation might look as the following
     428             :  * \code{.cpp}
     429             :  *
     430             :  *  MyDataset::~MyDataset()
     431             :  *  {
     432             :  *     try
     433             :  *     {
     434             :  *         MyDataset::Close();
     435             :  *     }
     436             :  *     catch (const std::exception &exc)
     437             :  *     {
     438             :  *         // If Close() can throw exception
     439             :  *         CPLError(CE_Failure, CPLE_AppDefined,
     440             :  *                  "Exception thrown in MyDataset::Close(): %s",
     441             :  *                  exc.what());
     442             :  *     }
     443             :  *     catch (...)
     444             :  *     {
     445             :  *         // If Close() can throw exception
     446             :  *         CPLError(CE_Failure, CPLE_AppDefined,
     447             :  *                  "Exception thrown in MyDataset::Close()");
     448             :  *     }
     449             :  *  }
     450             :  *
     451             :  *  CPLErr MyDataset::Close(GDALProgressFunc pfnProgress, void* pProgressData)
     452             :  *  {
     453             :  *      CPLErr eErr = CE_None;
     454             :  *      if( nOpenFlags != OPEN_FLAGS_CLOSED )
     455             :  *      {
     456             :  *          eErr = MyDataset::FlushCache(true);
     457             :  *
     458             :  *          // Do something driver specific
     459             :  *          if (m_fpImage)
     460             :  *          {
     461             :  *              if( VSIFCloseL(m_fpImage) != 0 )
     462             :  *              {
     463             :  *                  CPLError(CE_Failure, CPLE_FileIO, "VSIFCloseL() failed");
     464             :  *                  eErr = CE_Failure;
     465             :  *              }
     466             :  *          }
     467             :  *
     468             :  *          // Call parent Close() implementation.
     469             :  *          eErr = GDAL::Combine(eErr, MyParentDatasetClass::Close());
     470             :  *      }
     471             :  *      return eErr;
     472             :  *  }
     473             :  * \endcode
     474             :  *
     475             :  * @param pfnProgress (since GDAL 3.13) Progress callback, or nullptr
     476             :  * @param pProgressData (since GDAL 3.13) User data of progress callback, or nullptr
     477             :  * @return CE_None if no error
     478             :  *
     479             :  * @since GDAL 3.7
     480             :  */
     481      296124 : CPLErr GDALDataset::Close(GDALProgressFunc pfnProgress, void *pProgressData)
     482             : {
     483             :     (void)pfnProgress;
     484             :     (void)pProgressData;
     485             : 
     486      296124 :     if (nOpenFlags != OPEN_FLAGS_CLOSED)
     487             :     {
     488             :         // Call UnregisterFromSharedDataset() before altering nOpenFlags
     489      181112 :         UnregisterFromSharedDataset();
     490             : 
     491      181112 :         nOpenFlags = OPEN_FLAGS_CLOSED;
     492             :     }
     493             : 
     494      296124 :     if (IsMarkedSuppressOnClose())
     495             :     {
     496        3450 :         if (poDriver == nullptr ||
     497             :             // Someone issuing Create("foo.tif") on a
     498             :             // memory driver doesn't expect files with those names to be deleted
     499             :             // on a file system...
     500             :             // This is somewhat messy. Ideally there should be a way for the
     501             :             // driver to overload the default behavior
     502        1681 :             (!EQUAL(poDriver->GetDescription(), "MEM") &&
     503        1603 :              !EQUAL(poDriver->GetDescription(), "Memory")))
     504             :         {
     505        1691 :             if (VSIUnlink(GetDescription()) == 0)
     506         683 :                 UnMarkSuppressOnClose();
     507             :         }
     508             :     }
     509             : 
     510      296124 :     return CE_None;
     511             : }
     512             : 
     513             : /************************************************************************/
     514             : /*                   GDALDatasetRunCloseWithoutDestroying()             */
     515             : /************************************************************************/
     516             : 
     517             : /** Run the Close() method, without running destruction of the object.
     518             :  *
     519             :  * This ensures that content that should be written to file is written and
     520             :  * that all file descriptors are closed.
     521             :  *
     522             :  * Note that this is different from GDALClose() which also destroys
     523             :  * the underlying C++ object. GDALClose() or GDALReleaseDataset() are actually
     524             :  * the only functions that can be safely called on the dataset handle after
     525             :  * this function has been called.
     526             :  *
     527             :  * Most users want to use GDALClose() or GDALReleaseDataset() rather than
     528             :  * this function.
     529             :  *
     530             :  * This function is equivalent to the C++ method GDALDataset:Close()
     531             :  *
     532             :  * @param hDS dataset handle.
     533             :  * @return CE_None if no error
     534             :  *
     535             :  * @since GDAL 3.12
     536             :  * @see GDALClose(), GDALDatasetRunCloseWithoutDestroyingEx()
     537             :  */
     538           0 : CPLErr GDALDatasetRunCloseWithoutDestroying(GDALDatasetH hDS)
     539             : {
     540           0 :     VALIDATE_POINTER1(hDS, __func__, CE_Failure);
     541           0 :     return GDALDataset::FromHandle(hDS)->Close();
     542             : }
     543             : 
     544             : /************************************************************************/
     545             : /*                  GDALDatasetRunCloseWithoutDestroyingEx()            */
     546             : /************************************************************************/
     547             : 
     548             : /** Run the Close() method, without running destruction of the object.
     549             :  *
     550             :  * This ensures that content that should be written to file is written and
     551             :  * that all file descriptors are closed.
     552             :  *
     553             :  * Note that this is different from GDALClose() which also destroys
     554             :  * the underlying C++ object. GDALClose() or GDALReleaseDataset() are actually
     555             :  * the only functions that can be safely called on the dataset handle after
     556             :  * this function has been called.
     557             :  *
     558             :  * Most users want to use GDALClose() or GDALReleaseDataset() rather than
     559             :  * this function.
     560             :  *
     561             :  * This function may report progress if a progress
     562             :  * callback if provided in the pfnProgress argument and if the dataset returns
     563             :  * true for GDALDataset::GetCloseReportsProgress()
     564             :  *
     565             :  * This function is equivalent to the C++ method GDALDataset:Close()
     566             :  *
     567             :  * @param hDS dataset handle.
     568             :  * @param pfnProgress Progress callback, or nullptr
     569             :  * @param pProgressData User data of progress callback, or nullptr
     570             :  *
     571             :  * @return CE_None if no error
     572             :  *
     573             :  * @since GDAL 3.13
     574             :  * @see GDALClose()
     575             :  */
     576          12 : CPLErr GDALDatasetRunCloseWithoutDestroyingEx(GDALDatasetH hDS,
     577             :                                               GDALProgressFunc pfnProgress,
     578             :                                               void *pProgressData)
     579             : {
     580          12 :     VALIDATE_POINTER1(hDS, __func__, CE_Failure);
     581          12 :     return GDALDataset::FromHandle(hDS)->Close(pfnProgress, pProgressData);
     582             : }
     583             : 
     584             : /************************************************************************/
     585             : /*                         GetCloseReportsProgress()                    */
     586             : /************************************************************************/
     587             : 
     588             : /** Returns whether the Close() operation will report progress / is a potential
     589             :  * lengthy operation.
     590             :  *
     591             :  * At time of writing, only the COG driver will return true, if the dataset
     592             :  * has been created through the GDALDriver::Create() interface.
     593             :  *
     594             :  * This method is equivalent to the C function GDALDatasetGetCloseReportsProgress()
     595             :  *
     596             :  * @return true if the Close() operation will report progress
     597             :  * @since GDAL 3.13
     598             :  * @see Close()
     599             :  */
     600         213 : bool GDALDataset::GetCloseReportsProgress() const
     601             : {
     602         213 :     return false;
     603             : }
     604             : 
     605             : /************************************************************************/
     606             : /*                   GDALDatasetGetCloseReportsProgress()               */
     607             : /************************************************************************/
     608             : 
     609             : /** Returns whether the Close() operation will report progress / is a potential
     610             :  * lengthy operation.
     611             :  *
     612             :  * This function is equivalent to the C++ method GDALDataset::GetCloseReportsProgress()
     613             :  *
     614             :  * @param hDS dataset handle.
     615             :  * @return CE_None if no error
     616             :  *
     617             :  * @return true if the Close() operation will report progress
     618             :  * @since GDAL 3.13
     619             :  * @see GDALClose()
     620             :  */
     621           2 : bool GDALDatasetGetCloseReportsProgress(GDALDatasetH hDS)
     622             : {
     623           2 :     VALIDATE_POINTER1(hDS, __func__, false);
     624           2 :     return GDALDataset::FromHandle(hDS)->GetCloseReportsProgress();
     625             : }
     626             : 
     627             : /************************************************************************/
     628             : /*                   CanReopenWithCurrentDescription()                  */
     629             : /************************************************************************/
     630             : 
     631             : /** Returns whether, once this dataset is closed, it can be re-opened with
     632             :  * Open() using the current value of GetDescription()
     633             :  *
     634             :  * The default implementation returns true. Some drivers, like MVT in Create()
     635             :  * mode, can return false. Some drivers return true, but the re-opened dataset
     636             :  * may be opened by another driver (e.g. the COG driver will return true, but
     637             :  * the driver used for re-opening is GTiff).
     638             :  *
     639             :  * @return true if the dataset can be re-opened using the value as
     640             :  *         GetDescription() as connection string for Open()
     641             :  * @since GDAL 3.13
     642             :  */
     643           2 : bool GDALDataset::CanReopenWithCurrentDescription() const
     644             : {
     645           2 :     return true;
     646             : }
     647             : 
     648             : /************************************************************************/
     649             : /*                UnregisterFromSharedDataset()                         */
     650             : /************************************************************************/
     651             : 
     652      255053 : void GDALDataset::UnregisterFromSharedDataset()
     653             : {
     654      255053 :     if (!(!bIsInternal && bShared && poAllDatasetMap && phSharedDatasetSet))
     655      254642 :         return;
     656             : 
     657         822 :     CPLMutexHolderD(&hDLMutex);
     658             : 
     659             :     std::map<GDALDataset *, GIntBig>::iterator oIter =
     660         411 :         poAllDatasetMap->find(this);
     661         411 :     CPLAssert(oIter != poAllDatasetMap->end());
     662         411 :     const GIntBig nPIDCreatorForShared = oIter->second;
     663         411 :     bShared = false;
     664             :     SharedDatasetCtxt sStruct;
     665         411 :     sStruct.nPID = nPIDCreatorForShared;
     666         411 :     sStruct.nOpenFlags = nOpenFlags & ~GDAL_OF_SHARED;
     667         411 :     sStruct.pszDescription = const_cast<char *>(GetDescription());
     668             :     std::string osConcatenatedOpenOptions =
     669         822 :         GDALSharedDatasetConcatenateOpenOptions(papszOpenOptions);
     670         411 :     sStruct.pszConcatenatedOpenOptions = &osConcatenatedOpenOptions[0];
     671         411 :     sStruct.poDS = nullptr;
     672             :     SharedDatasetCtxt *psStruct = static_cast<SharedDatasetCtxt *>(
     673         411 :         CPLHashSetLookup(phSharedDatasetSet, &sStruct));
     674         411 :     if (psStruct && psStruct->poDS == this)
     675             :     {
     676         410 :         CPLHashSetRemove(phSharedDatasetSet, psStruct);
     677             :     }
     678             :     else
     679             :     {
     680           1 :         CPLDebug("GDAL",
     681             :                  "Should not happen. Cannot find %s, "
     682             :                  "this=%p in phSharedDatasetSet",
     683           1 :                  GetDescription(), this);
     684             :     }
     685             : }
     686             : 
     687             : /************************************************************************/
     688             : /*                      AddToDatasetOpenList()                          */
     689             : /************************************************************************/
     690             : 
     691       75274 : void GDALDataset::AddToDatasetOpenList()
     692             : {
     693             :     /* -------------------------------------------------------------------- */
     694             :     /*      Add this dataset to the open dataset list.                      */
     695             :     /* -------------------------------------------------------------------- */
     696       75274 :     bIsInternal = false;
     697             : 
     698       75274 :     CPLMutexHolderD(&hDLMutex);
     699             : 
     700       75274 :     if (poAllDatasetMap == nullptr)
     701       30703 :         poAllDatasetMap = new std::map<GDALDataset *, GIntBig>;
     702       75274 :     (*poAllDatasetMap)[this] = -1;
     703       75274 : }
     704             : 
     705             : /************************************************************************/
     706             : /*                             FlushCache()                             */
     707             : /************************************************************************/
     708             : 
     709             : /**
     710             :  * \brief Flush all write cached data to disk.
     711             :  *
     712             :  * Any raster (or other GDAL) data written via GDAL calls, but buffered
     713             :  * internally will be written to disk.
     714             :  *
     715             :  * The default implementation of this method just calls the FlushCache() method
     716             :  * on each of the raster bands and the SyncToDisk() method
     717             :  * on each of the layers.  Conceptually, calling FlushCache() on a dataset
     718             :  * should include any work that might be accomplished by calling SyncToDisk()
     719             :  * on layers in that dataset.
     720             :  *
     721             :  * Using this method does not prevent use from calling GDALClose()
     722             :  * to properly close a dataset and ensure that important data not addressed
     723             :  * by FlushCache() is written in the file.
     724             :  *
     725             :  * This method is the same as the C function GDALFlushCache().
     726             :  *
     727             :  * @param bAtClosing Whether this is called from a GDALDataset destructor
     728             :  * @return CE_None in case of success (note: return value added in GDAL 3.7)
     729             :  */
     730             : 
     731      120789 : CPLErr GDALDataset::FlushCache(bool bAtClosing)
     732             : 
     733             : {
     734      120789 :     CPLErr eErr = CE_None;
     735             :     // This sometimes happens if a dataset is destroyed before completely
     736             :     // built.
     737             : 
     738      120789 :     if (papoBands)
     739             :     {
     740     1936310 :         for (int i = 0; i < nBands; ++i)
     741             :         {
     742     1829450 :             if (papoBands[i])
     743             :             {
     744     1829450 :                 if (papoBands[i]->FlushCache(bAtClosing) != CE_None)
     745           7 :                     eErr = CE_Failure;
     746             :             }
     747             :         }
     748             :     }
     749             : 
     750      120789 :     const int nLayers = GetLayerCount();
     751             :     // cppcheck-suppress knownConditionTrueFalse
     752      120789 :     if (nLayers > 0)
     753             :     {
     754       16746 :         CPLMutexHolderD(m_poPrivate ? &(m_poPrivate->hMutex) : nullptr);
     755       26148 :         for (int i = 0; i < nLayers; ++i)
     756             :         {
     757       17775 :             OGRLayer *poLayer = GetLayer(i);
     758             : 
     759       17775 :             if (poLayer)
     760             :             {
     761       17775 :                 if (poLayer->SyncToDisk() != OGRERR_NONE)
     762           1 :                     eErr = CE_Failure;
     763             :             }
     764             :         }
     765             :     }
     766             : 
     767      120789 :     return eErr;
     768             : }
     769             : 
     770             : /************************************************************************/
     771             : /*                           GDALFlushCache()                           */
     772             : /************************************************************************/
     773             : 
     774             : /**
     775             :  * \brief Flush all write cached data to disk.
     776             :  *
     777             :  * @see GDALDataset::FlushCache().
     778             :  * @return CE_None in case of success (note: return value added in GDAL 3.7)
     779             :  */
     780             : 
     781        5055 : CPLErr CPL_STDCALL GDALFlushCache(GDALDatasetH hDS)
     782             : 
     783             : {
     784        5055 :     VALIDATE_POINTER1(hDS, "GDALFlushCache", CE_Failure);
     785             : 
     786        5055 :     return GDALDataset::FromHandle(hDS)->FlushCache(false);
     787             : }
     788             : 
     789             : /************************************************************************/
     790             : /*                             DropCache()                              */
     791             : /************************************************************************/
     792             : 
     793             : /**
     794             : * \brief Drop all write cached data
     795             : *
     796             : * This method is the same as the C function GDALDropCache().
     797             : *
     798             : * @return CE_None in case of success
     799             : * @since 3.9
     800             : */
     801             : 
     802           1 : CPLErr GDALDataset::DropCache()
     803             : 
     804             : {
     805           1 :     CPLErr eErr = CE_None;
     806             : 
     807           1 :     if (papoBands)
     808             :     {
     809           2 :         for (int i = 0; i < nBands; ++i)
     810             :         {
     811           1 :             if (papoBands[i])
     812             :             {
     813           1 :                 if (papoBands[i]->DropCache() != CE_None)
     814           0 :                     eErr = CE_Failure;
     815             :             }
     816             :         }
     817             :     }
     818             : 
     819           1 :     return eErr;
     820             : }
     821             : 
     822             : /************************************************************************/
     823             : /*                           GDALDropCache()                           */
     824             : /************************************************************************/
     825             : 
     826             : /**
     827             : * \brief Drop all write cached data
     828             : *
     829             : * @see GDALDataset::DropCache().
     830             : * @return CE_None in case of success
     831             : * @since 3.9
     832             : */
     833             : 
     834           0 : CPLErr CPL_STDCALL GDALDropCache(GDALDatasetH hDS)
     835             : 
     836             : {
     837           0 :     VALIDATE_POINTER1(hDS, "GDALDropCache", CE_Failure);
     838             : 
     839           0 :     return GDALDataset::FromHandle(hDS)->DropCache();
     840             : }
     841             : 
     842             : /************************************************************************/
     843             : /*                      GetEstimatedRAMUsage()                          */
     844             : /************************************************************************/
     845             : 
     846             : /**
     847             :  * \brief Return the intrinsic RAM usage of this dataset.
     848             :  *
     849             :  * The returned value should take into account caches in the underlying driver
     850             :  * and decoding library, but not the usage related to the GDAL block cache.
     851             :  *
     852             :  * At time of writing, this method is only implemented in the JP2OpenJPEG
     853             :  * driver. For single-tiled JPEG2000 images, the decoding of the image,
     854             :  * even partially, involves allocating at least
     855             :  * width * height * number_of_bands * sizeof(uint32_t) bytes inside the libopenjp2
     856             :  * library.
     857             :  *
     858             :  * This method is used by the GDALDatasetPool class, itself used by the GDAL VRT
     859             :  * driver, to determine how long a dataset in the pool must be kept open, given
     860             :  * the RAM usage of the dataset with respect to the usable total RAM.
     861             :  *
     862             :  * @since GDAL 3.7
     863             :  * @return RAM usage in bytes, or -1 if unknown (the default implementation
     864             :  * returns -1)
     865             :  */
     866             : 
     867        3338 : GIntBig GDALDataset::GetEstimatedRAMUsage()
     868             : {
     869        3338 :     return -1;
     870             : }
     871             : 
     872             : /************************************************************************/
     873             : /*                        BlockBasedFlushCache()                        */
     874             : /*                                                                      */
     875             : /*      This helper method can be called by the                         */
     876             : /*      GDALDataset::FlushCache() for particular drivers to ensure      */
     877             : /*      that buffers will be flushed in a manner suitable for pixel     */
     878             : /*      interleaved (by block) IO.  That is, if all the bands have      */
     879             : /*      the same size blocks then a given block will be flushed for     */
     880             : /*      all bands before proceeding to the next block.                  */
     881             : /************************************************************************/
     882             : 
     883             : //! @cond Doxygen_Suppress
     884         350 : CPLErr GDALDataset::BlockBasedFlushCache(bool bAtClosing)
     885             : 
     886             : {
     887         350 :     GDALRasterBand *poBand1 = GetRasterBand(1);
     888         350 :     if (poBand1 == nullptr || (IsMarkedSuppressOnClose() && bAtClosing))
     889             :     {
     890           7 :         return GDALDataset::FlushCache(bAtClosing);
     891             :     }
     892             : 
     893         343 :     int nBlockXSize = 0;
     894         343 :     int nBlockYSize = 0;
     895         343 :     poBand1->GetBlockSize(&nBlockXSize, &nBlockYSize);
     896             : 
     897             :     /* -------------------------------------------------------------------- */
     898             :     /*      Verify that all bands match.                                    */
     899             :     /* -------------------------------------------------------------------- */
     900        1108 :     for (int iBand = 1; iBand < nBands; ++iBand)
     901             :     {
     902         765 :         GDALRasterBand *poBand = GetRasterBand(iBand + 1);
     903             : 
     904             :         int nThisBlockXSize, nThisBlockYSize;
     905         765 :         poBand->GetBlockSize(&nThisBlockXSize, &nThisBlockYSize);
     906         765 :         if (nThisBlockXSize != nBlockXSize && nThisBlockYSize != nBlockYSize)
     907             :         {
     908           0 :             return GDALDataset::FlushCache(bAtClosing);
     909             :         }
     910             :     }
     911             : 
     912             :     /* -------------------------------------------------------------------- */
     913             :     /*      Now flush writable data.                                        */
     914             :     /* -------------------------------------------------------------------- */
     915         794 :     for (int iY = 0; iY < poBand1->nBlocksPerColumn; ++iY)
     916             :     {
     917         991 :         for (int iX = 0; iX < poBand1->nBlocksPerRow; ++iX)
     918             :         {
     919        1690 :             for (int iBand = 0; iBand < nBands; ++iBand)
     920             :             {
     921        1150 :                 const CPLErr eErr = papoBands[iBand]->FlushBlock(iX, iY);
     922             : 
     923        1150 :                 if (eErr != CE_None)
     924           0 :                     return CE_Failure;
     925             :             }
     926             :         }
     927             :     }
     928         343 :     return CE_None;
     929             : }
     930             : 
     931             : /************************************************************************/
     932             : /*                          RasterInitialize()                          */
     933             : /*                                                                      */
     934             : /*      Initialize raster size                                          */
     935             : /************************************************************************/
     936             : 
     937           0 : void GDALDataset::RasterInitialize(int nXSize, int nYSize)
     938             : 
     939             : {
     940           0 :     CPLAssert(nXSize > 0 && nYSize > 0);
     941             : 
     942           0 :     nRasterXSize = nXSize;
     943           0 :     nRasterYSize = nYSize;
     944           0 : }
     945             : 
     946             : //! @endcond
     947             : 
     948             : /************************************************************************/
     949             : /*                              AddBand()                               */
     950             : /************************************************************************/
     951             : 
     952             : /**
     953             :  * \fn GDALDataset::AddBand(GDALDataType, char**)
     954             :  * \brief Add a band to a dataset.
     955             :  *
     956             :  * This method will add a new band to the dataset if the underlying format
     957             :  * supports this action.  Most formats do not.
     958             :  *
     959             :  * Note that the new GDALRasterBand is not returned.  It may be fetched
     960             :  * after successful completion of the method by calling
     961             :  * GDALDataset::GetRasterBand(GDALDataset::GetRasterCount()) as the newest
     962             :  * band will always be the last band.
     963             :  *
     964             :  * @param eType the data type of the pixels in the new band.
     965             :  *
     966             :  * @param papszOptions a list of NAME=VALUE option strings.  The supported
     967             :  * options are format specific.  NULL may be passed by default.
     968             :  *
     969             :  * @return CE_None on success or CE_Failure on failure.
     970             :  */
     971             : 
     972           0 : CPLErr GDALDataset::AddBand(CPL_UNUSED GDALDataType eType,
     973             :                             CPL_UNUSED char **papszOptions)
     974             : 
     975             : {
     976           0 :     ReportError(CE_Failure, CPLE_NotSupported,
     977             :                 "Dataset does not support the AddBand() method.");
     978             : 
     979           0 :     return CE_Failure;
     980             : }
     981             : 
     982             : /************************************************************************/
     983             : /*                            GDALAddBand()                             */
     984             : /************************************************************************/
     985             : 
     986             : /**
     987             :  * \brief Add a band to a dataset.
     988             :  *
     989             :  * @see GDALDataset::AddBand().
     990             :  */
     991             : 
     992          32 : CPLErr CPL_STDCALL GDALAddBand(GDALDatasetH hDataset, GDALDataType eType,
     993             :                                CSLConstList papszOptions)
     994             : 
     995             : {
     996          32 :     VALIDATE_POINTER1(hDataset, "GDALAddBand", CE_Failure);
     997             : 
     998          64 :     return GDALDataset::FromHandle(hDataset)->AddBand(
     999          32 :         eType, const_cast<char **>(papszOptions));
    1000             : }
    1001             : 
    1002             : /************************************************************************/
    1003             : /*                              SetBand()                               */
    1004             : /************************************************************************/
    1005             : 
    1006             : //! @cond Doxygen_Suppress
    1007             : /**  Set a band in the band array, updating the band count, and array size
    1008             :  * appropriately.
    1009             :  *
    1010             :  * @param nNewBand new band number (indexing starts at 1)
    1011             :  * @param poBand band object.
    1012             :  */
    1013             : 
    1014     1680260 : void GDALDataset::SetBand(int nNewBand, GDALRasterBand *poBand)
    1015             : 
    1016             : {
    1017             :     /* -------------------------------------------------------------------- */
    1018             :     /*      Do we need to grow the bands list?                              */
    1019             :     /* -------------------------------------------------------------------- */
    1020     1680260 :     if (nBands < nNewBand || papoBands == nullptr)
    1021             :     {
    1022      945092 :         GDALRasterBand **papoNewBands = nullptr;
    1023             : 
    1024      945092 :         if (papoBands == nullptr)
    1025       97851 :             papoNewBands = static_cast<GDALRasterBand **>(VSICalloc(
    1026       97851 :                 sizeof(GDALRasterBand *), std::max(nNewBand, nBands)));
    1027             :         else
    1028             :             papoNewBands = static_cast<GDALRasterBand **>(
    1029      847241 :                 VSIRealloc(papoBands, sizeof(GDALRasterBand *) *
    1030      847241 :                                           std::max(nNewBand, nBands)));
    1031      945092 :         if (papoNewBands == nullptr)
    1032             :         {
    1033           0 :             ReportError(CE_Failure, CPLE_OutOfMemory,
    1034             :                         "Cannot allocate band array");
    1035           0 :             return;
    1036             :         }
    1037             : 
    1038      945092 :         papoBands = papoNewBands;
    1039             : 
    1040     1838970 :         for (int i = nBands; i < nNewBand; ++i)
    1041      893880 :             papoBands[i] = nullptr;
    1042             : 
    1043      945092 :         nBands = std::max(nBands, nNewBand);
    1044             : 
    1045      945092 :         if (m_poPrivate)
    1046             :         {
    1047      945092 :             for (int i = static_cast<int>(m_poPrivate->m_anBandMap.size());
    1048     2625350 :                  i < nBands; ++i)
    1049             :             {
    1050     1680260 :                 m_poPrivate->m_anBandMap.push_back(i + 1);
    1051             :             }
    1052             :         }
    1053             :     }
    1054             : 
    1055             :     /* -------------------------------------------------------------------- */
    1056             :     /*      Set the band.  Resetting the band is currently not permitted.   */
    1057             :     /* -------------------------------------------------------------------- */
    1058     1680260 :     if (papoBands[nNewBand - 1] != nullptr)
    1059             :     {
    1060           0 :         ReportError(CE_Failure, CPLE_NotSupported,
    1061             :                     "Cannot set band %d as it is already set", nNewBand);
    1062           0 :         return;
    1063             :     }
    1064             : 
    1065     1680260 :     papoBands[nNewBand - 1] = poBand;
    1066             : 
    1067             :     /* -------------------------------------------------------------------- */
    1068             :     /*      Set back reference information on the raster band.  Note        */
    1069             :     /*      that the GDALDataset is a friend of the GDALRasterBand          */
    1070             :     /*      specifically to allow this.                                     */
    1071             :     /* -------------------------------------------------------------------- */
    1072     1680260 :     poBand->nBand = nNewBand;
    1073     1680260 :     poBand->poDS = this;
    1074     1680260 :     poBand->nRasterXSize = nRasterXSize;
    1075     1680260 :     poBand->nRasterYSize = nRasterYSize;
    1076     1680260 :     poBand->eAccess = eAccess;  // Default access to be same as dataset.
    1077             : }
    1078             : 
    1079             : //! @endcond
    1080             : 
    1081             : /************************************************************************/
    1082             : /*                              SetBand()                               */
    1083             : /************************************************************************/
    1084             : 
    1085             : //! @cond Doxygen_Suppress
    1086             : /**  Set a band in the band array, updating the band count, and array size
    1087             :  * appropriately.
    1088             :  *
    1089             :  * @param nNewBand new band number (indexing starts at 1)
    1090             :  * @param poBand band object.
    1091             :  */
    1092             : 
    1093     1109450 : void GDALDataset::SetBand(int nNewBand, std::unique_ptr<GDALRasterBand> poBand)
    1094             : {
    1095     1109450 :     SetBand(nNewBand, poBand.release());
    1096     1109450 : }
    1097             : 
    1098             : //! @endcond
    1099             : 
    1100             : /************************************************************************/
    1101             : /*                           GetRasterXSize()                           */
    1102             : /************************************************************************/
    1103             : 
    1104             : /**
    1105             : 
    1106             :  \brief Fetch raster width in pixels.
    1107             : 
    1108             :  Equivalent of the C function GDALGetRasterXSize().
    1109             : 
    1110             :  @return the width in pixels of raster bands in this GDALDataset.
    1111             : 
    1112             : */
    1113             : 
    1114      713628 : int GDALDataset::GetRasterXSize() const
    1115             : {
    1116      713628 :     return nRasterXSize;
    1117             : }
    1118             : 
    1119             : /************************************************************************/
    1120             : /*                         GDALGetRasterXSize()                         */
    1121             : /************************************************************************/
    1122             : 
    1123             : /**
    1124             :  * \brief Fetch raster width in pixels.
    1125             :  *
    1126             :  * @see GDALDataset::GetRasterXSize().
    1127             :  */
    1128             : 
    1129       37790 : int CPL_STDCALL GDALGetRasterXSize(GDALDatasetH hDataset)
    1130             : 
    1131             : {
    1132       37790 :     VALIDATE_POINTER1(hDataset, "GDALGetRasterXSize", 0);
    1133             : 
    1134       37790 :     return GDALDataset::FromHandle(hDataset)->GetRasterXSize();
    1135             : }
    1136             : 
    1137             : /************************************************************************/
    1138             : /*                           GetRasterYSize()                           */
    1139             : /************************************************************************/
    1140             : 
    1141             : /**
    1142             : 
    1143             :  \brief Fetch raster height in pixels.
    1144             : 
    1145             :  Equivalent of the C function GDALGetRasterYSize().
    1146             : 
    1147             :  @return the height in pixels of raster bands in this GDALDataset.
    1148             : 
    1149             : */
    1150             : 
    1151      604431 : int GDALDataset::GetRasterYSize() const
    1152             : {
    1153      604431 :     return nRasterYSize;
    1154             : }
    1155             : 
    1156             : /************************************************************************/
    1157             : /*                         GDALGetRasterYSize()                         */
    1158             : /************************************************************************/
    1159             : 
    1160             : /**
    1161             :  * \brief Fetch raster height in pixels.
    1162             :  *
    1163             :  * @see GDALDataset::GetRasterYSize().
    1164             :  */
    1165             : 
    1166       37402 : int CPL_STDCALL GDALGetRasterYSize(GDALDatasetH hDataset)
    1167             : 
    1168             : {
    1169       37402 :     VALIDATE_POINTER1(hDataset, "GDALGetRasterYSize", 0);
    1170             : 
    1171       37402 :     return GDALDataset::FromHandle(hDataset)->GetRasterYSize();
    1172             : }
    1173             : 
    1174             : /************************************************************************/
    1175             : /*                           GetRasterBand()                            */
    1176             : /************************************************************************/
    1177             : 
    1178             : /**
    1179             : 
    1180             :  \brief Fetch a band object for a dataset.
    1181             : 
    1182             :  See GetBands() for a C++ iterator version of this method.
    1183             : 
    1184             :  Equivalent of the C function GDALGetRasterBand().
    1185             : 
    1186             :  @param nBandId the index number of the band to fetch, from 1 to
    1187             :                 GetRasterCount().
    1188             : 
    1189             :  @return the nBandId th band object
    1190             : 
    1191             : */
    1192             : 
    1193    12576500 : GDALRasterBand *GDALDataset::GetRasterBand(int nBandId)
    1194             : 
    1195             : {
    1196    12576500 :     if (papoBands)
    1197             :     {
    1198    12576500 :         if (nBandId < 1 || nBandId > nBands)
    1199             :         {
    1200          12 :             ReportError(CE_Failure, CPLE_IllegalArg,
    1201             :                         "GDALDataset::GetRasterBand(%d) - Illegal band #\n",
    1202             :                         nBandId);
    1203          12 :             return nullptr;
    1204             :         }
    1205             : 
    1206    12576500 :         return papoBands[nBandId - 1];
    1207             :     }
    1208          13 :     return nullptr;
    1209             : }
    1210             : 
    1211             : /************************************************************************/
    1212             : /*                           GetRasterBand()                            */
    1213             : /************************************************************************/
    1214             : 
    1215             : /**
    1216             : 
    1217             :  \brief Fetch a band object for a dataset.
    1218             : 
    1219             :  See GetBands() for a C++ iterator version of this method.
    1220             : 
    1221             :  Equivalent of the C function GDALGetRasterBand().
    1222             : 
    1223             :  @param nBandId the index number of the band to fetch, from 1 to
    1224             :                 GetRasterCount().
    1225             : 
    1226             :  @return the nBandId th band object
    1227             : 
    1228             : */
    1229             : 
    1230         594 : const GDALRasterBand *GDALDataset::GetRasterBand(int nBandId) const
    1231             : 
    1232             : {
    1233         594 :     if (papoBands)
    1234             :     {
    1235         594 :         if (nBandId < 1 || nBandId > nBands)
    1236             :         {
    1237           0 :             ReportError(CE_Failure, CPLE_IllegalArg,
    1238             :                         "GDALDataset::GetRasterBand(%d) - Illegal band #\n",
    1239             :                         nBandId);
    1240           0 :             return nullptr;
    1241             :         }
    1242             : 
    1243         594 :         return papoBands[nBandId - 1];
    1244             :     }
    1245           0 :     return nullptr;
    1246             : }
    1247             : 
    1248             : /************************************************************************/
    1249             : /*                         GDALGetRasterBand()                          */
    1250             : /************************************************************************/
    1251             : 
    1252             : /**
    1253             :  * \brief Fetch a band object for a dataset.
    1254             :  * @see GDALDataset::GetRasterBand().
    1255             :  */
    1256             : 
    1257      403285 : GDALRasterBandH CPL_STDCALL GDALGetRasterBand(GDALDatasetH hDS, int nBandId)
    1258             : 
    1259             : {
    1260      403285 :     VALIDATE_POINTER1(hDS, "GDALGetRasterBand", nullptr);
    1261             : 
    1262      403285 :     return GDALRasterBand::ToHandle(
    1263      403285 :         GDALDataset::FromHandle(hDS)->GetRasterBand(nBandId));
    1264             : }
    1265             : 
    1266             : /************************************************************************/
    1267             : /*                           GetRasterCount()                           */
    1268             : /************************************************************************/
    1269             : 
    1270             : /**
    1271             :  * \brief Fetch the number of raster bands on this dataset.
    1272             :  *
    1273             :  * Same as the C function GDALGetRasterCount().
    1274             :  *
    1275             :  * @return the number of raster bands.
    1276             :  */
    1277             : 
    1278     6425770 : int GDALDataset::GetRasterCount() const
    1279             : {
    1280     6425770 :     return papoBands ? nBands : 0;
    1281             : }
    1282             : 
    1283             : /************************************************************************/
    1284             : /*                         GDALGetRasterCount()                         */
    1285             : /************************************************************************/
    1286             : 
    1287             : /**
    1288             :  * \brief Fetch the number of raster bands on this dataset.
    1289             :  *
    1290             :  * @see GDALDataset::GetRasterCount().
    1291             :  */
    1292             : 
    1293      383257 : int CPL_STDCALL GDALGetRasterCount(GDALDatasetH hDS)
    1294             : 
    1295             : {
    1296      383257 :     VALIDATE_POINTER1(hDS, "GDALGetRasterCount", 0);
    1297             : 
    1298      383257 :     return GDALDataset::FromHandle(hDS)->GetRasterCount();
    1299             : }
    1300             : 
    1301             : /************************************************************************/
    1302             : /*                          GetProjectionRef()                          */
    1303             : /************************************************************************/
    1304             : 
    1305             : /**
    1306             :  * \brief Fetch the projection definition string for this dataset.
    1307             :  *
    1308             :  * Same as the C function GDALGetProjectionRef().
    1309             :  *
    1310             :  * The returned string defines the projection coordinate system of the
    1311             :  * image in OpenGIS WKT format.  It should be suitable for use with the
    1312             :  * OGRSpatialReference class.
    1313             :  *
    1314             :  * When a projection definition is not available an empty (but not NULL)
    1315             :  * string is returned.
    1316             :  *
    1317             :  * \note Starting with GDAL 3.0, this is a compatibility layer around
    1318             :  * GetSpatialRef()
    1319             :  *
    1320             :  * @return a pointer to an internal projection reference string.  It should
    1321             :  * not be altered, freed or expected to last for long.
    1322             :  *
    1323             :  * @see https://gdal.org/tutorials/osr_api_tut.html
    1324             :  */
    1325             : 
    1326        5409 : const char *GDALDataset::GetProjectionRef() const
    1327             : {
    1328        5409 :     const auto poSRS = GetSpatialRef();
    1329        5409 :     if (!poSRS || !m_poPrivate)
    1330             :     {
    1331        2429 :         return "";
    1332             :     }
    1333        2980 :     char *pszWKT = nullptr;
    1334        2980 :     poSRS->exportToWkt(&pszWKT);
    1335        2980 :     if (!pszWKT)
    1336             :     {
    1337           0 :         return "";
    1338             :     }
    1339             : 
    1340             :     // If called on a thread-safe dataset, we might be called by several
    1341             :     // threads, so make sure our accesses to m_pszWKTCached are protected
    1342             :     // by a mutex.
    1343        5960 :     std::lock_guard oLock(m_poPrivate->m_oMutexWKT);
    1344        2980 :     if (m_poPrivate->m_pszWKTCached &&
    1345         793 :         strcmp(pszWKT, m_poPrivate->m_pszWKTCached) == 0)
    1346             :     {
    1347         792 :         CPLFree(pszWKT);
    1348         792 :         return m_poPrivate->m_pszWKTCached;
    1349             :     }
    1350        2188 :     CPLFree(m_poPrivate->m_pszWKTCached);
    1351        2188 :     m_poPrivate->m_pszWKTCached = pszWKT;
    1352        2188 :     return m_poPrivate->m_pszWKTCached;
    1353             : }
    1354             : 
    1355             : /************************************************************************/
    1356             : /*                           GetSpatialRef()                            */
    1357             : /************************************************************************/
    1358             : 
    1359             : static thread_local int tlsEnableLayersInGetSpatialRefCounter = 0;
    1360             : 
    1361             : /**
    1362             :  * \brief Fetch the spatial reference for this dataset.
    1363             :  *
    1364             :  * Same as the C function GDALGetSpatialRef().
    1365             :  *
    1366             :  * When a projection definition is not available, null is returned. If used on
    1367             :  * a dataset where there are GCPs and not a geotransform, this method returns
    1368             :  * null. Use GetGCPSpatialRef() instead.
    1369             :  *
    1370             :  * Since GDAL 3.12, the default implementation of this method will iterate over
    1371             :  * vector layers and return their SRS if all geometry columns of all layers use
    1372             :  * the same SRS, or nullptr otherwise.
    1373             :  *
    1374             :  * @since GDAL 3.0
    1375             :  *
    1376             :  * @return a pointer to an internal object. It should not be altered or freed.
    1377             :  * Its lifetime will be the one of the dataset object.
    1378             :  *
    1379             :  * @see https://gdal.org/tutorials/osr_api_tut.html
    1380             :  */
    1381             : 
    1382       17603 : const OGRSpatialReference *GDALDataset::GetSpatialRef() const
    1383             : {
    1384       17603 :     if (tlsEnableLayersInGetSpatialRefCounter == 0)
    1385       17553 :         return GetSpatialRefVectorOnly();
    1386          50 :     return nullptr;
    1387             : }
    1388             : 
    1389             : /************************************************************************/
    1390             : /*                       GetSpatialRefVectorOnly()                      */
    1391             : /************************************************************************/
    1392             : 
    1393             : /**
    1394             :  * \brief Fetch the spatial reference for this dataset (only for vector layers)
    1395             :  *
    1396             :  * The default implementation of this method will iterate over
    1397             :  * vector layers and return their SRS if all geometry columns of all layers use
    1398             :  * the same SRS, or nullptr otherwise.
    1399             :  *
    1400             :  * @since GDAL 3.12
    1401             :  *
    1402             :  * @return a pointer to an internal object. It should not be altered or freed.
    1403             :  * Its lifetime will be the one of the dataset object.
    1404             :  */
    1405             : 
    1406       17553 : const OGRSpatialReference *GDALDataset::GetSpatialRefVectorOnly() const
    1407             : {
    1408       17553 :     bool bInit = false;
    1409       17553 :     const OGRSpatialReference *poGlobalSRS = nullptr;
    1410       33716 :     for (const OGRLayer *poLayer : GetLayers())
    1411             :     {
    1412       16164 :         for (const auto *poGeomFieldDefn :
    1413       48494 :              poLayer->GetLayerDefn()->GetGeomFields())
    1414             :         {
    1415       16167 :             const auto *poSRS = poGeomFieldDefn->GetSpatialRef();
    1416       16167 :             if (!bInit)
    1417             :             {
    1418         207 :                 bInit = true;
    1419         207 :                 poGlobalSRS = poSRS;
    1420             :             }
    1421       31918 :             else if ((poSRS && !poGlobalSRS) || (!poSRS && poGlobalSRS) ||
    1422       15958 :                      (poSRS && poGlobalSRS && !poSRS->IsSame(poGlobalSRS)))
    1423             :             {
    1424           3 :                 CPLDebug("GDAL",
    1425             :                          "Not all geometry fields or layers have the same CRS");
    1426           3 :                 return nullptr;
    1427             :             }
    1428             :         }
    1429             :     }
    1430       17550 :     return poGlobalSRS;
    1431             : }
    1432             : 
    1433             : /************************************************************************/
    1434             : /*                       GetSpatialRefRasterOnly()                      */
    1435             : /************************************************************************/
    1436             : 
    1437             : /**
    1438             :  * \brief Fetch the spatial reference for this dataset (ignoring vector layers)
    1439             :  *
    1440             :  * @since GDAL 3.12
    1441             :  *
    1442             :  * @return a pointer to an internal object. It should not be altered or freed.
    1443             :  * Its lifetime will be the one of the dataset object.
    1444             :  */
    1445             : 
    1446         901 : const OGRSpatialReference *GDALDataset::GetSpatialRefRasterOnly() const
    1447             : {
    1448         901 :     ++tlsEnableLayersInGetSpatialRefCounter;
    1449         901 :     const auto poRet = GetSpatialRef();
    1450         901 :     --tlsEnableLayersInGetSpatialRefCounter;
    1451         901 :     return poRet;
    1452             : }
    1453             : 
    1454             : /************************************************************************/
    1455             : /*                        GDALGetSpatialRef()                           */
    1456             : /************************************************************************/
    1457             : 
    1458             : /**
    1459             :  * \brief Fetch the spatial reference for this dataset.
    1460             :  *
    1461             :  * Same as the C++ method GDALDataset::GetSpatialRef()
    1462             :  *
    1463             :  * @since GDAL 3.0
    1464             :  *
    1465             :  * @see GDALDataset::GetSpatialRef()
    1466             :  */
    1467             : 
    1468        7135 : OGRSpatialReferenceH GDALGetSpatialRef(GDALDatasetH hDS)
    1469             : 
    1470             : {
    1471        7135 :     VALIDATE_POINTER1(hDS, "GDALGetSpatialRef", nullptr);
    1472             : 
    1473        7135 :     return OGRSpatialReference::ToHandle(const_cast<OGRSpatialReference *>(
    1474        7135 :         GDALDataset::FromHandle(hDS)->GetSpatialRef()));
    1475             : }
    1476             : 
    1477             : /************************************************************************/
    1478             : /*                        GDALGetProjectionRef()                        */
    1479             : /************************************************************************/
    1480             : 
    1481             : /**
    1482             :  * \brief Fetch the projection definition string for this dataset.
    1483             :  *
    1484             :  * @see GDALDataset::GetProjectionRef()
    1485             :  */
    1486             : 
    1487        1501 : const char *CPL_STDCALL GDALGetProjectionRef(GDALDatasetH hDS)
    1488             : 
    1489             : {
    1490        1501 :     VALIDATE_POINTER1(hDS, "GDALGetProjectionRef", nullptr);
    1491             : 
    1492        1501 :     return GDALDataset::FromHandle(hDS)->GetProjectionRef();
    1493             : }
    1494             : 
    1495             : /************************************************************************/
    1496             : /*                           SetProjection()                            */
    1497             : /************************************************************************/
    1498             : 
    1499             : /**
    1500             :  * \brief Set the projection reference string for this dataset.
    1501             :  *
    1502             :  * The string should be in OGC WKT or PROJ.4 format.  An error may occur
    1503             :  * because of incorrectly specified projection strings, because the dataset
    1504             :  * is not writable, or because the dataset does not support the indicated
    1505             :  * projection.  Many formats do not support writing projections.
    1506             :  *
    1507             :  * This method is the same as the C GDALSetProjection() function.
    1508             :  *
    1509             :  * \note Startig with GDAL 3.0, this is a compatibility layer around
    1510             :  * SetSpatialRef()
    1511             : 
    1512             :  * @param pszProjection projection reference string.
    1513             :  *
    1514             :  * @return CE_Failure if an error occurs, otherwise CE_None.
    1515             :  */
    1516             : 
    1517        2482 : CPLErr GDALDataset::SetProjection(const char *pszProjection)
    1518             : {
    1519        2482 :     if (pszProjection && pszProjection[0] != '\0')
    1520             :     {
    1521        4598 :         OGRSpatialReference oSRS;
    1522        2299 :         oSRS.SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
    1523        2299 :         if (oSRS.SetFromUserInput(pszProjection) != OGRERR_NONE)
    1524             :         {
    1525           2 :             return CE_Failure;
    1526             :         }
    1527        2297 :         return SetSpatialRef(&oSRS);
    1528             :     }
    1529             :     else
    1530             :     {
    1531         183 :         return SetSpatialRef(nullptr);
    1532             :     }
    1533             : }
    1534             : 
    1535             : /************************************************************************/
    1536             : /*                           SetSpatialRef()                            */
    1537             : /************************************************************************/
    1538             : 
    1539             : /**
    1540             :  * \brief Set the spatial reference system for this dataset.
    1541             :  *
    1542             :  * An error may occur because the dataset
    1543             :  * is not writable, or because the dataset does not support the indicated
    1544             :  * projection. Many formats do not support writing projections.
    1545             :  *
    1546             :  * This method is the same as the C GDALSetSpatialRef() function.
    1547             :  *
    1548             :  * @since GDAL 3.0
    1549             : 
    1550             :  * @param poSRS spatial reference system object. nullptr can potentially be
    1551             :  * passed for drivers that support unsetting the SRS.
    1552             :  *
    1553             :  * @return CE_Failure if an error occurs, otherwise CE_None.
    1554             :  */
    1555             : 
    1556           0 : CPLErr GDALDataset::SetSpatialRef(CPL_UNUSED const OGRSpatialReference *poSRS)
    1557             : {
    1558           0 :     if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
    1559           0 :         ReportError(CE_Failure, CPLE_NotSupported,
    1560             :                     "Dataset does not support the SetSpatialRef() method.");
    1561           0 :     return CE_Failure;
    1562             : }
    1563             : 
    1564             : /************************************************************************/
    1565             : /*                         GDALSetSpatialRef()                          */
    1566             : /************************************************************************/
    1567             : 
    1568             : /**
    1569             :  * \brief Set the spatial reference system for this dataset.
    1570             :  *
    1571             :  * @since GDAL 3.0
    1572             :  *
    1573             :  * @see GDALDataset::SetSpatialRef()
    1574             :  */
    1575             : 
    1576        1301 : CPLErr GDALSetSpatialRef(GDALDatasetH hDS, OGRSpatialReferenceH hSRS)
    1577             : 
    1578             : {
    1579        1301 :     VALIDATE_POINTER1(hDS, "GDALSetSpatialRef", CE_Failure);
    1580             : 
    1581        2602 :     return GDALDataset::FromHandle(hDS)->SetSpatialRef(
    1582        1301 :         OGRSpatialReference::FromHandle(hSRS));
    1583             : }
    1584             : 
    1585             : /************************************************************************/
    1586             : /*                         GDALSetProjection()                          */
    1587             : /************************************************************************/
    1588             : 
    1589             : /**
    1590             :  * \brief Set the projection reference string for this dataset.
    1591             :  *
    1592             :  * @see GDALDataset::SetProjection()
    1593             :  */
    1594             : 
    1595        1849 : CPLErr CPL_STDCALL GDALSetProjection(GDALDatasetH hDS,
    1596             :                                      const char *pszProjection)
    1597             : 
    1598             : {
    1599        1849 :     VALIDATE_POINTER1(hDS, "GDALSetProjection", CE_Failure);
    1600             : 
    1601        1849 :     return GDALDataset::FromHandle(hDS)->SetProjection(pszProjection);
    1602             : }
    1603             : 
    1604             : /************************************************************************/
    1605             : /*                          GetGeoTransform()                           */
    1606             : /************************************************************************/
    1607             : 
    1608             : /**
    1609             :  * \brief Fetch the affine transformation coefficients.
    1610             :  *
    1611             :  * Fetches the coefficients for transforming between pixel/line (P,L) raster
    1612             :  * space, and projection coordinates (Xp,Yp) space.
    1613             :  *
    1614             :  * \code
    1615             :  *   Xp = gt[0] + P*gt[1] + L*gt[2];
    1616             :  *   Yp = gt[3] + P*padfTransform[4] + L*gt[5];
    1617             :  * \endcode
    1618             :  *
    1619             :  * In a north up image, gt[1] is the pixel width, and
    1620             :  * gt[5] is the pixel height.  The upper left corner of the
    1621             :  * upper left pixel is at position (gt[0],gt[3]).
    1622             :  *
    1623             :  * The default transform is (0,1,0,0,0,1) and should be returned even when
    1624             :  * a CE_Failure error is returned, such as for formats that don't support
    1625             :  * transformation to projection coordinates.
    1626             :  *
    1627             :  * This method does the same thing as the C GDALGetGeoTransform() function.
    1628             :  *
    1629             :  * @param gt an existing six double buffer into which the
    1630             :  * transformation will be placed.
    1631             :  *
    1632             :  * @return CE_None on success, or CE_Failure if no transform can be fetched.
    1633             :  *
    1634             :  * @since 3.12
    1635             :  */
    1636             : 
    1637       16004 : CPLErr GDALDataset::GetGeoTransform(GDALGeoTransform &gt) const
    1638             : 
    1639             : {
    1640       16004 :     gt = GDALGeoTransform();
    1641             : 
    1642       16004 :     return CE_Failure;
    1643             : }
    1644             : 
    1645             : /************************************************************************/
    1646             : /*                          GetGeoTransform()                           */
    1647             : /************************************************************************/
    1648             : 
    1649             : /**
    1650             :  * \brief Fetch the affine transformation coefficients.
    1651             :  *
    1652             :  * Fetches the coefficients for transforming between pixel/line (P,L) raster
    1653             :  * space, and projection coordinates (Xp,Yp) space.
    1654             :  *
    1655             :  * \code
    1656             :  *   Xp = padfTransform[0] + P*padfTransform[1] + L*padfTransform[2];
    1657             :  *   Yp = padfTransform[3] + P*padfTransform[4] + L*padfTransform[5];
    1658             :  * \endcode
    1659             :  *
    1660             :  * In a north up image, padfTransform[1] is the pixel width, and
    1661             :  * padfTransform[5] is the pixel height.  The upper left corner of the
    1662             :  * upper left pixel is at position (padfTransform[0],padfTransform[3]).
    1663             :  *
    1664             :  * The default transform is (0,1,0,0,0,1) and should be returned even when
    1665             :  * a CE_Failure error is returned, such as for formats that don't support
    1666             :  * transformation to projection coordinates.
    1667             :  *
    1668             :  * This method does the same thing as the C GDALGetGeoTransform() function.
    1669             :  *
    1670             :  * @param padfTransform an existing six double buffer into which the
    1671             :  * transformation will be placed.
    1672             :  *
    1673             :  * @return CE_None on success, or CE_Failure if no transform can be fetched.
    1674             :  *
    1675             :  * @deprecated since 3.12. Use GetGeoTransform(GDALGeoTransform&) instead
    1676             :  */
    1677             : 
    1678           2 : CPLErr GDALDataset::GetGeoTransform(double *padfTransform) const
    1679             : 
    1680             : {
    1681           2 :     return GetGeoTransform(
    1682           2 :         *reinterpret_cast<GDALGeoTransform *>(padfTransform));
    1683             : }
    1684             : 
    1685             : /************************************************************************/
    1686             : /*                        GDALGetGeoTransform()                         */
    1687             : /************************************************************************/
    1688             : 
    1689             : /**
    1690             :  * \brief Fetch the affine transformation coefficients.
    1691             :  *
    1692             :  * @see GDALDataset::GetGeoTransform()
    1693             :  */
    1694             : 
    1695        9291 : CPLErr CPL_STDCALL GDALGetGeoTransform(GDALDatasetH hDS, double *padfTransform)
    1696             : 
    1697             : {
    1698        9291 :     VALIDATE_POINTER1(hDS, "GDALGetGeoTransform", CE_Failure);
    1699             : 
    1700       18582 :     return GDALDataset::FromHandle(hDS)->GetGeoTransform(
    1701        9291 :         *reinterpret_cast<GDALGeoTransform *>(padfTransform));
    1702             : }
    1703             : 
    1704             : /************************************************************************/
    1705             : /*                          SetGeoTransform()                           */
    1706             : /************************************************************************/
    1707             : 
    1708             : /**
    1709             :  * \fn GDALDataset::SetGeoTransform(const GDALGeoTransform&)
    1710             :  * \brief Set the affine transformation coefficients.
    1711             :  *
    1712             :  * See GetGeoTransform() for details on the meaning of the padfTransform
    1713             :  * coefficients.
    1714             :  *
    1715             :  * This method does the same thing as the C GDALSetGeoTransform() function.
    1716             :  *
    1717             :  * @param gt the transformation coefficients to be written with the dataset.
    1718             :  *
    1719             :  * @return CE_None on success, or CE_Failure if this transform cannot be
    1720             :  * written.
    1721             :  *
    1722             :  * @since 3.12
    1723             :  */
    1724             : 
    1725           0 : CPLErr GDALDataset::SetGeoTransform(CPL_UNUSED const GDALGeoTransform &gt)
    1726             : 
    1727             : {
    1728           0 :     if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
    1729           0 :         ReportError(CE_Failure, CPLE_NotSupported,
    1730             :                     "SetGeoTransform() not supported for this dataset.");
    1731             : 
    1732           0 :     return CE_Failure;
    1733             : }
    1734             : 
    1735             : /************************************************************************/
    1736             : /*                          SetGeoTransform()                           */
    1737             : /************************************************************************/
    1738             : 
    1739             : /**
    1740             :  * \brief Set the affine transformation coefficients.
    1741             :  *
    1742             :  * See GetGeoTransform() for details on the meaning of the padfTransform
    1743             :  * coefficients.
    1744             :  *
    1745             :  * This method does the same thing as the C GDALSetGeoTransform() function.
    1746             :  *
    1747             :  * @param padfTransform a six double buffer containing the transformation
    1748             :  * coefficients to be written with the dataset.
    1749             :  *
    1750             :  * @return CE_None on success, or CE_Failure if this transform cannot be
    1751             :  * written.
    1752             :  *
    1753             :  * @deprecated since 3.12. Use SetGeoTransform(const GDALGeoTransform&) instead
    1754             :  */
    1755          30 : CPLErr GDALDataset::SetGeoTransform(const double *padfTransform)
    1756             : 
    1757             : {
    1758          30 :     return SetGeoTransform(
    1759          30 :         *reinterpret_cast<const GDALGeoTransform *>(padfTransform));
    1760             : }
    1761             : 
    1762             : /************************************************************************/
    1763             : /*                        GDALSetGeoTransform()                         */
    1764             : /************************************************************************/
    1765             : 
    1766             : /**
    1767             :  * \brief Set the affine transformation coefficients.
    1768             :  *
    1769             :  * @see GDALDataset::SetGeoTransform()
    1770             :  */
    1771             : 
    1772        4319 : CPLErr CPL_STDCALL GDALSetGeoTransform(GDALDatasetH hDS,
    1773             :                                        const double *padfTransform)
    1774             : 
    1775             : {
    1776        4319 :     VALIDATE_POINTER1(hDS, "GDALSetGeoTransform", CE_Failure);
    1777        4319 :     VALIDATE_POINTER1(padfTransform, "GDALSetGeoTransform", CE_Failure);
    1778             : 
    1779        8638 :     return GDALDataset::FromHandle(hDS)->SetGeoTransform(
    1780        4319 :         *reinterpret_cast<const GDALGeoTransform *>(padfTransform));
    1781             : }
    1782             : 
    1783             : /************************************************************************/
    1784             : /*                         GetInternalHandle()                          */
    1785             : /************************************************************************/
    1786             : 
    1787             : /**
    1788             :  * \fn GDALDataset::GetInternalHandle(const char*)
    1789             :  * \brief Fetch a format specific internally meaningful handle.
    1790             :  *
    1791             :  * This method is the same as the C GDALGetInternalHandle() method.
    1792             :  *
    1793             :  * @param pszHandleName the handle name desired.  The meaningful names
    1794             :  * will be specific to the file format.
    1795             :  *
    1796             :  * @return the desired handle value, or NULL if not recognized/supported.
    1797             :  */
    1798             : 
    1799         194 : void *GDALDataset::GetInternalHandle(CPL_UNUSED const char *pszHandleName)
    1800             : 
    1801             : {
    1802         194 :     return nullptr;
    1803             : }
    1804             : 
    1805             : /************************************************************************/
    1806             : /*                       GDALGetInternalHandle()                        */
    1807             : /************************************************************************/
    1808             : 
    1809             : /**
    1810             :  * \brief Fetch a format specific internally meaningful handle.
    1811             :  *
    1812             :  * @see GDALDataset::GetInternalHandle()
    1813             :  */
    1814             : 
    1815          61 : void *CPL_STDCALL GDALGetInternalHandle(GDALDatasetH hDS,
    1816             :                                         const char *pszRequest)
    1817             : 
    1818             : {
    1819          61 :     VALIDATE_POINTER1(hDS, "GDALGetInternalHandle", nullptr);
    1820             : 
    1821          61 :     return GDALDataset::FromHandle(hDS)->GetInternalHandle(pszRequest);
    1822             : }
    1823             : 
    1824             : /************************************************************************/
    1825             : /*                             GetDriver()                              */
    1826             : /************************************************************************/
    1827             : 
    1828             : /**
    1829             :  * \brief Fetch the driver to which this dataset relates.
    1830             :  *
    1831             :  * This method is the same as the C GDALGetDatasetDriver() function.
    1832             :  *
    1833             :  * @return the driver on which the dataset was created with GDALOpen() or
    1834             :  * GDALCreate().
    1835             :  */
    1836             : 
    1837       32422 : GDALDriver *GDALDataset::GetDriver()
    1838             : {
    1839       32422 :     return poDriver;
    1840             : }
    1841             : 
    1842             : /************************************************************************/
    1843             : /*                        GDALGetDatasetDriver()                        */
    1844             : /************************************************************************/
    1845             : 
    1846             : /**
    1847             :  * \brief Fetch the driver to which this dataset relates.
    1848             :  *
    1849             :  * @see GDALDataset::GetDriver()
    1850             :  */
    1851             : 
    1852        2706 : GDALDriverH CPL_STDCALL GDALGetDatasetDriver(GDALDatasetH hDataset)
    1853             : 
    1854             : {
    1855        2706 :     VALIDATE_POINTER1(hDataset, "GDALGetDatasetDriver", nullptr);
    1856             : 
    1857             :     return static_cast<GDALDriverH>(
    1858        2706 :         GDALDataset::FromHandle(hDataset)->GetDriver());
    1859             : }
    1860             : 
    1861             : /************************************************************************/
    1862             : /*                             Reference()                              */
    1863             : /************************************************************************/
    1864             : 
    1865             : /**
    1866             :  * \brief Add one to dataset reference count.
    1867             :  *
    1868             :  * The reference is one after instantiation.
    1869             :  *
    1870             :  * This method is the same as the C GDALReferenceDataset() function.
    1871             :  *
    1872             :  * @return the post-increment reference count.
    1873             :  */
    1874             : 
    1875      259334 : int GDALDataset::Reference()
    1876             : {
    1877      259334 :     return ++nRefCount;
    1878             : }
    1879             : 
    1880             : /************************************************************************/
    1881             : /*                        GDALReferenceDataset()                        */
    1882             : /************************************************************************/
    1883             : 
    1884             : /**
    1885             :  * \brief Add one to dataset reference count.
    1886             :  *
    1887             :  * @see GDALDataset::Reference()
    1888             :  */
    1889             : 
    1890        1300 : int CPL_STDCALL GDALReferenceDataset(GDALDatasetH hDataset)
    1891             : 
    1892             : {
    1893        1300 :     VALIDATE_POINTER1(hDataset, "GDALReferenceDataset", 0);
    1894             : 
    1895        1300 :     return GDALDataset::FromHandle(hDataset)->Reference();
    1896             : }
    1897             : 
    1898             : /************************************************************************/
    1899             : /*                            Dereference()                             */
    1900             : /************************************************************************/
    1901             : 
    1902             : /**
    1903             :  * \brief Subtract one from dataset reference count.
    1904             :  *
    1905             :  * The reference is one after instantiation.  Generally when the reference
    1906             :  * count has dropped to zero the dataset may be safely deleted (closed).
    1907             :  *
    1908             :  * This method is the same as the C GDALDereferenceDataset() function.
    1909             :  *
    1910             :  * @return the post-decrement reference count.
    1911             :  */
    1912             : 
    1913      319948 : int GDALDataset::Dereference()
    1914             : {
    1915      319948 :     return --nRefCount;
    1916             : }
    1917             : 
    1918             : /************************************************************************/
    1919             : /*                       GDALDereferenceDataset()                       */
    1920             : /************************************************************************/
    1921             : 
    1922             : /**
    1923             :  * \brief Subtract one from dataset reference count.
    1924             :  *
    1925             :  * @see GDALDataset::Dereference()
    1926             :  */
    1927             : 
    1928       58861 : int CPL_STDCALL GDALDereferenceDataset(GDALDatasetH hDataset)
    1929             : 
    1930             : {
    1931       58861 :     VALIDATE_POINTER1(hDataset, "GDALDereferenceDataset", 0);
    1932             : 
    1933       58861 :     return GDALDataset::FromHandle(hDataset)->Dereference();
    1934             : }
    1935             : 
    1936             : /************************************************************************/
    1937             : /*                            ReleaseRef()                              */
    1938             : /************************************************************************/
    1939             : 
    1940             : /**
    1941             :  * \brief Drop a reference to this object, and destroy if no longer referenced.
    1942             :  * @return TRUE if the object has been destroyed.
    1943             :  */
    1944             : 
    1945      251798 : int GDALDataset::ReleaseRef()
    1946             : 
    1947             : {
    1948      251798 :     if (Dereference() <= 0)
    1949             :     {
    1950        7445 :         nRefCount = 1;
    1951        7445 :         delete this;
    1952        7445 :         return TRUE;
    1953             :     }
    1954      244353 :     return FALSE;
    1955             : }
    1956             : 
    1957             : /************************************************************************/
    1958             : /*                        GDALReleaseDataset()                          */
    1959             : /************************************************************************/
    1960             : 
    1961             : /**
    1962             :  * \brief Drop a reference to this object, and destroy if no longer referenced.
    1963             :  *
    1964             :  * @see GDALDataset::ReleaseRef()
    1965             :  */
    1966             : 
    1967        1537 : int CPL_STDCALL GDALReleaseDataset(GDALDatasetH hDataset)
    1968             : 
    1969             : {
    1970        1537 :     VALIDATE_POINTER1(hDataset, "GDALReleaseDataset", 0);
    1971             : 
    1972        1537 :     return GDALDataset::FromHandle(hDataset)->ReleaseRef();
    1973             : }
    1974             : 
    1975             : /************************************************************************/
    1976             : /*                             GetShared()                              */
    1977             : /************************************************************************/
    1978             : 
    1979             : /**
    1980             :  * \brief Returns shared flag.
    1981             :  *
    1982             :  * @return TRUE if the GDALDataset is available for sharing, or FALSE if not.
    1983             :  */
    1984             : 
    1985      309873 : int GDALDataset::GetShared() const
    1986             : {
    1987      309873 :     return bShared;
    1988             : }
    1989             : 
    1990             : /************************************************************************/
    1991             : /*                            MarkAsShared()                            */
    1992             : /************************************************************************/
    1993             : 
    1994             : /**
    1995             :  * \brief Mark this dataset as available for sharing.
    1996             :  */
    1997             : 
    1998         435 : void GDALDataset::MarkAsShared()
    1999             : 
    2000             : {
    2001         435 :     CPLAssert(!bShared);
    2002             : 
    2003         435 :     bShared = true;
    2004         435 :     if (bIsInternal)
    2005          23 :         return;
    2006             : 
    2007         412 :     GIntBig nPID = GDALGetResponsiblePIDForCurrentThread();
    2008             : 
    2009             :     // Insert the dataset in the set of shared opened datasets.
    2010         824 :     CPLMutexHolderD(&hDLMutex);
    2011         412 :     if (phSharedDatasetSet == nullptr)
    2012         276 :         phSharedDatasetSet =
    2013         276 :             CPLHashSetNew(GDALSharedDatasetHashFunc, GDALSharedDatasetEqualFunc,
    2014             :                           GDALSharedDatasetFreeFunc);
    2015             : 
    2016             :     SharedDatasetCtxt *psStruct =
    2017         412 :         static_cast<SharedDatasetCtxt *>(CPLMalloc(sizeof(SharedDatasetCtxt)));
    2018         412 :     psStruct->poDS = this;
    2019         412 :     psStruct->nPID = nPID;
    2020         412 :     psStruct->nOpenFlags = nOpenFlags & ~GDAL_OF_SHARED;
    2021         412 :     psStruct->pszDescription = CPLStrdup(GetDescription());
    2022             :     std::string osConcatenatedOpenOptions =
    2023         824 :         GDALSharedDatasetConcatenateOpenOptions(papszOpenOptions);
    2024         412 :     psStruct->pszConcatenatedOpenOptions =
    2025         412 :         CPLStrdup(osConcatenatedOpenOptions.c_str());
    2026         412 :     if (CPLHashSetLookup(phSharedDatasetSet, psStruct) != nullptr)
    2027             :     {
    2028           1 :         GDALSharedDatasetFreeFunc(psStruct);
    2029           1 :         ReportError(CE_Failure, CPLE_AppDefined,
    2030             :                     "An existing shared dataset already has this description. "
    2031             :                     "This should not happen.");
    2032             :     }
    2033             :     else
    2034             :     {
    2035         411 :         CPLHashSetInsert(phSharedDatasetSet, psStruct);
    2036             : 
    2037         411 :         (*poAllDatasetMap)[this] = nPID;
    2038             :     }
    2039             : }
    2040             : 
    2041             : /************************************************************************/
    2042             : /*                        MarkSuppressOnClose()                         */
    2043             : /************************************************************************/
    2044             : 
    2045             : /** Set that the dataset must be deleted on close.
    2046             :  *
    2047             :  * This is the same as C function GDALDatasetMarkSuppressOnClose()
    2048             :  */
    2049        1230 : void GDALDataset::MarkSuppressOnClose()
    2050             : {
    2051        1230 :     bSuppressOnClose = true;
    2052        1230 : }
    2053             : 
    2054             : /************************************************************************/
    2055             : /*                   GDALDatasetMarkSuppressOnClose()                   */
    2056             : /************************************************************************/
    2057             : 
    2058             : /** Set that the dataset must be deleted on close.
    2059             :  *
    2060             :  * This is the same as C++ method GDALDataset::MarkSuppressOnClose()
    2061             :  *
    2062             :  * @since GDAL 3.12
    2063             :  */
    2064             : 
    2065           4 : void GDALDatasetMarkSuppressOnClose(GDALDatasetH hDS)
    2066             : {
    2067           4 :     VALIDATE_POINTER0(hDS, "GDALDatasetMarkSuppressOnClose");
    2068             : 
    2069           4 :     return GDALDataset::FromHandle(hDS)->MarkSuppressOnClose();
    2070             : }
    2071             : 
    2072             : /************************************************************************/
    2073             : /*                       UnMarkSuppressOnClose()                        */
    2074             : /************************************************************************/
    2075             : 
    2076             : /** Remove the flag requesting the dataset to be deleted on close. */
    2077         684 : void GDALDataset::UnMarkSuppressOnClose()
    2078             : {
    2079         684 :     bSuppressOnClose = false;
    2080         684 : }
    2081             : 
    2082             : /************************************************************************/
    2083             : /*                        CleanupPostFileClosing()                      */
    2084             : /************************************************************************/
    2085             : 
    2086             : /** This method should be called by driver implementations in their destructor,
    2087             :  * after having closed all files, but before having freed resources that
    2088             :  * are needed for their GetFileList() implementation.
    2089             :  * This is used to implement MarkSuppressOnClose behavior.
    2090             :  */
    2091         259 : void GDALDataset::CleanupPostFileClosing()
    2092             : {
    2093         259 :     if (IsMarkedSuppressOnClose())
    2094             :     {
    2095           1 :         char **papszFileList = GetFileList();
    2096           3 :         for (int i = 0; papszFileList && papszFileList[i]; ++i)
    2097           2 :             VSIUnlink(papszFileList[i]);
    2098           1 :         CSLDestroy(papszFileList);
    2099             :     }
    2100         259 : }
    2101             : 
    2102             : /************************************************************************/
    2103             : /*                            GetGCPCount()                             */
    2104             : /************************************************************************/
    2105             : 
    2106             : /**
    2107             :  * \brief Get number of GCPs.
    2108             :  *
    2109             :  * This method is the same as the C function GDALGetGCPCount().
    2110             :  *
    2111             :  * @return number of GCPs for this dataset.  Zero if there are none.
    2112             :  */
    2113             : 
    2114       16546 : int GDALDataset::GetGCPCount()
    2115             : {
    2116       16546 :     return 0;
    2117             : }
    2118             : 
    2119             : /************************************************************************/
    2120             : /*                          GDALGetGCPCount()                           */
    2121             : /************************************************************************/
    2122             : 
    2123             : /**
    2124             :  * \brief Get number of GCPs.
    2125             :  *
    2126             :  * @see GDALDataset::GetGCPCount()
    2127             :  */
    2128             : 
    2129        2160 : int CPL_STDCALL GDALGetGCPCount(GDALDatasetH hDS)
    2130             : 
    2131             : {
    2132        2160 :     VALIDATE_POINTER1(hDS, "GDALGetGCPCount", 0);
    2133             : 
    2134        2160 :     return GDALDataset::FromHandle(hDS)->GetGCPCount();
    2135             : }
    2136             : 
    2137             : /************************************************************************/
    2138             : /*                          GetGCPProjection()                          */
    2139             : /************************************************************************/
    2140             : 
    2141             : /**
    2142             :  * \brief Get output projection for GCPs.
    2143             :  *
    2144             :  * This method is the same as the C function GDALGetGCPProjection().
    2145             :  *
    2146             :  * The projection string follows the normal rules from GetProjectionRef().
    2147             :  *
    2148             :  * \note Starting with GDAL 3.0, this is a compatibility layer around
    2149             :  * GetGCPSpatialRef()
    2150             :  *
    2151             :  * @return internal projection string or "" if there are no GCPs.
    2152             :  *  It should not be altered, freed or expected to last for long.
    2153             :  */
    2154             : 
    2155         930 : const char *GDALDataset::GetGCPProjection() const
    2156             : {
    2157         930 :     const auto poSRS = GetGCPSpatialRef();
    2158         930 :     if (!poSRS || !m_poPrivate)
    2159             :     {
    2160         594 :         return "";
    2161             :     }
    2162         336 :     char *pszWKT = nullptr;
    2163         336 :     poSRS->exportToWkt(&pszWKT);
    2164         336 :     if (!pszWKT)
    2165             :     {
    2166           0 :         return "";
    2167             :     }
    2168             : 
    2169             :     // If called on a thread-safe dataset, we might be called by several
    2170             :     // threads, so make sure our accesses to m_pszWKTCached are protected
    2171             :     // by a mutex.
    2172         672 :     std::lock_guard oLock(m_poPrivate->m_oMutexWKT);
    2173         336 :     if (m_poPrivate->m_pszWKTGCPCached &&
    2174         256 :         strcmp(pszWKT, m_poPrivate->m_pszWKTGCPCached) == 0)
    2175             :     {
    2176         256 :         CPLFree(pszWKT);
    2177         256 :         return m_poPrivate->m_pszWKTGCPCached;
    2178             :     }
    2179          80 :     CPLFree(m_poPrivate->m_pszWKTGCPCached);
    2180          80 :     m_poPrivate->m_pszWKTGCPCached = pszWKT;
    2181          80 :     return m_poPrivate->m_pszWKTGCPCached;
    2182             : }
    2183             : 
    2184             : /************************************************************************/
    2185             : /*                          GetGCPSpatialRef()                          */
    2186             : /************************************************************************/
    2187             : 
    2188             : /**
    2189             :  * \brief Get output spatial reference system for GCPs.
    2190             :  *
    2191             :  * Same as the C function GDALGetGCPSpatialRef().
    2192             :  *
    2193             :  * When a SRS is not available, null is returned. If used on
    2194             :  * a dataset where there is a geotransform, and not GCPs, this method returns
    2195             :  * null. Use GetSpatialRef() instead.
    2196             :  *
    2197             :  * @since GDAL 3.0
    2198             :  *
    2199             :  * @return a pointer to an internal object. It should not be altered or freed.
    2200             :  * Its lifetime will be the one of the dataset object, or until the next
    2201             :  * call to this method.
    2202             :  */
    2203             : 
    2204          39 : const OGRSpatialReference *GDALDataset::GetGCPSpatialRef() const
    2205             : {
    2206          39 :     return nullptr;
    2207             : }
    2208             : 
    2209             : /************************************************************************/
    2210             : /*                       GDALGetGCPSpatialRef()                         */
    2211             : /************************************************************************/
    2212             : 
    2213             : /**
    2214             :  * \brief Get output spatial reference system for GCPs.
    2215             :  *
    2216             :  * @since GDAL 3.0
    2217             :  *
    2218             :  * @see GDALDataset::GetGCPSpatialRef()
    2219             :  */
    2220             : 
    2221         468 : OGRSpatialReferenceH GDALGetGCPSpatialRef(GDALDatasetH hDS)
    2222             : 
    2223             : {
    2224         468 :     VALIDATE_POINTER1(hDS, "GDALGetGCPSpatialRef", nullptr);
    2225             : 
    2226         468 :     return OGRSpatialReference::ToHandle(const_cast<OGRSpatialReference *>(
    2227         468 :         GDALDataset::FromHandle(hDS)->GetGCPSpatialRef()));
    2228             : }
    2229             : 
    2230             : /************************************************************************/
    2231             : /*                        GDALGetGCPProjection()                        */
    2232             : /************************************************************************/
    2233             : 
    2234             : /**
    2235             :  * \brief Get output projection for GCPs.
    2236             :  *
    2237             :  * @see GDALDataset::GetGCPProjection()
    2238             :  */
    2239             : 
    2240         860 : const char *CPL_STDCALL GDALGetGCPProjection(GDALDatasetH hDS)
    2241             : 
    2242             : {
    2243         860 :     VALIDATE_POINTER1(hDS, "GDALGetGCPProjection", nullptr);
    2244             : 
    2245         860 :     return GDALDataset::FromHandle(hDS)->GetGCPProjection();
    2246             : }
    2247             : 
    2248             : /************************************************************************/
    2249             : /*                               GetGCPs()                              */
    2250             : /************************************************************************/
    2251             : 
    2252             : /**
    2253             :  * \brief Fetch GCPs.
    2254             :  *
    2255             :  * This method is the same as the C function GDALGetGCPs().
    2256             :  *
    2257             :  * @return pointer to internal GCP structure list.  It should not be modified,
    2258             :  * and may change on the next GDAL call.
    2259             :  */
    2260             : 
    2261          11 : const GDAL_GCP *GDALDataset::GetGCPs()
    2262             : {
    2263          11 :     return nullptr;
    2264             : }
    2265             : 
    2266             : /************************************************************************/
    2267             : /*                            GDALGetGCPs()                             */
    2268             : /************************************************************************/
    2269             : 
    2270             : /**
    2271             :  * \brief Fetch GCPs.
    2272             :  *
    2273             :  * @see GDALDataset::GetGCPs()
    2274             :  */
    2275             : 
    2276         579 : const GDAL_GCP *CPL_STDCALL GDALGetGCPs(GDALDatasetH hDS)
    2277             : 
    2278             : {
    2279         579 :     VALIDATE_POINTER1(hDS, "GDALGetGCPs", nullptr);
    2280             : 
    2281         579 :     return GDALDataset::FromHandle(hDS)->GetGCPs();
    2282             : }
    2283             : 
    2284             : /************************************************************************/
    2285             : /*                              SetGCPs()                               */
    2286             : /************************************************************************/
    2287             : 
    2288             : /**
    2289             :  * \brief Assign GCPs.
    2290             :  *
    2291             :  * This method is the same as the C function GDALSetGCPs().
    2292             :  *
    2293             :  * This method assigns the passed set of GCPs to this dataset, as well as
    2294             :  * setting their coordinate system.  Internally copies are made of the
    2295             :  * coordinate system and list of points, so the caller remains responsible for
    2296             :  * deallocating these arguments if appropriate.
    2297             :  *
    2298             :  * Most formats do not support setting of GCPs, even formats that can
    2299             :  * handle GCPs.  These formats will return CE_Failure.
    2300             :  *
    2301             :  * \note Startig with GDAL 3.0, this is a compatibility layer around
    2302             :  * SetGCPs(int, const GDAL_GCP*, const char*)
    2303             :  *
    2304             :  * @param nGCPCount number of GCPs being assigned.
    2305             :  *
    2306             :  * @param pasGCPList array of GCP structures being assign (nGCPCount in array).
    2307             :  *
    2308             :  * @param pszGCPProjection the new OGC WKT coordinate system to assign for the
    2309             :  * GCP output coordinates.  This parameter should be "" if no output coordinate
    2310             :  * system is known.
    2311             :  *
    2312             :  * @return CE_None on success, CE_Failure on failure (including if action is
    2313             :  * not supported for this format).
    2314             :  */
    2315             : 
    2316          52 : CPLErr GDALDataset::SetGCPs(int nGCPCount, const GDAL_GCP *pasGCPList,
    2317             :                             const char *pszGCPProjection)
    2318             : 
    2319             : {
    2320          52 :     if (pszGCPProjection && pszGCPProjection[0] != '\0')
    2321             :     {
    2322          66 :         OGRSpatialReference oSRS;
    2323          33 :         oSRS.SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
    2324          33 :         if (oSRS.importFromWkt(pszGCPProjection) != OGRERR_NONE)
    2325             :         {
    2326           0 :             return CE_Failure;
    2327             :         }
    2328          33 :         return SetGCPs(nGCPCount, pasGCPList, &oSRS);
    2329             :     }
    2330             :     else
    2331             :     {
    2332          19 :         return SetGCPs(nGCPCount, pasGCPList,
    2333          19 :                        static_cast<const OGRSpatialReference *>(nullptr));
    2334             :     }
    2335             : }
    2336             : 
    2337             : /************************************************************************/
    2338             : /*                              SetGCPs()                               */
    2339             : /************************************************************************/
    2340             : 
    2341             : /**
    2342             :  * \brief Assign GCPs.
    2343             :  *
    2344             :  * This method is the same as the C function GDALSetGCPs().
    2345             :  *
    2346             :  * This method assigns the passed set of GCPs to this dataset, as well as
    2347             :  * setting their coordinate system.  Internally copies are made of the
    2348             :  * coordinate system and list of points, so the caller remains responsible for
    2349             :  * deallocating these arguments if appropriate.
    2350             :  *
    2351             :  * Most formats do not support setting of GCPs, even formats that can
    2352             :  * handle GCPs.  These formats will return CE_Failure.
    2353             :  *
    2354             :  * @since GDAL 3.0
    2355             :  *
    2356             :  * @param nGCPCount number of GCPs being assigned.
    2357             :  *
    2358             :  * @param pasGCPList array of GCP structures being assign (nGCPCount in array).
    2359             :  *
    2360             :  * @param poGCP_SRS the new coordinate reference system to assign for the
    2361             :  * GCP output coordinates.  This parameter should be null if no output
    2362             :  * coordinate system is known.
    2363             :  *
    2364             :  * @return CE_None on success, CE_Failure on failure (including if action is
    2365             :  * not supported for this format).
    2366             :  */
    2367             : 
    2368           1 : CPLErr GDALDataset::SetGCPs(CPL_UNUSED int nGCPCount,
    2369             :                             CPL_UNUSED const GDAL_GCP *pasGCPList,
    2370             :                             CPL_UNUSED const OGRSpatialReference *poGCP_SRS)
    2371             : 
    2372             : {
    2373           1 :     if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
    2374           1 :         ReportError(CE_Failure, CPLE_NotSupported,
    2375             :                     "Dataset does not support the SetGCPs() method.");
    2376             : 
    2377           1 :     return CE_Failure;
    2378             : }
    2379             : 
    2380             : /************************************************************************/
    2381             : /*                            GDALSetGCPs()                             */
    2382             : /************************************************************************/
    2383             : 
    2384             : /**
    2385             :  * \brief Assign GCPs.
    2386             :  *
    2387             :  * @see GDALDataset::SetGCPs(int, const GDAL_GCP*, const char*)
    2388             :  */
    2389             : 
    2390          29 : CPLErr CPL_STDCALL GDALSetGCPs(GDALDatasetH hDS, int nGCPCount,
    2391             :                                const GDAL_GCP *pasGCPList,
    2392             :                                const char *pszGCPProjection)
    2393             : 
    2394             : {
    2395          29 :     VALIDATE_POINTER1(hDS, "GDALSetGCPs", CE_Failure);
    2396             : 
    2397          29 :     return GDALDataset::FromHandle(hDS)->SetGCPs(nGCPCount, pasGCPList,
    2398          29 :                                                  pszGCPProjection);
    2399             : }
    2400             : 
    2401             : /************************************************************************/
    2402             : /*                           GDALSetGCPs2()                             */
    2403             : /************************************************************************/
    2404             : 
    2405             : /**
    2406             :  * \brief Assign GCPs.
    2407             :  *
    2408             :  * @since GDAL 3.0
    2409             :  * @see GDALDataset::SetGCPs(int, const GDAL_GCP*, const OGRSpatialReference*)
    2410             :  */
    2411             : 
    2412           9 : CPLErr GDALSetGCPs2(GDALDatasetH hDS, int nGCPCount, const GDAL_GCP *pasGCPList,
    2413             :                     OGRSpatialReferenceH hSRS)
    2414             : 
    2415             : {
    2416           9 :     VALIDATE_POINTER1(hDS, "GDALSetGCPs2", CE_Failure);
    2417             : 
    2418          18 :     return GDALDataset::FromHandle(hDS)->SetGCPs(
    2419           9 :         nGCPCount, pasGCPList, OGRSpatialReference::FromHandle(hSRS));
    2420             : }
    2421             : 
    2422             : /************************************************************************/
    2423             : /*                           BuildOverviews()                           */
    2424             : /************************************************************************/
    2425             : 
    2426             : /**
    2427             :  * \brief Build raster overview(s)
    2428             :  *
    2429             :  * If the operation is not supported for the indicated dataset, then
    2430             :  * CE_Failure is returned, and CPLGetLastErrorNo() will return
    2431             :  * CPLE_NotSupported.
    2432             :  *
    2433             :  * Depending on the actual file format, all overviews level can be also
    2434             :  * deleted by specifying nOverviews == 0. This works at least for external
    2435             :  * overviews (.ovr), TIFF internal overviews, etc.
    2436             :  *
    2437             :  * Starting with GDAL 3.2, the GDAL_NUM_THREADS configuration option can be set
    2438             :  * to "ALL_CPUS" or a integer value to specify the number of threads to use for
    2439             :  * overview computation.
    2440             :  *
    2441             :  * This method is the same as the C function GDALBuildOverviewsEx().
    2442             :  *
    2443             :  * @param pszResampling one of "AVERAGE", "AVERAGE_MAGPHASE", "RMS",
    2444             :  * "BILINEAR", "CUBIC", "CUBICSPLINE", "GAUSS", "LANCZOS", "MODE", "NEAREST",
    2445             :  * or "NONE" controlling the downsampling method applied.
    2446             :  * @param nOverviews number of overviews to build, or 0 to clean overviews.
    2447             :  * @param panOverviewList the list of overview decimation factors (positive
    2448             :  *                        integers, normally larger or equal to 2) to build, or
    2449             :  *                        NULL if nOverviews == 0.
    2450             :  * @param nListBands number of bands to build overviews for in panBandList.
    2451             :  * Build for all bands if this is 0.
    2452             :  * @param panBandList list of band numbers.
    2453             :  * @param pfnProgress a function to call to report progress, or NULL.
    2454             :  * @param pProgressData application data to pass to the progress function.
    2455             :  * @param papszOptions (GDAL >= 3.6) NULL terminated list of options as
    2456             :  *                     key=value pairs, or NULL.
    2457             :  *                     Possible keys are the ones returned by
    2458             :  *                     GetDriver()->GetMetadataItem(GDAL_DMD_OVERVIEW_CREATIONOPTIONLIST)
    2459             :  *
    2460             :  * @return CE_None on success or CE_Failure if the operation doesn't work.
    2461             :  *
    2462             :  * For example, to build overview level 2, 4 and 8 on all bands the following
    2463             :  * call could be made:
    2464             :  * \code{.cpp}
    2465             :  *   int       anOverviewList[3] = { 2, 4, 8 };
    2466             :  *
    2467             :  *   poDataset->BuildOverviews( "NEAREST", 3, anOverviewList, 0, nullptr,
    2468             :  *                              GDALDummyProgress, nullptr );
    2469             :  * \endcode
    2470             :  *
    2471             :  * @see GDALRegenerateOverviewsEx()
    2472             :  */
    2473             : 
    2474         748 : CPLErr GDALDataset::BuildOverviews(const char *pszResampling, int nOverviews,
    2475             :                                    const int *panOverviewList, int nListBands,
    2476             :                                    const int *panBandList,
    2477             :                                    GDALProgressFunc pfnProgress,
    2478             :                                    void *pProgressData,
    2479             :                                    CSLConstList papszOptions)
    2480             : {
    2481         748 :     int *panAllBandList = nullptr;
    2482             : 
    2483        1496 :     CPLStringList aosOptions(papszOptions);
    2484         748 :     if (poDriver && !aosOptions.empty())
    2485             :     {
    2486             :         const char *pszOptionList =
    2487          28 :             poDriver->GetMetadataItem(GDAL_DMD_OVERVIEW_CREATIONOPTIONLIST);
    2488          28 :         if (pszOptionList)
    2489             :         {
    2490             :             // For backwards compatibility
    2491          28 :             if (const char *opt = aosOptions.FetchNameValue("USE_RRD"))
    2492             :             {
    2493           4 :                 if (strstr(pszOptionList, "<Value>RRD</Value>") &&
    2494           2 :                     aosOptions.FetchNameValue("LOCATION") == nullptr)
    2495             :                 {
    2496           2 :                     if (CPLTestBool(opt))
    2497           2 :                         aosOptions.SetNameValue("LOCATION", "RRD");
    2498           2 :                     aosOptions.SetNameValue("USE_RRD", nullptr);
    2499             :                 }
    2500             :             }
    2501          28 :             if (const char *opt =
    2502          28 :                     aosOptions.FetchNameValue("VRT_VIRTUAL_OVERVIEWS"))
    2503             :             {
    2504           3 :                 if (strstr(pszOptionList, "VIRTUAL"))
    2505             :                 {
    2506           3 :                     aosOptions.SetNameValue("VIRTUAL", opt);
    2507           3 :                     aosOptions.SetNameValue("VRT_VIRTUAL_OVERVIEWS", nullptr);
    2508             :                 }
    2509             :             }
    2510             : 
    2511          76 :             for (const auto &[pszKey, pszValue] :
    2512         104 :                  cpl::IterateNameValue(papszOptions))
    2513             :             {
    2514          38 :                 if (cpl::ends_with(std::string_view(pszKey), "_OVERVIEW"))
    2515             :                 {
    2516             :                     aosOptions.SetNameValue(
    2517          16 :                         std::string(pszKey)
    2518          16 :                             .substr(0, strlen(pszKey) - strlen("_OVERVIEW"))
    2519             :                             .c_str(),
    2520          16 :                         pszValue);
    2521           8 :                     aosOptions.SetNameValue(pszKey, nullptr);
    2522             :                 }
    2523             :             }
    2524             : 
    2525          56 :             CPLString osDriver;
    2526          28 :             osDriver.Printf("driver %s", poDriver->GetDescription());
    2527          28 :             GDALValidateOptions(pszOptionList, aosOptions.List(),
    2528             :                                 "overview creation option", osDriver);
    2529             :         }
    2530             :     }
    2531             : 
    2532         748 :     if (nListBands == 0)
    2533             :     {
    2534         736 :         nListBands = GetRasterCount();
    2535             :         panAllBandList =
    2536         736 :             static_cast<int *>(CPLMalloc(sizeof(int) * nListBands));
    2537       67468 :         for (int i = 0; i < nListBands; ++i)
    2538       66732 :             panAllBandList[i] = i + 1;
    2539             : 
    2540         736 :         panBandList = panAllBandList;
    2541             :     }
    2542             : 
    2543         748 :     if (pfnProgress == nullptr)
    2544         713 :         pfnProgress = GDALDummyProgress;
    2545             : 
    2546        1828 :     for (int i = 0; i < nOverviews; ++i)
    2547             :     {
    2548        1081 :         if (panOverviewList[i] <= 0)
    2549             :         {
    2550           1 :             CPLError(CE_Failure, CPLE_IllegalArg,
    2551             :                      "panOverviewList[%d] = %d is invalid. It must be a "
    2552             :                      "positive value",
    2553           1 :                      i, panOverviewList[i]);
    2554           1 :             CPLFree(panAllBandList);
    2555           1 :             return CE_Failure;
    2556             :         }
    2557             :     }
    2558             : 
    2559         747 :     const CPLErr eErr = IBuildOverviews(
    2560             :         pszResampling, nOverviews, panOverviewList, nListBands, panBandList,
    2561         747 :         pfnProgress, pProgressData, aosOptions.List());
    2562             : 
    2563         747 :     if (panAllBandList != nullptr)
    2564         734 :         CPLFree(panAllBandList);
    2565             : 
    2566         747 :     return eErr;
    2567             : }
    2568             : 
    2569             : /************************************************************************/
    2570             : /*                         GDALBuildOverviews()                         */
    2571             : /************************************************************************/
    2572             : 
    2573             : /**
    2574             :  * \brief Build raster overview(s)
    2575             :  *
    2576             :  * @see GDALDataset::BuildOverviews() and GDALBuildOverviews()
    2577             :  */
    2578             : 
    2579          27 : CPLErr CPL_STDCALL GDALBuildOverviews(GDALDatasetH hDataset,
    2580             :                                       const char *pszResampling, int nOverviews,
    2581             :                                       const int *panOverviewList,
    2582             :                                       int nListBands, const int *panBandList,
    2583             :                                       GDALProgressFunc pfnProgress,
    2584             :                                       void *pProgressData)
    2585             : 
    2586             : {
    2587          27 :     VALIDATE_POINTER1(hDataset, "GDALBuildOverviews", CE_Failure);
    2588             : 
    2589          27 :     return GDALDataset::FromHandle(hDataset)->BuildOverviews(
    2590             :         pszResampling, nOverviews, panOverviewList, nListBands, panBandList,
    2591          27 :         pfnProgress, pProgressData, nullptr);
    2592             : }
    2593             : 
    2594             : /************************************************************************/
    2595             : /*                         GDALBuildOverviews()                         */
    2596             : /************************************************************************/
    2597             : 
    2598             : /**
    2599             :  * \brief Build raster overview(s)
    2600             :  *
    2601             :  * @see GDALDataset::BuildOverviews()
    2602             :  * @since GDAL 3.6
    2603             :  */
    2604             : 
    2605             : CPLErr CPL_STDCALL
    2606         700 : GDALBuildOverviewsEx(GDALDatasetH hDataset, const char *pszResampling,
    2607             :                      int nOverviews, const int *panOverviewList, int nListBands,
    2608             :                      const int *panBandList, GDALProgressFunc pfnProgress,
    2609             :                      void *pProgressData, CSLConstList papszOptions)
    2610             : 
    2611             : {
    2612         700 :     VALIDATE_POINTER1(hDataset, "GDALBuildOverviews", CE_Failure);
    2613             : 
    2614         700 :     return GDALDataset::FromHandle(hDataset)->BuildOverviews(
    2615             :         pszResampling, nOverviews, panOverviewList, nListBands, panBandList,
    2616         700 :         pfnProgress, pProgressData, papszOptions);
    2617             : }
    2618             : 
    2619             : /************************************************************************/
    2620             : /*                          IBuildOverviews()                           */
    2621             : /*                                                                      */
    2622             : /*      Default implementation.                                         */
    2623             : /************************************************************************/
    2624             : 
    2625             : //! @cond Doxygen_Suppress
    2626         196 : CPLErr GDALDataset::IBuildOverviews(const char *pszResampling, int nOverviews,
    2627             :                                     const int *panOverviewList, int nListBands,
    2628             :                                     const int *panBandList,
    2629             :                                     GDALProgressFunc pfnProgress,
    2630             :                                     void *pProgressData,
    2631             :                                     CSLConstList papszOptions)
    2632             : 
    2633             : {
    2634         196 :     if (oOvManager.IsInitialized())
    2635         195 :         return oOvManager.BuildOverviews(
    2636             :             nullptr, pszResampling, nOverviews, panOverviewList, nListBands,
    2637         195 :             panBandList, pfnProgress, pProgressData, papszOptions);
    2638             :     else
    2639             :     {
    2640           1 :         ReportError(CE_Failure, CPLE_NotSupported,
    2641             :                     "BuildOverviews() not supported for this dataset.");
    2642             : 
    2643           1 :         return CE_Failure;
    2644             :     }
    2645             : }
    2646             : 
    2647             : //! @endcond
    2648             : 
    2649             : /************************************************************************/
    2650             : /*                            AddOverviews()                            */
    2651             : /*                                                                      */
    2652             : /*      Default implementation.                                         */
    2653             : /************************************************************************/
    2654             : 
    2655             : /**
    2656             :  * \brief Add overview from existing dataset(s)
    2657             :  *
    2658             :  * This function creates new overview levels or refresh existing one from
    2659             :  * the list of provided overview datasets.
    2660             :  * Source overviews may come from any GDAL supported format, provided they
    2661             :  * have the same number of bands and geospatial extent than the target
    2662             :  * dataset.
    2663             :  *
    2664             :  * If the operation is not supported for the indicated dataset, then
    2665             :  * CE_Failure is returned, and CPLGetLastErrorNo() will return
    2666             :  * CPLE_NotSupported.
    2667             :  *
    2668             :  * At time of writing, this method is only implemented for internal overviews
    2669             :  * of GeoTIFF datasets and external overviews in GeoTIFF format.
    2670             :  *
    2671             :  * @param apoSrcOvrDS Vector of source overviews.
    2672             :  * @param pfnProgress a function to call to report progress, or NULL.
    2673             :  * @param pProgressData application data to pass to the progress function.
    2674             :  * @param papszOptions NULL terminated list of options as
    2675             :  *                     key=value pairs, or NULL. Possible keys are the
    2676             :  *                     ones returned by
    2677             :  *                     GetDriver()->GetMetadataItem(GDAL_DMD_OVERVIEW_CREATIONOPTIONLIST)
    2678             :  *
    2679             :  * @return CE_None on success or CE_Failure if the operation doesn't work.
    2680             :  * @since 3.12
    2681             :  */
    2682           5 : CPLErr GDALDataset::AddOverviews(const std::vector<GDALDataset *> &apoSrcOvrDS,
    2683             :                                  GDALProgressFunc pfnProgress,
    2684             :                                  void *pProgressData, CSLConstList papszOptions)
    2685             : {
    2686           5 :     if (oOvManager.IsInitialized())
    2687             :     {
    2688           4 :         return oOvManager.AddOverviews(nullptr, apoSrcOvrDS, pfnProgress,
    2689           4 :                                        pProgressData, papszOptions);
    2690             :     }
    2691             :     else
    2692             :     {
    2693           1 :         ReportError(CE_Failure, CPLE_NotSupported,
    2694             :                     "AddOverviews() not supported for this dataset.");
    2695           1 :         return CE_Failure;
    2696             :     }
    2697             : }
    2698             : 
    2699             : /************************************************************************/
    2700             : /*                             IRasterIO()                              */
    2701             : /*                                                                      */
    2702             : /*      The default implementation of IRasterIO() is, in the general    */
    2703             : /*      case to pass the request off to each band objects rasterio      */
    2704             : /*      methods with appropriate arguments. In some cases, it might     */
    2705             : /*      choose instead the BlockBasedRasterIO() implementation.         */
    2706             : /************************************************************************/
    2707             : 
    2708             : //! @cond Doxygen_Suppress
    2709      444828 : CPLErr GDALDataset::IRasterIO(GDALRWFlag eRWFlag, int nXOff, int nYOff,
    2710             :                               int nXSize, int nYSize, void *pData,
    2711             :                               int nBufXSize, int nBufYSize,
    2712             :                               GDALDataType eBufType, int nBandCount,
    2713             :                               BANDMAP_TYPE panBandMap, GSpacing nPixelSpace,
    2714             :                               GSpacing nLineSpace, GSpacing nBandSpace,
    2715             :                               GDALRasterIOExtraArg *psExtraArg)
    2716             : 
    2717             : {
    2718      444828 :     const char *pszInterleave = nullptr;
    2719             : 
    2720      444828 :     CPLAssert(nullptr != pData);
    2721             : 
    2722      444828 :     const bool bHasSubpixelShift =
    2723      447111 :         psExtraArg->bFloatingPointWindowValidity &&
    2724      445621 :         psExtraArg->eResampleAlg != GRIORA_NearestNeighbour &&
    2725         793 :         (nXOff != psExtraArg->dfXOff || nYOff != psExtraArg->dfYOff);
    2726             : 
    2727      444712 :     if (!bHasSubpixelShift && nXSize == nBufXSize && nYSize == nBufYSize &&
    2728       70527 :         nBandCount > 1 &&
    2729       70527 :         (pszInterleave = GetMetadataItem("INTERLEAVE", "IMAGE_STRUCTURE")) !=
    2730      889540 :             nullptr &&
    2731       67447 :         EQUAL(pszInterleave, "PIXEL"))
    2732             :     {
    2733       64132 :         return BlockBasedRasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize, pData,
    2734             :                                   nBufXSize, nBufYSize, eBufType, nBandCount,
    2735             :                                   panBandMap, nPixelSpace, nLineSpace,
    2736       64132 :                                   nBandSpace, psExtraArg);
    2737             :     }
    2738             : 
    2739      380696 :     if (eRWFlag == GF_Read &&
    2740      201135 :         (psExtraArg->eResampleAlg == GRIORA_Cubic ||
    2741      200347 :          psExtraArg->eResampleAlg == GRIORA_CubicSpline ||
    2742      200346 :          psExtraArg->eResampleAlg == GRIORA_Bilinear ||
    2743      201135 :          psExtraArg->eResampleAlg == GRIORA_Lanczos) &&
    2744         951 :         !(nXSize == nBufXSize && nYSize == nBufYSize) && nBandCount > 1)
    2745             :     {
    2746         930 :         if (nBufXSize < nXSize && nBufYSize < nYSize && AreOverviewsEnabled())
    2747             :         {
    2748         719 :             int bTried = FALSE;
    2749         719 :             const CPLErr eErr = TryOverviewRasterIO(
    2750             :                 eRWFlag, nXOff, nYOff, nXSize, nYSize, pData, nBufXSize,
    2751             :                 nBufYSize, eBufType, nBandCount, panBandMap, nPixelSpace,
    2752             :                 nLineSpace, nBandSpace, psExtraArg, &bTried);
    2753         719 :             if (bTried)
    2754           1 :                 return eErr;
    2755             :         }
    2756             : 
    2757         929 :         GDALDataType eFirstBandDT = GDT_Unknown;
    2758         929 :         int nFirstMaskFlags = 0;
    2759         929 :         GDALRasterBand *poFirstMaskBand = nullptr;
    2760         929 :         int nOKBands = 0;
    2761             : 
    2762             :         // Check if bands share the same mask band
    2763        2921 :         for (int i = 0; i < nBandCount; ++i)
    2764             :         {
    2765        2652 :             GDALRasterBand *poBand = GetRasterBand(panBandMap[i]);
    2766        4629 :             if ((nBufXSize < nXSize || nBufYSize < nYSize) &&
    2767        1977 :                 poBand->GetOverviewCount())
    2768             :             {
    2769             :                 // Could be improved to select the appropriate overview.
    2770           3 :                 break;
    2771             :             }
    2772        2649 :             if (poBand->GetColorTable() != nullptr)
    2773             :             {
    2774           0 :                 break;
    2775             :             }
    2776        2649 :             const GDALDataType eDT = poBand->GetRasterDataType();
    2777        2649 :             if (GDALDataTypeIsComplex(eDT))
    2778             :             {
    2779          30 :                 break;
    2780             :             }
    2781        2619 :             if (i == 0)
    2782             :             {
    2783         896 :                 eFirstBandDT = eDT;
    2784         896 :                 nFirstMaskFlags = poBand->GetMaskFlags();
    2785         896 :                 if (nFirstMaskFlags == GMF_NODATA)
    2786             :                 {
    2787             :                     // The dataset-level resampling code is not ready for nodata
    2788             :                     // Fallback to band-level resampling
    2789          10 :                     break;
    2790             :                 }
    2791         886 :                 poFirstMaskBand = poBand->GetMaskBand();
    2792             :             }
    2793             :             else
    2794             :             {
    2795        1723 :                 if (eDT != eFirstBandDT)
    2796             :                 {
    2797           0 :                     break;
    2798             :                 }
    2799        1723 :                 int nMaskFlags = poBand->GetMaskFlags();
    2800        1723 :                 if (nMaskFlags == GMF_NODATA)
    2801             :                 {
    2802             :                     // The dataset-level resampling code is not ready for nodata
    2803             :                     // Fallback to band-level resampling
    2804           0 :                     break;
    2805             :                 }
    2806        1723 :                 GDALRasterBand *poMaskBand = poBand->GetMaskBand();
    2807        1723 :                 if (nFirstMaskFlags == GMF_ALL_VALID &&
    2808             :                     nMaskFlags == GMF_ALL_VALID)
    2809             :                 {
    2810             :                     // Ok.
    2811             :                 }
    2812        1077 :                 else if (poFirstMaskBand == poMaskBand)
    2813             :                 {
    2814             :                     // Ok.
    2815             :                 }
    2816             :                 else
    2817             :                 {
    2818         617 :                     break;
    2819             :                 }
    2820             :             }
    2821             : 
    2822        1992 :             ++nOKBands;
    2823             :         }
    2824             : 
    2825         929 :         GDALProgressFunc pfnProgressGlobal = psExtraArg->pfnProgress;
    2826         929 :         void *pProgressDataGlobal = psExtraArg->pProgressData;
    2827             : 
    2828         929 :         CPLErr eErr = CE_None;
    2829         929 :         if (nOKBands > 0)
    2830             :         {
    2831         886 :             if (nOKBands < nBandCount)
    2832             :             {
    2833         617 :                 psExtraArg->pfnProgress = GDALScaledProgress;
    2834        1234 :                 psExtraArg->pProgressData = GDALCreateScaledProgress(
    2835         617 :                     0.0, static_cast<double>(nOKBands) / nBandCount,
    2836             :                     pfnProgressGlobal, pProgressDataGlobal);
    2837         617 :                 if (psExtraArg->pProgressData == nullptr)
    2838         228 :                     psExtraArg->pfnProgress = nullptr;
    2839             :             }
    2840             : 
    2841         886 :             eErr = RasterIOResampled(eRWFlag, nXOff, nYOff, nXSize, nYSize,
    2842             :                                      pData, nBufXSize, nBufYSize, eBufType,
    2843             :                                      nOKBands, panBandMap, nPixelSpace,
    2844             :                                      nLineSpace, nBandSpace, psExtraArg);
    2845             : 
    2846         886 :             if (nOKBands < nBandCount)
    2847             :             {
    2848         617 :                 GDALDestroyScaledProgress(psExtraArg->pProgressData);
    2849             :             }
    2850             :         }
    2851         929 :         if (eErr == CE_None && nOKBands < nBandCount)
    2852             :         {
    2853         657 :             if (nOKBands > 0)
    2854             :             {
    2855         614 :                 psExtraArg->pfnProgress = GDALScaledProgress;
    2856        1228 :                 psExtraArg->pProgressData = GDALCreateScaledProgress(
    2857         614 :                     static_cast<double>(nOKBands) / nBandCount, 1.0,
    2858             :                     pfnProgressGlobal, pProgressDataGlobal);
    2859         614 :                 if (psExtraArg->pProgressData == nullptr)
    2860         225 :                     psExtraArg->pfnProgress = nullptr;
    2861             :             }
    2862        1314 :             eErr = BandBasedRasterIO(
    2863             :                 eRWFlag, nXOff, nYOff, nXSize, nYSize,
    2864         657 :                 static_cast<GByte *>(pData) + nBandSpace * nOKBands, nBufXSize,
    2865             :                 nBufYSize, eBufType, nBandCount - nOKBands,
    2866         657 :                 panBandMap + nOKBands, nPixelSpace, nLineSpace, nBandSpace,
    2867             :                 psExtraArg);
    2868         657 :             if (nOKBands > 0)
    2869             :             {
    2870         614 :                 GDALDestroyScaledProgress(psExtraArg->pProgressData);
    2871             :             }
    2872             :         }
    2873             : 
    2874         929 :         psExtraArg->pfnProgress = pfnProgressGlobal;
    2875         929 :         psExtraArg->pProgressData = pProgressDataGlobal;
    2876             : 
    2877         929 :         return eErr;
    2878             :     }
    2879             : 
    2880      379766 :     return BandBasedRasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize, pData,
    2881             :                              nBufXSize, nBufYSize, eBufType, nBandCount,
    2882             :                              panBandMap, nPixelSpace, nLineSpace, nBandSpace,
    2883      379766 :                              psExtraArg);
    2884             : }
    2885             : 
    2886             : //! @endcond
    2887             : 
    2888             : /************************************************************************/
    2889             : /*                         BandBasedRasterIO()                          */
    2890             : /*                                                                      */
    2891             : /*      Pass the request off to each band objects rasterio methods with */
    2892             : /*      appropriate arguments.                                          */
    2893             : /************************************************************************/
    2894             : 
    2895             : //! @cond Doxygen_Suppress
    2896      652980 : CPLErr GDALDataset::BandBasedRasterIO(
    2897             :     GDALRWFlag eRWFlag, int nXOff, int nYOff, int nXSize, int nYSize,
    2898             :     void *pData, int nBufXSize, int nBufYSize, GDALDataType eBufType,
    2899             :     int nBandCount, const int *panBandMap, GSpacing nPixelSpace,
    2900             :     GSpacing nLineSpace, GSpacing nBandSpace, GDALRasterIOExtraArg *psExtraArg)
    2901             : 
    2902             : {
    2903             :     int iBandIndex;
    2904      652980 :     CPLErr eErr = CE_None;
    2905             : 
    2906      652980 :     GDALProgressFunc pfnProgressGlobal = psExtraArg->pfnProgress;
    2907      652980 :     void *pProgressDataGlobal = psExtraArg->pProgressData;
    2908             : 
    2909     1692830 :     for (iBandIndex = 0; iBandIndex < nBandCount && eErr == CE_None;
    2910             :          ++iBandIndex)
    2911             :     {
    2912     1039850 :         GDALRasterBand *poBand = GetRasterBand(panBandMap[iBandIndex]);
    2913             : 
    2914     1039850 :         if (poBand == nullptr)
    2915             :         {
    2916           0 :             eErr = CE_Failure;
    2917           0 :             break;
    2918             :         }
    2919             : 
    2920     1039850 :         GByte *pabyBandData =
    2921     1039850 :             static_cast<GByte *>(pData) + iBandIndex * nBandSpace;
    2922             : 
    2923     1039850 :         if (nBandCount > 1)
    2924             :         {
    2925      570384 :             psExtraArg->pfnProgress = GDALScaledProgress;
    2926     1140770 :             psExtraArg->pProgressData = GDALCreateScaledProgress(
    2927             :                 1.0 * iBandIndex / nBandCount,
    2928      570384 :                 1.0 * (iBandIndex + 1) / nBandCount, pfnProgressGlobal,
    2929             :                 pProgressDataGlobal);
    2930      570384 :             if (psExtraArg->pProgressData == nullptr)
    2931      567369 :                 psExtraArg->pfnProgress = nullptr;
    2932             :         }
    2933             : 
    2934     2079700 :         eErr = poBand->IRasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize,
    2935             :                                  pabyBandData, nBufXSize, nBufYSize, eBufType,
    2936     1039850 :                                  nPixelSpace, nLineSpace, psExtraArg);
    2937             : 
    2938     1039850 :         if (nBandCount > 1)
    2939      570384 :             GDALDestroyScaledProgress(psExtraArg->pProgressData);
    2940             :     }
    2941             : 
    2942      652980 :     psExtraArg->pfnProgress = pfnProgressGlobal;
    2943      652980 :     psExtraArg->pProgressData = pProgressDataGlobal;
    2944             : 
    2945      652980 :     return eErr;
    2946             : }
    2947             : 
    2948             : //! @endcond
    2949             : 
    2950             : /************************************************************************/
    2951             : /*               ValidateRasterIOOrAdviseReadParameters()               */
    2952             : /************************************************************************/
    2953             : 
    2954             : //! @cond Doxygen_Suppress
    2955      750371 : CPLErr GDALDataset::ValidateRasterIOOrAdviseReadParameters(
    2956             :     const char *pszCallingFunc, int *pbStopProcessingOnCENone, int nXOff,
    2957             :     int nYOff, int nXSize, int nYSize, int nBufXSize, int nBufYSize,
    2958             :     int nBandCount, const int *panBandMap)
    2959             : {
    2960             : 
    2961             :     /* -------------------------------------------------------------------- */
    2962             :     /*      Some size values are "noop".  Lets just return to avoid         */
    2963             :     /*      stressing lower level functions.                                */
    2964             :     /* -------------------------------------------------------------------- */
    2965      750371 :     if (nXSize < 1 || nYSize < 1 || nBufXSize < 1 || nBufYSize < 1)
    2966             :     {
    2967          27 :         CPLDebug("GDAL",
    2968             :                  "%s skipped for odd window or buffer size.\n"
    2969             :                  "  Window = (%d,%d)x%dx%d\n"
    2970             :                  "  Buffer = %dx%d",
    2971             :                  pszCallingFunc, nXOff, nYOff, nXSize, nYSize, nBufXSize,
    2972             :                  nBufYSize);
    2973             : 
    2974          27 :         *pbStopProcessingOnCENone = TRUE;
    2975          27 :         return CE_None;
    2976             :     }
    2977             : 
    2978      750344 :     CPLErr eErr = CE_None;
    2979      750344 :     *pbStopProcessingOnCENone = FALSE;
    2980             : 
    2981      750344 :     if (nXOff < 0 || nXOff > INT_MAX - nXSize ||
    2982      750343 :         nXOff + nXSize > nRasterXSize || nYOff < 0 ||
    2983      750342 :         nYOff > INT_MAX - nYSize || nYOff + nYSize > nRasterYSize)
    2984             :     {
    2985           2 :         ReportError(CE_Failure, CPLE_IllegalArg,
    2986             :                     "Access window out of range in %s.  Requested "
    2987             :                     "(%d,%d) of size %dx%d on raster of %dx%d.",
    2988             :                     pszCallingFunc, nXOff, nYOff, nXSize, nYSize, nRasterXSize,
    2989             :                     nRasterYSize);
    2990           2 :         eErr = CE_Failure;
    2991             :     }
    2992             : 
    2993      750344 :     if (panBandMap == nullptr && nBandCount > GetRasterCount())
    2994             :     {
    2995           0 :         ReportError(CE_Failure, CPLE_IllegalArg,
    2996             :                     "%s: nBandCount cannot be greater than %d", pszCallingFunc,
    2997             :                     GetRasterCount());
    2998           0 :         eErr = CE_Failure;
    2999             :     }
    3000             : 
    3001     2250340 :     for (int i = 0; i < nBandCount && eErr == CE_None; ++i)
    3002             :     {
    3003     1499990 :         int iBand = (panBandMap != nullptr) ? panBandMap[i] : i + 1;
    3004     1499990 :         if (iBand < 1 || iBand > GetRasterCount())
    3005             :         {
    3006           3 :             ReportError(
    3007             :                 CE_Failure, CPLE_IllegalArg,
    3008             :                 "%s: panBandMap[%d] = %d, this band does not exist on dataset.",
    3009             :                 pszCallingFunc, i, iBand);
    3010           3 :             eErr = CE_Failure;
    3011             :         }
    3012             : 
    3013     1499990 :         if (eErr == CE_None && GetRasterBand(iBand) == nullptr)
    3014             :         {
    3015           0 :             ReportError(
    3016             :                 CE_Failure, CPLE_IllegalArg,
    3017             :                 "%s: panBandMap[%d]=%d, this band should exist but is NULL!",
    3018             :                 pszCallingFunc, i, iBand);
    3019           0 :             eErr = CE_Failure;
    3020             :         }
    3021             :     }
    3022             : 
    3023      750344 :     return eErr;
    3024             : }
    3025             : 
    3026             : //! @endcond
    3027             : 
    3028             : /************************************************************************/
    3029             : /*                              RasterIO()                              */
    3030             : /************************************************************************/
    3031             : 
    3032             : /**
    3033             :  * \brief Read/write a region of image data from multiple bands.
    3034             :  *
    3035             :  * This method allows reading a region of one or more GDALRasterBands from
    3036             :  * this dataset into a buffer,  or writing data from a buffer into a region
    3037             :  * of the GDALRasterBands.  It automatically takes care of data type
    3038             :  * translation if the data type (eBufType) of the buffer is different than
    3039             :  * that of the GDALRasterBand.
    3040             :  * The method also takes care of image decimation / replication if the
    3041             :  * buffer size (nBufXSize x nBufYSize) is different than the size of the
    3042             :  * region being accessed (nXSize x nYSize).
    3043             :  *
    3044             :  * The window of interest expressed by (nXOff, nYOff, nXSize, nYSize) should be
    3045             :  * fully within the raster space, that is nXOff >= 0, nYOff >= 0,
    3046             :  * nXOff + nXSize <= GetRasterXSize() and nYOff + nYSize <= GetRasterYSize().
    3047             :  * If reads larger than the raster space are wished, GDALTranslate() might be used.
    3048             :  * Or use nLineSpace and a possibly shifted pData value.
    3049             :  *
    3050             :  * The nPixelSpace, nLineSpace and nBandSpace parameters allow reading into or
    3051             :  * writing from various organization of buffers.
    3052             :  *
    3053             :  * Some formats may efficiently implement decimation into a buffer by
    3054             :  * reading from lower resolution overview images. The logic of the default
    3055             :  * implementation in the base class GDALRasterBand is the following one. It
    3056             :  * computes a target_downscaling_factor from the window of interest and buffer
    3057             :  * size which is min(nXSize/nBufXSize, nYSize/nBufYSize).
    3058             :  * It then walks through overviews and will select the first one whose
    3059             :  * downscaling factor is greater than target_downscaling_factor / 1.2.
    3060             :  *
    3061             :  * Let's assume we have overviews at downscaling factors 2, 4 and 8.
    3062             :  * The relationship between target_downscaling_factor and the select overview
    3063             :  * level is the following one:
    3064             :  *
    3065             :  * target_downscaling_factor  | selected_overview
    3066             :  * -------------------------  | -----------------
    3067             :  * ]0,       2 / 1.2]         | full resolution band
    3068             :  * ]2 / 1.2, 4 / 1.2]         | 2x downsampled band
    3069             :  * ]4 / 1.2, 8 / 1.2]         | 4x downsampled band
    3070             :  * ]8 / 1.2, infinity[        | 8x downsampled band
    3071             :  *
    3072             :  * Note that starting with GDAL 3.9, this 1.2 oversampling factor can be
    3073             :  * modified by setting the GDAL_OVERVIEW_OVERSAMPLING_THRESHOLD configuration
    3074             :  * option. Also note that starting with GDAL 3.9, when the resampling algorithm
    3075             :  * specified in psExtraArg->eResampleAlg is different from GRIORA_NearestNeighbour,
    3076             :  * this oversampling threshold defaults to 1. Consequently if there are overviews
    3077             :  * of downscaling factor 2, 4 and 8, and the desired downscaling factor is
    3078             :  * 7.99, the overview of factor 4 will be selected for a non nearest resampling.
    3079             :  *
    3080             :  * For highest performance full resolution data access, read and write
    3081             :  * on "block boundaries" as returned by GetBlockSize(), or use the
    3082             :  * ReadBlock() and WriteBlock() methods.
    3083             :  *
    3084             :  * This method is the same as the C GDALDatasetRasterIO() or
    3085             :  * GDALDatasetRasterIOEx() functions.
    3086             :  *
    3087             :  * @param eRWFlag Either GF_Read to read a region of data, or GF_Write to
    3088             :  * write a region of data.
    3089             :  *
    3090             :  * @param nXOff The pixel offset to the top left corner of the region
    3091             :  * of the band to be accessed.  This would be zero to start from the left side.
    3092             :  *
    3093             :  * @param nYOff The line offset to the top left corner of the region
    3094             :  * of the band to be accessed.  This would be zero to start from the top.
    3095             :  *
    3096             :  * @param nXSize The width of the region of the band to be accessed in pixels.
    3097             :  *
    3098             :  * @param nYSize The height of the region of the band to be accessed in lines.
    3099             :  *
    3100             :  * @param pData The buffer into which the data should be read, or from which
    3101             :  * it should be written.  This buffer must contain at least
    3102             :  * nBufXSize * nBufYSize * nBandCount words of type eBufType.  It is organized
    3103             :  * in left to right,top to bottom pixel order.  Spacing is controlled by the
    3104             :  * nPixelSpace, and nLineSpace parameters.
    3105             :  * Note that even with eRWFlag==GF_Write, the content of the buffer might be
    3106             :  * temporarily modified during the execution of this method (and eventually
    3107             :  * restored back to its original content), so it is not safe to use a buffer
    3108             :  * stored in a read-only section of the calling program.
    3109             :  *
    3110             :  * @param nBufXSize the width of the buffer image into which the desired region
    3111             :  * is to be read, or from which it is to be written.
    3112             :  *
    3113             :  * @param nBufYSize the height of the buffer image into which the desired
    3114             :  * region is to be read, or from which it is to be written.
    3115             :  *
    3116             :  * @param eBufType the type of the pixel values in the pData data buffer. The
    3117             :  * pixel values will automatically be translated to/from the GDALRasterBand
    3118             :  * data type as needed. Most driver implementations will use GDALCopyWords64()
    3119             :  * to perform data type translation.
    3120             :  *
    3121             :  * @param nBandCount the number of bands being read or written.
    3122             :  *
    3123             :  * @param panBandMap the list of nBandCount band numbers being read/written.
    3124             :  * Note band numbers are 1 based. This may be NULL to select the first
    3125             :  * nBandCount bands. (Note: before GDAL 3.10, argument type was "int*", and
    3126             :  * not "const int*")
    3127             :  *
    3128             :  * @param nPixelSpace The byte offset from the start of one pixel value in
    3129             :  * pData to the start of the next pixel value within a scanline. If defaulted
    3130             :  * (0) the size of the datatype eBufType is used.
    3131             :  *
    3132             :  * @param nLineSpace The byte offset from the start of one scanline in
    3133             :  * pData to the start of the next. If defaulted (0) the size of the datatype
    3134             :  * eBufType * nBufXSize is used.
    3135             :  *
    3136             :  * @param nBandSpace the byte offset from the start of one bands data to the
    3137             :  * start of the next. If defaulted (0) the value will be
    3138             :  * nLineSpace * nBufYSize implying band sequential organization
    3139             :  * of the data buffer.
    3140             :  *
    3141             :  * @param psExtraArg pointer to a GDALRasterIOExtraArg
    3142             :  * structure with additional arguments to specify resampling and progress
    3143             :  * callback, or NULL for default behavior. The GDAL_RASTERIO_RESAMPLING
    3144             :  * configuration option can also be defined to override the default resampling
    3145             :  * to one of BILINEAR, CUBIC, CUBICSPLINE, LANCZOS, AVERAGE or MODE.
    3146             :  *
    3147             :  * @return CE_Failure if the access fails, otherwise CE_None.
    3148             :  */
    3149             : 
    3150      735135 : CPLErr GDALDataset::RasterIO(GDALRWFlag eRWFlag, int nXOff, int nYOff,
    3151             :                              int nXSize, int nYSize, void *pData, int nBufXSize,
    3152             :                              int nBufYSize, GDALDataType eBufType,
    3153             :                              int nBandCount, const int *panBandMap,
    3154             :                              GSpacing nPixelSpace, GSpacing nLineSpace,
    3155             :                              GSpacing nBandSpace,
    3156             :                              GDALRasterIOExtraArg *psExtraArg)
    3157             : 
    3158             : {
    3159             :     GDALRasterIOExtraArg sExtraArg;
    3160      735135 :     if (psExtraArg == nullptr)
    3161             :     {
    3162      542182 :         INIT_RASTERIO_EXTRA_ARG(sExtraArg);
    3163             : 
    3164             :         // 4 below inits are not strictly needed but make Coverity Scan
    3165             :         // happy
    3166      542182 :         sExtraArg.dfXOff = nXOff;
    3167      542182 :         sExtraArg.dfYOff = nYOff;
    3168      542182 :         sExtraArg.dfXSize = nXSize;
    3169      542182 :         sExtraArg.dfYSize = nYSize;
    3170             : 
    3171      542182 :         psExtraArg = &sExtraArg;
    3172             :     }
    3173      192953 :     else if (CPL_UNLIKELY(psExtraArg->nVersion >
    3174             :                           RASTERIO_EXTRA_ARG_CURRENT_VERSION))
    3175             :     {
    3176           0 :         ReportError(CE_Failure, CPLE_AppDefined,
    3177             :                     "Unhandled version of GDALRasterIOExtraArg");
    3178           0 :         return CE_Failure;
    3179             :     }
    3180             : 
    3181      735135 :     GDALRasterIOExtraArgSetResampleAlg(psExtraArg, nXSize, nYSize, nBufXSize,
    3182             :                                        nBufYSize);
    3183             : 
    3184      735135 :     if (CPL_UNLIKELY(nullptr == pData))
    3185             :     {
    3186           0 :         ReportError(CE_Failure, CPLE_AppDefined,
    3187             :                     "The buffer into which the data should be read is null");
    3188           0 :         return CE_Failure;
    3189             :     }
    3190             : 
    3191             :     /* -------------------------------------------------------------------- */
    3192             :     /*      Do some validation of parameters.                               */
    3193             :     /* -------------------------------------------------------------------- */
    3194             : 
    3195      735135 :     if (CPL_UNLIKELY(eRWFlag != GF_Read && eRWFlag != GF_Write))
    3196             :     {
    3197           0 :         ReportError(
    3198             :             CE_Failure, CPLE_IllegalArg,
    3199             :             "eRWFlag = %d, only GF_Read (0) and GF_Write (1) are legal.",
    3200             :             eRWFlag);
    3201           0 :         return CE_Failure;
    3202             :     }
    3203             : 
    3204      735135 :     if (eRWFlag == GF_Write)
    3205             :     {
    3206      216560 :         if (CPL_UNLIKELY(eAccess != GA_Update))
    3207             :         {
    3208           2 :             ReportError(CE_Failure, CPLE_AppDefined,
    3209             :                         "Write operation not permitted on dataset opened "
    3210             :                         "in read-only mode");
    3211           2 :             return CE_Failure;
    3212             :         }
    3213             :     }
    3214             : 
    3215      735133 :     int bStopProcessing = FALSE;
    3216      735133 :     CPLErr eErr = ValidateRasterIOOrAdviseReadParameters(
    3217             :         "RasterIO()", &bStopProcessing, nXOff, nYOff, nXSize, nYSize, nBufXSize,
    3218             :         nBufYSize, nBandCount, panBandMap);
    3219      735133 :     if (eErr != CE_None || bStopProcessing)
    3220           9 :         return eErr;
    3221      735124 :     if (CPL_UNLIKELY(eBufType == GDT_Unknown || eBufType == GDT_TypeCount))
    3222             :     {
    3223           2 :         ReportError(CE_Failure, CPLE_AppDefined,
    3224             :                     "Illegal GDT_Unknown/GDT_TypeCount argument");
    3225           2 :         return CE_Failure;
    3226             :     }
    3227             : 
    3228             :     /* -------------------------------------------------------------------- */
    3229             :     /*      If pixel and line spacing are defaulted assign reasonable      */
    3230             :     /*      value assuming a packed buffer.                                 */
    3231             :     /* -------------------------------------------------------------------- */
    3232      735122 :     if (nPixelSpace == 0)
    3233      424302 :         nPixelSpace = GDALGetDataTypeSizeBytes(eBufType);
    3234             : 
    3235      735122 :     if (nLineSpace == 0)
    3236             :     {
    3237      481617 :         nLineSpace = nPixelSpace * nBufXSize;
    3238             :     }
    3239             : 
    3240      735122 :     if (nBandSpace == 0 && nBandCount > 1)
    3241             :     {
    3242       66905 :         nBandSpace = nLineSpace * nBufYSize;
    3243             :     }
    3244             : 
    3245      735122 :     if (panBandMap == nullptr)
    3246             :     {
    3247      359140 :         if (!m_poPrivate)
    3248           0 :             return CE_Failure;
    3249      359140 :         CPLAssert(static_cast<int>(m_poPrivate->m_anBandMap.size()) == nBands);
    3250      359140 :         panBandMap = m_poPrivate->m_anBandMap.data();
    3251             :     }
    3252             : 
    3253      735122 :     int bCallLeaveReadWrite = EnterReadWrite(eRWFlag);
    3254             : 
    3255             :     /* -------------------------------------------------------------------- */
    3256             :     /*      We are being forced to use cached IO instead of a driver        */
    3257             :     /*      specific implementation.                                        */
    3258             :     /* -------------------------------------------------------------------- */
    3259      735122 :     if (bForceCachedIO)
    3260             :     {
    3261          21 :         eErr = BlockBasedRasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize, pData,
    3262             :                                   nBufXSize, nBufYSize, eBufType, nBandCount,
    3263             :                                   panBandMap, nPixelSpace, nLineSpace,
    3264          21 :                                   nBandSpace, psExtraArg);
    3265             :     }
    3266             : 
    3267             :     /* -------------------------------------------------------------------- */
    3268             :     /*      Call the format specific function.                              */
    3269             :     /* -------------------------------------------------------------------- */
    3270             :     else
    3271             :     {
    3272      735101 :         eErr = IRasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize, pData,
    3273             :                          nBufXSize, nBufYSize, eBufType, nBandCount,
    3274             :                          // TODO: remove this const_cast once IRasterIO()
    3275             :                          // takes a const int*
    3276             :                          const_cast<int *>(panBandMap), nPixelSpace, nLineSpace,
    3277      735101 :                          nBandSpace, psExtraArg);
    3278             :     }
    3279             : 
    3280      735122 :     if (bCallLeaveReadWrite)
    3281      407675 :         LeaveReadWrite();
    3282             : 
    3283      735122 :     return eErr;
    3284             : }
    3285             : 
    3286             : /************************************************************************/
    3287             : /*                        GDALDatasetRasterIO()                         */
    3288             : /************************************************************************/
    3289             : 
    3290             : /**
    3291             :  * \brief Read/write a region of image data from multiple bands.
    3292             :  *
    3293             :  * Use GDALDatasetRasterIOEx() if 64 bit spacings or extra arguments (resampling
    3294             :  * resolution, progress callback, etc. are needed)
    3295             :  *
    3296             :  * Note: before GDAL 3.10, panBandMap type was "int*", and not "const int*"
    3297             :  *
    3298             :  * @see GDALDataset::RasterIO()
    3299             :  */
    3300             : 
    3301        4762 : CPLErr CPL_STDCALL GDALDatasetRasterIO(GDALDatasetH hDS, GDALRWFlag eRWFlag,
    3302             :                                        int nXOff, int nYOff, int nXSize,
    3303             :                                        int nYSize, void *pData, int nBufXSize,
    3304             :                                        int nBufYSize, GDALDataType eBufType,
    3305             :                                        int nBandCount, const int *panBandMap,
    3306             :                                        int nPixelSpace, int nLineSpace,
    3307             :                                        int nBandSpace)
    3308             : 
    3309             : {
    3310        4762 :     VALIDATE_POINTER1(hDS, "GDALDatasetRasterIO", CE_Failure);
    3311             : 
    3312        4762 :     GDALDataset *poDS = GDALDataset::FromHandle(hDS);
    3313             : 
    3314        4762 :     return poDS->RasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize, pData,
    3315             :                           nBufXSize, nBufYSize, eBufType, nBandCount,
    3316             :                           panBandMap, nPixelSpace, nLineSpace, nBandSpace,
    3317        4762 :                           nullptr);
    3318             : }
    3319             : 
    3320             : /************************************************************************/
    3321             : /*                       GDALDatasetRasterIOEx()                        */
    3322             : /************************************************************************/
    3323             : 
    3324             : /**
    3325             :  * \brief Read/write a region of image data from multiple bands.
    3326             :  *
    3327             :  * Note: before GDAL 3.10, panBandMap type was "int*", and not "const int*"
    3328             :  *
    3329             :  * @see GDALDataset::RasterIO()
    3330             :  */
    3331             : 
    3332      353278 : CPLErr CPL_STDCALL GDALDatasetRasterIOEx(
    3333             :     GDALDatasetH hDS, GDALRWFlag eRWFlag, int nXOff, int nYOff, int nXSize,
    3334             :     int nYSize, void *pData, int nBufXSize, int nBufYSize,
    3335             :     GDALDataType eBufType, int nBandCount, const int *panBandMap,
    3336             :     GSpacing nPixelSpace, GSpacing nLineSpace, GSpacing nBandSpace,
    3337             :     GDALRasterIOExtraArg *psExtraArg)
    3338             : 
    3339             : {
    3340      353278 :     VALIDATE_POINTER1(hDS, "GDALDatasetRasterIOEx", CE_Failure);
    3341             : 
    3342      353278 :     GDALDataset *poDS = GDALDataset::FromHandle(hDS);
    3343             : 
    3344      353278 :     return poDS->RasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize, pData,
    3345             :                           nBufXSize, nBufYSize, eBufType, nBandCount,
    3346             :                           panBandMap, nPixelSpace, nLineSpace, nBandSpace,
    3347      353278 :                           psExtraArg);
    3348             : }
    3349             : 
    3350             : /************************************************************************/
    3351             : /*                          GetOpenDatasets()                           */
    3352             : /************************************************************************/
    3353             : 
    3354             : /**
    3355             :  * \brief Fetch all open GDAL dataset handles.
    3356             :  *
    3357             :  * This method is the same as the C function GDALGetOpenDatasets().
    3358             :  *
    3359             :  * NOTE: This method is not thread safe.  The returned list may change
    3360             :  * at any time and it should not be freed.
    3361             :  *
    3362             :  * @param pnCount integer into which to place the count of dataset pointers
    3363             :  * being returned.
    3364             :  *
    3365             :  * @return a pointer to an array of dataset handles.
    3366             :  */
    3367             : 
    3368        2268 : GDALDataset **GDALDataset::GetOpenDatasets(int *pnCount)
    3369             : 
    3370             : {
    3371        4536 :     CPLMutexHolderD(&hDLMutex);
    3372             : 
    3373        2268 :     if (poAllDatasetMap == nullptr)
    3374             :     {
    3375        2246 :         *pnCount = 0;
    3376        2246 :         return nullptr;
    3377             :     }
    3378             : 
    3379          22 :     *pnCount = static_cast<int>(poAllDatasetMap->size());
    3380          22 :     ppDatasets = static_cast<GDALDataset **>(
    3381          22 :         CPLRealloc(ppDatasets, (*pnCount) * sizeof(GDALDataset *)));
    3382          22 :     std::map<GDALDataset *, GIntBig>::iterator oIter = poAllDatasetMap->begin();
    3383         606 :     for (int i = 0; oIter != poAllDatasetMap->end(); ++oIter, ++i)
    3384         584 :         ppDatasets[i] = oIter->first;
    3385          22 :     return ppDatasets;
    3386             : }
    3387             : 
    3388             : /************************************************************************/
    3389             : /*                        GDALGetOpenDatasets()                         */
    3390             : /************************************************************************/
    3391             : 
    3392             : /**
    3393             :  * \brief Fetch all open GDAL dataset handles.
    3394             :  *
    3395             :  * @see GDALDataset::GetOpenDatasets()
    3396             :  */
    3397             : 
    3398           0 : void CPL_STDCALL GDALGetOpenDatasets(GDALDatasetH **ppahDSList, int *pnCount)
    3399             : 
    3400             : {
    3401           0 :     VALIDATE_POINTER0(ppahDSList, "GDALGetOpenDatasets");
    3402           0 :     VALIDATE_POINTER0(pnCount, "GDALGetOpenDatasets");
    3403             : 
    3404           0 :     *ppahDSList =
    3405           0 :         reinterpret_cast<GDALDatasetH *>(GDALDataset::GetOpenDatasets(pnCount));
    3406             : }
    3407             : 
    3408             : /************************************************************************/
    3409             : /*                        GDALCleanOpenDatasetsList()                   */
    3410             : /************************************************************************/
    3411             : 
    3412             : // Useful when called from the child of a fork(), to avoid closing
    3413             : // the datasets of the parent at the child termination.
    3414           0 : void GDALNullifyOpenDatasetsList()
    3415             : {
    3416           0 :     poAllDatasetMap = nullptr;
    3417           0 :     phSharedDatasetSet = nullptr;
    3418           0 :     ppDatasets = nullptr;
    3419           0 :     hDLMutex = nullptr;
    3420           0 : }
    3421             : 
    3422             : /************************************************************************/
    3423             : /*                             GDALGetAccess()                          */
    3424             : /************************************************************************/
    3425             : 
    3426             : /**
    3427             :  * \brief Return access flag
    3428             :  *
    3429             :  * @see GDALDataset::GetAccess()
    3430             :  */
    3431             : 
    3432           0 : int CPL_STDCALL GDALGetAccess(GDALDatasetH hDS)
    3433             : {
    3434           0 :     VALIDATE_POINTER1(hDS, "GDALGetAccess", 0);
    3435             : 
    3436           0 :     return GDALDataset::FromHandle(hDS)->GetAccess();
    3437             : }
    3438             : 
    3439             : /************************************************************************/
    3440             : /*                             AdviseRead()                             */
    3441             : /************************************************************************/
    3442             : 
    3443             : /**
    3444             :  * \brief Advise driver of upcoming read requests.
    3445             :  *
    3446             :  * Some GDAL drivers operate more efficiently if they know in advance what
    3447             :  * set of upcoming read requests will be made.  The AdviseRead() method allows
    3448             :  * an application to notify the driver of the region and bands of interest,
    3449             :  * and at what resolution the region will be read.
    3450             :  *
    3451             :  * Many drivers just ignore the AdviseRead() call, but it can dramatically
    3452             :  * accelerate access via some drivers.
    3453             :  *
    3454             :  * Depending on call paths, drivers might receive several calls to
    3455             :  * AdviseRead() with the same parameters.
    3456             :  *
    3457             :  * @param nXOff The pixel offset to the top left corner of the region
    3458             :  * of the band to be accessed.  This would be zero to start from the left side.
    3459             :  *
    3460             :  * @param nYOff The line offset to the top left corner of the region
    3461             :  * of the band to be accessed.  This would be zero to start from the top.
    3462             :  *
    3463             :  * @param nXSize The width of the region of the band to be accessed in pixels.
    3464             :  *
    3465             :  * @param nYSize The height of the region of the band to be accessed in lines.
    3466             :  *
    3467             :  * @param nBufXSize the width of the buffer image into which the desired region
    3468             :  * is to be read, or from which it is to be written.
    3469             :  *
    3470             :  * @param nBufYSize the height of the buffer image into which the desired
    3471             :  * region is to be read, or from which it is to be written.
    3472             :  *
    3473             :  * @param eBufType the type of the pixel values in the pData data buffer.  The
    3474             :  * pixel values will automatically be translated to/from the GDALRasterBand
    3475             :  * data type as needed.
    3476             :  *
    3477             :  * @param nBandCount the number of bands being read or written.
    3478             :  *
    3479             :  * @param panBandMap the list of nBandCount band numbers being read/written.
    3480             :  * Note band numbers are 1 based.   This may be NULL to select the first
    3481             :  * nBandCount bands.
    3482             :  *
    3483             :  * @param papszOptions a list of name=value strings with special control
    3484             :  * options.  Normally this is NULL.
    3485             :  *
    3486             :  * @return CE_Failure if the request is invalid and CE_None if it works or
    3487             :  * is ignored.
    3488             :  */
    3489             : 
    3490       14989 : CPLErr GDALDataset::AdviseRead(int nXOff, int nYOff, int nXSize, int nYSize,
    3491             :                                int nBufXSize, int nBufYSize,
    3492             :                                GDALDataType eBufType, int nBandCount,
    3493             :                                int *panBandMap, char **papszOptions)
    3494             : 
    3495             : {
    3496             :     /* -------------------------------------------------------------------- */
    3497             :     /*      Do some validation of parameters.                               */
    3498             :     /* -------------------------------------------------------------------- */
    3499       14989 :     int bStopProcessing = FALSE;
    3500       14989 :     CPLErr eErr = ValidateRasterIOOrAdviseReadParameters(
    3501             :         "AdviseRead()", &bStopProcessing, nXOff, nYOff, nXSize, nYSize,
    3502             :         nBufXSize, nBufYSize, nBandCount, panBandMap);
    3503       14989 :     if (eErr != CE_None || bStopProcessing)
    3504          23 :         return eErr;
    3505             : 
    3506      129197 :     for (int iBand = 0; iBand < nBandCount; ++iBand)
    3507             :     {
    3508      114231 :         GDALRasterBand *poBand = nullptr;
    3509             : 
    3510      114231 :         if (panBandMap == nullptr)
    3511      112871 :             poBand = GetRasterBand(iBand + 1);
    3512             :         else
    3513        1360 :             poBand = GetRasterBand(panBandMap[iBand]);
    3514             : 
    3515      114231 :         if (poBand == nullptr)
    3516           0 :             return CE_Failure;
    3517             : 
    3518      228462 :         eErr = poBand->AdviseRead(nXOff, nYOff, nXSize, nYSize, nBufXSize,
    3519      114231 :                                   nBufYSize, eBufType, papszOptions);
    3520             : 
    3521      114231 :         if (eErr != CE_None)
    3522           0 :             return eErr;
    3523             :     }
    3524             : 
    3525       14966 :     return CE_None;
    3526             : }
    3527             : 
    3528             : /************************************************************************/
    3529             : /*                       GDALDatasetAdviseRead()                        */
    3530             : /************************************************************************/
    3531             : 
    3532             : /**
    3533             :  * \brief Advise driver of upcoming read requests.
    3534             :  *
    3535             :  * @see GDALDataset::AdviseRead()
    3536             :  */
    3537           1 : CPLErr CPL_STDCALL GDALDatasetAdviseRead(GDALDatasetH hDS, int nXOff, int nYOff,
    3538             :                                          int nXSize, int nYSize, int nBufXSize,
    3539             :                                          int nBufYSize, GDALDataType eDT,
    3540             :                                          int nBandCount, int *panBandMap,
    3541             :                                          CSLConstList papszOptions)
    3542             : 
    3543             : {
    3544           1 :     VALIDATE_POINTER1(hDS, "GDALDatasetAdviseRead", CE_Failure);
    3545             : 
    3546           2 :     return GDALDataset::FromHandle(hDS)->AdviseRead(
    3547             :         nXOff, nYOff, nXSize, nYSize, nBufXSize, nBufYSize, eDT, nBandCount,
    3548           1 :         panBandMap, const_cast<char **>(papszOptions));
    3549             : }
    3550             : 
    3551             : /************************************************************************/
    3552             : /*                         GDALAntiRecursionStruct                      */
    3553             : /************************************************************************/
    3554             : 
    3555             : // Prevent infinite recursion.
    3556             : struct GDALAntiRecursionStruct
    3557             : {
    3558             :     struct DatasetContext
    3559             :     {
    3560             :         std::string osFilename;
    3561             :         int nOpenFlags;
    3562             :         std::string osAllowedDrivers;
    3563             : 
    3564       82367 :         DatasetContext(const std::string &osFilenameIn, int nOpenFlagsIn,
    3565             :                        const std::string &osAllowedDriversIn)
    3566       82367 :             : osFilename(osFilenameIn), nOpenFlags(nOpenFlagsIn),
    3567       82367 :               osAllowedDrivers(osAllowedDriversIn)
    3568             :         {
    3569       82367 :         }
    3570             :     };
    3571             : 
    3572             :     struct DatasetContextCompare
    3573             :     {
    3574      965343 :         bool operator()(const DatasetContext &lhs,
    3575             :                         const DatasetContext &rhs) const
    3576             :         {
    3577     2821010 :             return lhs.osFilename < rhs.osFilename ||
    3578      934619 :                    (lhs.osFilename == rhs.osFilename &&
    3579      921050 :                     (lhs.nOpenFlags < rhs.nOpenFlags ||
    3580     1841640 :                      (lhs.nOpenFlags == rhs.nOpenFlags &&
    3581     1886100 :                       lhs.osAllowedDrivers < rhs.osAllowedDrivers)));
    3582             :         }
    3583             :     };
    3584             : 
    3585        1359 :     ~GDALAntiRecursionStruct()
    3586        1359 :     {
    3587        1359 :         CPLAssert(aosDatasetNamesWithFlags.empty());
    3588        1359 :         CPLAssert(nRecLevel == 0);
    3589        1359 :         CPLAssert(m_oMapDepth.empty());
    3590        1359 :     }
    3591             : 
    3592             :     std::set<DatasetContext, DatasetContextCompare> aosDatasetNamesWithFlags{};
    3593             :     int nRecLevel = 0;
    3594             :     std::map<std::string, int> m_oMapDepth{};
    3595             : };
    3596             : 
    3597             : #ifdef _WIN32
    3598             : // Currently thread_local and C++ objects don't work well with DLL on Windows
    3599             : static void FreeAntiRecursionOpen(void *pData)
    3600             : {
    3601             :     delete static_cast<GDALAntiRecursionStruct *>(pData);
    3602             : }
    3603             : 
    3604             : static GDALAntiRecursionStruct &GetAntiRecursionOpen()
    3605             : {
    3606             :     static GDALAntiRecursionStruct dummy;
    3607             :     int bMemoryErrorOccurred = false;
    3608             :     void *pData =
    3609             :         CPLGetTLSEx(CTLS_GDALOPEN_ANTIRECURSION, &bMemoryErrorOccurred);
    3610             :     if (bMemoryErrorOccurred)
    3611             :     {
    3612             :         return dummy;
    3613             :     }
    3614             :     if (pData == nullptr)
    3615             :     {
    3616             :         auto pAntiRecursion = new GDALAntiRecursionStruct();
    3617             :         CPLSetTLSWithFreeFuncEx(CTLS_GDALOPEN_ANTIRECURSION, pAntiRecursion,
    3618             :                                 FreeAntiRecursionOpen, &bMemoryErrorOccurred);
    3619             :         if (bMemoryErrorOccurred)
    3620             :         {
    3621             :             delete pAntiRecursion;
    3622             :             return dummy;
    3623             :         }
    3624             :         return *pAntiRecursion;
    3625             :     }
    3626             :     return *static_cast<GDALAntiRecursionStruct *>(pData);
    3627             : }
    3628             : #else
    3629             : static thread_local GDALAntiRecursionStruct g_tls_antiRecursion;
    3630             : 
    3631      346974 : static GDALAntiRecursionStruct &GetAntiRecursionOpen()
    3632             : {
    3633      346974 :     return g_tls_antiRecursion;
    3634             : }
    3635             : #endif
    3636             : 
    3637             : //! @cond Doxygen_Suppress
    3638      264607 : GDALAntiRecursionGuard::GDALAntiRecursionGuard(const std::string &osIdentifier)
    3639      264607 :     : m_psAntiRecursionStruct(&GetAntiRecursionOpen()),
    3640             :       m_osIdentifier(osIdentifier),
    3641      264607 :       m_nDepth(++m_psAntiRecursionStruct->m_oMapDepth[m_osIdentifier])
    3642             : {
    3643      264607 :     CPLAssert(!osIdentifier.empty());
    3644      264607 : }
    3645             : 
    3646      264607 : GDALAntiRecursionGuard::GDALAntiRecursionGuard(
    3647      264607 :     const GDALAntiRecursionGuard &other, const std::string &osIdentifier)
    3648      264607 :     : m_psAntiRecursionStruct(other.m_psAntiRecursionStruct),
    3649      264607 :       m_osIdentifier(osIdentifier.empty()
    3650             :                          ? osIdentifier
    3651       30574 :                          : other.m_osIdentifier + osIdentifier),
    3652      264607 :       m_nDepth(m_osIdentifier.empty()
    3653      264607 :                    ? 0
    3654      295181 :                    : ++m_psAntiRecursionStruct->m_oMapDepth[m_osIdentifier])
    3655             : {
    3656      264607 : }
    3657             : 
    3658      529214 : GDALAntiRecursionGuard::~GDALAntiRecursionGuard()
    3659             : {
    3660      529214 :     if (!m_osIdentifier.empty())
    3661             :     {
    3662      295181 :         auto oIter = m_psAntiRecursionStruct->m_oMapDepth.find(m_osIdentifier);
    3663      295181 :         CPLAssert(oIter != m_psAntiRecursionStruct->m_oMapDepth.end());
    3664      295181 :         if (--(oIter->second) == 0)
    3665      290729 :             m_psAntiRecursionStruct->m_oMapDepth.erase(oIter);
    3666             :     }
    3667      529214 : }
    3668             : 
    3669             : //! @endcond
    3670             : 
    3671             : /************************************************************************/
    3672             : /*                            GetFileList()                             */
    3673             : /************************************************************************/
    3674             : 
    3675             : /**
    3676             :  * \brief Fetch files forming dataset.
    3677             :  *
    3678             :  * Returns a list of files believed to be part of this dataset.  If it returns
    3679             :  * an empty list of files it means there is believed to be no local file
    3680             :  * system files associated with the dataset (for instance a virtual dataset).
    3681             :  * The returned file list is owned by the caller and should be deallocated
    3682             :  * with CSLDestroy().
    3683             :  *
    3684             :  * The returned filenames will normally be relative or absolute paths
    3685             :  * depending on the path used to originally open the dataset.  The strings
    3686             :  * will be UTF-8 encoded.
    3687             :  *
    3688             :  * This method is the same as the C GDALGetFileList() function.
    3689             :  *
    3690             :  * @return NULL or a NULL terminated array of file names.
    3691             :  */
    3692             : 
    3693        4685 : char **GDALDataset::GetFileList()
    3694             : 
    3695             : {
    3696        9370 :     CPLString osMainFilename = GetDescription();
    3697             :     VSIStatBufL sStat;
    3698             : 
    3699        4685 :     GDALAntiRecursionStruct &sAntiRecursion = GetAntiRecursionOpen();
    3700             :     GDALAntiRecursionStruct::DatasetContext datasetCtxt(osMainFilename, 0,
    3701        9370 :                                                         std::string());
    3702        4685 :     auto &aosDatasetList = sAntiRecursion.aosDatasetNamesWithFlags;
    3703        4685 :     if (cpl::contains(aosDatasetList, datasetCtxt))
    3704           0 :         return nullptr;
    3705             : 
    3706             :     /* -------------------------------------------------------------------- */
    3707             :     /*      Is the main filename even a real filesystem object?             */
    3708             :     /* -------------------------------------------------------------------- */
    3709             :     int bMainFileReal =
    3710        4685 :         VSIStatExL(osMainFilename, &sStat, VSI_STAT_EXISTS_FLAG) == 0;
    3711             : 
    3712             :     /* -------------------------------------------------------------------- */
    3713             :     /*      Form new list.                                                  */
    3714             :     /* -------------------------------------------------------------------- */
    3715        4685 :     char **papszList = nullptr;
    3716             : 
    3717        4685 :     if (bMainFileReal)
    3718        4605 :         papszList = CSLAddString(papszList, osMainFilename);
    3719             : 
    3720        4685 :     if (sAntiRecursion.nRecLevel == 100)
    3721             :     {
    3722           0 :         CPLError(CE_Failure, CPLE_AppDefined,
    3723             :                  "GetFileList() called with too many recursion levels");
    3724           0 :         return papszList;
    3725             :     }
    3726        4685 :     ++sAntiRecursion.nRecLevel;
    3727             : 
    3728             :     /* -------------------------------------------------------------------- */
    3729             :     /*      Do we have a known overview file?                               */
    3730             :     /* -------------------------------------------------------------------- */
    3731        4685 :     if (oOvManager.IsInitialized() && oOvManager.poODS != nullptr)
    3732             :     {
    3733          60 :         auto iter = aosDatasetList.insert(datasetCtxt).first;
    3734          60 :         char **papszOvrList = oOvManager.poODS->GetFileList();
    3735          60 :         papszList = CSLInsertStrings(papszList, -1, papszOvrList);
    3736          60 :         CSLDestroy(papszOvrList);
    3737          60 :         aosDatasetList.erase(iter);
    3738             :     }
    3739             : 
    3740             :     /* -------------------------------------------------------------------- */
    3741             :     /*      Do we have a known mask file?                                   */
    3742             :     /* -------------------------------------------------------------------- */
    3743        4685 :     if (oOvManager.HaveMaskFile())
    3744             :     {
    3745           9 :         auto iter = aosDatasetList.insert(std::move(datasetCtxt)).first;
    3746           9 :         for (const char *pszFile :
    3747          18 :              CPLStringList(oOvManager.poMaskDS->GetFileList()))
    3748             :         {
    3749           9 :             if (CSLFindString(papszList, pszFile) < 0)
    3750           9 :                 papszList = CSLAddString(papszList, pszFile);
    3751             :         }
    3752           9 :         aosDatasetList.erase(iter);
    3753             :     }
    3754             : 
    3755        4685 :     --sAntiRecursion.nRecLevel;
    3756             : 
    3757        4685 :     return papszList;
    3758             : }
    3759             : 
    3760             : /************************************************************************/
    3761             : /*                          GDALGetFileList()                           */
    3762             : /************************************************************************/
    3763             : 
    3764             : /**
    3765             :  * \brief Fetch files forming dataset.
    3766             :  *
    3767             :  * @see GDALDataset::GetFileList()
    3768             :  */
    3769             : 
    3770        3869 : char **CPL_STDCALL GDALGetFileList(GDALDatasetH hDS)
    3771             : 
    3772             : {
    3773        3869 :     VALIDATE_POINTER1(hDS, "GDALGetFileList", nullptr);
    3774             : 
    3775        3869 :     return GDALDataset::FromHandle(hDS)->GetFileList();
    3776             : }
    3777             : 
    3778             : /************************************************************************/
    3779             : /*                           CreateMaskBand()                           */
    3780             : /************************************************************************/
    3781             : 
    3782             : /**
    3783             :  * \brief Adds a mask band to the dataset
    3784             :  *
    3785             :  * The default implementation of the CreateMaskBand() method is implemented
    3786             :  * based on similar rules to the .ovr handling implemented using the
    3787             :  * GDALDefaultOverviews object. A TIFF file with the extension .msk will
    3788             :  * be created with the same basename as the original file, and it will have
    3789             :  * one band.
    3790             :  * The mask images will be deflate compressed tiled images with the same
    3791             :  * block size as the original image if possible.
    3792             :  * It will have INTERNAL_MASK_FLAGS_xx metadata items set at the dataset
    3793             :  * level, where xx matches the band number of a band of the main dataset. The
    3794             :  * value of those items will be the one of the nFlagsIn parameter.
    3795             :  *
    3796             :  * Note that if you got a mask band with a previous call to GetMaskBand(), it
    3797             :  * might be invalidated by CreateMaskBand(). So you have to call GetMaskBand()
    3798             :  * again.
    3799             :  *
    3800             :  *
    3801             :  * @param nFlagsIn 0 or combination of GMF_PER_DATASET / GMF_ALPHA.
    3802             :  *                 GMF_PER_DATASET will be always set, even if not explicitly
    3803             :  *                 specified.
    3804             :  * @return CE_None on success or CE_Failure on an error.
    3805             :  *
    3806             :  * @see https://gdal.org/development/rfc/rfc15_nodatabitmask.html
    3807             :  * @see GDALRasterBand::CreateMaskBand()
    3808             :  *
    3809             :  */
    3810          17 : CPLErr GDALDataset::CreateMaskBand(int nFlagsIn)
    3811             : 
    3812             : {
    3813          17 :     if (oOvManager.IsInitialized())
    3814             :     {
    3815          17 :         CPLErr eErr = oOvManager.CreateMaskBand(nFlagsIn, -1);
    3816          17 :         if (eErr != CE_None)
    3817           0 :             return eErr;
    3818             : 
    3819             :         // Invalidate existing raster band masks.
    3820          45 :         for (int i = 0; i < nBands; ++i)
    3821             :         {
    3822          28 :             GDALRasterBand *poBand = papoBands[i];
    3823          28 :             poBand->poMask.reset();
    3824             :         }
    3825             : 
    3826          17 :         return CE_None;
    3827             :     }
    3828             : 
    3829           0 :     ReportError(CE_Failure, CPLE_NotSupported,
    3830             :                 "CreateMaskBand() not supported for this dataset.");
    3831             : 
    3832           0 :     return CE_Failure;
    3833             : }
    3834             : 
    3835             : /************************************************************************/
    3836             : /*                     GDALCreateDatasetMaskBand()                      */
    3837             : /************************************************************************/
    3838             : 
    3839             : /**
    3840             :  * \brief Adds a mask band to the dataset
    3841             :  * @see GDALDataset::CreateMaskBand()
    3842             :  */
    3843         107 : CPLErr CPL_STDCALL GDALCreateDatasetMaskBand(GDALDatasetH hDS, int nFlags)
    3844             : 
    3845             : {
    3846         107 :     VALIDATE_POINTER1(hDS, "GDALCreateDatasetMaskBand", CE_Failure);
    3847             : 
    3848         107 :     return GDALDataset::FromHandle(hDS)->CreateMaskBand(nFlags);
    3849             : }
    3850             : 
    3851             : /************************************************************************/
    3852             : /*                              GDALOpen()                              */
    3853             : /************************************************************************/
    3854             : 
    3855             : /**
    3856             :  * \brief Open a raster file as a GDALDataset.
    3857             :  *
    3858             :  * This function will try to open the passed file, or virtual dataset
    3859             :  * name by invoking the Open method of each registered GDALDriver in turn.
    3860             :  * The first successful open will result in a returned dataset.  If all
    3861             :  * drivers fail then NULL is returned and an error is issued.
    3862             :  *
    3863             :  * Several recommendations :
    3864             :  * <ul>
    3865             :  * <li>If you open a dataset object with GA_Update access, it is not recommended
    3866             :  * to open a new dataset on the same underlying file.</li>
    3867             :  * <li>The returned dataset should only be accessed by one thread at a time. If
    3868             :  * you want to use it from different threads, you must add all necessary code
    3869             :  * (mutexes, etc.)  to avoid concurrent use of the object. (Some drivers, such
    3870             :  * as GeoTIFF, maintain internal state variables that are updated each time a
    3871             :  * new block is read, thus preventing concurrent use.) </li>
    3872             :  * </ul>
    3873             :  *
    3874             :  * For drivers supporting the VSI virtual file API, it is possible to open a
    3875             :  * file in a .zip archive (see VSIInstallZipFileHandler()), in a
    3876             :  * .tar/.tar.gz/.tgz archive (see VSIInstallTarFileHandler()) or on a HTTP / FTP
    3877             :  * server (see VSIInstallCurlFileHandler())
    3878             :  *
    3879             :  * \sa GDALOpenShared()
    3880             :  * \sa GDALOpenEx()
    3881             :  *
    3882             :  * @param pszFilename the name of the file to access.  In the case of
    3883             :  * exotic drivers this may not refer to a physical file, but instead contain
    3884             :  * information for the driver on how to access a dataset.  It should be in UTF-8
    3885             :  * encoding.
    3886             :  *
    3887             :  * @param eAccess the desired access, either GA_Update or GA_ReadOnly.  Many
    3888             :  * drivers support only read only access.
    3889             :  *
    3890             :  * @return A GDALDatasetH handle or NULL on failure.  For C++ applications
    3891             :  * this handle can be cast to a GDALDataset *.
    3892             :  */
    3893             : 
    3894       25543 : GDALDatasetH CPL_STDCALL GDALOpen(const char *pszFilename, GDALAccess eAccess)
    3895             : 
    3896             : {
    3897       25543 :     const int nUpdateFlag = eAccess == GA_Update ? GDAL_OF_UPDATE : 0;
    3898       25543 :     const int nOpenFlags = GDAL_OF_RASTER | nUpdateFlag | GDAL_OF_VERBOSE_ERROR;
    3899             :     GDALDatasetH hDataset =
    3900       25543 :         GDALOpenEx(pszFilename, nOpenFlags, nullptr, nullptr, nullptr);
    3901       25543 :     return hDataset;
    3902             : }
    3903             : 
    3904             : /************************************************************************/
    3905             : /*                             GetSharedDS()                            */
    3906             : /************************************************************************/
    3907             : 
    3908        6485 : static GDALDataset *GetSharedDS(const char *pszFilename,
    3909             :                                 unsigned int nOpenFlags,
    3910             :                                 const char *const *papszOpenOptions)
    3911             : {
    3912       12970 :     CPLMutexHolderD(&hDLMutex);
    3913             : 
    3914        6485 :     if (phSharedDatasetSet != nullptr)
    3915             :     {
    3916        6244 :         const GIntBig nThisPID = GDALGetResponsiblePIDForCurrentThread();
    3917             :         SharedDatasetCtxt sStruct;
    3918             : 
    3919        6244 :         sStruct.nPID = nThisPID;
    3920        6244 :         sStruct.pszDescription = const_cast<char *>(pszFilename);
    3921        6244 :         sStruct.nOpenFlags = nOpenFlags & ~GDAL_OF_SHARED;
    3922             :         std::string osConcatenatedOpenOptions =
    3923        6244 :             GDALSharedDatasetConcatenateOpenOptions(papszOpenOptions);
    3924        6244 :         sStruct.pszConcatenatedOpenOptions = &osConcatenatedOpenOptions[0];
    3925        6244 :         sStruct.poDS = nullptr;
    3926             :         SharedDatasetCtxt *psStruct = static_cast<SharedDatasetCtxt *>(
    3927        6244 :             CPLHashSetLookup(phSharedDatasetSet, &sStruct));
    3928        6244 :         if (psStruct == nullptr && (nOpenFlags & GDAL_OF_UPDATE) == 0)
    3929             :         {
    3930         139 :             sStruct.nOpenFlags |= GDAL_OF_UPDATE;
    3931             :             psStruct = static_cast<SharedDatasetCtxt *>(
    3932         139 :                 CPLHashSetLookup(phSharedDatasetSet, &sStruct));
    3933             :         }
    3934        6244 :         if (psStruct)
    3935             :         {
    3936        6106 :             return psStruct->poDS;
    3937             :         }
    3938             :     }
    3939         379 :     return nullptr;
    3940             : }
    3941             : 
    3942             : /************************************************************************/
    3943             : /*                             GDALOpenEx()                             */
    3944             : /************************************************************************/
    3945             : 
    3946             : /**
    3947             :  * \brief Open a raster or vector file as a GDALDataset.
    3948             :  *
    3949             :  * This function will try to open the passed file, or virtual dataset
    3950             :  * name by invoking the Open method of each registered GDALDriver in turn.
    3951             :  * The first successful open will result in a returned dataset.  If all
    3952             :  * drivers fail then NULL is returned and an error is issued.
    3953             :  *
    3954             :  * Several recommendations :
    3955             :  * <ul>
    3956             :  * <li>If you open a dataset object with GDAL_OF_UPDATE access, it is not
    3957             :  * recommended to open a new dataset on the same underlying file.</li>
    3958             :  * <li>The returned dataset should only be accessed by one thread at a time. If
    3959             :  * you want to use it from different threads, you must add all necessary code
    3960             :  * (mutexes, etc.)  to avoid concurrent use of the object. (Some drivers, such
    3961             :  * as GeoTIFF, maintain internal state variables that are updated each time a
    3962             :  * new block is read, thus preventing concurrent use.) </li>
    3963             :  * </ul>
    3964             :  *
    3965             :  * For drivers supporting the VSI virtual file API, it is possible to open a
    3966             :  * file in a .zip archive (see VSIInstallZipFileHandler()), in a
    3967             :  * .tar/.tar.gz/.tgz archive (see VSIInstallTarFileHandler()) or on a HTTP / FTP
    3968             :  * server (see VSIInstallCurlFileHandler())
    3969             :  *
    3970             :  * In order to reduce the need for searches through the operating system
    3971             :  * file system machinery, it is possible to give an optional list of files with
    3972             :  * the papszSiblingFiles parameter.
    3973             :  * This is the list of all files at the same level in the file system as the
    3974             :  * target file, including the target file. The filenames must not include any
    3975             :  * path components, are essentially just the output of VSIReadDir() on the
    3976             :  * parent directory. If the target object does not have filesystem semantics
    3977             :  * then the file list should be NULL.
    3978             :  *
    3979             :  * @param pszFilename the name of the file to access.  In the case of
    3980             :  * exotic drivers this may not refer to a physical file, but instead contain
    3981             :  * information for the driver on how to access a dataset.  It should be in UTF-8
    3982             :  * encoding.
    3983             :  *
    3984             :  * @param nOpenFlags a combination of GDAL_OF_ flags that may be combined
    3985             :  * through logical or operator.
    3986             :  * <ul>
    3987             :  * <li>Driver kind:
    3988             :  *   <ul>
    3989             :  *     <li>GDAL_OF_RASTER for raster drivers,</li>
    3990             :  *     <li>GDAL_OF_MULTIDIM_RASTER for multidimensional raster drivers,</li>
    3991             :  *     <li>GDAL_OF_VECTOR for vector drivers,</li>
    3992             :  *     <li>GDAL_OF_GNM for Geographic Network Model drivers.</li>
    3993             :  *    </ul>
    3994             :  * GDAL_OF_RASTER and GDAL_OF_MULTIDIM_RASTER are generally mutually
    3995             :  * exclusive. If none of the value is specified, GDAL_OF_RASTER | GDAL_OF_VECTOR
    3996             :  * | GDAL_OF_GNM is implied.
    3997             :  * </li>
    3998             :  * <li>Access mode: GDAL_OF_READONLY (exclusive)or GDAL_OF_UPDATE.
    3999             :  * </li>
    4000             :  * <li>Shared mode: GDAL_OF_SHARED. If set,
    4001             :  * it allows the sharing of GDALDataset handles for a dataset with other callers
    4002             :  * that have set GDAL_OF_SHARED. In particular, GDALOpenEx() will first consult
    4003             :  * its list of currently open and shared GDALDataset's, and if the
    4004             :  * GetDescription() name for one exactly matches the pszFilename passed to
    4005             :  * GDALOpenEx() it will be referenced and returned, if GDALOpenEx() is called
    4006             :  * from the same thread.
    4007             :  * </li>
    4008             :  * <li>Thread safe mode: GDAL_OF_THREAD_SAFE (added in 3.10).
    4009             :  * This must be use in combination with GDAL_OF_RASTER, and is mutually
    4010             :  * exclusive with GDAL_OF_UPDATE, GDAL_OF_VECTOR, GDAL_OF_MULTIDIM_RASTER or
    4011             :  * GDAL_OF_GNM.
    4012             :  * </li>
    4013             :  * <li>Verbose error: GDAL_OF_VERBOSE_ERROR. If set,
    4014             :  * a failed attempt to open the file will lead to an error message to be
    4015             :  * reported.
    4016             :  * </li>
    4017             :  * </ul>
    4018             :  *
    4019             :  * @param papszAllowedDrivers NULL to consider all candidate drivers, or a NULL
    4020             :  * terminated list of strings with the driver short names that must be
    4021             :  * considered.
    4022             :  *
    4023             :  * @param papszOpenOptions NULL, or a NULL terminated list of strings with open
    4024             :  * options passed to candidate drivers. An option exists for all drivers,
    4025             :  * OVERVIEW_LEVEL=level, to select a particular overview level of a dataset.
    4026             :  * The level index starts at 0. The level number can be suffixed by "only" to
    4027             :  * specify that only this overview level must be visible, and not sub-levels.
    4028             :  * Open options are validated by default, and a warning is emitted in case the
    4029             :  * option is not recognized. In some scenarios, it might be not desirable (e.g.
    4030             :  * when not knowing which driver will open the file), so the special open option
    4031             :  * VALIDATE_OPEN_OPTIONS can be set to NO to avoid such warnings. Alternatively,
    4032             :  * that it may not cause a warning if the driver doesn't declare this option.
    4033             :  * Starting with GDAL 3.3, OVERVIEW_LEVEL=NONE is supported to indicate that
    4034             :  * no overviews should be exposed.
    4035             :  *
    4036             :  * @param papszSiblingFiles NULL, or a NULL terminated list of strings that are
    4037             :  * filenames that are auxiliary to the main filename. If NULL is passed, a
    4038             :  * probing of the file system will be done.
    4039             :  *
    4040             :  * @return A GDALDatasetH handle or NULL on failure.  For C++ applications
    4041             :  * this handle can be cast to a GDALDataset *.
    4042             :  *
    4043             :  */
    4044             : 
    4045       83792 : GDALDatasetH CPL_STDCALL GDALOpenEx(const char *pszFilename,
    4046             :                                     unsigned int nOpenFlags,
    4047             :                                     const char *const *papszAllowedDrivers,
    4048             :                                     const char *const *papszOpenOptions,
    4049             :                                     const char *const *papszSiblingFiles)
    4050             : {
    4051       83792 :     VALIDATE_POINTER1(pszFilename, "GDALOpen", nullptr);
    4052             : 
    4053             :     // Hack for the ZARR driver. We translate the CACHE_KERCHUNK_JSON
    4054             :     // into VSIKERCHUNK_USE_CACHE config option
    4055       83792 :     std::unique_ptr<CPLConfigOptionSetter> poVSIKERCHUNK_USE_CACHESetter;
    4056       83792 :     if (CPLFetchBool(papszOpenOptions, "CACHE_KERCHUNK_JSON", false))
    4057             :     {
    4058          13 :         poVSIKERCHUNK_USE_CACHESetter = std::make_unique<CPLConfigOptionSetter>(
    4059          26 :             "VSIKERCHUNK_USE_CACHE", "YES", false);
    4060             :     }
    4061             : 
    4062             :     // Do some sanity checks on incompatible flags with thread-safe mode.
    4063       83792 :     if ((nOpenFlags & GDAL_OF_THREAD_SAFE) != 0)
    4064             :     {
    4065             :         const struct
    4066             :         {
    4067             :             int nFlag;
    4068             :             const char *pszFlagName;
    4069         128 :         } asFlags[] = {
    4070             :             {GDAL_OF_UPDATE, "GDAL_OF_UPDATE"},
    4071             :             {GDAL_OF_VECTOR, "GDAL_OF_VECTOR"},
    4072             :             {GDAL_OF_MULTIDIM_RASTER, "GDAL_OF_MULTIDIM_RASTER"},
    4073             :             {GDAL_OF_GNM, "GDAL_OF_GNM"},
    4074             :         };
    4075             : 
    4076         630 :         for (const auto &asFlag : asFlags)
    4077             :         {
    4078         506 :             if ((nOpenFlags & asFlag.nFlag) != 0)
    4079             :             {
    4080           4 :                 CPLError(CE_Failure, CPLE_IllegalArg,
    4081             :                          "GDAL_OF_THREAD_SAFE and %s are mutually "
    4082             :                          "exclusive",
    4083           4 :                          asFlag.pszFlagName);
    4084           4 :                 return nullptr;
    4085             :             }
    4086             :         }
    4087             :     }
    4088             : 
    4089             :     // If no driver kind is specified, assume all are to be probed.
    4090       83788 :     if ((nOpenFlags & GDAL_OF_KIND_MASK) == 0)
    4091        7584 :         nOpenFlags |= GDAL_OF_KIND_MASK & ~GDAL_OF_MULTIDIM_RASTER;
    4092             : 
    4093             :     /* -------------------------------------------------------------------- */
    4094             :     /*      In case of shared dataset, first scan the existing list to see  */
    4095             :     /*      if it could already contain the requested dataset.              */
    4096             :     /* -------------------------------------------------------------------- */
    4097       83788 :     if (nOpenFlags & GDAL_OF_SHARED)
    4098             :     {
    4099        6485 :         if (nOpenFlags & GDAL_OF_INTERNAL)
    4100             :         {
    4101           0 :             CPLError(CE_Failure, CPLE_IllegalArg,
    4102             :                      "GDAL_OF_SHARED and GDAL_OF_INTERNAL are exclusive");
    4103           0 :             return nullptr;
    4104             :         }
    4105             : 
    4106             :         auto poSharedDS =
    4107        6485 :             GetSharedDS(pszFilename, nOpenFlags, papszOpenOptions);
    4108        6485 :         if (poSharedDS)
    4109             :         {
    4110        6106 :             poSharedDS->Reference();
    4111        6106 :             return poSharedDS;
    4112             :         }
    4113             :     }
    4114             : 
    4115       77682 :     GDALDriverManager *poDM = GetGDALDriverManager();
    4116             :     // CPLLocaleC  oLocaleForcer;
    4117             : 
    4118       77682 :     CPLErrorReset();
    4119       77682 :     VSIErrorReset();
    4120       77682 :     CPLAssert(nullptr != poDM);
    4121             : 
    4122             :     // Build GDALOpenInfo just now to avoid useless file stat'ing if a
    4123             :     // shared dataset was asked before.
    4124             :     GDALOpenInfo oOpenInfo(pszFilename, nOpenFlags,
    4125      155364 :                            const_cast<char **>(papszSiblingFiles));
    4126       77682 :     oOpenInfo.papszAllowedDrivers = papszAllowedDrivers;
    4127             : 
    4128       77682 :     GDALAntiRecursionStruct &sAntiRecursion = GetAntiRecursionOpen();
    4129       77682 :     if (sAntiRecursion.nRecLevel == 100)
    4130             :     {
    4131           0 :         CPLError(CE_Failure, CPLE_AppDefined,
    4132             :                  "GDALOpen() called with too many recursion levels");
    4133           0 :         return nullptr;
    4134             :     }
    4135             : 
    4136      155364 :     std::string osAllowedDrivers;
    4137      169536 :     for (const char *pszDriverName : cpl::Iterate(papszAllowedDrivers))
    4138       91854 :         osAllowedDrivers += pszDriverName;
    4139             :     auto dsCtxt = GDALAntiRecursionStruct::DatasetContext(
    4140      233046 :         std::string(pszFilename), nOpenFlags, osAllowedDrivers);
    4141       77682 :     if (cpl::contains(sAntiRecursion.aosDatasetNamesWithFlags, dsCtxt))
    4142             :     {
    4143           0 :         CPLError(CE_Failure, CPLE_AppDefined,
    4144             :                  "GDALOpen() called on %s recursively", pszFilename);
    4145           0 :         return nullptr;
    4146             :     }
    4147             : 
    4148             :     // Remove leading @ if present.
    4149             :     char **papszOpenOptionsCleaned =
    4150       77682 :         CSLDuplicate(const_cast<char **>(papszOpenOptions));
    4151       83311 :     for (char **papszIter = papszOpenOptionsCleaned; papszIter && *papszIter;
    4152             :          ++papszIter)
    4153             :     {
    4154        5629 :         char *pszOption = *papszIter;
    4155        5629 :         if (pszOption[0] == '@')
    4156         212 :             memmove(pszOption, pszOption + 1, strlen(pszOption + 1) + 1);
    4157             :     }
    4158             : 
    4159       77682 :     oOpenInfo.papszOpenOptions = papszOpenOptionsCleaned;
    4160       77682 :     oOpenInfo.nOpenFlags |= GDAL_OF_FROM_GDALOPEN;
    4161             : 
    4162             : #ifdef OGRAPISPY_ENABLED
    4163       77682 :     const bool bUpdate = (nOpenFlags & GDAL_OF_UPDATE) != 0;
    4164             :     const int iSnapshot =
    4165       19389 :         (nOpenFlags & GDAL_OF_VECTOR) != 0 && (nOpenFlags & GDAL_OF_RASTER) == 0
    4166       97071 :             ? OGRAPISpyOpenTakeSnapshot(pszFilename, bUpdate)
    4167       77682 :             : INT_MIN;
    4168             : #endif
    4169             : 
    4170       77682 :     const int nDriverCount = poDM->GetDriverCount(/*bIncludeHidden=*/true);
    4171       77682 :     GDALDriver *poMissingPluginDriver = nullptr;
    4172      155364 :     std::vector<GDALDriver *> apoSecondPassDrivers;
    4173             : 
    4174             :     // Lookup of matching driver for dataset can involve up to 2 passes:
    4175             :     // - in the first pass, all drivers that are compabile of the request mode
    4176             :     //   (raster/vector/etc.) are probed using their Identify() method if it
    4177             :     //   exists. If the Identify() method returns FALSE, the driver is skipped.
    4178             :     //   If the Identify() methods returns GDAL_IDENTIFY_UNKNOWN and that the
    4179             :     //   driver is a deferred-loading plugin, it is added to the
    4180             :     //   apoSecondPassDrivers list for potential later probing, and execution
    4181             :     //   continues to the next driver in the list.
    4182             :     //   Otherwise if Identify() returns non-FALSE, the Open() method is used.
    4183             :     //   If Open() returns a non-NULL dataset, the loop stops and it is
    4184             :     //   returned. Otherwise looping over remaining drivers continues.
    4185             :     // - the second pass is optional, only if at least one driver was added
    4186             :     //   into apoSecondPassDrivers during the first pass. It is similar
    4187             :     //   to the first pass except it runs only on apoSecondPassDrivers drivers.
    4188             :     //   And the Open() method of such drivers is used, causing them to be
    4189             :     //   loaded for real.
    4190       77682 :     int iPass = 1;
    4191       77696 : retry:
    4192     8030770 :     for (int iDriver = 0;
    4193     8030800 :          iDriver < (iPass == 1 ? nDriverCount
    4194          34 :                                : static_cast<int>(apoSecondPassDrivers.size()));
    4195             :          ++iDriver)
    4196             :     {
    4197             :         GDALDriver *poDriver =
    4198     8011720 :             iPass == 1 ? poDM->GetDriver(iDriver, /*bIncludeHidden=*/true)
    4199          25 :                        : apoSecondPassDrivers[iDriver];
    4200    11704500 :         if (papszAllowedDrivers != nullptr &&
    4201     3692820 :             CSLFindString(papszAllowedDrivers,
    4202             :                           GDALGetDriverShortName(poDriver)) == -1)
    4203             :         {
    4204     7551410 :             continue;
    4205             :         }
    4206             : 
    4207     4405660 :         if (poDriver->GetMetadataItem(GDAL_DCAP_OPEN) == nullptr)
    4208       43195 :             continue;
    4209             : 
    4210    11572500 :         if ((nOpenFlags & GDAL_OF_RASTER) != 0 &&
    4211     6309930 :             (nOpenFlags & GDAL_OF_VECTOR) == 0 &&
    4212     1947470 :             poDriver->GetMetadataItem(GDAL_DCAP_RASTER) == nullptr)
    4213      463734 :             continue;
    4214    11432500 :         if ((nOpenFlags & GDAL_OF_VECTOR) != 0 &&
    4215     5725340 :             (nOpenFlags & GDAL_OF_RASTER) == 0 &&
    4216     1826610 :             poDriver->GetMetadataItem(GDAL_DCAP_VECTOR) == nullptr)
    4217     1372020 :             continue;
    4218     5352890 :         if ((nOpenFlags & GDAL_OF_MULTIDIM_RASTER) != 0 &&
    4219     2677710 :             (nOpenFlags & GDAL_OF_RASTER) == 0 &&
    4220      151005 :             poDriver->GetMetadataItem(GDAL_DCAP_MULTIDIM_RASTER) == nullptr)
    4221      142065 :             continue;
    4222             : 
    4223             :         // Remove general OVERVIEW_LEVEL open options from list before passing
    4224             :         // it to the driver, if it isn't a driver specific option already.
    4225     2384640 :         char **papszTmpOpenOptions = nullptr;
    4226     2384640 :         char **papszTmpOpenOptionsToValidate = nullptr;
    4227     2384640 :         char **papszOptionsToValidate = const_cast<char **>(papszOpenOptions);
    4228     2384640 :         if (CSLFetchNameValue(papszOpenOptionsCleaned, "OVERVIEW_LEVEL") !=
    4229     2384790 :                 nullptr &&
    4230         152 :             !poDriver->HasOpenOption("OVERVIEW_LEVEL"))
    4231             :         {
    4232         152 :             papszTmpOpenOptions = CSLDuplicate(papszOpenOptionsCleaned);
    4233             :             papszTmpOpenOptions =
    4234         152 :                 CSLSetNameValue(papszTmpOpenOptions, "OVERVIEW_LEVEL", nullptr);
    4235         152 :             oOpenInfo.papszOpenOptions = papszTmpOpenOptions;
    4236             : 
    4237         152 :             papszOptionsToValidate = CSLDuplicate(papszOptionsToValidate);
    4238         152 :             papszOptionsToValidate = CSLSetNameValue(papszOptionsToValidate,
    4239             :                                                      "OVERVIEW_LEVEL", nullptr);
    4240         152 :             papszTmpOpenOptionsToValidate = papszOptionsToValidate;
    4241             :         }
    4242             : 
    4243             :         const int nIdentifyRes =
    4244     2384640 :             poDriver->pfnIdentifyEx
    4245     4769270 :                 ? poDriver->pfnIdentifyEx(poDriver, &oOpenInfo)
    4246     2384630 :             : poDriver->pfnIdentify ? poDriver->pfnIdentify(&oOpenInfo)
    4247     2384640 :                                     : GDAL_IDENTIFY_UNKNOWN;
    4248     2384640 :         if (nIdentifyRes == FALSE)
    4249             :         {
    4250     1924260 :             CSLDestroy(papszTmpOpenOptions);
    4251     1924260 :             CSLDestroy(papszTmpOpenOptionsToValidate);
    4252     1924260 :             oOpenInfo.papszOpenOptions = papszOpenOptionsCleaned;
    4253     1924260 :             continue;
    4254             :         }
    4255      460359 :         else if (iPass == 1 && nIdentifyRes < 0 &&
    4256      920849 :                  poDriver->pfnOpen == nullptr &&
    4257         106 :                  poDriver->GetMetadataItem("IS_NON_LOADED_PLUGIN"))
    4258             :         {
    4259             :             // Not loaded plugin
    4260         104 :             apoSecondPassDrivers.push_back(poDriver);
    4261         104 :             CSLDestroy(papszTmpOpenOptions);
    4262         104 :             CSLDestroy(papszTmpOpenOptionsToValidate);
    4263         104 :             oOpenInfo.papszOpenOptions = papszOpenOptionsCleaned;
    4264         104 :             continue;
    4265             :         }
    4266             : 
    4267      460280 :         const bool bIdentifyRes = nIdentifyRes == GDAL_IDENTIFY_TRUE;
    4268      460280 :         if (bIdentifyRes)
    4269             :         {
    4270       57665 :             GDALValidateOpenOptions(poDriver, papszOptionsToValidate);
    4271             :         }
    4272             : 
    4273             : #ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
    4274             :         const bool bFpAvailableBefore = oOpenInfo.fpL != nullptr;
    4275             :         CPLErrorReset();
    4276             : #endif
    4277             : 
    4278      460280 :         sAntiRecursion.nRecLevel++;
    4279      460280 :         sAntiRecursion.aosDatasetNamesWithFlags.insert(dsCtxt);
    4280             : 
    4281      460280 :         GDALDataset *poDS = poDriver->Open(&oOpenInfo, false);
    4282             : 
    4283      460280 :         sAntiRecursion.nRecLevel--;
    4284      460280 :         sAntiRecursion.aosDatasetNamesWithFlags.erase(dsCtxt);
    4285             : 
    4286      460280 :         if (poDriver->pfnOpen != nullptr)
    4287             :         {
    4288             :             // If we couldn't determine for sure with Identify() (it returned
    4289             :             // -1), but Open() managed to open the file, post validate options.
    4290      460277 :             if (poDS != nullptr &&
    4291       57577 :                 (poDriver->pfnIdentify || poDriver->pfnIdentifyEx) &&
    4292       57012 :                 !bIdentifyRes)
    4293             :             {
    4294         815 :                 GDALValidateOpenOptions(poDriver, papszOptionsToValidate);
    4295             :             }
    4296             :         }
    4297           3 :         else if (poDriver->pfnOpenWithDriverArg != nullptr)
    4298             :         {
    4299             :             // do nothing
    4300             :         }
    4301           0 :         else if (bIdentifyRes &&
    4302           0 :                  poDriver->GetMetadataItem("MISSING_PLUGIN_FILENAME"))
    4303             :         {
    4304           0 :             if (!poMissingPluginDriver)
    4305             :             {
    4306           0 :                 poMissingPluginDriver = poDriver;
    4307             :             }
    4308             :         }
    4309             :         else
    4310             :         {
    4311             :             // should not happen given the GDAL_DCAP_OPEN check
    4312           0 :             CSLDestroy(papszTmpOpenOptions);
    4313           0 :             CSLDestroy(papszTmpOpenOptionsToValidate);
    4314           0 :             oOpenInfo.papszOpenOptions = papszOpenOptionsCleaned;
    4315           0 :             continue;
    4316             :         }
    4317             : 
    4318      460280 :         CSLDestroy(papszTmpOpenOptions);
    4319      460280 :         CSLDestroy(papszTmpOpenOptionsToValidate);
    4320      460280 :         oOpenInfo.papszOpenOptions = papszOpenOptionsCleaned;
    4321             : 
    4322      460280 :         if (poDS != nullptr)
    4323             :         {
    4324       57580 :             if (poDS->papszOpenOptions == nullptr)
    4325             :             {
    4326       57317 :                 poDS->papszOpenOptions = papszOpenOptionsCleaned;
    4327       57317 :                 papszOpenOptionsCleaned = nullptr;
    4328             :             }
    4329             : 
    4330             :             // Deal with generic OVERVIEW_LEVEL open option, unless it is
    4331             :             // driver specific.
    4332       57580 :             if (CSLFetchNameValue(papszOpenOptions, "OVERVIEW_LEVEL") !=
    4333       57619 :                     nullptr &&
    4334          39 :                 !poDriver->HasOpenOption("OVERVIEW_LEVEL"))
    4335             :             {
    4336             :                 CPLString osVal(
    4337          78 :                     CSLFetchNameValue(papszOpenOptions, "OVERVIEW_LEVEL"));
    4338          39 :                 const int nOvrLevel = EQUAL(osVal, "NONE") ? -1 : atoi(osVal);
    4339             :                 const bool bThisLevelOnly =
    4340          39 :                     nOvrLevel == -1 || osVal.ifind("only") != std::string::npos;
    4341             :                 GDALDataset *poOvrDS =
    4342          39 :                     GDALCreateOverviewDataset(poDS, nOvrLevel, bThisLevelOnly);
    4343          39 :                 if (poOvrDS && (nOpenFlags & GDAL_OF_SHARED) != 0)
    4344             :                 {
    4345           4 :                     if (strcmp(pszFilename, poDS->GetDescription()) != 0)
    4346             :                     {
    4347           0 :                         CPLError(
    4348             :                             CE_Warning, CPLE_NotSupported,
    4349             :                             "A dataset opened by GDALOpenShared should have "
    4350             :                             "the same filename (%s) "
    4351             :                             "and description (%s)",
    4352           0 :                             pszFilename, poDS->GetDescription());
    4353             :                     }
    4354             :                     else
    4355             :                     {
    4356           4 :                         CSLDestroy(poDS->papszOpenOptions);
    4357           4 :                         poDS->papszOpenOptions = CSLDuplicate(papszOpenOptions);
    4358           4 :                         poDS->papszOpenOptions = CSLSetNameValue(
    4359             :                             poDS->papszOpenOptions, "OVERVIEW_LEVEL", nullptr);
    4360             :                     }
    4361             :                 }
    4362          39 :                 poDS->ReleaseRef();
    4363          39 :                 poDS = poOvrDS;
    4364          39 :                 if (poDS == nullptr)
    4365             :                 {
    4366           1 :                     if (nOpenFlags & GDAL_OF_VERBOSE_ERROR)
    4367             :                     {
    4368           1 :                         CPLError(CE_Failure, CPLE_OpenFailed,
    4369             :                                  "Cannot open overview level %d of %s",
    4370             :                                  nOvrLevel, pszFilename);
    4371             :                     }
    4372             :                 }
    4373             :                 else
    4374             :                 {
    4375             :                     // For thread-safe opening, currently poDS is what will be
    4376             :                     // the "master" dataset owned by the thread-safe dataset
    4377             :                     // returned to the user, hence we do not register it as a
    4378             :                     // visible one in the open dataset list, or mark it as shared.
    4379          38 :                     if (!(nOpenFlags & GDAL_OF_INTERNAL) &&
    4380          36 :                         !(nOpenFlags & GDAL_OF_THREAD_SAFE))
    4381             :                     {
    4382          35 :                         poDS->AddToDatasetOpenList();
    4383             :                     }
    4384          38 :                     if (nOpenFlags & GDAL_OF_SHARED)
    4385             :                     {
    4386           4 :                         CSLDestroy(poDS->papszOpenOptions);
    4387           4 :                         poDS->papszOpenOptions = CSLDuplicate(papszOpenOptions);
    4388           4 :                         poDS->nOpenFlags = nOpenFlags;
    4389           4 :                         if (!(nOpenFlags & GDAL_OF_THREAD_SAFE))
    4390           4 :                             poDS->MarkAsShared();
    4391             :                     }
    4392             :                 }
    4393             :             }
    4394       57541 :             else if (nOpenFlags & GDAL_OF_SHARED)
    4395             :             {
    4396         369 :                 if (strcmp(pszFilename, poDS->GetDescription()) != 0)
    4397             :                 {
    4398           2 :                     CPLError(CE_Warning, CPLE_NotSupported,
    4399             :                              "A dataset opened by GDALOpenShared should have "
    4400             :                              "the same filename (%s) "
    4401             :                              "and description (%s)",
    4402           2 :                              pszFilename, poDS->GetDescription());
    4403             :                 }
    4404         367 :                 else if (!(nOpenFlags & GDAL_OF_THREAD_SAFE))
    4405             :                 {
    4406             :                     // For thread-safe opening, currently poDS is what will be
    4407             :                     // the "master" dataset owned by the thread-safe dataset
    4408             :                     // returned to the user, hence we do not or mark it as shared.
    4409         367 :                     poDS->MarkAsShared();
    4410             :                 }
    4411             :             }
    4412             : 
    4413       57580 :             VSIErrorReset();
    4414             : 
    4415       57580 :             CSLDestroy(papszOpenOptionsCleaned);
    4416             : 
    4417             : #ifdef OGRAPISPY_ENABLED
    4418       57580 :             if (iSnapshot != INT_MIN)
    4419             :             {
    4420       11564 :                 GDALDatasetH hDS = GDALDataset::ToHandle(poDS);
    4421       11564 :                 OGRAPISpyOpen(pszFilename, bUpdate, iSnapshot, &hDS);
    4422       11564 :                 poDS = GDALDataset::FromHandle(hDS);
    4423             :             }
    4424             : #endif
    4425             : 
    4426       57580 :             if (poDS)
    4427             :             {
    4428       57579 :                 poDS->m_bCanBeReopened = true;
    4429             : 
    4430       57579 :                 if ((nOpenFlags & GDAL_OF_THREAD_SAFE) != 0)
    4431             :                 {
    4432             :                     poDS =
    4433         248 :                         GDALGetThreadSafeDataset(
    4434         248 :                             std::unique_ptr<GDALDataset>(poDS), GDAL_OF_RASTER)
    4435         124 :                             .release();
    4436         124 :                     if (poDS)
    4437             :                     {
    4438         124 :                         poDS->m_bCanBeReopened = true;
    4439         124 :                         poDS->poDriver = poDriver;
    4440         124 :                         poDS->nOpenFlags = nOpenFlags;
    4441         124 :                         if (!(nOpenFlags & GDAL_OF_INTERNAL))
    4442         124 :                             poDS->AddToDatasetOpenList();
    4443         124 :                         if (nOpenFlags & GDAL_OF_SHARED)
    4444           0 :                             poDS->MarkAsShared();
    4445             :                     }
    4446             :                 }
    4447             :             }
    4448             : 
    4449       58616 :             return poDS;
    4450             :         }
    4451             : 
    4452             : #ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
    4453             :         if (bFpAvailableBefore && oOpenInfo.fpL == nullptr)
    4454             :         {
    4455             :             // In case the file descriptor was "consumed" by a driver
    4456             :             // that ultimately failed, re-open it for next drivers.
    4457             :             oOpenInfo.fpL = VSIFOpenL(
    4458             :                 pszFilename, (oOpenInfo.eAccess == GA_Update) ? "r+b" : "rb");
    4459             :         }
    4460             : #else
    4461      402700 :         if (CPLGetLastErrorNo() != 0 && CPLGetLastErrorType() > CE_Warning)
    4462             :         {
    4463        1036 :             CSLDestroy(papszOpenOptionsCleaned);
    4464             : 
    4465             : #ifdef OGRAPISPY_ENABLED
    4466        1036 :             if (iSnapshot != INT_MIN)
    4467             :             {
    4468         193 :                 GDALDatasetH hDS = nullptr;
    4469         193 :                 OGRAPISpyOpen(pszFilename, bUpdate, iSnapshot, &hDS);
    4470             :             }
    4471             : #endif
    4472        1036 :             return nullptr;
    4473             :         }
    4474             : #endif
    4475             :     }
    4476             : 
    4477             :     // cppcheck-suppress knownConditionTrueFalse
    4478       19080 :     if (iPass == 1 && !apoSecondPassDrivers.empty())
    4479             :     {
    4480          14 :         CPLDebugOnly("GDAL", "GDALOpen(): Second pass");
    4481          14 :         iPass = 2;
    4482          14 :         goto retry;
    4483             :     }
    4484             : 
    4485       19066 :     CSLDestroy(papszOpenOptionsCleaned);
    4486             : 
    4487             : #ifdef OGRAPISPY_ENABLED
    4488       19066 :     if (iSnapshot != INT_MIN)
    4489             :     {
    4490         654 :         GDALDatasetH hDS = nullptr;
    4491         654 :         OGRAPISpyOpen(pszFilename, bUpdate, iSnapshot, &hDS);
    4492             :     }
    4493             : #endif
    4494             : 
    4495       19066 :     if (nOpenFlags & GDAL_OF_VERBOSE_ERROR)
    4496             :     {
    4497        5729 :         if (nDriverCount == 0)
    4498             :         {
    4499           0 :             CPLError(CE_Failure, CPLE_OpenFailed, "No driver registered.");
    4500             :         }
    4501        5729 :         else if (poMissingPluginDriver)
    4502             :         {
    4503           0 :             std::string osMsg("`");
    4504           0 :             osMsg += pszFilename;
    4505             :             osMsg += "' not recognized as being in a supported file format. "
    4506           0 :                      "It could have been recognized by driver ";
    4507           0 :             osMsg += poMissingPluginDriver->GetDescription();
    4508           0 :             osMsg += ", but plugin ";
    4509             :             osMsg +=
    4510           0 :                 GDALGetMessageAboutMissingPluginDriver(poMissingPluginDriver);
    4511             : 
    4512           0 :             CPLError(CE_Failure, CPLE_OpenFailed, "%s", osMsg.c_str());
    4513             :         }
    4514             :         // Check to see if there was a filesystem error, and report it if so.
    4515             :         // If not, return a more generic error.
    4516        5729 :         else if (!VSIToCPLError(CE_Failure, CPLE_OpenFailed))
    4517             :         {
    4518         355 :             if (oOpenInfo.bStatOK)
    4519             :             {
    4520         352 :                 CPLError(CE_Failure, CPLE_OpenFailed,
    4521             :                          "`%s' not recognized as being in a supported file "
    4522             :                          "format.",
    4523             :                          pszFilename);
    4524             :             }
    4525             :             else
    4526             :             {
    4527             :                 // If Stat failed and no VSI error was set, assume it is because
    4528             :                 // the file did not exist on the filesystem.
    4529           3 :                 CPLError(CE_Failure, CPLE_OpenFailed,
    4530             :                          "`%s' does not exist in the file system, "
    4531             :                          "and is not recognized as a supported dataset name.",
    4532             :                          pszFilename);
    4533             :             }
    4534             :         }
    4535             :     }
    4536             : 
    4537       19066 :     return nullptr;
    4538             : }
    4539             : 
    4540             : /************************************************************************/
    4541             : /*                           GDALOpenShared()                           */
    4542             : /************************************************************************/
    4543             : 
    4544             : /**
    4545             :  * \brief Open a raster file as a GDALDataset.
    4546             :  *
    4547             :  * This function works the same as GDALOpen(), but allows the sharing of
    4548             :  * GDALDataset handles for a dataset with other callers to GDALOpenShared().
    4549             :  *
    4550             :  * In particular, GDALOpenShared() will first consult its list of currently
    4551             :  * open and shared GDALDataset's, and if the GetDescription() name for one
    4552             :  * exactly matches the pszFilename passed to GDALOpenShared() it will be
    4553             :  * referenced and returned.
    4554             :  *
    4555             :  * If GDALOpenShared() is called on the same
    4556             :  * pszFilename from two different threads, a different GDALDataset object will
    4557             :  * be returned as it is not safe to use the same dataset from different threads,
    4558             :  * unless the user does explicitly use mutexes in its code.
    4559             :  *
    4560             :  * For drivers supporting the VSI virtual file API, it is possible to open a
    4561             :  * file in a .zip archive (see VSIInstallZipFileHandler()), in a
    4562             :  * .tar/.tar.gz/.tgz archive (see VSIInstallTarFileHandler()) or on a HTTP / FTP
    4563             :  * server (see VSIInstallCurlFileHandler())
    4564             :  *
    4565             :  * \sa GDALOpen()
    4566             :  * \sa GDALOpenEx()
    4567             :  *
    4568             :  * @param pszFilename the name of the file to access.  In the case of
    4569             :  * exotic drivers this may not refer to a physical file, but instead contain
    4570             :  * information for the driver on how to access a dataset.  It should be in
    4571             :  * UTF-8 encoding.
    4572             :  *
    4573             :  * @param eAccess the desired access, either GA_Update or GA_ReadOnly.  Many
    4574             :  * drivers support only read only access.
    4575             :  *
    4576             :  * @return A GDALDatasetH handle or NULL on failure.  For C++ applications
    4577             :  * this handle can be cast to a GDALDataset *.
    4578             :  */
    4579             : 
    4580        5204 : GDALDatasetH CPL_STDCALL GDALOpenShared(const char *pszFilename,
    4581             :                                         GDALAccess eAccess)
    4582             : {
    4583        5204 :     VALIDATE_POINTER1(pszFilename, "GDALOpenShared", nullptr);
    4584        5204 :     return GDALOpenEx(pszFilename,
    4585             :                       GDAL_OF_RASTER |
    4586             :                           (eAccess == GA_Update ? GDAL_OF_UPDATE : 0) |
    4587             :                           GDAL_OF_SHARED | GDAL_OF_VERBOSE_ERROR,
    4588        5204 :                       nullptr, nullptr, nullptr);
    4589             : }
    4590             : 
    4591             : /************************************************************************/
    4592             : /*                             GDALClose()                              */
    4593             : /************************************************************************/
    4594             : 
    4595             : /**
    4596             :  * \brief Close GDAL dataset.
    4597             :  *
    4598             :  * For non-shared datasets (opened with GDALOpen()) the dataset is closed
    4599             :  * using the C++ "delete" operator, recovering all dataset related resources.
    4600             :  * For shared datasets (opened with GDALOpenShared()) the dataset is
    4601             :  * dereferenced, and closed only if the referenced count has dropped below 1.
    4602             :  *
    4603             :  * @param hDS The dataset to close, or nullptr.
    4604             :  * @return CE_None in case of success (return value since GDAL 3.7). On a
    4605             :  * shared dataset whose reference count is not dropped below 1, CE_None will
    4606             :  * be returned.
    4607             :  *
    4608             :  * @see GDALCloseEx()
    4609             :  */
    4610             : 
    4611       73317 : CPLErr CPL_STDCALL GDALClose(GDALDatasetH hDS)
    4612             : 
    4613             : {
    4614       73317 :     return GDALCloseEx(hDS, nullptr, nullptr);
    4615             : }
    4616             : 
    4617             : /************************************************************************/
    4618             : /*                             GDALCloseEx()                            */
    4619             : /************************************************************************/
    4620             : 
    4621             : /**
    4622             :  * \brief Close GDAL dataset.
    4623             :  *
    4624             :  * For non-shared datasets (opened with GDALOpen()) the dataset is closed
    4625             :  * using the C++ "delete" operator, recovering all dataset related resources.
    4626             :  * For shared datasets (opened with GDALOpenShared()) the dataset is
    4627             :  * dereferenced, and closed only if the referenced count has dropped below 1.
    4628             :  *
    4629             :  * This function may report progress if a progress
    4630             :  * callback if provided in the pfnProgress argument and if the dataset returns
    4631             :  * true for GDALDataset::GetCloseReportsProgress()
    4632             : 
    4633             :  * @param hDS The dataset to close, or nullptr
    4634             :  * @param pfnProgress Progress callback, or nullptr
    4635             :  * @param pProgressData User data of progress callback, or nullptr
    4636             :  *
    4637             :  * @return CE_None in case of success. On a
    4638             :  * shared dataset whose reference count is not dropped below 1, CE_None will
    4639             :  * be returned.
    4640             :  *
    4641             :  * @since GDAL 3.13
    4642             :  * @see GDALClose()
    4643             :  */
    4644             : 
    4645       77465 : CPLErr GDALCloseEx(GDALDatasetH hDS, GDALProgressFunc pfnProgress,
    4646             :                    void *pProgressData)
    4647             : {
    4648       77465 :     if (!hDS)
    4649         402 :         return CE_None;
    4650             : 
    4651             : #ifdef OGRAPISPY_ENABLED
    4652       77063 :     if (bOGRAPISpyEnabled)
    4653          11 :         OGRAPISpyPreClose(hDS);
    4654             : #endif
    4655             : 
    4656       77063 :     GDALDataset *poDS = GDALDataset::FromHandle(hDS);
    4657             : 
    4658       77063 :     if (poDS->GetShared())
    4659             :     {
    4660             :         /* --------------------------------------------------------------------
    4661             :          */
    4662             :         /*      If this file is in the shared dataset list then dereference */
    4663             :         /*      it, and only delete/remote it if the reference count has */
    4664             :         /*      dropped to zero. */
    4665             :         /* --------------------------------------------------------------------
    4666             :          */
    4667         236 :         if (poDS->Dereference() > 0)
    4668          15 :             return CE_None;
    4669             :     }
    4670             : 
    4671       77048 :     CPLErr eErr = poDS->Close(pfnProgress, pProgressData);
    4672       77048 :     delete poDS;
    4673             : 
    4674             : #ifdef OGRAPISPY_ENABLED
    4675       77048 :     if (bOGRAPISpyEnabled)
    4676          11 :         OGRAPISpyPostClose();
    4677             : #endif
    4678       77048 :     return eErr;
    4679             : }
    4680             : 
    4681             : /************************************************************************/
    4682             : /*                        GDALDumpOpenDataset()                         */
    4683             : /************************************************************************/
    4684             : 
    4685           0 : static int GDALDumpOpenSharedDatasetsForeach(void *elt, void *user_data)
    4686             : {
    4687           0 :     SharedDatasetCtxt *psStruct = static_cast<SharedDatasetCtxt *>(elt);
    4688           0 :     FILE *fp = static_cast<FILE *>(user_data);
    4689           0 :     GDALDataset *poDS = psStruct->poDS;
    4690             : 
    4691           0 :     const char *pszDriverName = poDS->GetDriver() == nullptr
    4692           0 :                                     ? "DriverIsNULL"
    4693           0 :                                     : poDS->GetDriver()->GetDescription();
    4694             : 
    4695           0 :     poDS->Reference();
    4696           0 :     CPL_IGNORE_RET_VAL(
    4697           0 :         VSIFPrintf(fp, "  %d %c %-6s %7d %dx%dx%d %s\n", poDS->Dereference(),
    4698           0 :                    poDS->GetShared() ? 'S' : 'N', pszDriverName,
    4699           0 :                    static_cast<int>(psStruct->nPID), poDS->GetRasterXSize(),
    4700             :                    poDS->GetRasterYSize(), poDS->GetRasterCount(),
    4701           0 :                    poDS->GetDescription()));
    4702             : 
    4703           0 :     return TRUE;
    4704             : }
    4705             : 
    4706           0 : static int GDALDumpOpenDatasetsForeach(GDALDataset *poDS, FILE *fp)
    4707             : {
    4708             : 
    4709             :     // Don't list shared datasets. They have already been listed by
    4710             :     // GDALDumpOpenSharedDatasetsForeach.
    4711           0 :     if (poDS->GetShared())
    4712           0 :         return TRUE;
    4713             : 
    4714           0 :     const char *pszDriverName = poDS->GetDriver() == nullptr
    4715           0 :                                     ? "DriverIsNULL"
    4716           0 :                                     : poDS->GetDriver()->GetDescription();
    4717             : 
    4718           0 :     poDS->Reference();
    4719           0 :     CPL_IGNORE_RET_VAL(
    4720           0 :         VSIFPrintf(fp, "  %d %c %-6s %7d %dx%dx%d %s\n", poDS->Dereference(),
    4721           0 :                    poDS->GetShared() ? 'S' : 'N', pszDriverName, -1,
    4722             :                    poDS->GetRasterXSize(), poDS->GetRasterYSize(),
    4723           0 :                    poDS->GetRasterCount(), poDS->GetDescription()));
    4724             : 
    4725           0 :     return TRUE;
    4726             : }
    4727             : 
    4728             : /**
    4729             :  * \brief List open datasets.
    4730             :  *
    4731             :  * Dumps a list of all open datasets (shared or not) to the indicated
    4732             :  * text file (may be stdout or stderr).   This function is primarily intended
    4733             :  * to assist in debugging "dataset leaks" and reference counting issues.
    4734             :  * The information reported includes the dataset name, referenced count,
    4735             :  * shared status, driver name, size, and band count.
    4736             :  */
    4737             : 
    4738         272 : int CPL_STDCALL GDALDumpOpenDatasets(FILE *fp)
    4739             : 
    4740             : {
    4741         272 :     VALIDATE_POINTER1(fp, "GDALDumpOpenDatasets", 0);
    4742             : 
    4743         544 :     CPLMutexHolderD(&hDLMutex);
    4744             : 
    4745         272 :     if (poAllDatasetMap == nullptr)
    4746         272 :         return 0;
    4747             : 
    4748           0 :     CPL_IGNORE_RET_VAL(VSIFPrintf(fp, "Open GDAL Datasets:\n"));
    4749             : 
    4750           0 :     for (const auto &oIter : *poAllDatasetMap)
    4751             :     {
    4752           0 :         GDALDumpOpenDatasetsForeach(oIter.first, fp);
    4753             :     }
    4754             : 
    4755           0 :     if (phSharedDatasetSet != nullptr)
    4756             :     {
    4757           0 :         CPLHashSetForeach(phSharedDatasetSet, GDALDumpOpenSharedDatasetsForeach,
    4758             :                           fp);
    4759             :     }
    4760           0 :     return static_cast<int>(poAllDatasetMap->size());
    4761             : }
    4762             : 
    4763             : /************************************************************************/
    4764             : /*                        BeginAsyncReader()                            */
    4765             : /************************************************************************/
    4766             : 
    4767             : /**
    4768             :  * \brief Sets up an asynchronous data request
    4769             :  *
    4770             :  * This method establish an asynchronous raster read request for the
    4771             :  * indicated window on the dataset into the indicated buffer.  The parameters
    4772             :  * for windowing, buffer size, buffer type and buffer organization are similar
    4773             :  * to those for GDALDataset::RasterIO(); however, this call only launches
    4774             :  * the request and filling the buffer is accomplished via calls to
    4775             :  * GetNextUpdatedRegion() on the return GDALAsyncReader session object.
    4776             :  *
    4777             :  * Once all processing for the created session is complete, or if no further
    4778             :  * refinement of the request is required, the GDALAsyncReader object should
    4779             :  * be destroyed with the GDALDataset::EndAsyncReader() method.
    4780             :  *
    4781             :  * Note that the data buffer (pData) will potentially continue to be
    4782             :  * updated as long as the session lives, but it is not deallocated when
    4783             :  * the session (GDALAsyncReader) is destroyed with EndAsyncReader().  It
    4784             :  * should be deallocated by the application at that point.
    4785             :  *
    4786             :  * Additional information on asynchronous IO in GDAL may be found at:
    4787             :  *   https://gdal.org/development/rfc/rfc24_progressive_data_support.html
    4788             :  *
    4789             :  * This method is the same as the C GDALBeginAsyncReader() function.
    4790             :  *
    4791             :  * @param nXOff The pixel offset to the top left corner of the region
    4792             :  * of the band to be accessed.  This would be zero to start from the left side.
    4793             :  *
    4794             :  * @param nYOff The line offset to the top left corner of the region
    4795             :  * of the band to be accessed.  This would be zero to start from the top.
    4796             :  *
    4797             :  * @param nXSize The width of the region of the band to be accessed in pixels.
    4798             :  *
    4799             :  * @param nYSize The height of the region of the band to be accessed in lines.
    4800             :  *
    4801             :  * @param pBuf The buffer into which the data should be read. This buffer must
    4802             :  * contain at least nBufXSize * nBufYSize * nBandCount words of type eBufType.
    4803             :  * It is organized in left to right,top to bottom pixel order.  Spacing is
    4804             :  * controlled by the nPixelSpace, and nLineSpace parameters.
    4805             :  *
    4806             :  * @param nBufXSize the width of the buffer image into which the desired region
    4807             :  * is to be read, or from which it is to be written.
    4808             :  *
    4809             :  * @param nBufYSize the height of the buffer image into which the desired
    4810             :  * region is to be read, or from which it is to be written.
    4811             :  *
    4812             :  * @param eBufType the type of the pixel values in the pData data buffer.  The
    4813             :  * pixel values will automatically be translated to/from the GDALRasterBand
    4814             :  * data type as needed.
    4815             :  *
    4816             :  * @param nBandCount the number of bands being read or written.
    4817             :  *
    4818             :  * @param panBandMap the list of nBandCount band numbers being read/written.
    4819             :  * Note band numbers are 1 based.   This may be NULL to select the first
    4820             :  * nBandCount bands.
    4821             :  *
    4822             :  * @param nPixelSpace The byte offset from the start of one pixel value in
    4823             :  * pData to the start of the next pixel value within a scanline.  If defaulted
    4824             :  * (0) the size of the datatype eBufType is used.
    4825             :  *
    4826             :  * @param nLineSpace The byte offset from the start of one scanline in
    4827             :  * pData to the start of the next.  If defaulted the size of the datatype
    4828             :  * eBufType * nBufXSize is used.
    4829             :  *
    4830             :  * @param nBandSpace the byte offset from the start of one bands data to the
    4831             :  * start of the next.  If defaulted (zero) the value will be
    4832             :  * nLineSpace * nBufYSize implying band sequential organization
    4833             :  * of the data buffer.
    4834             :  *
    4835             :  * @param papszOptions Driver specific control options in a string list or NULL.
    4836             :  * Consult driver documentation for options supported.
    4837             :  *
    4838             :  * @return The GDALAsyncReader object representing the request.
    4839             :  */
    4840             : 
    4841           1 : GDALAsyncReader *GDALDataset::BeginAsyncReader(
    4842             :     int nXOff, int nYOff, int nXSize, int nYSize, void *pBuf, int nBufXSize,
    4843             :     int nBufYSize, GDALDataType eBufType, int nBandCount, int *panBandMap,
    4844             :     int nPixelSpace, int nLineSpace, int nBandSpace, char **papszOptions)
    4845             : {
    4846             :     // See gdaldefaultasync.cpp
    4847             : 
    4848           1 :     return GDALGetDefaultAsyncReader(this, nXOff, nYOff, nXSize, nYSize, pBuf,
    4849             :                                      nBufXSize, nBufYSize, eBufType, nBandCount,
    4850             :                                      panBandMap, nPixelSpace, nLineSpace,
    4851           1 :                                      nBandSpace, papszOptions);
    4852             : }
    4853             : 
    4854             : /************************************************************************/
    4855             : /*                        GDALBeginAsyncReader()                      */
    4856             : /************************************************************************/
    4857             : 
    4858             : /**
    4859             :  * \brief Sets up an asynchronous data request
    4860             :  *
    4861             :  * This method establish an asynchronous raster read request for the
    4862             :  * indicated window on the dataset into the indicated buffer.  The parameters
    4863             :  * for windowing, buffer size, buffer type and buffer organization are similar
    4864             :  * to those for GDALDataset::RasterIO(); however, this call only launches
    4865             :  * the request and filling the buffer is accomplished via calls to
    4866             :  * GetNextUpdatedRegion() on the return GDALAsyncReader session object.
    4867             :  *
    4868             :  * Once all processing for the created session is complete, or if no further
    4869             :  * refinement of the request is required, the GDALAsyncReader object should
    4870             :  * be destroyed with the GDALDataset::EndAsyncReader() method.
    4871             :  *
    4872             :  * Note that the data buffer (pData) will potentially continue to be
    4873             :  * updated as long as the session lives, but it is not deallocated when
    4874             :  * the session (GDALAsyncReader) is destroyed with EndAsyncReader().  It
    4875             :  * should be deallocated by the application at that point.
    4876             :  *
    4877             :  * Additional information on asynchronous IO in GDAL may be found at:
    4878             :  *   https://gdal.org/development/rfc/rfc24_progressive_data_support.html
    4879             :  *
    4880             :  * This method is the same as the C++ GDALDataset::BeginAsyncReader() method.
    4881             :  *
    4882             :  * @param hDS handle to the dataset object.
    4883             :  *
    4884             :  * @param nXOff The pixel offset to the top left corner of the region
    4885             :  * of the band to be accessed.  This would be zero to start from the left side.
    4886             :  *
    4887             :  * @param nYOff The line offset to the top left corner of the region
    4888             :  * of the band to be accessed.  This would be zero to start from the top.
    4889             :  *
    4890             :  * @param nXSize The width of the region of the band to be accessed in pixels.
    4891             :  *
    4892             :  * @param nYSize The height of the region of the band to be accessed in lines.
    4893             :  *
    4894             :  * @param pBuf The buffer into which the data should be read. This buffer must
    4895             :  * contain at least nBufXSize * nBufYSize * nBandCount words of type eBufType.
    4896             :  * It is organized in left to right,top to bottom pixel order.  Spacing is
    4897             :  * controlled by the nPixelSpace, and nLineSpace parameters.
    4898             :  *
    4899             :  * @param nBufXSize the width of the buffer image into which the desired region
    4900             :  * is to be read, or from which it is to be written.
    4901             :  *
    4902             :  * @param nBufYSize the height of the buffer image into which the desired
    4903             :  * region is to be read, or from which it is to be written.
    4904             :  *
    4905             :  * @param eBufType the type of the pixel values in the pData data buffer.  The
    4906             :  * pixel values will automatically be translated to/from the GDALRasterBand
    4907             :  * data type as needed.
    4908             :  *
    4909             :  * @param nBandCount the number of bands being read or written.
    4910             :  *
    4911             :  * @param panBandMap the list of nBandCount band numbers being read/written.
    4912             :  * Note band numbers are 1 based.   This may be NULL to select the first
    4913             :  * nBandCount bands.
    4914             :  *
    4915             :  * @param nPixelSpace The byte offset from the start of one pixel value in
    4916             :  * pData to the start of the next pixel value within a scanline.  If defaulted
    4917             :  * (0) the size of the datatype eBufType is used.
    4918             :  *
    4919             :  * @param nLineSpace The byte offset from the start of one scanline in
    4920             :  * pData to the start of the next.  If defaulted the size of the datatype
    4921             :  * eBufType * nBufXSize is used.
    4922             :  *
    4923             :  * @param nBandSpace the byte offset from the start of one bands data to the
    4924             :  * start of the next.  If defaulted (zero) the value will be
    4925             :  * nLineSpace * nBufYSize implying band sequential organization
    4926             :  * of the data buffer.
    4927             :  *
    4928             :  * @param papszOptions Driver specific control options in a string list or NULL.
    4929             :  * Consult driver documentation for options supported.
    4930             :  *
    4931             :  * @return handle representing the request.
    4932             :  */
    4933             : 
    4934           2 : GDALAsyncReaderH CPL_STDCALL GDALBeginAsyncReader(
    4935             :     GDALDatasetH hDS, int nXOff, int nYOff, int nXSize, int nYSize, void *pBuf,
    4936             :     int nBufXSize, int nBufYSize, GDALDataType eBufType, int nBandCount,
    4937             :     int *panBandMap, int nPixelSpace, int nLineSpace, int nBandSpace,
    4938             :     CSLConstList papszOptions)
    4939             : 
    4940             : {
    4941           2 :     VALIDATE_POINTER1(hDS, "GDALDataset", nullptr);
    4942             :     return static_cast<GDALAsyncReaderH>(
    4943           2 :         GDALDataset::FromHandle(hDS)->BeginAsyncReader(
    4944             :             nXOff, nYOff, nXSize, nYSize, pBuf, nBufXSize, nBufYSize, eBufType,
    4945             :             nBandCount, panBandMap, nPixelSpace, nLineSpace, nBandSpace,
    4946           2 :             const_cast<char **>(papszOptions)));
    4947             : }
    4948             : 
    4949             : /************************************************************************/
    4950             : /*                        EndAsyncReader()                            */
    4951             : /************************************************************************/
    4952             : 
    4953             : /**
    4954             :  * End asynchronous request.
    4955             :  *
    4956             :  * This method destroys an asynchronous io request and recovers all
    4957             :  * resources associated with it.
    4958             :  *
    4959             :  * This method is the same as the C function GDALEndAsyncReader().
    4960             :  *
    4961             :  * @param poARIO pointer to a GDALAsyncReader
    4962             :  */
    4963             : 
    4964           1 : void GDALDataset::EndAsyncReader(GDALAsyncReader *poARIO)
    4965             : {
    4966           1 :     delete poARIO;
    4967           1 : }
    4968             : 
    4969             : /************************************************************************/
    4970             : /*                        GDALEndAsyncReader()                        */
    4971             : /************************************************************************/
    4972             : 
    4973             : /**
    4974             :  * End asynchronous request.
    4975             :  *
    4976             :  * This method destroys an asynchronous io request and recovers all
    4977             :  * resources associated with it.
    4978             :  *
    4979             :  * This method is the same as the C++ method GDALDataset::EndAsyncReader().
    4980             :  *
    4981             :  * @param hDS handle to the dataset object.
    4982             :  * @param hAsyncReaderH handle returned by GDALBeginAsyncReader()
    4983             :  */
    4984             : 
    4985           1 : void CPL_STDCALL GDALEndAsyncReader(GDALDatasetH hDS,
    4986             :                                     GDALAsyncReaderH hAsyncReaderH)
    4987             : {
    4988           1 :     VALIDATE_POINTER0(hDS, "GDALDataset");
    4989           1 :     VALIDATE_POINTER0(hAsyncReaderH, "GDALAsyncReader");
    4990           1 :     GDALDataset::FromHandle(hDS)->EndAsyncReader(
    4991           1 :         static_cast<GDALAsyncReader *>(hAsyncReaderH));
    4992             : }
    4993             : 
    4994             : /************************************************************************/
    4995             : /*                       CloseDependentDatasets()                       */
    4996             : /************************************************************************/
    4997             : 
    4998             : /**
    4999             :  * Drop references to any other datasets referenced by this dataset.
    5000             :  *
    5001             :  * This method should release any reference to other datasets (e.g. a VRT
    5002             :  * dataset to its sources), but not close the current dataset itself.
    5003             :  *
    5004             :  * If at least, one reference to a dependent dataset has been dropped,
    5005             :  * this method should return TRUE. Otherwise it *should* return FALSE.
    5006             :  * (Failure to return the proper value might result in infinite loop)
    5007             :  *
    5008             :  * This method can be called several times on a given dataset. After
    5009             :  * the first time, it should not do anything and return FALSE.
    5010             :  *
    5011             :  * The driver implementation may choose to destroy its raster bands,
    5012             :  * so be careful not to call any method on the raster bands afterwards.
    5013             :  *
    5014             :  * Basically the only safe action you can do after calling
    5015             :  * CloseDependentDatasets() is to call the destructor.
    5016             :  *
    5017             :  * Note: the only legitimate caller of CloseDependentDatasets() is
    5018             :  * GDALDriverManager::~GDALDriverManager()
    5019             :  *
    5020             :  * @return TRUE if at least one reference to another dataset has been dropped.
    5021             :  */
    5022       18793 : int GDALDataset::CloseDependentDatasets()
    5023             : {
    5024       18793 :     return oOvManager.CloseDependentDatasets();
    5025             : }
    5026             : 
    5027             : /************************************************************************/
    5028             : /*                            ReportError()                             */
    5029             : /************************************************************************/
    5030             : 
    5031             : #ifndef DOXYGEN_XML
    5032             : /**
    5033             :  * \brief Emits an error related to a dataset.
    5034             :  *
    5035             :  * This function is a wrapper for regular CPLError(). The only difference
    5036             :  * with CPLError() is that it prepends the error message with the dataset
    5037             :  * name.
    5038             :  *
    5039             :  * @param eErrClass one of CE_Warning, CE_Failure or CE_Fatal.
    5040             :  * @param err_no the error number (CPLE_*) from cpl_error.h.
    5041             :  * @param fmt a printf() style format string.  Any additional arguments
    5042             :  * will be treated as arguments to fill in this format in a manner
    5043             :  * similar to printf().
    5044             :  *
    5045             :  */
    5046             : 
    5047         102 : void GDALDataset::ReportError(CPLErr eErrClass, CPLErrorNum err_no,
    5048             :                               const char *fmt, ...) const
    5049             : {
    5050             :     va_list args;
    5051         102 :     va_start(args, fmt);
    5052         102 :     ReportErrorV(GetDescription(), eErrClass, err_no, fmt, args);
    5053         102 :     va_end(args);
    5054         102 : }
    5055             : 
    5056             : /**
    5057             :  * \brief Emits an error related to a dataset (static method)
    5058             :  *
    5059             :  * This function is a wrapper for regular CPLError(). The only difference
    5060             :  * with CPLError() is that it prepends the error message with the dataset
    5061             :  * name.
    5062             :  *
    5063             :  * @param pszDSName dataset name.
    5064             :  * @param eErrClass one of CE_Warning, CE_Failure or CE_Fatal.
    5065             :  * @param err_no the error number (CPLE_*) from cpl_error.h.
    5066             :  * @param fmt a printf() style format string.  Any additional arguments
    5067             :  * will be treated as arguments to fill in this format in a manner
    5068             :  * similar to printf().
    5069             :  *
    5070             :  * @since GDAL 3.2.0
    5071             :  */
    5072             : 
    5073         124 : void GDALDataset::ReportError(const char *pszDSName, CPLErr eErrClass,
    5074             :                               CPLErrorNum err_no, const char *fmt, ...)
    5075             : {
    5076             :     va_list args;
    5077         124 :     va_start(args, fmt);
    5078         124 :     ReportErrorV(pszDSName, eErrClass, err_no, fmt, args);
    5079         124 :     va_end(args);
    5080         124 : }
    5081             : 
    5082         226 : void GDALDataset::ReportErrorV(const char *pszDSName, CPLErr eErrClass,
    5083             :                                CPLErrorNum err_no, const char *fmt,
    5084             :                                va_list args)
    5085             : {
    5086         226 :     pszDSName = CPLGetFilename(pszDSName);
    5087         226 :     if (pszDSName[0] != '\0')
    5088             :     {
    5089         209 :         CPLError(eErrClass, err_no, "%s",
    5090         418 :                  std::string(pszDSName)
    5091         209 :                      .append(": ")
    5092         418 :                      .append(CPLString().vPrintf(fmt, args))
    5093             :                      .c_str());
    5094             :     }
    5095             :     else
    5096             :     {
    5097          17 :         CPLErrorV(eErrClass, err_no, fmt, args);
    5098             :     }
    5099         226 : }
    5100             : #endif
    5101             : 
    5102             : /************************************************************************/
    5103             : /*                            GetMetadata()                             */
    5104             : /************************************************************************/
    5105       71915 : char **GDALDataset::GetMetadata(const char *pszDomain)
    5106             : {
    5107             : #ifndef WITHOUT_DERIVED
    5108       71915 :     if (pszDomain != nullptr && EQUAL(pszDomain, "DERIVED_SUBDATASETS"))
    5109             :     {
    5110          10 :         oDerivedMetadataList.Clear();
    5111             : 
    5112             :         // First condition: at least one raster band.
    5113          10 :         if (GetRasterCount() > 0)
    5114             :         {
    5115             :             // Check if there is at least one complex band.
    5116          10 :             bool hasAComplexBand = false;
    5117             : 
    5118          19 :             for (int rasterId = 1; rasterId <= GetRasterCount(); ++rasterId)
    5119             :             {
    5120          11 :                 if (GDALDataTypeIsComplex(
    5121          11 :                         GetRasterBand(rasterId)->GetRasterDataType()))
    5122             :                 {
    5123           2 :                     hasAComplexBand = true;
    5124           2 :                     break;
    5125             :                 }
    5126             :             }
    5127             : 
    5128          10 :             unsigned int nbSupportedDerivedDS = 0;
    5129             :             const DerivedDatasetDescription *poDDSDesc =
    5130          10 :                 GDALGetDerivedDatasetDescriptions(&nbSupportedDerivedDS);
    5131             : 
    5132          10 :             int nNumDataset = 1;
    5133          80 :             for (unsigned int derivedId = 0; derivedId < nbSupportedDerivedDS;
    5134             :                  ++derivedId)
    5135             :             {
    5136         126 :                 if (hasAComplexBand ||
    5137         126 :                     CPLString(poDDSDesc[derivedId].pszInputPixelType) !=
    5138             :                         "complex")
    5139             :                 {
    5140             :                     oDerivedMetadataList.SetNameValue(
    5141             :                         CPLSPrintf("DERIVED_SUBDATASET_%d_NAME", nNumDataset),
    5142             :                         CPLSPrintf("DERIVED_SUBDATASET:%s:%s",
    5143          22 :                                    poDDSDesc[derivedId].pszDatasetName,
    5144          22 :                                    GetDescription()));
    5145             : 
    5146             :                     CPLString osDesc(
    5147             :                         CPLSPrintf("%s from %s",
    5148          22 :                                    poDDSDesc[derivedId].pszDatasetDescription,
    5149          22 :                                    GetDescription()));
    5150             :                     oDerivedMetadataList.SetNameValue(
    5151             :                         CPLSPrintf("DERIVED_SUBDATASET_%d_DESC", nNumDataset),
    5152          22 :                         osDesc.c_str());
    5153             : 
    5154          22 :                     nNumDataset++;
    5155             :                 }
    5156             :             }
    5157             :         }
    5158          10 :         return oDerivedMetadataList.List();
    5159             :     }
    5160             : #endif
    5161             : 
    5162       71905 :     return GDALMajorObject::GetMetadata(pszDomain);
    5163             : }
    5164             : 
    5165             : // clang-format off
    5166             : 
    5167             : /**
    5168             :  * \fn GDALDataset::SetMetadata( char ** papszMetadata, const char * pszDomain)
    5169             :  * \brief Set metadata.
    5170             :  *
    5171             :  * CAUTION: depending on the format, older values of the updated information
    5172             :  * might still be found in the file in a "ghost" state, even if no longer
    5173             :  * accessible through the GDAL API. This is for example the case of the GTiff
    5174             :  * format (this is not a exhaustive list)
    5175             :  *
    5176             :  * The C function GDALSetMetadata() does the same thing as this method.
    5177             :  *
    5178             :  * @param papszMetadata the metadata in name=value string list format to
    5179             :  * apply.
    5180             :  * @param pszDomain the domain of interest.  Use "" or NULL for the default
    5181             :  * domain.
    5182             :  * @return CE_None on success, CE_Failure on failure and CE_Warning if the
    5183             :  * metadata has been accepted, but is likely not maintained persistently
    5184             :  * by the underlying object between sessions.
    5185             :  */
    5186             : 
    5187             : /**
    5188             :  * \fn GDALDataset::SetMetadataItem( const char * pszName, const char * pszValue, const char * pszDomain)
    5189             :  * \brief Set single metadata item.
    5190             :  *
    5191             :  * CAUTION: depending on the format, older values of the updated information
    5192             :  * might still be found in the file in a "ghost" state, even if no longer
    5193             :  * accessible through the GDAL API. This is for example the case of the GTiff
    5194             :  * format (this is not a exhaustive list)
    5195             :  *
    5196             :  * The C function GDALSetMetadataItem() does the same thing as this method.
    5197             :  *
    5198             :  * @param pszName the key for the metadata item to fetch.
    5199             :  * @param pszValue the value to assign to the key.
    5200             :  * @param pszDomain the domain to set within, use NULL for the default domain.
    5201             :  *
    5202             :  * @return CE_None on success, or an error code on failure.
    5203             :  */
    5204             : 
    5205             : // clang-format on
    5206             : 
    5207             : /************************************************************************/
    5208             : /*                            GetMetadataDomainList()                   */
    5209             : /************************************************************************/
    5210             : 
    5211        1045 : char **GDALDataset::GetMetadataDomainList()
    5212             : {
    5213        1045 :     char **currentDomainList = CSLDuplicate(oMDMD.GetDomainList());
    5214             : 
    5215             :     // Ensure that we do not duplicate DERIVED domain.
    5216        1188 :     if (GetRasterCount() > 0 &&
    5217         143 :         CSLFindString(currentDomainList, "DERIVED_SUBDATASETS") == -1)
    5218             :     {
    5219             :         currentDomainList =
    5220         143 :             CSLAddString(currentDomainList, "DERIVED_SUBDATASETS");
    5221             :     }
    5222        1045 :     return currentDomainList;
    5223             : }
    5224             : 
    5225             : /************************************************************************/
    5226             : /*                            GetDriverName()                           */
    5227             : /************************************************************************/
    5228             : 
    5229             : /** Return driver name.
    5230             :  * @return driver name.
    5231             :  */
    5232        2065 : const char *GDALDataset::GetDriverName() const
    5233             : {
    5234        2065 :     if (poDriver)
    5235        2053 :         return poDriver->GetDescription();
    5236          12 :     return "";
    5237             : }
    5238             : 
    5239             : /************************************************************************/
    5240             : /*                     GDALDatasetReleaseResultSet()                    */
    5241             : /************************************************************************/
    5242             : 
    5243             : /**
    5244             :  \brief Release results of ExecuteSQL().
    5245             : 
    5246             :  This function should only be used to deallocate OGRLayers resulting from
    5247             :  an ExecuteSQL() call on the same GDALDataset.  Failure to deallocate a
    5248             :  results set before destroying the GDALDataset may cause errors.
    5249             : 
    5250             :  This function is the same as the C++ method GDALDataset::ReleaseResultSet()
    5251             : 
    5252             : 
    5253             :  @param hDS the dataset handle.
    5254             :  @param hLayer the result of a previous ExecuteSQL() call.
    5255             : 
    5256             : */
    5257        3501 : void GDALDatasetReleaseResultSet(GDALDatasetH hDS, OGRLayerH hLayer)
    5258             : 
    5259             : {
    5260        3501 :     VALIDATE_POINTER0(hDS, "GDALDatasetReleaseResultSet");
    5261             : 
    5262             : #ifdef OGRAPISPY_ENABLED
    5263        3501 :     if (bOGRAPISpyEnabled)
    5264           6 :         OGRAPISpy_DS_ReleaseResultSet(hDS, hLayer);
    5265             : #endif
    5266             : 
    5267        7002 :     GDALDataset::FromHandle(hDS)->ReleaseResultSet(
    5268        3501 :         OGRLayer::FromHandle(hLayer));
    5269             : }
    5270             : 
    5271             : /************************************************************************/
    5272             : /*                       GDALDatasetGetLayerCount()                     */
    5273             : /************************************************************************/
    5274             : 
    5275             : /**
    5276             :  \brief Get the number of layers in this dataset.
    5277             : 
    5278             :  This function is the same as the C++ method GDALDataset::GetLayerCount()
    5279             : 
    5280             : 
    5281             :  @param hDS the dataset handle.
    5282             :  @return layer count.
    5283             : */
    5284             : 
    5285        1481 : int GDALDatasetGetLayerCount(GDALDatasetH hDS)
    5286             : 
    5287             : {
    5288        1481 :     VALIDATE_POINTER1(hDS, "GDALDatasetH", 0);
    5289             : 
    5290             : #ifdef OGRAPISPY_ENABLED
    5291        1481 :     if (bOGRAPISpyEnabled)
    5292           2 :         OGRAPISpy_DS_GetLayerCount(reinterpret_cast<GDALDatasetH>(hDS));
    5293             : #endif
    5294             : 
    5295        1481 :     return GDALDataset::FromHandle(hDS)->GetLayerCount();
    5296             : }
    5297             : 
    5298             : /************************************************************************/
    5299             : /*                        GDALDatasetGetLayer()                         */
    5300             : /************************************************************************/
    5301             : 
    5302             : /**
    5303             :  \brief Fetch a layer by index.
    5304             : 
    5305             :  The returned layer remains owned by the
    5306             :  GDALDataset and should not be deleted by the application.
    5307             : 
    5308             :  This function is the same as the C++ method GDALDataset::GetLayer()
    5309             : 
    5310             : 
    5311             :  @param hDS the dataset handle.
    5312             :  @param iLayer a layer number between 0 and GetLayerCount()-1.
    5313             : 
    5314             :  @return the layer, or NULL if iLayer is out of range or an error occurs.
    5315             : */
    5316             : 
    5317        9892 : OGRLayerH GDALDatasetGetLayer(GDALDatasetH hDS, int iLayer)
    5318             : 
    5319             : {
    5320        9892 :     VALIDATE_POINTER1(hDS, "GDALDatasetGetLayer", nullptr);
    5321             : 
    5322             :     OGRLayerH hLayer =
    5323        9892 :         OGRLayer::ToHandle(GDALDataset::FromHandle(hDS)->GetLayer(iLayer));
    5324             : 
    5325             : #ifdef OGRAPISPY_ENABLED
    5326        9892 :     if (bOGRAPISpyEnabled)
    5327           3 :         OGRAPISpy_DS_GetLayer(hDS, iLayer, hLayer);
    5328             : #endif
    5329             : 
    5330        9892 :     return hLayer;
    5331             : }
    5332             : 
    5333             : /************************************************************************/
    5334             : /*                     GDALDatasetGetLayerByName()                      */
    5335             : /************************************************************************/
    5336             : 
    5337             : /**
    5338             :  \brief Fetch a layer by name.
    5339             : 
    5340             :  The returned layer remains owned by the
    5341             :  GDALDataset and should not be deleted by the application.
    5342             : 
    5343             :  This function is the same as the C++ method GDALDataset::GetLayerByName()
    5344             : 
    5345             : 
    5346             :  @param hDS the dataset handle.
    5347             :  @param pszName the layer name of the layer to fetch.
    5348             : 
    5349             :  @return the layer, or NULL if Layer is not found or an error occurs.
    5350             : */
    5351             : 
    5352        3413 : OGRLayerH GDALDatasetGetLayerByName(GDALDatasetH hDS, const char *pszName)
    5353             : 
    5354             : {
    5355        3413 :     VALIDATE_POINTER1(hDS, "GDALDatasetGetLayerByName", nullptr);
    5356             : 
    5357        3413 :     OGRLayerH hLayer = OGRLayer::ToHandle(
    5358        3413 :         GDALDataset::FromHandle(hDS)->GetLayerByName(pszName));
    5359             : 
    5360             : #ifdef OGRAPISPY_ENABLED
    5361        3413 :     if (bOGRAPISpyEnabled)
    5362           4 :         OGRAPISpy_DS_GetLayerByName(hDS, pszName, hLayer);
    5363             : #endif
    5364             : 
    5365        3413 :     return hLayer;
    5366             : }
    5367             : 
    5368             : /************************************************************************/
    5369             : /*                        GDALDatasetIsLayerPrivate()                   */
    5370             : /************************************************************************/
    5371             : 
    5372             : /**
    5373             :  \brief Returns true if the layer at the specified index is deemed a private or
    5374             :  system table, or an internal detail only.
    5375             : 
    5376             :  This function is the same as the C++ method GDALDataset::IsLayerPrivate()
    5377             : 
    5378             :  @since GDAL 3.4
    5379             : 
    5380             :  @param hDS the dataset handle.
    5381             :  @param iLayer a layer number between 0 and GetLayerCount()-1.
    5382             : 
    5383             :  @return true if the layer is a private or system table.
    5384             : */
    5385             : 
    5386          91 : int GDALDatasetIsLayerPrivate(GDALDatasetH hDS, int iLayer)
    5387             : 
    5388             : {
    5389          91 :     VALIDATE_POINTER1(hDS, "GDALDatasetIsLayerPrivate", false);
    5390             : 
    5391          91 :     const bool res = GDALDataset::FromHandle(hDS)->IsLayerPrivate(iLayer);
    5392             : 
    5393          91 :     return res ? 1 : 0;
    5394             : }
    5395             : 
    5396             : /************************************************************************/
    5397             : /*                            GetLayerIndex()                           */
    5398             : /************************************************************************/
    5399             : 
    5400             : /**
    5401             :  \brief Returns the index of the layer specified by name.
    5402             : 
    5403             :  @since GDAL 3.12
    5404             : 
    5405             :  @param pszName layer name (not NULL)
    5406             : 
    5407             :  @return an index >= 0, or -1 if not found.
    5408             : */
    5409             : 
    5410           3 : int GDALDataset::GetLayerIndex(const char *pszName) const
    5411             : {
    5412           3 :     const int nLayerCount = GetLayerCount();
    5413           3 :     int iMatch = -1;
    5414           6 :     for (int i = 0; i < nLayerCount; ++i)
    5415             :     {
    5416           5 :         if (const auto poLayer = GetLayer(i))
    5417             :         {
    5418           5 :             const char *pszLayerName = poLayer->GetDescription();
    5419           5 :             if (strcmp(pszName, pszLayerName) == 0)
    5420             :             {
    5421           2 :                 iMatch = i;
    5422           2 :                 break;
    5423             :             }
    5424           3 :             else if (EQUAL(pszName, pszLayerName))
    5425             :             {
    5426           0 :                 iMatch = i;
    5427             :             }
    5428             :         }
    5429             :     }
    5430           3 :     return iMatch;
    5431             : }
    5432             : 
    5433             : /************************************************************************/
    5434             : /*                        GDALDatasetDeleteLayer()                      */
    5435             : /************************************************************************/
    5436             : 
    5437             : /**
    5438             :  \brief Delete the indicated layer from the datasource.
    5439             : 
    5440             :  If this function is supported
    5441             :  the ODsCDeleteLayer capability will test TRUE on the GDALDataset.
    5442             : 
    5443             :  This method is the same as the C++ method GDALDataset::DeleteLayer().
    5444             : 
    5445             : 
    5446             :  @param hDS the dataset handle.
    5447             :  @param iLayer the index of the layer to delete.
    5448             : 
    5449             :  @return OGRERR_NONE on success, or OGRERR_UNSUPPORTED_OPERATION if deleting
    5450             :  layers is not supported for this datasource.
    5451             : 
    5452             : */
    5453          41 : OGRErr GDALDatasetDeleteLayer(GDALDatasetH hDS, int iLayer)
    5454             : 
    5455             : {
    5456          41 :     VALIDATE_POINTER1(hDS, "GDALDatasetH", OGRERR_INVALID_HANDLE);
    5457             : 
    5458             : #ifdef OGRAPISPY_ENABLED
    5459          41 :     if (bOGRAPISpyEnabled)
    5460           2 :         OGRAPISpy_DS_DeleteLayer(hDS, iLayer);
    5461             : #endif
    5462             : 
    5463          41 :     return GDALDataset::FromHandle(hDS)->DeleteLayer(iLayer);
    5464             : }
    5465             : 
    5466             : /************************************************************************/
    5467             : /*                            CreateLayer()                             */
    5468             : /************************************************************************/
    5469             : 
    5470             : /**
    5471             : \brief This method attempts to create a new layer on the dataset with the
    5472             : indicated name, coordinate system, geometry type.
    5473             : 
    5474             : The papszOptions argument
    5475             : can be used to control driver specific creation options.  These options are
    5476             : normally documented in the format specific documentation.
    5477             : That function will try to validate the creation option list passed to the
    5478             : driver with the GDALValidateCreationOptions() method. This check can be
    5479             : disabled by defining the configuration option GDAL_VALIDATE_CREATION_OPTIONS set
    5480             : to NO.
    5481             : 
    5482             : Drivers should extend the ICreateLayer() method and not
    5483             : CreateLayer(). CreateLayer() adds validation of layer creation options, before
    5484             : delegating the actual work to ICreateLayer().
    5485             : 
    5486             : This method is the same as the C function GDALDatasetCreateLayer() and the
    5487             : deprecated OGR_DS_CreateLayer().
    5488             : 
    5489             : Example:
    5490             : 
    5491             : \code{.cpp}
    5492             : #include "gdal.h"
    5493             : #include "cpl_string.h"
    5494             : 
    5495             : ...
    5496             : 
    5497             :         OGRLayer *poLayer;
    5498             :         char     **papszOptions;
    5499             : 
    5500             :         if( !poDS->TestCapability( ODsCCreateLayer ) )
    5501             :         {
    5502             :         ...
    5503             :         }
    5504             : 
    5505             :         papszOptions = CSLSetNameValue( papszOptions, "DIM", "2" );
    5506             :         poLayer = poDS->CreateLayer( "NewLayer", nullptr, wkbUnknown,
    5507             :                                      papszOptions );
    5508             :         CSLDestroy( papszOptions );
    5509             : 
    5510             :         if( poLayer == NULL )
    5511             :         {
    5512             :             ...
    5513             :         }
    5514             : \endcode
    5515             : 
    5516             : @param pszName the name for the new layer.  This should ideally not
    5517             : match any existing layer on the datasource.
    5518             : @param poSpatialRef the coordinate system to use for the new layer, or NULL if
    5519             : no coordinate system is available.
    5520             : @param eGType the geometry type for the layer.  Use wkbUnknown if there
    5521             : are no constraints on the types geometry to be written.
    5522             : @param papszOptions a StringList of name=value options.  Options are driver
    5523             : specific.
    5524             : 
    5525             : @return NULL is returned on failure, or a new OGRLayer handle on success.
    5526             : 
    5527             : */
    5528             : 
    5529        8249 : OGRLayer *GDALDataset::CreateLayer(const char *pszName,
    5530             :                                    const OGRSpatialReference *poSpatialRef,
    5531             :                                    OGRwkbGeometryType eGType,
    5532             :                                    CSLConstList papszOptions)
    5533             : 
    5534             : {
    5535        8249 :     if (eGType == wkbNone)
    5536             :     {
    5537         519 :         return CreateLayer(pszName, nullptr, papszOptions);
    5538             :     }
    5539             :     else
    5540             :     {
    5541       15460 :         OGRGeomFieldDefn oGeomFieldDefn("", eGType);
    5542        7730 :         oGeomFieldDefn.SetSpatialRef(poSpatialRef);
    5543        7730 :         return CreateLayer(pszName, &oGeomFieldDefn, papszOptions);
    5544             :     }
    5545             : }
    5546             : 
    5547             : /**
    5548             : \brief This method attempts to create a new layer on the dataset with the
    5549             : indicated name and geometry field definition.
    5550             : 
    5551             : When poGeomFieldDefn is not null, most drivers should honor
    5552             : poGeomFieldDefn->GetType() and poGeomFieldDefn->GetSpatialRef().
    5553             : Drivers that honor poGeomFieldDefn->GetCoordinatePrecision() will declare the
    5554             : GDAL_DCAP_HONOR_GEOM_COORDINATE_PRECISION capability. Drivers may honor
    5555             : poGeomFieldDefn->GetNameRef() and poGeomFieldDefn->IsNullable(), but there are
    5556             : very few currently.
    5557             : 
    5558             : Note that even if a geometry coordinate precision is set and a driver honors the
    5559             : GDAL_DCAP_HONOR_GEOM_COORDINATE_PRECISION capability, geometries passed to
    5560             : OGRLayer::CreateFeature() and OGRLayer::SetFeature() are assumed to be compatible
    5561             : with the coordinate precision. That is they are assumed to be valid once their
    5562             : coordinates are rounded to it. If it might not be the case, the user may set
    5563             : the OGR_APPLY_GEOM_SET_PRECISION configuration option before calling CreateFeature()
    5564             : or SetFeature() to force the OGRGeometry::SetPrecision() method to be called on
    5565             : the passed geometries.
    5566             : 
    5567             : The papszOptions argument
    5568             : can be used to control driver specific creation options. These options are
    5569             : normally documented in the format specific documentation.
    5570             : This function will try to validate the creation option list passed to the
    5571             : driver with the GDALValidateCreationOptions() method. This check can be
    5572             : disabled by defining the configuration option GDAL_VALIDATE_CREATION_OPTIONS set
    5573             : to NO.
    5574             : 
    5575             : Drivers should extend the ICreateLayer() method and not
    5576             : CreateLayer(). CreateLayer() adds validation of layer creation options, before
    5577             : delegating the actual work to ICreateLayer().
    5578             : 
    5579             : This method is the same as the C function GDALDatasetCreateLayerFromGeomFieldDefn().
    5580             : 
    5581             : @param pszName the name for the new layer.  This should ideally not
    5582             : match any existing layer on the datasource.
    5583             : @param poGeomFieldDefn the geometry field definition to use for the new layer,
    5584             : or NULL if there is no geometry field.
    5585             : @param papszOptions a StringList of name=value options.  Options are driver
    5586             : specific.
    5587             : 
    5588             : @return NULL is returned on failure, or a new OGRLayer handle on success.
    5589             : @since 3.9
    5590             : 
    5591             : */
    5592             : 
    5593        9624 : OGRLayer *GDALDataset::CreateLayer(const char *pszName,
    5594             :                                    const OGRGeomFieldDefn *poGeomFieldDefn,
    5595             :                                    CSLConstList papszOptions)
    5596             : 
    5597             : {
    5598        9624 :     if (CPLTestBool(
    5599             :             CPLGetConfigOption("GDAL_VALIDATE_CREATION_OPTIONS", "YES")))
    5600             :     {
    5601        9624 :         ValidateLayerCreationOptions(papszOptions);
    5602             :     }
    5603             : 
    5604             :     OGRLayer *poLayer;
    5605        9624 :     if (poGeomFieldDefn)
    5606             :     {
    5607        8696 :         OGRGeomFieldDefn oGeomFieldDefn(poGeomFieldDefn);
    5608        8790 :         if (OGR_GT_IsNonLinear(poGeomFieldDefn->GetType()) &&
    5609          94 :             !TestCapability(ODsCCurveGeometries))
    5610             :         {
    5611          23 :             oGeomFieldDefn.SetType(
    5612             :                 OGR_GT_GetLinear(poGeomFieldDefn->GetType()));
    5613             :         }
    5614             : 
    5615        8696 :         poLayer = ICreateLayer(pszName, &oGeomFieldDefn, papszOptions);
    5616             :     }
    5617             :     else
    5618             :     {
    5619         928 :         poLayer = ICreateLayer(pszName, nullptr, papszOptions);
    5620             :     }
    5621             : #ifdef DEBUG
    5622        9695 :     if (poLayer != nullptr && OGR_GT_IsNonLinear(poLayer->GetGeomType()) &&
    5623          71 :         !poLayer->TestCapability(OLCCurveGeometries))
    5624             :     {
    5625           0 :         CPLError(CE_Warning, CPLE_AppDefined,
    5626             :                  "Inconsistent driver: Layer geometry type is non-linear, but "
    5627             :                  "TestCapability(OLCCurveGeometries) returns FALSE.");
    5628             :     }
    5629             : #endif
    5630             : 
    5631        9624 :     return poLayer;
    5632             : }
    5633             : 
    5634             : //! @cond Doxygen_Suppress
    5635             : 
    5636             : // Technical override to avoid ambiguous choice between the old and new
    5637             : // new CreateLayer() signatures.
    5638          12 : OGRLayer *GDALDataset::CreateLayer(const char *pszName)
    5639             : {
    5640          24 :     OGRGeomFieldDefn oGeomFieldDefn("", wkbUnknown);
    5641          24 :     return CreateLayer(pszName, &oGeomFieldDefn, nullptr);
    5642             : }
    5643             : 
    5644             : // Technical override to avoid ambiguous choice between the old and new
    5645             : // new CreateLayer() signatures.
    5646           1 : OGRLayer *GDALDataset::CreateLayer(const char *pszName, std::nullptr_t)
    5647             : {
    5648           2 :     OGRGeomFieldDefn oGeomFieldDefn("", wkbUnknown);
    5649           2 :     return CreateLayer(pszName, &oGeomFieldDefn, nullptr);
    5650             : }
    5651             : 
    5652             : //!@endcond
    5653             : 
    5654             : /************************************************************************/
    5655             : /*                         GDALDatasetCreateLayer()                     */
    5656             : /************************************************************************/
    5657             : 
    5658             : /**
    5659             : \brief This function attempts to create a new layer on the dataset with the
    5660             : indicated name, coordinate system, geometry type.
    5661             : 
    5662             : The papszOptions argument can be used to control driver specific creation
    5663             : options.  These options are normally documented in the format specific
    5664             : documentation.
    5665             : 
    5666             : This method is the same as the C++ method GDALDataset::CreateLayer().
    5667             : 
    5668             : Example:
    5669             : 
    5670             : \code{.c}
    5671             : #include "gdal.h"
    5672             : #include "cpl_string.h"
    5673             : 
    5674             : ...
    5675             : 
    5676             :         OGRLayerH  hLayer;
    5677             :         char     **papszOptions;
    5678             : 
    5679             :         if( !GDALDatasetTestCapability( hDS, ODsCCreateLayer ) )
    5680             :         {
    5681             :         ...
    5682             :         }
    5683             : 
    5684             :         papszOptions = CSLSetNameValue( papszOptions, "DIM", "2" );
    5685             :         hLayer = GDALDatasetCreateLayer( hDS, "NewLayer", NULL, wkbUnknown,
    5686             :                                          papszOptions );
    5687             :         CSLDestroy( papszOptions );
    5688             : 
    5689             :         if( hLayer == NULL )
    5690             :         {
    5691             :             ...
    5692             :         }
    5693             : \endcode
    5694             : 
    5695             : 
    5696             : @param hDS the dataset handle
    5697             : @param pszName the name for the new layer.  This should ideally not
    5698             : match any existing layer on the datasource.
    5699             : @param hSpatialRef the coordinate system to use for the new layer, or NULL if
    5700             : no coordinate system is available.
    5701             : @param eGType the geometry type for the layer.  Use wkbUnknown if there
    5702             : are no constraints on the types geometry to be written.
    5703             : @param papszOptions a StringList of name=value options.  Options are driver
    5704             : specific.
    5705             : 
    5706             : @return NULL is returned on failure, or a new OGRLayer handle on success.
    5707             : 
    5708             : */
    5709             : 
    5710        6400 : OGRLayerH GDALDatasetCreateLayer(GDALDatasetH hDS, const char *pszName,
    5711             :                                  OGRSpatialReferenceH hSpatialRef,
    5712             :                                  OGRwkbGeometryType eGType,
    5713             :                                  CSLConstList papszOptions)
    5714             : 
    5715             : {
    5716        6400 :     VALIDATE_POINTER1(hDS, "GDALDatasetCreateLayer", nullptr);
    5717             : 
    5718        6400 :     if (pszName == nullptr)
    5719             :     {
    5720           0 :         CPLError(CE_Failure, CPLE_ObjectNull,
    5721             :                  "Name was NULL in GDALDatasetCreateLayer");
    5722           0 :         return nullptr;
    5723             :     }
    5724             : 
    5725             :     OGRLayerH hLayer =
    5726       12800 :         OGRLayer::ToHandle(GDALDataset::FromHandle(hDS)->CreateLayer(
    5727        6400 :             pszName, OGRSpatialReference::FromHandle(hSpatialRef), eGType,
    5728             :             const_cast<char **>(papszOptions)));
    5729             : 
    5730             : #ifdef OGRAPISPY_ENABLED
    5731        6400 :     if (bOGRAPISpyEnabled)
    5732           8 :         OGRAPISpy_DS_CreateLayer(hDS, pszName, hSpatialRef, eGType,
    5733             :                                  const_cast<char **>(papszOptions), hLayer);
    5734             : #endif
    5735             : 
    5736        6400 :     return hLayer;
    5737             : }
    5738             : 
    5739             : /************************************************************************/
    5740             : /*                 GDALDatasetCreateLayerFromGeomFieldDefn()            */
    5741             : /************************************************************************/
    5742             : 
    5743             : /**
    5744             : \brief This function attempts to create a new layer on the dataset with the
    5745             : indicated name and geometry field.
    5746             : 
    5747             : When poGeomFieldDefn is not null, most drivers should honor
    5748             : poGeomFieldDefn->GetType() and poGeomFieldDefn->GetSpatialRef().
    5749             : Drivers that honor poGeomFieldDefn->GetCoordinatePrecision() will declare the
    5750             : GDAL_DCAP_HONOR_GEOM_COORDINATE_PRECISION capability. Drivers may honor
    5751             : poGeomFieldDefn->GetNameRef() and poGeomFieldDefn->IsNullable(), but there are
    5752             : very few currently.
    5753             : 
    5754             : Note that even if a geometry coordinate precision is set and a driver honors the
    5755             : GDAL_DCAP_HONOR_GEOM_COORDINATE_PRECISION capability, geometries passed to
    5756             : OGRLayer::CreateFeature() and OGRLayer::SetFeature() are assumed to be compatible
    5757             : with the coordinate precision. That is they are assumed to be valid once their
    5758             : coordinates are rounded to it. If it might not be the case, the user may set
    5759             : the OGR_APPLY_GEOM_SET_PRECISION configuration option before calling CreateFeature()
    5760             : or SetFeature() to force the OGRGeometry::SetPrecision() method to be called on
    5761             : the passed geometries.
    5762             : 
    5763             : The papszOptions argument can be used to control driver specific creation
    5764             : options.  These options are normally documented in the format specific
    5765             : documentation.
    5766             : 
    5767             : This method is the same as the C++ method GDALDataset::CreateLayer().
    5768             : 
    5769             : @param hDS the dataset handle
    5770             : @param pszName the name for the new layer.  This should ideally not
    5771             : match any existing layer on the datasource.
    5772             : @param hGeomFieldDefn the geometry field definition. May be NULL to indicate
    5773             : a non-spatial file (or if adding geometry fields later with OGR_L_CreateGeomField()
    5774             : for drivers supporting that interface).
    5775             : @param papszOptions a StringList of name=value options.  Options are driver
    5776             : specific.
    5777             : 
    5778             : @return NULL is returned on failure, or a new OGRLayer handle on success.
    5779             : 
    5780             : @since GDAL 3.9
    5781             : 
    5782             : */
    5783             : 
    5784             : OGRLayerH
    5785          14 : GDALDatasetCreateLayerFromGeomFieldDefn(GDALDatasetH hDS, const char *pszName,
    5786             :                                         OGRGeomFieldDefnH hGeomFieldDefn,
    5787             :                                         CSLConstList papszOptions)
    5788             : 
    5789             : {
    5790          14 :     VALIDATE_POINTER1(hDS, "GDALDatasetCreateLayerFromGeomFieldDefn", nullptr);
    5791             : 
    5792          14 :     if (!pszName)
    5793             :     {
    5794           0 :         CPLError(CE_Failure, CPLE_ObjectNull,
    5795             :                  "Name was NULL in GDALDatasetCreateLayerFromGeomFieldDefn");
    5796           0 :         return nullptr;
    5797             :     }
    5798             : 
    5799             :     OGRLayerH hLayer =
    5800          28 :         OGRLayer::ToHandle(GDALDataset::FromHandle(hDS)->CreateLayer(
    5801          14 :             pszName, OGRGeomFieldDefn::FromHandle(hGeomFieldDefn),
    5802             :             papszOptions));
    5803          14 :     return hLayer;
    5804             : }
    5805             : 
    5806             : /************************************************************************/
    5807             : /*                         GDALDatasetCopyLayer()                       */
    5808             : /************************************************************************/
    5809             : 
    5810             : /**
    5811             :  \brief Duplicate an existing layer.
    5812             : 
    5813             :  This function creates a new layer, duplicate the field definitions of the
    5814             :  source layer and then duplicate each features of the source layer.
    5815             :  The papszOptions argument
    5816             :  can be used to control driver specific creation options.  These options are
    5817             :  normally documented in the format specific documentation.
    5818             :  The source layer may come from another dataset.
    5819             : 
    5820             :  This method is the same as the C++ method GDALDataset::CopyLayer()
    5821             : 
    5822             : 
    5823             :  @param hDS the dataset handle.
    5824             :  @param hSrcLayer source layer.
    5825             :  @param pszNewName the name of the layer to create.
    5826             :  @param papszOptions a StringList of name=value options.  Options are driver
    5827             :                      specific.
    5828             : 
    5829             :  @return a handle to the layer, or NULL if an error occurs.
    5830             : */
    5831          20 : OGRLayerH GDALDatasetCopyLayer(GDALDatasetH hDS, OGRLayerH hSrcLayer,
    5832             :                                const char *pszNewName,
    5833             :                                CSLConstList papszOptions)
    5834             : 
    5835             : {
    5836          20 :     VALIDATE_POINTER1(hDS, "OGR_DS_CopyGDALDatasetCopyLayerLayer", nullptr);
    5837          20 :     VALIDATE_POINTER1(hSrcLayer, "GDALDatasetCopyLayer", nullptr);
    5838          20 :     VALIDATE_POINTER1(pszNewName, "GDALDatasetCopyLayer", nullptr);
    5839             : 
    5840          40 :     return OGRLayer::ToHandle(GDALDataset::FromHandle(hDS)->CopyLayer(
    5841             :         OGRLayer::FromHandle(hSrcLayer), pszNewName,
    5842          40 :         const_cast<char **>(papszOptions)));
    5843             : }
    5844             : 
    5845             : /************************************************************************/
    5846             : /*                        GDALDatasetExecuteSQL()                       */
    5847             : /************************************************************************/
    5848             : 
    5849             : /**
    5850             :  \brief Execute an SQL statement against the data store.
    5851             : 
    5852             :  The result of an SQL query is either NULL for statements that are in error,
    5853             :  or that have no results set, or an OGRLayer pointer representing a results
    5854             :  set from the query.  Note that this OGRLayer is in addition to the layers
    5855             :  in the data store and must be destroyed with
    5856             :  ReleaseResultSet() before the dataset is closed
    5857             :  (destroyed).
    5858             : 
    5859             :  This method is the same as the C++ method GDALDataset::ExecuteSQL()
    5860             : 
    5861             :  For more information on the SQL dialect supported internally by OGR
    5862             :  review the <a href="https://gdal.org/user/ogr_sql_dialect.html">OGR SQL</a>
    5863             :  document.  Some drivers (i.e. Oracle and PostGIS) pass the SQL directly through
    5864             :  to the underlying RDBMS.
    5865             : 
    5866             :  Starting with OGR 1.10, the <a
    5867             :  href="https://gdal.org/user/sql_sqlite_dialect.html">SQLITE dialect</a> can
    5868             :  also be used.
    5869             : 
    5870             : 
    5871             :  @param hDS the dataset handle.
    5872             :  @param pszStatement the SQL statement to execute.
    5873             :  @param hSpatialFilter geometry which represents a spatial filter. Can be NULL.
    5874             : 
    5875             :  @param pszDialect allows control of the statement dialect. If set to NULL, the
    5876             :  OGR SQL engine will be used, except for RDBMS drivers that will use their
    5877             :  dedicated SQL engine, unless OGRSQL is explicitly passed as the
    5878             :  dialect. Starting with OGR 1.10, the SQLITE dialect can also be used.
    5879             : 
    5880             :  @return an OGRLayer containing the results of the query.  Deallocate with
    5881             :  GDALDatasetReleaseResultSet().
    5882             : 
    5883             : */
    5884             : 
    5885       10544 : OGRLayerH GDALDatasetExecuteSQL(GDALDatasetH hDS, const char *pszStatement,
    5886             :                                 OGRGeometryH hSpatialFilter,
    5887             :                                 const char *pszDialect)
    5888             : 
    5889             : {
    5890       10544 :     VALIDATE_POINTER1(hDS, "GDALDatasetExecuteSQL", nullptr);
    5891             : 
    5892             :     OGRLayerH hLayer =
    5893       21088 :         OGRLayer::ToHandle(GDALDataset::FromHandle(hDS)->ExecuteSQL(
    5894       10544 :             pszStatement, OGRGeometry::FromHandle(hSpatialFilter), pszDialect));
    5895             : 
    5896             : #ifdef OGRAPISPY_ENABLED
    5897       10544 :     if (bOGRAPISpyEnabled)
    5898           4 :         OGRAPISpy_DS_ExecuteSQL(hDS, pszStatement, hSpatialFilter, pszDialect,
    5899             :                                 hLayer);
    5900             : #endif
    5901             : 
    5902       10544 :     return hLayer;
    5903             : }
    5904             : 
    5905             : /************************************************************************/
    5906             : /*                        GDALDatasetAbortSQL()                         */
    5907             : /************************************************************************/
    5908             : 
    5909             : /**
    5910             :  \brief Abort any SQL statement running in the data store.
    5911             : 
    5912             :  This function can be safely called from any thread (pending that the dataset
    5913             :  object is still alive). Driver implementations will make sure that it can be
    5914             :  called in a thread-safe way.
    5915             : 
    5916             :  This might not be implemented by all drivers. At time of writing, only SQLite,
    5917             :  GPKG and PG drivers implement it
    5918             : 
    5919             :  This method is the same as the C++ method GDALDataset::AbortSQL()
    5920             : 
    5921             :  @since GDAL 3.2.0
    5922             : 
    5923             :  @param hDS the dataset handle.
    5924             : 
    5925             :  @return OGRERR_NONE on success, or OGRERR_UNSUPPORTED_OPERATION if AbortSQL
    5926             :  is not supported for this datasource. .
    5927             : 
    5928             : */
    5929             : 
    5930           6 : OGRErr GDALDatasetAbortSQL(GDALDatasetH hDS)
    5931             : 
    5932             : {
    5933           6 :     VALIDATE_POINTER1(hDS, "GDALDatasetAbortSQL", OGRERR_FAILURE);
    5934           6 :     return GDALDataset::FromHandle(hDS)->AbortSQL();
    5935             : }
    5936             : 
    5937             : /************************************************************************/
    5938             : /*                      GDALDatasetGetStyleTable()                      */
    5939             : /************************************************************************/
    5940             : 
    5941             : /**
    5942             :  \brief Returns dataset style table.
    5943             : 
    5944             :  This function is the same as the C++ method GDALDataset::GetStyleTable()
    5945             : 
    5946             : 
    5947             :  @param hDS the dataset handle
    5948             :  @return handle to a style table which should not be modified or freed by the
    5949             :  caller.
    5950             : */
    5951             : 
    5952           6 : OGRStyleTableH GDALDatasetGetStyleTable(GDALDatasetH hDS)
    5953             : 
    5954             : {
    5955           6 :     VALIDATE_POINTER1(hDS, "OGR_DS_GetStyleTable", nullptr);
    5956             : 
    5957             :     return reinterpret_cast<OGRStyleTableH>(
    5958           6 :         GDALDataset::FromHandle(hDS)->GetStyleTable());
    5959             : }
    5960             : 
    5961             : /************************************************************************/
    5962             : /*                    GDALDatasetSetStyleTableDirectly()                */
    5963             : /************************************************************************/
    5964             : 
    5965             : /**
    5966             :  \brief Set dataset style table.
    5967             : 
    5968             :  This function operate exactly as GDALDatasetSetStyleTable() except that it
    5969             :  assumes ownership of the passed table.
    5970             : 
    5971             :  This function is the same as the C++ method
    5972             :  GDALDataset::SetStyleTableDirectly()
    5973             : 
    5974             : 
    5975             :  @param hDS the dataset handle
    5976             :  @param hStyleTable style table handle to set
    5977             : 
    5978             : */
    5979             : 
    5980           0 : void GDALDatasetSetStyleTableDirectly(GDALDatasetH hDS,
    5981             :                                       OGRStyleTableH hStyleTable)
    5982             : 
    5983             : {
    5984           0 :     VALIDATE_POINTER0(hDS, "OGR_DS_SetStyleTableDirectly");
    5985             : 
    5986           0 :     GDALDataset::FromHandle(hDS)->SetStyleTableDirectly(
    5987           0 :         reinterpret_cast<OGRStyleTable *>(hStyleTable));
    5988             : }
    5989             : 
    5990             : /************************************************************************/
    5991             : /*                     GDALDatasetSetStyleTable()                       */
    5992             : /************************************************************************/
    5993             : 
    5994             : /**
    5995             :  \brief Set dataset style table.
    5996             : 
    5997             :  This function operate exactly as GDALDatasetSetStyleTableDirectly() except that
    5998             :  it assumes ownership of the passed table.
    5999             : 
    6000             :  This function is the same as the C++ method GDALDataset::SetStyleTable()
    6001             : 
    6002             : 
    6003             :  @param hDS the dataset handle
    6004             :  @param hStyleTable style table handle to set
    6005             : 
    6006             : */
    6007             : 
    6008           5 : void GDALDatasetSetStyleTable(GDALDatasetH hDS, OGRStyleTableH hStyleTable)
    6009             : 
    6010             : {
    6011           5 :     VALIDATE_POINTER0(hDS, "OGR_DS_SetStyleTable");
    6012           5 :     VALIDATE_POINTER0(hStyleTable, "OGR_DS_SetStyleTable");
    6013             : 
    6014           5 :     GDALDataset::FromHandle(hDS)->SetStyleTable(
    6015           5 :         reinterpret_cast<OGRStyleTable *>(hStyleTable));
    6016             : }
    6017             : 
    6018             : /************************************************************************/
    6019             : /*                    ValidateLayerCreationOptions()                    */
    6020             : /************************************************************************/
    6021             : 
    6022             : //! @cond Doxygen_Suppress
    6023        9624 : int GDALDataset::ValidateLayerCreationOptions(const char *const *papszLCO)
    6024             : {
    6025             :     const char *pszOptionList =
    6026        9624 :         GetMetadataItem(GDAL_DS_LAYER_CREATIONOPTIONLIST);
    6027        9624 :     if (pszOptionList == nullptr && poDriver != nullptr)
    6028             :     {
    6029             :         pszOptionList =
    6030        9583 :             poDriver->GetMetadataItem(GDAL_DS_LAYER_CREATIONOPTIONLIST);
    6031             :     }
    6032       19248 :     CPLString osDataset;
    6033        9624 :     osDataset.Printf("dataset %s", GetDescription());
    6034        9624 :     return GDALValidateOptions(pszOptionList, papszLCO, "layer creation option",
    6035       19248 :                                osDataset);
    6036             : }
    6037             : 
    6038             : //! @endcond
    6039             : 
    6040             : /************************************************************************/
    6041             : /*                              Release()                               */
    6042             : /************************************************************************/
    6043             : 
    6044             : /**
    6045             : \brief Drop a reference to this dataset, and if the reference count drops to one
    6046             : close (destroy) the dataset.
    6047             : 
    6048             : This method is the same as the C function OGRReleaseDataSource().
    6049             : 
    6050             : @deprecated. Use GDALClose() instead
    6051             : 
    6052             : @return OGRERR_NONE on success or an error code.
    6053             : */
    6054             : 
    6055        4333 : OGRErr GDALDataset::Release()
    6056             : 
    6057             : {
    6058        4333 :     ReleaseRef();
    6059        4333 :     return OGRERR_NONE;
    6060             : }
    6061             : 
    6062             : /************************************************************************/
    6063             : /*                            GetRefCount()                             */
    6064             : /************************************************************************/
    6065             : 
    6066             : /**
    6067             : \brief Fetch reference count.
    6068             : 
    6069             : This method is the same as the C function OGR_DS_GetRefCount().
    6070             : 
    6071             : @return the current reference count for the datasource object itself.
    6072             : */
    6073             : 
    6074        5104 : int GDALDataset::GetRefCount() const
    6075             : {
    6076        5104 :     return nRefCount;
    6077             : }
    6078             : 
    6079             : /************************************************************************/
    6080             : /*                         GetSummaryRefCount()                         */
    6081             : /************************************************************************/
    6082             : 
    6083             : /**
    6084             : \brief Fetch reference count of datasource and all owned layers.
    6085             : 
    6086             : This method is the same as the C function  OGR_DS_GetSummaryRefCount().
    6087             : 
    6088             : @deprecated
    6089             : 
    6090             : @return the current summary reference count for the datasource and its layers.
    6091             : */
    6092             : 
    6093           0 : int GDALDataset::GetSummaryRefCount() const
    6094             : 
    6095             : {
    6096           0 :     CPLMutexHolderD(m_poPrivate ? &(m_poPrivate->hMutex) : nullptr);
    6097           0 :     int nSummaryCount = nRefCount;
    6098           0 :     GDALDataset *poUseThis = const_cast<GDALDataset *>(this);
    6099             : 
    6100           0 :     for (int iLayer = 0; iLayer < poUseThis->GetLayerCount(); ++iLayer)
    6101           0 :         nSummaryCount += poUseThis->GetLayer(iLayer)->GetRefCount();
    6102             : 
    6103           0 :     return nSummaryCount;
    6104             : }
    6105             : 
    6106             : /************************************************************************/
    6107             : /*                           ICreateLayer()                             */
    6108             : /************************************************************************/
    6109             : 
    6110             : /**
    6111             :  \brief This method attempts to create a new layer on the dataset with the
    6112             :  indicated name, coordinate system, geometry type.
    6113             : 
    6114             :  This method is reserved to implementation by drivers.
    6115             : 
    6116             :  The papszOptions argument can be used to control driver specific creation
    6117             :  options.  These options are normally documented in the format specific
    6118             :  documentation.
    6119             : 
    6120             :  @param pszName the name for the new layer.  This should ideally not
    6121             :  match any existing layer on the datasource.
    6122             :  @param poGeomFieldDefn the geometry field definition to use for the new layer,
    6123             :  or NULL if there is no geometry field.
    6124             :  @param papszOptions a StringList of name=value options.  Options are driver
    6125             :  specific.
    6126             : 
    6127             :  @return NULL is returned on failure, or a new OGRLayer handle on success.
    6128             : 
    6129             : */
    6130             : 
    6131             : OGRLayer *
    6132          16 : GDALDataset::ICreateLayer(CPL_UNUSED const char *pszName,
    6133             :                           CPL_UNUSED const OGRGeomFieldDefn *poGeomFieldDefn,
    6134             :                           CPL_UNUSED CSLConstList papszOptions)
    6135             : 
    6136             : {
    6137          16 :     CPLError(CE_Failure, CPLE_NotSupported,
    6138             :              "CreateLayer() not supported by this dataset.");
    6139             : 
    6140          16 :     return nullptr;
    6141             : }
    6142             : 
    6143             : /************************************************************************/
    6144             : /*                             CopyLayer()                              */
    6145             : /************************************************************************/
    6146             : 
    6147             : /**
    6148             :  \brief Duplicate an existing layer.
    6149             : 
    6150             :  This method creates a new layer, duplicate the field definitions of the
    6151             :  source layer and then duplicate each features of the source layer.
    6152             :  The papszOptions argument
    6153             :  can be used to control driver specific creation options.  These options are
    6154             :  normally documented in the format specific documentation.
    6155             :  The source layer may come from another dataset.
    6156             : 
    6157             :  This method is the same as the C function GDALDatasetCopyLayer() and the
    6158             :  deprecated OGR_DS_CopyLayer().
    6159             : 
    6160             :  @param poSrcLayer source layer.
    6161             :  @param pszNewName the name of the layer to create.
    6162             :  @param papszOptions a StringList of name=value options.  Options are driver
    6163             :                      specific. There is a common option to set output layer
    6164             :                      spatial reference: DST_SRSWKT. The option should be in
    6165             :                      WKT format. Starting with GDAL 3.7, the common option
    6166             :                      COPY_MD can be set to NO to prevent the default copying
    6167             :                      of the metadata from the source layer to the target layer.
    6168             : 
    6169             :  @return a handle to the layer, or NULL if an error occurs.
    6170             : */
    6171             : 
    6172         136 : OGRLayer *GDALDataset::CopyLayer(OGRLayer *poSrcLayer, const char *pszNewName,
    6173             :                                  char **papszOptions)
    6174             : 
    6175             : {
    6176             :     /* -------------------------------------------------------------------- */
    6177             :     /*      Create the layer.                                               */
    6178             :     /* -------------------------------------------------------------------- */
    6179         136 :     if (!TestCapability(ODsCCreateLayer))
    6180             :     {
    6181           0 :         CPLError(CE_Failure, CPLE_NotSupported,
    6182             :                  "This datasource does not support creation of layers.");
    6183           0 :         return nullptr;
    6184             :     }
    6185             : 
    6186         136 :     const char *pszSRSWKT = CSLFetchNameValue(papszOptions, "DST_SRSWKT");
    6187         272 :     OGRSpatialReference oDstSpaRef(pszSRSWKT);
    6188         136 :     oDstSpaRef.SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
    6189         136 :     OGRFeatureDefn *poSrcDefn = poSrcLayer->GetLayerDefn();
    6190         136 :     OGRLayer *poDstLayer = nullptr;
    6191             : 
    6192         272 :     CPLStringList aosCleanedUpOptions(CSLDuplicate(papszOptions));
    6193         136 :     aosCleanedUpOptions.SetNameValue("DST_SRSWKT", nullptr);
    6194         136 :     aosCleanedUpOptions.SetNameValue("COPY_MD", nullptr);
    6195             : 
    6196         136 :     CPLErrorReset();
    6197         136 :     const int nSrcGeomFieldCount = poSrcDefn->GetGeomFieldCount();
    6198         136 :     if (nSrcGeomFieldCount == 1)
    6199             :     {
    6200          84 :         OGRGeomFieldDefn oGeomFieldDefn(poSrcDefn->GetGeomFieldDefn(0));
    6201          84 :         if (pszSRSWKT)
    6202           5 :             oGeomFieldDefn.SetSpatialRef(&oDstSpaRef);
    6203          84 :         poDstLayer = ICreateLayer(pszNewName, &oGeomFieldDefn,
    6204          84 :                                   aosCleanedUpOptions.List());
    6205             :     }
    6206             :     else
    6207             :     {
    6208             :         poDstLayer =
    6209          52 :             ICreateLayer(pszNewName, nullptr, aosCleanedUpOptions.List());
    6210             :     }
    6211             : 
    6212         136 :     if (poDstLayer == nullptr)
    6213           0 :         return nullptr;
    6214             : 
    6215         136 :     if (CPLTestBool(CSLFetchNameValueDef(papszOptions, "COPY_MD", "YES")))
    6216             :     {
    6217         135 :         char **papszMD = poSrcLayer->GetMetadata();
    6218         135 :         if (papszMD)
    6219           9 :             poDstLayer->SetMetadata(papszMD);
    6220             :     }
    6221             : 
    6222             :     /* -------------------------------------------------------------------- */
    6223             :     /*      Add fields.  Default to copy all fields, and make sure to       */
    6224             :     /*      establish a mapping between indices, rather than names, in      */
    6225             :     /*      case the target datasource has altered it (e.g. Shapefile       */
    6226             :     /*      limited to 10 char field names).                                */
    6227             :     /* -------------------------------------------------------------------- */
    6228         136 :     const int nSrcFieldCount = poSrcDefn->GetFieldCount();
    6229             : 
    6230             :     // Initialize the index-to-index map to -1's.
    6231         272 :     std::vector<int> anMap(nSrcFieldCount, -1);
    6232             : 
    6233             :     // Caution: At the time of writing, the MapInfo driver
    6234             :     // returns NULL until a field has been added.
    6235         136 :     OGRFeatureDefn *poDstFDefn = poDstLayer->GetLayerDefn();
    6236         136 :     int nDstFieldCount = poDstFDefn ? poDstFDefn->GetFieldCount() : 0;
    6237         293 :     for (int iField = 0; iField < nSrcFieldCount; ++iField)
    6238             :     {
    6239         157 :         OGRFieldDefn *poSrcFieldDefn = poSrcDefn->GetFieldDefn(iField);
    6240         314 :         OGRFieldDefn oFieldDefn(poSrcFieldDefn);
    6241             : 
    6242             :         // The field may have been already created at layer creation.
    6243         157 :         int iDstField = -1;
    6244         157 :         if (poDstFDefn)
    6245         157 :             iDstField = poDstFDefn->GetFieldIndex(oFieldDefn.GetNameRef());
    6246         157 :         if (iDstField >= 0)
    6247             :         {
    6248           0 :             anMap[iField] = iDstField;
    6249             :         }
    6250         157 :         else if (poDstLayer->CreateField(&oFieldDefn) == OGRERR_NONE)
    6251             :         {
    6252             :             // Now that we've created a field, GetLayerDefn() won't return NULL.
    6253         157 :             if (poDstFDefn == nullptr)
    6254           0 :                 poDstFDefn = poDstLayer->GetLayerDefn();
    6255             : 
    6256             :             // Sanity check: if it fails, the driver is buggy.
    6257         314 :             if (poDstFDefn != nullptr &&
    6258         157 :                 poDstFDefn->GetFieldCount() != nDstFieldCount + 1)
    6259             :             {
    6260           0 :                 CPLError(CE_Warning, CPLE_AppDefined,
    6261             :                          "The output driver has claimed to have added the %s "
    6262             :                          "field, but it did not!",
    6263             :                          oFieldDefn.GetNameRef());
    6264             :             }
    6265             :             else
    6266             :             {
    6267         157 :                 anMap[iField] = nDstFieldCount;
    6268         157 :                 ++nDstFieldCount;
    6269             :             }
    6270             :         }
    6271             :     }
    6272             : 
    6273             :     /* -------------------------------------------------------------------- */
    6274         136 :     std::unique_ptr<OGRCoordinateTransformation> poCT;
    6275         136 :     const OGRSpatialReference *sourceSRS = poSrcLayer->GetSpatialRef();
    6276         136 :     if (sourceSRS != nullptr && pszSRSWKT != nullptr && !oDstSpaRef.IsEmpty() &&
    6277           0 :         sourceSRS->IsSame(&oDstSpaRef) == FALSE)
    6278             :     {
    6279           0 :         poCT.reset(OGRCreateCoordinateTransformation(sourceSRS, &oDstSpaRef));
    6280           0 :         if (nullptr == poCT)
    6281             :         {
    6282           0 :             CPLError(CE_Failure, CPLE_NotSupported,
    6283             :                      "This input/output spatial reference is not supported.");
    6284           0 :             return nullptr;
    6285             :         }
    6286             :     }
    6287             :     /* -------------------------------------------------------------------- */
    6288             :     /*      Create geometry fields.                                         */
    6289             :     /* -------------------------------------------------------------------- */
    6290         137 :     if (nSrcGeomFieldCount > 1 &&
    6291           1 :         TestCapability(ODsCCreateGeomFieldAfterCreateLayer))
    6292             :     {
    6293             : 
    6294           3 :         for (int iField = 0; iField < nSrcGeomFieldCount; ++iField)
    6295             :         {
    6296           2 :             if (nullptr == pszSRSWKT)
    6297             :             {
    6298           2 :                 poDstLayer->CreateGeomField(
    6299           2 :                     poSrcDefn->GetGeomFieldDefn(iField));
    6300             :             }
    6301             :             else
    6302             :             {
    6303             :                 OGRGeomFieldDefn *pDstGeomFieldDefn =
    6304           0 :                     poSrcDefn->GetGeomFieldDefn(iField);
    6305           0 :                 pDstGeomFieldDefn->SetSpatialRef(&oDstSpaRef);
    6306           0 :                 poDstLayer->CreateGeomField(pDstGeomFieldDefn);
    6307             :             }
    6308             :         }
    6309             :     }
    6310             : 
    6311             :     /* -------------------------------------------------------------------- */
    6312             :     /*      Check if the destination layer supports transactions and set a  */
    6313             :     /*      default number of features in a single transaction.             */
    6314             :     /* -------------------------------------------------------------------- */
    6315             :     const int nGroupTransactions =
    6316         136 :         poDstLayer->TestCapability(OLCTransactions) ? 128 : 0;
    6317             : 
    6318             :     /* -------------------------------------------------------------------- */
    6319             :     /*      Transfer features.                                              */
    6320             :     /* -------------------------------------------------------------------- */
    6321         136 :     poSrcLayer->ResetReading();
    6322             : 
    6323         136 :     if (nGroupTransactions <= 0)
    6324             :     {
    6325             :         while (true)
    6326             :         {
    6327             :             auto poFeature =
    6328         468 :                 std::unique_ptr<OGRFeature>(poSrcLayer->GetNextFeature());
    6329             : 
    6330         468 :             if (poFeature == nullptr)
    6331         133 :                 break;
    6332             : 
    6333         335 :             CPLErrorReset();
    6334             :             auto poDstFeature =
    6335         335 :                 std::make_unique<OGRFeature>(poDstLayer->GetLayerDefn());
    6336             : 
    6337         335 :             if (poDstFeature->SetFrom(poFeature.get(), anMap.data(), TRUE) !=
    6338             :                 OGRERR_NONE)
    6339             :             {
    6340           0 :                 CPLError(CE_Failure, CPLE_AppDefined,
    6341             :                          "Unable to translate feature " CPL_FRMT_GIB
    6342             :                          " from layer %s.",
    6343           0 :                          poFeature->GetFID(), poSrcDefn->GetName());
    6344           0 :                 return poDstLayer;
    6345             :             }
    6346             : 
    6347         335 :             if (nullptr != poCT)
    6348             :             {
    6349           0 :                 for (int iField = 0; iField < nSrcGeomFieldCount; ++iField)
    6350             :                 {
    6351           0 :                     OGRGeometry *pGeom = poDstFeature->GetGeomFieldRef(iField);
    6352           0 :                     if (nullptr == pGeom)
    6353           0 :                         continue;
    6354             : 
    6355           0 :                     const OGRErr eErr = pGeom->transform(poCT.get());
    6356           0 :                     if (eErr == OGRERR_NONE)
    6357           0 :                         continue;
    6358             : 
    6359           0 :                     CPLError(CE_Failure, CPLE_AppDefined,
    6360             :                              "Unable to transform geometry " CPL_FRMT_GIB
    6361             :                              " from layer %s.",
    6362           0 :                              poFeature->GetFID(), poSrcDefn->GetName());
    6363           0 :                     return poDstLayer;
    6364             :                 }
    6365             :             }
    6366             : 
    6367         335 :             poDstFeature->SetFID(poFeature->GetFID());
    6368             : 
    6369         335 :             CPLErrorReset();
    6370         335 :             if (poDstLayer->CreateFeature(poDstFeature.get()) != OGRERR_NONE)
    6371             :             {
    6372           0 :                 return poDstLayer;
    6373             :             }
    6374         335 :         }
    6375             :     }
    6376             :     else
    6377             :     {
    6378           3 :         std::vector<std::unique_ptr<OGRFeature>> apoDstFeatures;
    6379             :         try
    6380             :         {
    6381           3 :             apoDstFeatures.resize(nGroupTransactions);
    6382             :         }
    6383           0 :         catch (const std::exception &e)
    6384             :         {
    6385           0 :             CPLError(CE_Failure, CPLE_OutOfMemory, "%s", e.what());
    6386           0 :             return poDstLayer;
    6387             :         }
    6388           3 :         bool bStopTransfer = false;
    6389           6 :         while (!bStopTransfer)
    6390             :         {
    6391             :             /* --------------------------------------------------------------------
    6392             :              */
    6393             :             /*      Fill the array with features. */
    6394             :             /* --------------------------------------------------------------------
    6395             :              */
    6396             :             // Number of features in the temporary array.
    6397           3 :             int nFeatCount = 0;  // Used after for.
    6398          33 :             for (nFeatCount = 0; nFeatCount < nGroupTransactions; ++nFeatCount)
    6399             :             {
    6400             :                 auto poFeature =
    6401          33 :                     std::unique_ptr<OGRFeature>(poSrcLayer->GetNextFeature());
    6402             : 
    6403          33 :                 if (poFeature == nullptr)
    6404             :                 {
    6405           3 :                     bStopTransfer = true;
    6406           3 :                     break;
    6407             :                 }
    6408             : 
    6409          30 :                 CPLErrorReset();
    6410          30 :                 apoDstFeatures[nFeatCount] =
    6411          60 :                     std::make_unique<OGRFeature>(poDstLayer->GetLayerDefn());
    6412             : 
    6413          60 :                 if (apoDstFeatures[nFeatCount]->SetFrom(
    6414          60 :                         poFeature.get(), anMap.data(), TRUE) != OGRERR_NONE)
    6415             :                 {
    6416           0 :                     CPLError(CE_Failure, CPLE_AppDefined,
    6417             :                              "Unable to translate feature " CPL_FRMT_GIB
    6418             :                              " from layer %s.",
    6419           0 :                              poFeature->GetFID(), poSrcDefn->GetName());
    6420           0 :                     bStopTransfer = true;
    6421           0 :                     poFeature.reset();
    6422           0 :                     break;
    6423             :                 }
    6424             : 
    6425          30 :                 if (nullptr != poCT)
    6426             :                 {
    6427           0 :                     for (int iField = 0; iField < nSrcGeomFieldCount; ++iField)
    6428             :                     {
    6429             :                         OGRGeometry *pGeom =
    6430           0 :                             apoDstFeatures[nFeatCount]->GetGeomFieldRef(iField);
    6431           0 :                         if (nullptr == pGeom)
    6432           0 :                             continue;
    6433             : 
    6434           0 :                         const OGRErr eErr = pGeom->transform(poCT.get());
    6435           0 :                         if (eErr == OGRERR_NONE)
    6436           0 :                             continue;
    6437             : 
    6438           0 :                         CPLError(CE_Failure, CPLE_AppDefined,
    6439             :                                  "Unable to transform geometry " CPL_FRMT_GIB
    6440             :                                  " from layer %s.",
    6441           0 :                                  poFeature->GetFID(), poSrcDefn->GetName());
    6442           0 :                         bStopTransfer = true;
    6443           0 :                         poFeature.reset();
    6444           0 :                         break;
    6445             :                     }
    6446             :                 }
    6447             : 
    6448          30 :                 if (poFeature)
    6449             :                 {
    6450          30 :                     apoDstFeatures[nFeatCount]->SetFID(poFeature->GetFID());
    6451             :                 }
    6452             :             }
    6453             : 
    6454           3 :             CPLErrorReset();
    6455           3 :             bool bStopTransaction = false;
    6456           6 :             while (!bStopTransaction)
    6457             :             {
    6458           3 :                 bStopTransaction = true;
    6459           3 :                 if (poDstLayer->StartTransaction() != OGRERR_NONE)
    6460           0 :                     break;
    6461          33 :                 for (int i = 0; i < nFeatCount; ++i)
    6462             :                 {
    6463          30 :                     if (poDstLayer->CreateFeature(apoDstFeatures[i].get()) !=
    6464             :                         OGRERR_NONE)
    6465             :                     {
    6466           0 :                         bStopTransfer = true;
    6467           0 :                         bStopTransaction = false;
    6468           0 :                         break;
    6469             :                     }
    6470          30 :                     apoDstFeatures[i].reset();
    6471             :                 }
    6472           3 :                 if (bStopTransaction)
    6473             :                 {
    6474           3 :                     if (poDstLayer->CommitTransaction() != OGRERR_NONE)
    6475           0 :                         break;
    6476             :                 }
    6477             :                 else
    6478             :                 {
    6479           0 :                     poDstLayer->RollbackTransaction();
    6480             :                 }
    6481             :             }
    6482             :         }
    6483             :     }
    6484             : 
    6485         136 :     return poDstLayer;
    6486             : }
    6487             : 
    6488             : /************************************************************************/
    6489             : /*                            DeleteLayer()                             */
    6490             : /************************************************************************/
    6491             : 
    6492             : /**
    6493             :  \fn GDALDataset::DeleteLayer(int)
    6494             :  \brief Delete the indicated layer from the datasource.
    6495             : 
    6496             :  If this method is supported
    6497             :  the ODsCDeleteLayer capability will test TRUE on the GDALDataset.
    6498             : 
    6499             :  This method is the same as the C function GDALDatasetDeleteLayer() and the
    6500             :  deprecated OGR_DS_DeleteLayer().
    6501             : 
    6502             :  @param iLayer the index of the layer to delete.
    6503             : 
    6504             :  @return OGRERR_NONE on success, or OGRERR_UNSUPPORTED_OPERATION if deleting
    6505             :  layers is not supported for this datasource.
    6506             : 
    6507             : */
    6508             : 
    6509         389 : OGRErr GDALDataset::DeleteLayer(CPL_UNUSED int iLayer)
    6510             : 
    6511             : {
    6512         389 :     CPLError(CE_Failure, CPLE_NotSupported,
    6513             :              "DeleteLayer() not supported by this dataset.");
    6514             : 
    6515         389 :     return OGRERR_UNSUPPORTED_OPERATION;
    6516             : }
    6517             : 
    6518             : /************************************************************************/
    6519             : /*                           GetLayerByName()                           */
    6520             : /************************************************************************/
    6521             : 
    6522             : /**
    6523             :  \brief Fetch a layer by name.
    6524             : 
    6525             :  The returned layer remains owned by the
    6526             :  GDALDataset and should not be deleted by the application.
    6527             : 
    6528             :  This method is the same as the C function GDALDatasetGetLayerByName() and the
    6529             :  deprecated OGR_DS_GetLayerByName().
    6530             : 
    6531             :  @param pszName the layer name of the layer to fetch.
    6532             : 
    6533             :  @return the layer, or NULL if Layer is not found or an error occurs.
    6534             : */
    6535             : 
    6536       30001 : OGRLayer *GDALDataset::GetLayerByName(const char *pszName)
    6537             : 
    6538             : {
    6539       60002 :     CPLMutexHolderD(m_poPrivate ? &(m_poPrivate->hMutex) : nullptr);
    6540             : 
    6541       30001 :     if (!pszName)
    6542           0 :         return nullptr;
    6543             : 
    6544             :     // First a case sensitive check.
    6545      932538 :     for (int i = 0; i < GetLayerCount(); ++i)
    6546             :     {
    6547      914349 :         OGRLayer *poLayer = GetLayer(i);
    6548             : 
    6549      914349 :         if (strcmp(pszName, poLayer->GetName()) == 0)
    6550       11812 :             return poLayer;
    6551             :     }
    6552             : 
    6553             :     // Then case insensitive.
    6554      893794 :     for (int i = 0; i < GetLayerCount(); ++i)
    6555             :     {
    6556      875829 :         OGRLayer *poLayer = GetLayer(i);
    6557             : 
    6558      875829 :         if (EQUAL(pszName, poLayer->GetName()))
    6559         224 :             return poLayer;
    6560             :     }
    6561             : 
    6562       17965 :     return nullptr;
    6563             : }
    6564             : 
    6565             : //! @cond Doxygen_Suppress
    6566             : /************************************************************************/
    6567             : /*                       ProcessSQLCreateIndex()                        */
    6568             : /*                                                                      */
    6569             : /*      The correct syntax for creating an index in our dialect of      */
    6570             : /*      SQL is:                                                         */
    6571             : /*                                                                      */
    6572             : /*        CREATE INDEX ON <layername> USING <columnname>                */
    6573             : /************************************************************************/
    6574             : 
    6575          28 : OGRErr GDALDataset::ProcessSQLCreateIndex(const char *pszSQLCommand)
    6576             : 
    6577             : {
    6578          28 :     char **papszTokens = CSLTokenizeString(pszSQLCommand);
    6579             : 
    6580             :     /* -------------------------------------------------------------------- */
    6581             :     /*      Do some general syntax checking.                                */
    6582             :     /* -------------------------------------------------------------------- */
    6583          56 :     if (CSLCount(papszTokens) != 6 || !EQUAL(papszTokens[0], "CREATE") ||
    6584          84 :         !EQUAL(papszTokens[1], "INDEX") || !EQUAL(papszTokens[2], "ON") ||
    6585          28 :         !EQUAL(papszTokens[4], "USING"))
    6586             :     {
    6587           0 :         CSLDestroy(papszTokens);
    6588           0 :         CPLError(CE_Failure, CPLE_AppDefined,
    6589             :                  "Syntax error in CREATE INDEX command.\n"
    6590             :                  "Was '%s'\n"
    6591             :                  "Should be of form 'CREATE INDEX ON <table> USING <field>'",
    6592             :                  pszSQLCommand);
    6593           0 :         return OGRERR_FAILURE;
    6594             :     }
    6595             : 
    6596             :     /* -------------------------------------------------------------------- */
    6597             :     /*      Find the named layer.                                           */
    6598             :     /* -------------------------------------------------------------------- */
    6599          28 :     OGRLayer *poLayer = GetLayerByName(papszTokens[3]);
    6600          28 :     if (poLayer == nullptr)
    6601             :     {
    6602           0 :         CPLError(CE_Failure, CPLE_AppDefined,
    6603             :                  "CREATE INDEX ON failed, no such layer as `%s'.",
    6604           0 :                  papszTokens[3]);
    6605           0 :         CSLDestroy(papszTokens);
    6606           0 :         return OGRERR_FAILURE;
    6607             :     }
    6608             : 
    6609             :     /* -------------------------------------------------------------------- */
    6610             :     /*      Does this layer even support attribute indexes?                 */
    6611             :     /* -------------------------------------------------------------------- */
    6612          28 :     if (poLayer->GetIndex() == nullptr)
    6613             :     {
    6614           0 :         CPLError(CE_Failure, CPLE_AppDefined,
    6615             :                  "CREATE INDEX ON not supported by this driver.");
    6616           0 :         CSLDestroy(papszTokens);
    6617           0 :         return OGRERR_FAILURE;
    6618             :     }
    6619             : 
    6620             :     /* -------------------------------------------------------------------- */
    6621             :     /*      Find the named field.                                           */
    6622             :     /* -------------------------------------------------------------------- */
    6623          28 :     int i = poLayer->GetLayerDefn()->GetFieldIndex(papszTokens[5]);
    6624             : 
    6625          28 :     CSLDestroy(papszTokens);
    6626             : 
    6627          28 :     if (i >= poLayer->GetLayerDefn()->GetFieldCount())
    6628             :     {
    6629           0 :         CPLError(CE_Failure, CPLE_AppDefined, "`%s' failed, field not found.",
    6630             :                  pszSQLCommand);
    6631           0 :         return OGRERR_FAILURE;
    6632             :     }
    6633             : 
    6634             :     /* -------------------------------------------------------------------- */
    6635             :     /*      Attempt to create the index.                                    */
    6636             :     /* -------------------------------------------------------------------- */
    6637          28 :     OGRErr eErr = poLayer->GetIndex()->CreateIndex(i);
    6638          28 :     if (eErr == OGRERR_NONE)
    6639             :     {
    6640          28 :         eErr = poLayer->GetIndex()->IndexAllFeatures(i);
    6641             :     }
    6642             :     else
    6643             :     {
    6644           0 :         if (strlen(CPLGetLastErrorMsg()) == 0)
    6645           0 :             CPLError(CE_Failure, CPLE_AppDefined, "Cannot '%s'", pszSQLCommand);
    6646             :     }
    6647             : 
    6648          28 :     return eErr;
    6649             : }
    6650             : 
    6651             : /************************************************************************/
    6652             : /*                        ProcessSQLDropIndex()                         */
    6653             : /*                                                                      */
    6654             : /*      The correct syntax for dropping one or more indexes in          */
    6655             : /*      the OGR SQL dialect is:                                         */
    6656             : /*                                                                      */
    6657             : /*          DROP INDEX ON <layername> [USING <columnname>]              */
    6658             : /************************************************************************/
    6659             : 
    6660          10 : OGRErr GDALDataset::ProcessSQLDropIndex(const char *pszSQLCommand)
    6661             : 
    6662             : {
    6663          10 :     char **papszTokens = CSLTokenizeString(pszSQLCommand);
    6664             : 
    6665             :     /* -------------------------------------------------------------------- */
    6666             :     /*      Do some general syntax checking.                                */
    6667             :     /* -------------------------------------------------------------------- */
    6668          20 :     if ((CSLCount(papszTokens) != 4 && CSLCount(papszTokens) != 6) ||
    6669          10 :         !EQUAL(papszTokens[0], "DROP") || !EQUAL(papszTokens[1], "INDEX") ||
    6670          30 :         !EQUAL(papszTokens[2], "ON") ||
    6671          10 :         (CSLCount(papszTokens) == 6 && !EQUAL(papszTokens[4], "USING")))
    6672             :     {
    6673           0 :         CSLDestroy(papszTokens);
    6674           0 :         CPLError(CE_Failure, CPLE_AppDefined,
    6675             :                  "Syntax error in DROP INDEX command.\n"
    6676             :                  "Was '%s'\n"
    6677             :                  "Should be of form 'DROP INDEX ON <table> [USING <field>]'",
    6678             :                  pszSQLCommand);
    6679           0 :         return OGRERR_FAILURE;
    6680             :     }
    6681             : 
    6682             :     /* -------------------------------------------------------------------- */
    6683             :     /*      Find the named layer.                                           */
    6684             :     /* -------------------------------------------------------------------- */
    6685          10 :     OGRLayer *poLayer = GetLayerByName(papszTokens[3]);
    6686          10 :     if (poLayer == nullptr)
    6687             :     {
    6688           0 :         CPLError(CE_Failure, CPLE_AppDefined,
    6689             :                  "DROP INDEX ON failed, no such layer as `%s'.",
    6690           0 :                  papszTokens[3]);
    6691           0 :         CSLDestroy(papszTokens);
    6692           0 :         return OGRERR_FAILURE;
    6693             :     }
    6694             : 
    6695             :     /* -------------------------------------------------------------------- */
    6696             :     /*      Does this layer even support attribute indexes?                 */
    6697             :     /* -------------------------------------------------------------------- */
    6698          10 :     if (poLayer->GetIndex() == nullptr)
    6699             :     {
    6700           0 :         CPLError(CE_Failure, CPLE_AppDefined,
    6701             :                  "Indexes not supported by this driver.");
    6702           0 :         CSLDestroy(papszTokens);
    6703           0 :         return OGRERR_FAILURE;
    6704             :     }
    6705             : 
    6706             :     /* -------------------------------------------------------------------- */
    6707             :     /*      If we were not given a field name, drop all indexes.            */
    6708             :     /* -------------------------------------------------------------------- */
    6709          10 :     if (CSLCount(papszTokens) == 4)
    6710             :     {
    6711           0 :         for (int i = 0; i < poLayer->GetLayerDefn()->GetFieldCount(); ++i)
    6712             :         {
    6713             :             OGRAttrIndex *poAttrIndex;
    6714             : 
    6715           0 :             poAttrIndex = poLayer->GetIndex()->GetFieldIndex(i);
    6716           0 :             if (poAttrIndex != nullptr)
    6717             :             {
    6718           0 :                 const OGRErr eErr = poLayer->GetIndex()->DropIndex(i);
    6719           0 :                 if (eErr != OGRERR_NONE)
    6720             :                 {
    6721           0 :                     CSLDestroy(papszTokens);
    6722           0 :                     return eErr;
    6723             :                 }
    6724             :             }
    6725             :         }
    6726             : 
    6727           0 :         CSLDestroy(papszTokens);
    6728           0 :         return OGRERR_NONE;
    6729             :     }
    6730             : 
    6731             :     /* -------------------------------------------------------------------- */
    6732             :     /*      Find the named field.                                           */
    6733             :     /* -------------------------------------------------------------------- */
    6734          10 :     int i = poLayer->GetLayerDefn()->GetFieldIndex(papszTokens[5]);
    6735          10 :     CSLDestroy(papszTokens);
    6736             : 
    6737          10 :     if (i >= poLayer->GetLayerDefn()->GetFieldCount())
    6738             :     {
    6739           0 :         CPLError(CE_Failure, CPLE_AppDefined, "`%s' failed, field not found.",
    6740             :                  pszSQLCommand);
    6741           0 :         return OGRERR_FAILURE;
    6742             :     }
    6743             : 
    6744             :     /* -------------------------------------------------------------------- */
    6745             :     /*      Attempt to drop the index.                                      */
    6746             :     /* -------------------------------------------------------------------- */
    6747          10 :     const OGRErr eErr = poLayer->GetIndex()->DropIndex(i);
    6748             : 
    6749          10 :     return eErr;
    6750             : }
    6751             : 
    6752             : /************************************************************************/
    6753             : /*                        ProcessSQLDropTable()                         */
    6754             : /*                                                                      */
    6755             : /*      The correct syntax for dropping a table (layer) in the OGR SQL  */
    6756             : /*      dialect is:                                                     */
    6757             : /*                                                                      */
    6758             : /*          DROP TABLE <layername>                                      */
    6759             : /************************************************************************/
    6760             : 
    6761         500 : OGRErr GDALDataset::ProcessSQLDropTable(const char *pszSQLCommand)
    6762             : 
    6763             : {
    6764         500 :     char **papszTokens = CSLTokenizeString(pszSQLCommand);
    6765             : 
    6766             :     /* -------------------------------------------------------------------- */
    6767             :     /*      Do some general syntax checking.                                */
    6768             :     /* -------------------------------------------------------------------- */
    6769        1000 :     if (CSLCount(papszTokens) != 3 || !EQUAL(papszTokens[0], "DROP") ||
    6770         500 :         !EQUAL(papszTokens[1], "TABLE"))
    6771             :     {
    6772           0 :         CSLDestroy(papszTokens);
    6773           0 :         CPLError(CE_Failure, CPLE_AppDefined,
    6774             :                  "Syntax error in DROP TABLE command.\n"
    6775             :                  "Was '%s'\n"
    6776             :                  "Should be of form 'DROP TABLE <table>'",
    6777             :                  pszSQLCommand);
    6778           0 :         return OGRERR_FAILURE;
    6779             :     }
    6780             : 
    6781             :     /* -------------------------------------------------------------------- */
    6782             :     /*      Find the named layer.                                           */
    6783             :     /* -------------------------------------------------------------------- */
    6784         500 :     OGRLayer *poLayer = nullptr;
    6785             : 
    6786         500 :     int i = 0;  // Used after for.
    6787       40199 :     for (; i < GetLayerCount(); ++i)
    6788             :     {
    6789       40199 :         poLayer = GetLayer(i);
    6790             : 
    6791       40199 :         if (poLayer != nullptr && EQUAL(poLayer->GetName(), papszTokens[2]))
    6792         500 :             break;
    6793       39699 :         poLayer = nullptr;
    6794             :     }
    6795             : 
    6796         500 :     if (poLayer == nullptr)
    6797             :     {
    6798           0 :         CPLError(CE_Failure, CPLE_AppDefined,
    6799           0 :                  "DROP TABLE failed, no such layer as `%s'.", papszTokens[2]);
    6800           0 :         CSLDestroy(papszTokens);
    6801           0 :         return OGRERR_FAILURE;
    6802             :     }
    6803             : 
    6804         500 :     CSLDestroy(papszTokens);
    6805             : 
    6806             :     /* -------------------------------------------------------------------- */
    6807             :     /*      Delete it.                                                      */
    6808             :     /* -------------------------------------------------------------------- */
    6809             : 
    6810         500 :     return DeleteLayer(i);
    6811             : }
    6812             : 
    6813             : //! @endcond
    6814             : 
    6815             : /************************************************************************/
    6816             : /*                    GDALDatasetParseSQLType()                       */
    6817             : /************************************************************************/
    6818             : 
    6819             : /* All arguments will be altered */
    6820           6 : static OGRFieldType GDALDatasetParseSQLType(char *pszType, int &nWidth,
    6821             :                                             int &nPrecision)
    6822             : {
    6823           6 :     char *pszParenthesis = strchr(pszType, '(');
    6824           6 :     if (pszParenthesis)
    6825             :     {
    6826           4 :         nWidth = atoi(pszParenthesis + 1);
    6827           4 :         *pszParenthesis = '\0';
    6828           4 :         char *pszComma = strchr(pszParenthesis + 1, ',');
    6829           4 :         if (pszComma)
    6830           2 :             nPrecision = atoi(pszComma + 1);
    6831             :     }
    6832             : 
    6833           6 :     OGRFieldType eType = OFTString;
    6834           6 :     if (EQUAL(pszType, "INTEGER"))
    6835           0 :         eType = OFTInteger;
    6836           6 :     else if (EQUAL(pszType, "INTEGER[]"))
    6837           0 :         eType = OFTIntegerList;
    6838           6 :     else if (EQUAL(pszType, "FLOAT") || EQUAL(pszType, "NUMERIC") ||
    6839           4 :              EQUAL(pszType, "DOUBLE") /* unofficial alias */ ||
    6840           4 :              EQUAL(pszType, "REAL") /* unofficial alias */)
    6841           2 :         eType = OFTReal;
    6842           4 :     else if (EQUAL(pszType, "FLOAT[]") || EQUAL(pszType, "NUMERIC[]") ||
    6843           4 :              EQUAL(pszType, "DOUBLE[]") /* unofficial alias */ ||
    6844           4 :              EQUAL(pszType, "REAL[]") /* unofficial alias */)
    6845           0 :         eType = OFTRealList;
    6846           4 :     else if (EQUAL(pszType, "CHARACTER") ||
    6847           0 :              EQUAL(pszType, "TEXT") /* unofficial alias */ ||
    6848           0 :              EQUAL(pszType, "STRING") /* unofficial alias */ ||
    6849           0 :              EQUAL(pszType, "VARCHAR") /* unofficial alias */)
    6850           4 :         eType = OFTString;
    6851           0 :     else if (EQUAL(pszType, "TEXT[]") ||
    6852           0 :              EQUAL(pszType, "STRING[]") /* unofficial alias */ ||
    6853           0 :              EQUAL(pszType, "VARCHAR[]") /* unofficial alias */)
    6854           0 :         eType = OFTStringList;
    6855           0 :     else if (EQUAL(pszType, "DATE"))
    6856           0 :         eType = OFTDate;
    6857           0 :     else if (EQUAL(pszType, "TIME"))
    6858           0 :         eType = OFTTime;
    6859           0 :     else if (EQUAL(pszType, "TIMESTAMP") ||
    6860           0 :              EQUAL(pszType, "DATETIME") /* unofficial alias */)
    6861           0 :         eType = OFTDateTime;
    6862             :     else
    6863           0 :         CPLError(CE_Warning, CPLE_NotSupported,
    6864             :                  "Unsupported column type '%s'. Defaulting to VARCHAR",
    6865             :                  pszType);
    6866             : 
    6867           6 :     return eType;
    6868             : }
    6869             : 
    6870             : /************************************************************************/
    6871             : /*                    ProcessSQLAlterTableAddColumn()                   */
    6872             : /*                                                                      */
    6873             : /*      The correct syntax for adding a column in the OGR SQL           */
    6874             : /*      dialect is:                                                     */
    6875             : /*                                                                      */
    6876             : /*       ALTER TABLE <layername> ADD [COLUMN] <columnname> <columntype> */
    6877             : /************************************************************************/
    6878             : 
    6879             : //! @cond Doxygen_Suppress
    6880           2 : OGRErr GDALDataset::ProcessSQLAlterTableAddColumn(const char *pszSQLCommand)
    6881             : 
    6882             : {
    6883           2 :     char **papszTokens = CSLTokenizeString(pszSQLCommand);
    6884             : 
    6885             :     /* -------------------------------------------------------------------- */
    6886             :     /*      Do some general syntax checking.                                */
    6887             :     /* -------------------------------------------------------------------- */
    6888           2 :     const char *pszLayerName = nullptr;
    6889           2 :     const char *pszColumnName = nullptr;
    6890           2 :     int iTypeIndex = 0;
    6891           2 :     const int nTokens = CSLCount(papszTokens);
    6892             : 
    6893           2 :     if (nTokens >= 7 && EQUAL(papszTokens[0], "ALTER") &&
    6894           2 :         EQUAL(papszTokens[1], "TABLE") && EQUAL(papszTokens[3], "ADD") &&
    6895           2 :         EQUAL(papszTokens[4], "COLUMN"))
    6896             :     {
    6897           1 :         pszLayerName = papszTokens[2];
    6898           1 :         pszColumnName = papszTokens[5];
    6899           1 :         iTypeIndex = 6;
    6900             :     }
    6901           1 :     else if (nTokens >= 6 && EQUAL(papszTokens[0], "ALTER") &&
    6902           1 :              EQUAL(papszTokens[1], "TABLE") && EQUAL(papszTokens[3], "ADD"))
    6903             :     {
    6904           1 :         pszLayerName = papszTokens[2];
    6905           1 :         pszColumnName = papszTokens[4];
    6906           1 :         iTypeIndex = 5;
    6907             :     }
    6908             :     else
    6909             :     {
    6910           0 :         CSLDestroy(papszTokens);
    6911           0 :         CPLError(CE_Failure, CPLE_AppDefined,
    6912             :                  "Syntax error in ALTER TABLE ADD COLUMN command.\n"
    6913             :                  "Was '%s'\n"
    6914             :                  "Should be of form 'ALTER TABLE <layername> ADD [COLUMN] "
    6915             :                  "<columnname> <columntype>'",
    6916             :                  pszSQLCommand);
    6917           0 :         return OGRERR_FAILURE;
    6918             :     }
    6919             : 
    6920             :     /* -------------------------------------------------------------------- */
    6921             :     /*      Merge type components into a single string if there were split  */
    6922             :     /*      with spaces                                                     */
    6923             :     /* -------------------------------------------------------------------- */
    6924           4 :     CPLString osType;
    6925           6 :     for (int i = iTypeIndex; i < nTokens; ++i)
    6926             :     {
    6927           4 :         osType += papszTokens[i];
    6928           4 :         CPLFree(papszTokens[i]);
    6929             :     }
    6930           2 :     char *pszType = papszTokens[iTypeIndex] = CPLStrdup(osType);
    6931           2 :     papszTokens[iTypeIndex + 1] = nullptr;
    6932             : 
    6933             :     /* -------------------------------------------------------------------- */
    6934             :     /*      Find the named layer.                                           */
    6935             :     /* -------------------------------------------------------------------- */
    6936           2 :     OGRLayer *poLayer = GetLayerByName(pszLayerName);
    6937           2 :     if (poLayer == nullptr)
    6938             :     {
    6939           0 :         CPLError(CE_Failure, CPLE_AppDefined,
    6940             :                  "%s failed, no such layer as `%s'.", pszSQLCommand,
    6941             :                  pszLayerName);
    6942           0 :         CSLDestroy(papszTokens);
    6943           0 :         return OGRERR_FAILURE;
    6944             :     }
    6945             : 
    6946             :     /* -------------------------------------------------------------------- */
    6947             :     /*      Add column.                                                     */
    6948             :     /* -------------------------------------------------------------------- */
    6949             : 
    6950           2 :     int nWidth = 0;
    6951           2 :     int nPrecision = 0;
    6952           2 :     OGRFieldType eType = GDALDatasetParseSQLType(pszType, nWidth, nPrecision);
    6953           4 :     OGRFieldDefn oFieldDefn(pszColumnName, eType);
    6954           2 :     oFieldDefn.SetWidth(nWidth);
    6955           2 :     oFieldDefn.SetPrecision(nPrecision);
    6956             : 
    6957           2 :     CSLDestroy(papszTokens);
    6958             : 
    6959           2 :     return poLayer->CreateField(&oFieldDefn);
    6960             : }
    6961             : 
    6962             : /************************************************************************/
    6963             : /*                    ProcessSQLAlterTableDropColumn()                  */
    6964             : /*                                                                      */
    6965             : /*      The correct syntax for dropping a column in the OGR SQL         */
    6966             : /*      dialect is:                                                     */
    6967             : /*                                                                      */
    6968             : /*          ALTER TABLE <layername> DROP [COLUMN] <columnname>          */
    6969             : /************************************************************************/
    6970             : 
    6971           2 : OGRErr GDALDataset::ProcessSQLAlterTableDropColumn(const char *pszSQLCommand)
    6972             : 
    6973             : {
    6974           2 :     char **papszTokens = CSLTokenizeString(pszSQLCommand);
    6975             : 
    6976             :     /* -------------------------------------------------------------------- */
    6977             :     /*      Do some general syntax checking.                                */
    6978             :     /* -------------------------------------------------------------------- */
    6979           2 :     const char *pszLayerName = nullptr;
    6980           2 :     const char *pszColumnName = nullptr;
    6981           3 :     if (CSLCount(papszTokens) == 6 && EQUAL(papszTokens[0], "ALTER") &&
    6982           4 :         EQUAL(papszTokens[1], "TABLE") && EQUAL(papszTokens[3], "DROP") &&
    6983           1 :         EQUAL(papszTokens[4], "COLUMN"))
    6984             :     {
    6985           1 :         pszLayerName = papszTokens[2];
    6986           1 :         pszColumnName = papszTokens[5];
    6987             :     }
    6988           2 :     else if (CSLCount(papszTokens) == 5 && EQUAL(papszTokens[0], "ALTER") &&
    6989           2 :              EQUAL(papszTokens[1], "TABLE") && EQUAL(papszTokens[3], "DROP"))
    6990             :     {
    6991           1 :         pszLayerName = papszTokens[2];
    6992           1 :         pszColumnName = papszTokens[4];
    6993             :     }
    6994             :     else
    6995             :     {
    6996           0 :         CSLDestroy(papszTokens);
    6997           0 :         CPLError(CE_Failure, CPLE_AppDefined,
    6998             :                  "Syntax error in ALTER TABLE DROP COLUMN command.\n"
    6999             :                  "Was '%s'\n"
    7000             :                  "Should be of form 'ALTER TABLE <layername> DROP [COLUMN] "
    7001             :                  "<columnname>'",
    7002             :                  pszSQLCommand);
    7003           0 :         return OGRERR_FAILURE;
    7004             :     }
    7005             : 
    7006             :     /* -------------------------------------------------------------------- */
    7007             :     /*      Find the named layer.                                           */
    7008             :     /* -------------------------------------------------------------------- */
    7009           2 :     OGRLayer *poLayer = GetLayerByName(pszLayerName);
    7010           2 :     if (poLayer == nullptr)
    7011             :     {
    7012           0 :         CPLError(CE_Failure, CPLE_AppDefined,
    7013             :                  "%s failed, no such layer as `%s'.", pszSQLCommand,
    7014             :                  pszLayerName);
    7015           0 :         CSLDestroy(papszTokens);
    7016           0 :         return OGRERR_FAILURE;
    7017             :     }
    7018             : 
    7019             :     /* -------------------------------------------------------------------- */
    7020             :     /*      Find the field.                                                 */
    7021             :     /* -------------------------------------------------------------------- */
    7022             : 
    7023           2 :     int nFieldIndex = poLayer->GetLayerDefn()->GetFieldIndex(pszColumnName);
    7024           2 :     if (nFieldIndex < 0)
    7025             :     {
    7026           0 :         CPLError(CE_Failure, CPLE_AppDefined,
    7027             :                  "%s failed, no such field as `%s'.", pszSQLCommand,
    7028             :                  pszColumnName);
    7029           0 :         CSLDestroy(papszTokens);
    7030           0 :         return OGRERR_FAILURE;
    7031             :     }
    7032             : 
    7033             :     /* -------------------------------------------------------------------- */
    7034             :     /*      Remove it.                                                      */
    7035             :     /* -------------------------------------------------------------------- */
    7036             : 
    7037           2 :     CSLDestroy(papszTokens);
    7038             : 
    7039           2 :     return poLayer->DeleteField(nFieldIndex);
    7040             : }
    7041             : 
    7042             : /************************************************************************/
    7043             : /*                 ProcessSQLAlterTableRenameColumn()                   */
    7044             : /*                                                                      */
    7045             : /*      The correct syntax for renaming a column in the OGR SQL         */
    7046             : /*      dialect is:                                                     */
    7047             : /*                                                                      */
    7048             : /*       ALTER TABLE <layername> RENAME [COLUMN] <oldname> TO <newname> */
    7049             : /************************************************************************/
    7050             : 
    7051           2 : OGRErr GDALDataset::ProcessSQLAlterTableRenameColumn(const char *pszSQLCommand)
    7052             : 
    7053             : {
    7054           2 :     char **papszTokens = CSLTokenizeString(pszSQLCommand);
    7055             : 
    7056             :     /* -------------------------------------------------------------------- */
    7057             :     /*      Do some general syntax checking.                                */
    7058             :     /* -------------------------------------------------------------------- */
    7059           2 :     const char *pszLayerName = nullptr;
    7060           2 :     const char *pszOldColName = nullptr;
    7061           2 :     const char *pszNewColName = nullptr;
    7062           3 :     if (CSLCount(papszTokens) == 8 && EQUAL(papszTokens[0], "ALTER") &&
    7063           1 :         EQUAL(papszTokens[1], "TABLE") && EQUAL(papszTokens[3], "RENAME") &&
    7064           3 :         EQUAL(papszTokens[4], "COLUMN") && EQUAL(papszTokens[6], "TO"))
    7065             :     {
    7066           1 :         pszLayerName = papszTokens[2];
    7067           1 :         pszOldColName = papszTokens[5];
    7068           1 :         pszNewColName = papszTokens[7];
    7069             :     }
    7070           2 :     else if (CSLCount(papszTokens) == 7 && EQUAL(papszTokens[0], "ALTER") &&
    7071           1 :              EQUAL(papszTokens[1], "TABLE") &&
    7072           2 :              EQUAL(papszTokens[3], "RENAME") && EQUAL(papszTokens[5], "TO"))
    7073             :     {
    7074           1 :         pszLayerName = papszTokens[2];
    7075           1 :         pszOldColName = papszTokens[4];
    7076           1 :         pszNewColName = papszTokens[6];
    7077             :     }
    7078             :     else
    7079             :     {
    7080           0 :         CSLDestroy(papszTokens);
    7081           0 :         CPLError(CE_Failure, CPLE_AppDefined,
    7082             :                  "Syntax error in ALTER TABLE RENAME COLUMN command.\n"
    7083             :                  "Was '%s'\n"
    7084             :                  "Should be of form 'ALTER TABLE <layername> RENAME [COLUMN] "
    7085             :                  "<columnname> TO <newname>'",
    7086             :                  pszSQLCommand);
    7087           0 :         return OGRERR_FAILURE;
    7088             :     }
    7089             : 
    7090             :     /* -------------------------------------------------------------------- */
    7091             :     /*      Find the named layer.                                           */
    7092             :     /* -------------------------------------------------------------------- */
    7093           2 :     OGRLayer *poLayer = GetLayerByName(pszLayerName);
    7094           2 :     if (poLayer == nullptr)
    7095             :     {
    7096           0 :         CPLError(CE_Failure, CPLE_AppDefined,
    7097             :                  "%s failed, no such layer as `%s'.", pszSQLCommand,
    7098             :                  pszLayerName);
    7099           0 :         CSLDestroy(papszTokens);
    7100           0 :         return OGRERR_FAILURE;
    7101             :     }
    7102             : 
    7103             :     /* -------------------------------------------------------------------- */
    7104             :     /*      Find the field.                                                 */
    7105             :     /* -------------------------------------------------------------------- */
    7106             : 
    7107             :     const int nFieldIndex =
    7108           2 :         poLayer->GetLayerDefn()->GetFieldIndex(pszOldColName);
    7109           2 :     if (nFieldIndex < 0)
    7110             :     {
    7111           0 :         CPLError(CE_Failure, CPLE_AppDefined,
    7112             :                  "%s failed, no such field as `%s'.", pszSQLCommand,
    7113             :                  pszOldColName);
    7114           0 :         CSLDestroy(papszTokens);
    7115           0 :         return OGRERR_FAILURE;
    7116             :     }
    7117             : 
    7118             :     /* -------------------------------------------------------------------- */
    7119             :     /*      Rename column.                                                  */
    7120             :     /* -------------------------------------------------------------------- */
    7121             :     OGRFieldDefn *poOldFieldDefn =
    7122           2 :         poLayer->GetLayerDefn()->GetFieldDefn(nFieldIndex);
    7123           4 :     OGRFieldDefn oNewFieldDefn(poOldFieldDefn);
    7124           2 :     oNewFieldDefn.SetName(pszNewColName);
    7125             : 
    7126           2 :     CSLDestroy(papszTokens);
    7127             : 
    7128           2 :     return poLayer->AlterFieldDefn(nFieldIndex, &oNewFieldDefn,
    7129           2 :                                    ALTER_NAME_FLAG);
    7130             : }
    7131             : 
    7132             : /************************************************************************/
    7133             : /*                 ProcessSQLAlterTableAlterColumn()                    */
    7134             : /*                                                                      */
    7135             : /*      The correct syntax for altering the type of a column in the     */
    7136             : /*      OGR SQL dialect is:                                             */
    7137             : /*                                                                      */
    7138             : /*   ALTER TABLE <layername> ALTER [COLUMN] <columnname> TYPE <newtype> */
    7139             : /************************************************************************/
    7140             : 
    7141           4 : OGRErr GDALDataset::ProcessSQLAlterTableAlterColumn(const char *pszSQLCommand)
    7142             : 
    7143             : {
    7144           4 :     char **papszTokens = CSLTokenizeString(pszSQLCommand);
    7145             : 
    7146             :     /* -------------------------------------------------------------------- */
    7147             :     /*      Do some general syntax checking.                                */
    7148             :     /* -------------------------------------------------------------------- */
    7149           4 :     const char *pszLayerName = nullptr;
    7150           4 :     const char *pszColumnName = nullptr;
    7151           4 :     int iTypeIndex = 0;
    7152           4 :     const int nTokens = CSLCount(papszTokens);
    7153             : 
    7154           4 :     if (nTokens >= 8 && EQUAL(papszTokens[0], "ALTER") &&
    7155           2 :         EQUAL(papszTokens[1], "TABLE") && EQUAL(papszTokens[3], "ALTER") &&
    7156           2 :         EQUAL(papszTokens[4], "COLUMN") && EQUAL(papszTokens[6], "TYPE"))
    7157             :     {
    7158           2 :         pszLayerName = papszTokens[2];
    7159           2 :         pszColumnName = papszTokens[5];
    7160           2 :         iTypeIndex = 7;
    7161             :     }
    7162           2 :     else if (nTokens >= 7 && EQUAL(papszTokens[0], "ALTER") &&
    7163           2 :              EQUAL(papszTokens[1], "TABLE") && EQUAL(papszTokens[3], "ALTER") &&
    7164           2 :              EQUAL(papszTokens[5], "TYPE"))
    7165             :     {
    7166           2 :         pszLayerName = papszTokens[2];
    7167           2 :         pszColumnName = papszTokens[4];
    7168           2 :         iTypeIndex = 6;
    7169             :     }
    7170             :     else
    7171             :     {
    7172           0 :         CSLDestroy(papszTokens);
    7173           0 :         CPLError(CE_Failure, CPLE_AppDefined,
    7174             :                  "Syntax error in ALTER TABLE ALTER COLUMN command.\n"
    7175             :                  "Was '%s'\n"
    7176             :                  "Should be of form 'ALTER TABLE <layername> ALTER [COLUMN] "
    7177             :                  "<columnname> TYPE <columntype>'",
    7178             :                  pszSQLCommand);
    7179           0 :         return OGRERR_FAILURE;
    7180             :     }
    7181             : 
    7182             :     /* -------------------------------------------------------------------- */
    7183             :     /*      Merge type components into a single string if there were split  */
    7184             :     /*      with spaces                                                     */
    7185             :     /* -------------------------------------------------------------------- */
    7186           8 :     CPLString osType;
    7187           8 :     for (int i = iTypeIndex; i < nTokens; ++i)
    7188             :     {
    7189           4 :         osType += papszTokens[i];
    7190           4 :         CPLFree(papszTokens[i]);
    7191             :     }
    7192           4 :     char *pszType = papszTokens[iTypeIndex] = CPLStrdup(osType);
    7193           4 :     papszTokens[iTypeIndex + 1] = nullptr;
    7194             : 
    7195             :     /* -------------------------------------------------------------------- */
    7196             :     /*      Find the named layer.                                           */
    7197             :     /* -------------------------------------------------------------------- */
    7198           4 :     OGRLayer *poLayer = GetLayerByName(pszLayerName);
    7199           4 :     if (poLayer == nullptr)
    7200             :     {
    7201           0 :         CPLError(CE_Failure, CPLE_AppDefined,
    7202             :                  "%s failed, no such layer as `%s'.", pszSQLCommand,
    7203             :                  pszLayerName);
    7204           0 :         CSLDestroy(papszTokens);
    7205           0 :         return OGRERR_FAILURE;
    7206             :     }
    7207             : 
    7208             :     /* -------------------------------------------------------------------- */
    7209             :     /*      Find the field.                                                 */
    7210             :     /* -------------------------------------------------------------------- */
    7211             : 
    7212             :     const int nFieldIndex =
    7213           4 :         poLayer->GetLayerDefn()->GetFieldIndex(pszColumnName);
    7214           4 :     if (nFieldIndex < 0)
    7215             :     {
    7216           0 :         CPLError(CE_Failure, CPLE_AppDefined,
    7217             :                  "%s failed, no such field as `%s'.", pszSQLCommand,
    7218             :                  pszColumnName);
    7219           0 :         CSLDestroy(papszTokens);
    7220           0 :         return OGRERR_FAILURE;
    7221             :     }
    7222             : 
    7223             :     /* -------------------------------------------------------------------- */
    7224             :     /*      Alter column.                                                   */
    7225             :     /* -------------------------------------------------------------------- */
    7226             : 
    7227             :     OGRFieldDefn *poOldFieldDefn =
    7228           4 :         poLayer->GetLayerDefn()->GetFieldDefn(nFieldIndex);
    7229           8 :     OGRFieldDefn oNewFieldDefn(poOldFieldDefn);
    7230             : 
    7231           4 :     int nWidth = 0;
    7232           4 :     int nPrecision = 0;
    7233           4 :     OGRFieldType eType = GDALDatasetParseSQLType(pszType, nWidth, nPrecision);
    7234           4 :     oNewFieldDefn.SetType(eType);
    7235           4 :     oNewFieldDefn.SetWidth(nWidth);
    7236           4 :     oNewFieldDefn.SetPrecision(nPrecision);
    7237             : 
    7238           4 :     int l_nFlags = 0;
    7239           4 :     if (poOldFieldDefn->GetType() != oNewFieldDefn.GetType())
    7240           2 :         l_nFlags |= ALTER_TYPE_FLAG;
    7241           4 :     if (poOldFieldDefn->GetWidth() != oNewFieldDefn.GetWidth() ||
    7242           0 :         poOldFieldDefn->GetPrecision() != oNewFieldDefn.GetPrecision())
    7243           4 :         l_nFlags |= ALTER_WIDTH_PRECISION_FLAG;
    7244             : 
    7245           4 :     CSLDestroy(papszTokens);
    7246             : 
    7247           4 :     if (l_nFlags == 0)
    7248           0 :         return OGRERR_NONE;
    7249             : 
    7250           4 :     return poLayer->AlterFieldDefn(nFieldIndex, &oNewFieldDefn, l_nFlags);
    7251             : }
    7252             : 
    7253             : //! @endcond
    7254             : 
    7255             : /************************************************************************/
    7256             : /*                             ExecuteSQL()                             */
    7257             : /************************************************************************/
    7258             : 
    7259             : /**
    7260             :  \brief Execute an SQL statement against the data store.
    7261             : 
    7262             :  The result of an SQL query is either NULL for statements that are in error,
    7263             :  or that have no results set, or an OGRLayer pointer representing a results
    7264             :  set from the query.  Note that this OGRLayer is in addition to the layers
    7265             :  in the data store and must be destroyed with
    7266             :  ReleaseResultSet() before the dataset is closed
    7267             :  (destroyed).
    7268             : 
    7269             :  This method is the same as the C function GDALDatasetExecuteSQL() and the
    7270             :  deprecated OGR_DS_ExecuteSQL().
    7271             : 
    7272             :  For more information on the SQL dialect supported internally by OGR
    7273             :  review the <a href="https://gdal.org/user/ogr_sql_dialect.html">OGR SQL</a>
    7274             :  document.  Some drivers (i.e. Oracle and PostGIS) pass the SQL directly through
    7275             :  to the underlying RDBMS.
    7276             : 
    7277             :  Starting with OGR 1.10, the <a
    7278             :  href="https://gdal.org/user/sql_sqlite_dialect.html">SQLITE dialect</a> can
    7279             :  also be used.
    7280             : 
    7281             :  @param pszStatement the SQL statement to execute.
    7282             :  @param poSpatialFilter geometry which represents a spatial filter. Can be NULL.
    7283             :  @param pszDialect allows control of the statement dialect. If set to NULL, the
    7284             :  OGR SQL engine will be used, except for RDBMS drivers that will use their
    7285             :  dedicated SQL engine, unless OGRSQL is explicitly passed as the
    7286             :  dialect. Starting with OGR 1.10, the SQLITE dialect can also be used.
    7287             : 
    7288             :  @return an OGRLayer containing the results of the query.  Deallocate with
    7289             :  ReleaseResultSet().
    7290             : 
    7291             : */
    7292             : 
    7293        3575 : OGRLayer *GDALDataset::ExecuteSQL(const char *pszStatement,
    7294             :                                   OGRGeometry *poSpatialFilter,
    7295             :                                   const char *pszDialect)
    7296             : 
    7297             : {
    7298        3575 :     return ExecuteSQL(pszStatement, poSpatialFilter, pszDialect, nullptr);
    7299             : }
    7300             : 
    7301             : //! @cond Doxygen_Suppress
    7302             : OGRLayer *
    7303        3583 : GDALDataset::ExecuteSQL(const char *pszStatement, OGRGeometry *poSpatialFilter,
    7304             :                         const char *pszDialect,
    7305             :                         swq_select_parse_options *poSelectParseOptions)
    7306             : 
    7307             : {
    7308        3583 :     if (pszDialect != nullptr && EQUAL(pszDialect, "SQLite"))
    7309             :     {
    7310             : #ifdef SQLITE_ENABLED
    7311         650 :         return OGRSQLiteExecuteSQL(this, pszStatement, poSpatialFilter,
    7312         650 :                                    pszDialect);
    7313             : #else
    7314             :         CPLError(CE_Failure, CPLE_NotSupported,
    7315             :                  "The SQLite driver needs to be compiled to support the "
    7316             :                  "SQLite SQL dialect");
    7317             :         return nullptr;
    7318             : #endif
    7319             :     }
    7320             : 
    7321        2933 :     if (pszDialect != nullptr && !EQUAL(pszDialect, "") &&
    7322          14 :         !EQUAL(pszDialect, "OGRSQL"))
    7323             :     {
    7324           6 :         std::string osDialectList = "'OGRSQL'";
    7325             : #ifdef SQLITE_ENABLED
    7326           3 :         osDialectList += ", 'SQLITE'";
    7327             : #endif
    7328             :         const char *pszDialects =
    7329           3 :             GetMetadataItem(GDAL_DMD_SUPPORTED_SQL_DIALECTS);
    7330           3 :         if (pszDialects)
    7331             :         {
    7332             :             const CPLStringList aosTokens(
    7333           0 :                 CSLTokenizeString2(pszDialects, " ", 0));
    7334           0 :             for (int i = 0; i < aosTokens.size(); ++i)
    7335             :             {
    7336           0 :                 if (!EQUAL(aosTokens[i], "OGRSQL") &&
    7337           0 :                     !EQUAL(aosTokens[i], "SQLITE"))
    7338             :                 {
    7339           0 :                     osDialectList += ", '";
    7340           0 :                     osDialectList += aosTokens[i];
    7341           0 :                     osDialectList += "'";
    7342             :                 }
    7343             :             }
    7344             :         }
    7345           3 :         CPLError(CE_Warning, CPLE_NotSupported,
    7346             :                  "Dialect '%s' is unsupported. Only supported dialects are %s. "
    7347             :                  "Defaulting to OGRSQL",
    7348             :                  pszDialect, osDialectList.c_str());
    7349             :     }
    7350             : 
    7351             :     /* -------------------------------------------------------------------- */
    7352             :     /*      Handle CREATE INDEX statements specially.                       */
    7353             :     /* -------------------------------------------------------------------- */
    7354        2933 :     if (STARTS_WITH_CI(pszStatement, "CREATE INDEX"))
    7355             :     {
    7356          28 :         ProcessSQLCreateIndex(pszStatement);
    7357          28 :         return nullptr;
    7358             :     }
    7359             : 
    7360             :     /* -------------------------------------------------------------------- */
    7361             :     /*      Handle DROP INDEX statements specially.                         */
    7362             :     /* -------------------------------------------------------------------- */
    7363        2905 :     if (STARTS_WITH_CI(pszStatement, "DROP INDEX"))
    7364             :     {
    7365          10 :         ProcessSQLDropIndex(pszStatement);
    7366          10 :         return nullptr;
    7367             :     }
    7368             : 
    7369             :     /* -------------------------------------------------------------------- */
    7370             :     /*      Handle DROP TABLE statements specially.                         */
    7371             :     /* -------------------------------------------------------------------- */
    7372        2895 :     if (STARTS_WITH_CI(pszStatement, "DROP TABLE"))
    7373             :     {
    7374         500 :         ProcessSQLDropTable(pszStatement);
    7375         500 :         return nullptr;
    7376             :     }
    7377             : 
    7378             :     /* -------------------------------------------------------------------- */
    7379             :     /*      Handle ALTER TABLE statements specially.                        */
    7380             :     /* -------------------------------------------------------------------- */
    7381        2395 :     if (STARTS_WITH_CI(pszStatement, "ALTER TABLE"))
    7382             :     {
    7383          11 :         char **papszTokens = CSLTokenizeString(pszStatement);
    7384          11 :         const int nTokens = CSLCount(papszTokens);
    7385          11 :         if (nTokens >= 4 && EQUAL(papszTokens[3], "ADD"))
    7386             :         {
    7387           2 :             ProcessSQLAlterTableAddColumn(pszStatement);
    7388           2 :             CSLDestroy(papszTokens);
    7389           2 :             return nullptr;
    7390             :         }
    7391           9 :         else if (nTokens >= 4 && EQUAL(papszTokens[3], "DROP"))
    7392             :         {
    7393           2 :             ProcessSQLAlterTableDropColumn(pszStatement);
    7394           2 :             CSLDestroy(papszTokens);
    7395           2 :             return nullptr;
    7396             :         }
    7397           7 :         else if (nTokens == 6 && EQUAL(papszTokens[3], "RENAME") &&
    7398           1 :                  EQUAL(papszTokens[4], "TO"))
    7399             :         {
    7400           1 :             const char *pszSrcTableName = papszTokens[2];
    7401           1 :             const char *pszDstTableName = papszTokens[5];
    7402           1 :             auto poSrcLayer = GetLayerByName(pszSrcTableName);
    7403           1 :             if (poSrcLayer)
    7404             :             {
    7405           1 :                 CPL_IGNORE_RET_VAL(poSrcLayer->Rename(pszDstTableName));
    7406             :             }
    7407             :             else
    7408             :             {
    7409           0 :                 CPLError(CE_Failure, CPLE_AppDefined, "Invalid layer name");
    7410             :             }
    7411           1 :             CSLDestroy(papszTokens);
    7412           1 :             return nullptr;
    7413             :         }
    7414           6 :         else if (nTokens >= 4 && EQUAL(papszTokens[3], "RENAME"))
    7415             :         {
    7416           2 :             ProcessSQLAlterTableRenameColumn(pszStatement);
    7417           2 :             CSLDestroy(papszTokens);
    7418           2 :             return nullptr;
    7419             :         }
    7420           4 :         else if (nTokens >= 4 && EQUAL(papszTokens[3], "ALTER"))
    7421             :         {
    7422           4 :             ProcessSQLAlterTableAlterColumn(pszStatement);
    7423           4 :             CSLDestroy(papszTokens);
    7424           4 :             return nullptr;
    7425             :         }
    7426             :         else
    7427             :         {
    7428           0 :             CPLError(CE_Failure, CPLE_AppDefined,
    7429             :                      "Unsupported ALTER TABLE command : %s", pszStatement);
    7430           0 :             CSLDestroy(papszTokens);
    7431           0 :             return nullptr;
    7432             :         }
    7433             :     }
    7434             : 
    7435             :     /* -------------------------------------------------------------------- */
    7436             :     /*      Preparse the SQL statement.                                     */
    7437             :     /* -------------------------------------------------------------------- */
    7438        2384 :     swq_select *psSelectInfo = new swq_select();
    7439        2384 :     swq_custom_func_registrar *poCustomFuncRegistrar = nullptr;
    7440        2384 :     if (poSelectParseOptions != nullptr)
    7441           8 :         poCustomFuncRegistrar = poSelectParseOptions->poCustomFuncRegistrar;
    7442        2384 :     if (psSelectInfo->preparse(pszStatement,
    7443        2384 :                                poCustomFuncRegistrar != nullptr) != CE_None)
    7444             :     {
    7445         143 :         delete psSelectInfo;
    7446         143 :         return nullptr;
    7447             :     }
    7448             : 
    7449             :     /* -------------------------------------------------------------------- */
    7450             :     /*      If there is no UNION ALL, build result layer.                   */
    7451             :     /* -------------------------------------------------------------------- */
    7452        2241 :     if (psSelectInfo->poOtherSelect == nullptr)
    7453             :     {
    7454        2235 :         return BuildLayerFromSelectInfo(psSelectInfo, poSpatialFilter,
    7455        2235 :                                         pszDialect, poSelectParseOptions);
    7456             :     }
    7457             : 
    7458             :     /* -------------------------------------------------------------------- */
    7459             :     /*      Build result union layer.                                       */
    7460             :     /* -------------------------------------------------------------------- */
    7461           6 :     int nSrcLayers = 0;
    7462           6 :     OGRLayer **papoSrcLayers = nullptr;
    7463             : 
    7464           6 :     do
    7465             :     {
    7466          12 :         swq_select *psNextSelectInfo = psSelectInfo->poOtherSelect;
    7467          12 :         psSelectInfo->poOtherSelect = nullptr;
    7468             : 
    7469          12 :         OGRLayer *poLayer = BuildLayerFromSelectInfo(
    7470             :             psSelectInfo, poSpatialFilter, pszDialect, poSelectParseOptions);
    7471          12 :         if (poLayer == nullptr)
    7472             :         {
    7473             :             // Each source layer owns an independent select info.
    7474           0 :             for (int i = 0; i < nSrcLayers; ++i)
    7475           0 :                 delete papoSrcLayers[i];
    7476           0 :             CPLFree(papoSrcLayers);
    7477             : 
    7478             :             // So we just have to destroy the remaining select info.
    7479           0 :             delete psNextSelectInfo;
    7480             : 
    7481           0 :             return nullptr;
    7482             :         }
    7483             :         else
    7484             :         {
    7485          24 :             papoSrcLayers = static_cast<OGRLayer **>(CPLRealloc(
    7486          12 :                 papoSrcLayers, sizeof(OGRLayer *) * (nSrcLayers + 1)));
    7487          12 :             papoSrcLayers[nSrcLayers] = poLayer;
    7488          12 :             ++nSrcLayers;
    7489             : 
    7490          12 :             psSelectInfo = psNextSelectInfo;
    7491             :         }
    7492          12 :     } while (psSelectInfo != nullptr);
    7493             : 
    7494           6 :     return new OGRUnionLayer("SELECT", nSrcLayers, papoSrcLayers, TRUE);
    7495             : }
    7496             : 
    7497             : //! @endcond
    7498             : 
    7499             : /************************************************************************/
    7500             : /*                             AbortSQL()                             */
    7501             : /************************************************************************/
    7502             : 
    7503             : /**
    7504             :  \brief Abort any SQL statement running in the data store.
    7505             : 
    7506             :  This function can be safely called from any thread (pending that the dataset
    7507             :  object is still alive). Driver implementations will make sure that it can be
    7508             :  called in a thread-safe way.
    7509             : 
    7510             :  This might not be implemented by all drivers. At time of writing, only SQLite,
    7511             :  GPKG and PG drivers implement it
    7512             : 
    7513             :  This method is the same as the C method GDALDatasetAbortSQL()
    7514             : 
    7515             :  @since GDAL 3.2.0
    7516             : 
    7517             : 
    7518             : */
    7519             : 
    7520           0 : OGRErr GDALDataset::AbortSQL()
    7521             : {
    7522           0 :     CPLError(CE_Failure, CPLE_NotSupported,
    7523             :              "AbortSQL is not supported for this driver.");
    7524           0 :     return OGRERR_UNSUPPORTED_OPERATION;
    7525             : }
    7526             : 
    7527             : /************************************************************************/
    7528             : /*                        BuildLayerFromSelectInfo()                    */
    7529             : /************************************************************************/
    7530             : 
    7531             : struct GDALSQLParseInfo
    7532             : {
    7533             :     swq_field_list sFieldList;
    7534             :     int nExtraDSCount;
    7535             :     GDALDataset **papoExtraDS;
    7536             :     char *pszWHERE;
    7537             : };
    7538             : 
    7539        2247 : OGRLayer *GDALDataset::BuildLayerFromSelectInfo(
    7540             :     swq_select *psSelectInfo, OGRGeometry *poSpatialFilter,
    7541             :     const char *pszDialect, swq_select_parse_options *poSelectParseOptions)
    7542             : {
    7543        4494 :     std::unique_ptr<swq_select> psSelectInfoUnique(psSelectInfo);
    7544             : 
    7545        2247 :     std::unique_ptr<OGRGenSQLResultsLayer> poResults;
    7546             :     GDALSQLParseInfo *psParseInfo =
    7547        2247 :         BuildParseInfo(psSelectInfoUnique.get(), poSelectParseOptions);
    7548             : 
    7549        2247 :     if (psParseInfo)
    7550             :     {
    7551        2212 :         const auto nErrorCounter = CPLGetErrorCounter();
    7552        4424 :         poResults = std::make_unique<OGRGenSQLResultsLayer>(
    7553        2212 :             this, std::move(psSelectInfoUnique), poSpatialFilter,
    7554        4424 :             psParseInfo->pszWHERE, pszDialect);
    7555        2289 :         if (CPLGetErrorCounter() > nErrorCounter &&
    7556          77 :             CPLGetLastErrorType() != CE_None)
    7557          77 :             poResults.reset();
    7558             :     }
    7559             : 
    7560        2247 :     DestroyParseInfo(psParseInfo);
    7561             : 
    7562        4494 :     return poResults.release();
    7563             : }
    7564             : 
    7565             : /************************************************************************/
    7566             : /*                             DestroyParseInfo()                       */
    7567             : /************************************************************************/
    7568             : 
    7569             : //! @cond Doxygen_Suppress
    7570        2316 : void GDALDataset::DestroyParseInfo(GDALSQLParseInfo *psParseInfo)
    7571             : {
    7572        2316 :     if (psParseInfo == nullptr)
    7573          35 :         return;
    7574             : 
    7575        2281 :     CPLFree(psParseInfo->sFieldList.names);
    7576        2281 :     CPLFree(psParseInfo->sFieldList.types);
    7577        2281 :     CPLFree(psParseInfo->sFieldList.table_ids);
    7578        2281 :     CPLFree(psParseInfo->sFieldList.ids);
    7579             : 
    7580             :     // Release the datasets we have opened with OGROpenShared()
    7581             :     // It is safe to do that as the 'new OGRGenSQLResultsLayer' itself
    7582             :     // has taken a reference on them, which it will release in its
    7583             :     // destructor.
    7584        2288 :     for (int iEDS = 0; iEDS < psParseInfo->nExtraDSCount; ++iEDS)
    7585           7 :         GDALClose(psParseInfo->papoExtraDS[iEDS]);
    7586             : 
    7587        2281 :     CPLFree(psParseInfo->papoExtraDS);
    7588        2281 :     CPLFree(psParseInfo->pszWHERE);
    7589        2281 :     CPLFree(psParseInfo);
    7590             : }
    7591             : 
    7592             : /************************************************************************/
    7593             : /*                            BuildParseInfo()                          */
    7594             : /************************************************************************/
    7595             : 
    7596             : GDALSQLParseInfo *
    7597        2281 : GDALDataset::BuildParseInfo(swq_select *psSelectInfo,
    7598             :                             swq_select_parse_options *poSelectParseOptions)
    7599             : {
    7600        2281 :     int nFirstLayerFirstSpecialFieldIndex = 0;
    7601             : 
    7602             :     GDALSQLParseInfo *psParseInfo =
    7603        2281 :         static_cast<GDALSQLParseInfo *>(CPLCalloc(1, sizeof(GDALSQLParseInfo)));
    7604             : 
    7605             :     /* -------------------------------------------------------------------- */
    7606             :     /*      Validate that all the source tables are recognized, count       */
    7607             :     /*      fields.                                                         */
    7608             :     /* -------------------------------------------------------------------- */
    7609        2281 :     int nFieldCount = 0;
    7610             : 
    7611        4630 :     for (int iTable = 0; iTable < psSelectInfo->table_count; iTable++)
    7612             :     {
    7613        2352 :         swq_table_def *psTableDef = psSelectInfo->table_defs + iTable;
    7614        2352 :         GDALDataset *poTableDS = this;
    7615             : 
    7616        2352 :         if (psTableDef->data_source != nullptr)
    7617             :         {
    7618           7 :             poTableDS = GDALDataset::FromHandle(
    7619           7 :                 OGROpenShared(psTableDef->data_source, FALSE, nullptr));
    7620           7 :             if (poTableDS == nullptr)
    7621             :             {
    7622           0 :                 if (strlen(CPLGetLastErrorMsg()) == 0)
    7623           0 :                     CPLError(CE_Failure, CPLE_AppDefined,
    7624             :                              "Unable to open secondary datasource "
    7625             :                              "`%s' required by JOIN.",
    7626             :                              psTableDef->data_source);
    7627             : 
    7628           0 :                 DestroyParseInfo(psParseInfo);
    7629           0 :                 return nullptr;
    7630             :             }
    7631             : 
    7632             :             // Keep in an array to release at the end of this function.
    7633          14 :             psParseInfo->papoExtraDS = static_cast<GDALDataset **>(CPLRealloc(
    7634           7 :                 psParseInfo->papoExtraDS,
    7635           7 :                 sizeof(GDALDataset *) * (psParseInfo->nExtraDSCount + 1)));
    7636           7 :             psParseInfo->papoExtraDS[psParseInfo->nExtraDSCount++] = poTableDS;
    7637             :         }
    7638             : 
    7639             :         OGRLayer *poSrcLayer =
    7640        2352 :             poTableDS->GetLayerByName(psTableDef->table_name);
    7641             : 
    7642        2352 :         if (poSrcLayer == nullptr)
    7643             :         {
    7644           3 :             CPLError(CE_Failure, CPLE_AppDefined,
    7645             :                      "SELECT from table %s failed, no such table/featureclass.",
    7646             :                      psTableDef->table_name);
    7647             : 
    7648           3 :             DestroyParseInfo(psParseInfo);
    7649           3 :             return nullptr;
    7650             :         }
    7651             : 
    7652        2349 :         nFieldCount += poSrcLayer->GetLayerDefn()->GetFieldCount();
    7653        2349 :         if (iTable == 0 ||
    7654          34 :             (poSelectParseOptions &&
    7655          34 :              poSelectParseOptions->bAddSecondaryTablesGeometryFields))
    7656        2312 :             nFieldCount += poSrcLayer->GetLayerDefn()->GetGeomFieldCount();
    7657             : 
    7658        2349 :         const char *pszFID = poSrcLayer->GetFIDColumn();
    7659        2960 :         if (pszFID && !EQUAL(pszFID, "") && !EQUAL(pszFID, "FID") &&
    7660         611 :             poSrcLayer->GetLayerDefn()->GetFieldIndex(pszFID) < 0)
    7661         561 :             nFieldCount++;
    7662             :     }
    7663             : 
    7664             :     /* -------------------------------------------------------------------- */
    7665             :     /*      Build the field list for all indicated tables.                  */
    7666             :     /* -------------------------------------------------------------------- */
    7667             : 
    7668        2278 :     psParseInfo->sFieldList.table_count = psSelectInfo->table_count;
    7669        2278 :     psParseInfo->sFieldList.table_defs = psSelectInfo->table_defs;
    7670             : 
    7671        2278 :     psParseInfo->sFieldList.count = 0;
    7672        2278 :     psParseInfo->sFieldList.names = static_cast<char **>(
    7673        2278 :         CPLMalloc(sizeof(char *) * (nFieldCount + SPECIAL_FIELD_COUNT)));
    7674        4556 :     psParseInfo->sFieldList.types = static_cast<swq_field_type *>(CPLMalloc(
    7675        2278 :         sizeof(swq_field_type) * (nFieldCount + SPECIAL_FIELD_COUNT)));
    7676        2278 :     psParseInfo->sFieldList.table_ids = static_cast<int *>(
    7677        2278 :         CPLMalloc(sizeof(int) * (nFieldCount + SPECIAL_FIELD_COUNT)));
    7678        2278 :     psParseInfo->sFieldList.ids = static_cast<int *>(
    7679        2278 :         CPLMalloc(sizeof(int) * (nFieldCount + SPECIAL_FIELD_COUNT)));
    7680             : 
    7681        2278 :     bool bIsFID64 = false;
    7682        4627 :     for (int iTable = 0; iTable < psSelectInfo->table_count; iTable++)
    7683             :     {
    7684        2349 :         swq_table_def *psTableDef = psSelectInfo->table_defs + iTable;
    7685        2349 :         GDALDataset *poTableDS = this;
    7686             : 
    7687        2349 :         if (psTableDef->data_source != nullptr)
    7688             :         {
    7689           7 :             poTableDS = GDALDataset::FromHandle(
    7690           7 :                 OGROpenShared(psTableDef->data_source, FALSE, nullptr));
    7691           7 :             CPLAssert(poTableDS != nullptr);
    7692           7 :             poTableDS->Dereference();
    7693             :         }
    7694             : 
    7695             :         OGRLayer *poSrcLayer =
    7696        2349 :             poTableDS->GetLayerByName(psTableDef->table_name);
    7697             : 
    7698        2349 :         for (int iField = 0;
    7699       18567 :              iField < poSrcLayer->GetLayerDefn()->GetFieldCount(); iField++)
    7700             :         {
    7701             :             OGRFieldDefn *poFDefn =
    7702       16218 :                 poSrcLayer->GetLayerDefn()->GetFieldDefn(iField);
    7703       16218 :             const int iOutField = psParseInfo->sFieldList.count++;
    7704       32436 :             psParseInfo->sFieldList.names[iOutField] =
    7705       16218 :                 const_cast<char *>(poFDefn->GetNameRef());
    7706       16218 :             if (poFDefn->GetType() == OFTInteger)
    7707             :             {
    7708        4089 :                 if (poFDefn->GetSubType() == OFSTBoolean)
    7709         160 :                     psParseInfo->sFieldList.types[iOutField] = SWQ_BOOLEAN;
    7710             :                 else
    7711        3929 :                     psParseInfo->sFieldList.types[iOutField] = SWQ_INTEGER;
    7712             :             }
    7713       12129 :             else if (poFDefn->GetType() == OFTInteger64)
    7714             :             {
    7715         759 :                 if (poFDefn->GetSubType() == OFSTBoolean)
    7716           0 :                     psParseInfo->sFieldList.types[iOutField] = SWQ_BOOLEAN;
    7717             :                 else
    7718         759 :                     psParseInfo->sFieldList.types[iOutField] = SWQ_INTEGER64;
    7719             :             }
    7720       11370 :             else if (poFDefn->GetType() == OFTReal)
    7721        2721 :                 psParseInfo->sFieldList.types[iOutField] = SWQ_FLOAT;
    7722        8649 :             else if (poFDefn->GetType() == OFTString)
    7723        5595 :                 psParseInfo->sFieldList.types[iOutField] = SWQ_STRING;
    7724        3054 :             else if (poFDefn->GetType() == OFTTime)
    7725          83 :                 psParseInfo->sFieldList.types[iOutField] = SWQ_TIME;
    7726        2971 :             else if (poFDefn->GetType() == OFTDate)
    7727         143 :                 psParseInfo->sFieldList.types[iOutField] = SWQ_DATE;
    7728        2828 :             else if (poFDefn->GetType() == OFTDateTime)
    7729         939 :                 psParseInfo->sFieldList.types[iOutField] = SWQ_TIMESTAMP;
    7730             :             else
    7731        1889 :                 psParseInfo->sFieldList.types[iOutField] = SWQ_OTHER;
    7732             : 
    7733       16218 :             psParseInfo->sFieldList.table_ids[iOutField] = iTable;
    7734       16218 :             psParseInfo->sFieldList.ids[iOutField] = iField;
    7735             :         }
    7736             : 
    7737        2349 :         if (iTable == 0)
    7738             :         {
    7739        2278 :             nFirstLayerFirstSpecialFieldIndex = psParseInfo->sFieldList.count;
    7740             :         }
    7741             : 
    7742        2349 :         if (iTable == 0 ||
    7743          34 :             (poSelectParseOptions &&
    7744          34 :              poSelectParseOptions->bAddSecondaryTablesGeometryFields))
    7745             :         {
    7746             : 
    7747        2312 :             for (int iField = 0;
    7748        4273 :                  iField < poSrcLayer->GetLayerDefn()->GetGeomFieldCount();
    7749             :                  iField++)
    7750             :             {
    7751             :                 OGRGeomFieldDefn *poFDefn =
    7752        1961 :                     poSrcLayer->GetLayerDefn()->GetGeomFieldDefn(iField);
    7753        1961 :                 const int iOutField = psParseInfo->sFieldList.count++;
    7754        3922 :                 psParseInfo->sFieldList.names[iOutField] =
    7755        1961 :                     const_cast<char *>(poFDefn->GetNameRef());
    7756        1961 :                 if (*psParseInfo->sFieldList.names[iOutField] == '\0')
    7757        1141 :                     psParseInfo->sFieldList.names[iOutField] =
    7758             :                         const_cast<char *>(OGR_GEOMETRY_DEFAULT_NON_EMPTY_NAME);
    7759        1961 :                 psParseInfo->sFieldList.types[iOutField] = SWQ_GEOMETRY;
    7760             : 
    7761        1961 :                 psParseInfo->sFieldList.table_ids[iOutField] = iTable;
    7762        1961 :                 psParseInfo->sFieldList.ids[iOutField] =
    7763        1961 :                     GEOM_FIELD_INDEX_TO_ALL_FIELD_INDEX(
    7764             :                         poSrcLayer->GetLayerDefn(), iField);
    7765             :             }
    7766             :         }
    7767             : 
    7768        2350 :         if (iTable == 0 && poSrcLayer->GetMetadataItem(OLMD_FID64) != nullptr &&
    7769           1 :             EQUAL(poSrcLayer->GetMetadataItem(OLMD_FID64), "YES"))
    7770             :         {
    7771           1 :             bIsFID64 = true;
    7772             :         }
    7773             :     }
    7774             : 
    7775             :     /* -------------------------------------------------------------------- */
    7776             :     /*      Expand '*' in 'SELECT *' now before we add the pseudo fields    */
    7777             :     /* -------------------------------------------------------------------- */
    7778        2278 :     const bool bAlwaysPrefixWithTableName =
    7779        2320 :         poSelectParseOptions &&
    7780          42 :         poSelectParseOptions->bAlwaysPrefixWithTableName;
    7781        2278 :     if (psSelectInfo->expand_wildcard(&psParseInfo->sFieldList,
    7782        2278 :                                       bAlwaysPrefixWithTableName) != CE_None)
    7783             :     {
    7784           2 :         DestroyParseInfo(psParseInfo);
    7785           2 :         return nullptr;
    7786             :     }
    7787             : 
    7788       13656 :     for (int iField = 0; iField < SPECIAL_FIELD_COUNT; iField++)
    7789             :     {
    7790       11380 :         psParseInfo->sFieldList.names[psParseInfo->sFieldList.count] =
    7791       11380 :             const_cast<char *>(SpecialFieldNames[iField]);
    7792       11380 :         psParseInfo->sFieldList.types[psParseInfo->sFieldList.count] =
    7793       11380 :             (iField == SPF_FID && bIsFID64) ? SWQ_INTEGER64
    7794             :                                             : SpecialFieldTypes[iField];
    7795       11380 :         psParseInfo->sFieldList.table_ids[psParseInfo->sFieldList.count] = 0;
    7796       11380 :         psParseInfo->sFieldList.ids[psParseInfo->sFieldList.count] =
    7797       11380 :             nFirstLayerFirstSpecialFieldIndex + iField;
    7798       11380 :         psParseInfo->sFieldList.count++;
    7799             :     }
    7800             : 
    7801             :     /* In the case a layer has an explicit FID column name, then add it */
    7802             :     /* so it can be selected */
    7803        4623 :     for (int iTable = 0; iTable < psSelectInfo->table_count; iTable++)
    7804             :     {
    7805        2347 :         swq_table_def *psTableDef = psSelectInfo->table_defs + iTable;
    7806        2347 :         GDALDataset *poTableDS = this;
    7807             : 
    7808        2347 :         if (psTableDef->data_source != nullptr)
    7809             :         {
    7810           7 :             poTableDS = GDALDataset::FromHandle(
    7811           7 :                 OGROpenShared(psTableDef->data_source, FALSE, nullptr));
    7812           7 :             CPLAssert(poTableDS != nullptr);
    7813           7 :             poTableDS->Dereference();
    7814             :         }
    7815             : 
    7816             :         OGRLayer *poSrcLayer =
    7817        2347 :             poTableDS->GetLayerByName(psTableDef->table_name);
    7818             : 
    7819        2347 :         const char *pszFID = poSrcLayer->GetFIDColumn();
    7820        2958 :         if (pszFID && !EQUAL(pszFID, "") && !EQUAL(pszFID, "FID") &&
    7821         611 :             poSrcLayer->GetLayerDefn()->GetFieldIndex(pszFID) < 0)
    7822             :         {
    7823         561 :             const int iOutField = psParseInfo->sFieldList.count++;
    7824         561 :             psParseInfo->sFieldList.names[iOutField] =
    7825             :                 const_cast<char *>(pszFID);
    7826         561 :             if (poSrcLayer->GetMetadataItem(OLMD_FID64) != nullptr &&
    7827           0 :                 EQUAL(poSrcLayer->GetMetadataItem(OLMD_FID64), "YES"))
    7828             :             {
    7829           0 :                 psParseInfo->sFieldList.types[iOutField] = SWQ_INTEGER64;
    7830             :             }
    7831             :             else
    7832             :             {
    7833         561 :                 psParseInfo->sFieldList.types[iOutField] = SWQ_INTEGER;
    7834             :             }
    7835         561 :             psParseInfo->sFieldList.table_ids[iOutField] = iTable;
    7836        1122 :             psParseInfo->sFieldList.ids[iOutField] =
    7837         561 :                 poSrcLayer->GetLayerDefn()->GetFieldCount() + SPF_FID;
    7838             :         }
    7839             :     }
    7840             : 
    7841             :     /* -------------------------------------------------------------------- */
    7842             :     /*      Finish the parse operation.                                     */
    7843             :     /* -------------------------------------------------------------------- */
    7844        2276 :     if (psSelectInfo->parse(&psParseInfo->sFieldList, poSelectParseOptions) !=
    7845             :         CE_None)
    7846             :     {
    7847          30 :         DestroyParseInfo(psParseInfo);
    7848          30 :         return nullptr;
    7849             :     }
    7850             : 
    7851             :     /* -------------------------------------------------------------------- */
    7852             :     /*      Extract the WHERE expression to use separately.                 */
    7853             :     /* -------------------------------------------------------------------- */
    7854        2246 :     if (psSelectInfo->where_expr != nullptr)
    7855             :     {
    7856         963 :         psParseInfo->pszWHERE =
    7857         963 :             psSelectInfo->where_expr->Unparse(&psParseInfo->sFieldList, '"');
    7858             :         // CPLDebug( "OGR", "Unparse() -> %s", pszWHERE );
    7859             :     }
    7860             : 
    7861        2246 :     return psParseInfo;
    7862             : }
    7863             : 
    7864             : //! @endcond
    7865             : 
    7866             : /************************************************************************/
    7867             : /*                          ReleaseResultSet()                          */
    7868             : /************************************************************************/
    7869             : 
    7870             : /**
    7871             :  \brief Release results of ExecuteSQL().
    7872             : 
    7873             :  This method should only be used to deallocate OGRLayers resulting from
    7874             :  an ExecuteSQL() call on the same GDALDataset.  Failure to deallocate a
    7875             :  results set before destroying the GDALDataset may cause errors.
    7876             : 
    7877             :  This method is the same as the C function GDALDatasetReleaseResultSet() and the
    7878             :  deprecated OGR_DS_ReleaseResultSet().
    7879             : 
    7880             :  @param poResultsSet the result of a previous ExecuteSQL() call.
    7881             : */
    7882             : 
    7883        2162 : void GDALDataset::ReleaseResultSet(OGRLayer *poResultsSet)
    7884             : 
    7885             : {
    7886        2162 :     delete poResultsSet;
    7887        2162 : }
    7888             : 
    7889             : /************************************************************************/
    7890             : /*                            GetStyleTable()                           */
    7891             : /************************************************************************/
    7892             : 
    7893             : /**
    7894             :  \brief Returns dataset style table.
    7895             : 
    7896             :  This method is the same as the C function GDALDatasetGetStyleTable() and the
    7897             :  deprecated OGR_DS_GetStyleTable().
    7898             : 
    7899             :  @return pointer to a style table which should not be modified or freed by the
    7900             :  caller.
    7901             : */
    7902             : 
    7903         933 : OGRStyleTable *GDALDataset::GetStyleTable()
    7904             : {
    7905         933 :     return m_poStyleTable;
    7906             : }
    7907             : 
    7908             : /************************************************************************/
    7909             : /*                         SetStyleTableDirectly()                      */
    7910             : /************************************************************************/
    7911             : 
    7912             : /**
    7913             :  \brief Set dataset style table.
    7914             : 
    7915             :  This method operate exactly as SetStyleTable() except that it
    7916             :  assumes ownership of the passed table.
    7917             : 
    7918             :  This method is the same as the C function GDALDatasetSetStyleTableDirectly()
    7919             :  and the deprecated OGR_DS_SetStyleTableDirectly().
    7920             : 
    7921             :  @param poStyleTable pointer to style table to set
    7922             : 
    7923             : */
    7924           0 : void GDALDataset::SetStyleTableDirectly(OGRStyleTable *poStyleTable)
    7925             : {
    7926           0 :     if (m_poStyleTable)
    7927           0 :         delete m_poStyleTable;
    7928           0 :     m_poStyleTable = poStyleTable;
    7929           0 : }
    7930             : 
    7931             : /************************************************************************/
    7932             : /*                            SetStyleTable()                           */
    7933             : /************************************************************************/
    7934             : 
    7935             : /**
    7936             :  \brief Set dataset style table.
    7937             : 
    7938             :  This method operate exactly as SetStyleTableDirectly() except
    7939             :  that it does not assume ownership of the passed table.
    7940             : 
    7941             :  This method is the same as the C function GDALDatasetSetStyleTable() and the
    7942             :  deprecated OGR_DS_SetStyleTable().
    7943             : 
    7944             :  @param poStyleTable pointer to style table to set
    7945             : 
    7946             : */
    7947             : 
    7948         929 : void GDALDataset::SetStyleTable(OGRStyleTable *poStyleTable)
    7949             : {
    7950         929 :     if (m_poStyleTable)
    7951           0 :         delete m_poStyleTable;
    7952         929 :     if (poStyleTable)
    7953           1 :         m_poStyleTable = poStyleTable->Clone();
    7954         929 : }
    7955             : 
    7956             : /************************************************************************/
    7957             : /*                         IsGenericSQLDialect()                        */
    7958             : /************************************************************************/
    7959             : 
    7960             : //! @cond Doxygen_Suppress
    7961        1748 : int GDALDataset::IsGenericSQLDialect(const char *pszDialect)
    7962             : {
    7963        3188 :     return pszDialect != nullptr &&
    7964        3188 :            (EQUAL(pszDialect, "OGRSQL") || EQUAL(pszDialect, "SQLITE"));
    7965             : }
    7966             : 
    7967             : //! @endcond
    7968             : 
    7969             : /************************************************************************/
    7970             : /*                            GetLayerCount()                           */
    7971             : /************************************************************************/
    7972             : 
    7973             : /**
    7974             :  \brief Get the number of layers in this dataset.
    7975             : 
    7976             :  This method is the same as the C function GDALDatasetGetLayerCount(),
    7977             :  and the deprecated OGR_DS_GetLayerCount().
    7978             : 
    7979             :  Note that even if this method is const, there is no guarantee it can be
    7980             :  safely called by concurrent threads on the same GDALDataset object.
    7981             : 
    7982             :  @return layer count.
    7983             : */
    7984             : 
    7985      117238 : int GDALDataset::GetLayerCount() const
    7986             : {
    7987      117238 :     return 0;
    7988             : }
    7989             : 
    7990             : /************************************************************************/
    7991             : /*                                GetLayer()                            */
    7992             : /************************************************************************/
    7993             : 
    7994             : /**
    7995             :  \fn const GDALDataset::GetLayer(int) const
    7996             :  \brief Fetch a layer by index.
    7997             : 
    7998             :  The returned layer remains owned by the
    7999             :  GDALDataset and should not be deleted by the application.
    8000             : 
    8001             :  Note that even if this method is const, there is no guarantee it can be
    8002             :  safely called by concurrent threads on the same GDALDataset object.
    8003             : 
    8004             :  See GetLayers() for a C++ iterator version of this method.
    8005             : 
    8006             :  This method is the same as the C function GDALDatasetGetLayer() and the
    8007             :  deprecated OGR_DS_GetLayer().
    8008             : 
    8009             :  @param iLayer a layer number between 0 and GetLayerCount()-1.
    8010             : 
    8011             :  @return the layer, or NULL if iLayer is out of range or an error occurs.
    8012             : 
    8013             :  @see GetLayers()
    8014             : 
    8015             :  @since GDAL 3.12
    8016             : */
    8017             : 
    8018           0 : const OGRLayer *GDALDataset::GetLayer(CPL_UNUSED int iLayer) const
    8019             : {
    8020           0 :     return nullptr;
    8021             : }
    8022             : 
    8023             : /**
    8024             :  \fn GDALDataset::GetLayer(int)
    8025             :  \brief Fetch a layer by index.
    8026             : 
    8027             :  The returned layer remains owned by the
    8028             :  GDALDataset and should not be deleted by the application.
    8029             : 
    8030             :  See GetLayers() for a C++ iterator version of this method.
    8031             : 
    8032             :  This method is the same as the C function GDALDatasetGetLayer() and the
    8033             :  deprecated OGR_DS_GetLayer().
    8034             : 
    8035             :  @param iLayer a layer number between 0 and GetLayerCount()-1.
    8036             : 
    8037             :  @return the layer, or NULL if iLayer is out of range or an error occurs.
    8038             : 
    8039             :  @see GetLayers()
    8040             : */
    8041             : 
    8042             : /************************************************************************/
    8043             : /*                                IsLayerPrivate()                      */
    8044             : /************************************************************************/
    8045             : 
    8046             : /**
    8047             :  \fn GDALDataset::IsLayerPrivate(int)
    8048             :  \brief Returns true if the layer at the specified index is deemed a private or
    8049             :  system table, or an internal detail only.
    8050             : 
    8051             :  This method is the same as the C function GDALDatasetIsLayerPrivate().
    8052             : 
    8053             :  @param iLayer a layer number between 0 and GetLayerCount()-1.
    8054             : 
    8055             :  @return true if the layer is a private or system table.
    8056             : 
    8057             :  @since GDAL 3.4
    8058             : */
    8059             : 
    8060         950 : bool GDALDataset::IsLayerPrivate(CPL_UNUSED int iLayer) const
    8061             : {
    8062         950 :     return false;
    8063             : }
    8064             : 
    8065             : /************************************************************************/
    8066             : /*                           ResetReading()                             */
    8067             : /************************************************************************/
    8068             : 
    8069             : /**
    8070             :  \brief Reset feature reading to start on the first feature.
    8071             : 
    8072             :  This affects GetNextFeature().
    8073             : 
    8074             :  Depending on drivers, this may also have the side effect of calling
    8075             :  OGRLayer::ResetReading() on the layers of this dataset.
    8076             : 
    8077             :  This method is the same as the C function GDALDatasetResetReading().
    8078             : 
    8079             : */
    8080           7 : void GDALDataset::ResetReading()
    8081             : {
    8082           7 :     if (!m_poPrivate)
    8083           0 :         return;
    8084           7 :     m_poPrivate->nCurrentLayerIdx = 0;
    8085           7 :     m_poPrivate->nLayerCount = -1;
    8086           7 :     m_poPrivate->poCurrentLayer = nullptr;
    8087           7 :     m_poPrivate->nFeatureReadInLayer = 0;
    8088           7 :     m_poPrivate->nFeatureReadInDataset = 0;
    8089           7 :     m_poPrivate->nTotalFeaturesInLayer = TOTAL_FEATURES_NOT_INIT;
    8090           7 :     m_poPrivate->nTotalFeatures = TOTAL_FEATURES_NOT_INIT;
    8091             : }
    8092             : 
    8093             : /************************************************************************/
    8094             : /*                         GDALDatasetResetReading()                    */
    8095             : /************************************************************************/
    8096             : 
    8097             : /**
    8098             :  \brief Reset feature reading to start on the first feature.
    8099             : 
    8100             :  This affects GDALDatasetGetNextFeature().
    8101             : 
    8102             :  Depending on drivers, this may also have the side effect of calling
    8103             :  OGR_L_ResetReading() on the layers of this dataset.
    8104             : 
    8105             :  This method is the same as the C++ method GDALDataset::ResetReading()
    8106             : 
    8107             :  @param hDS dataset handle
    8108             : */
    8109          14 : void CPL_DLL GDALDatasetResetReading(GDALDatasetH hDS)
    8110             : {
    8111          14 :     VALIDATE_POINTER0(hDS, "GDALDatasetResetReading");
    8112             : 
    8113          14 :     return GDALDataset::FromHandle(hDS)->ResetReading();
    8114             : }
    8115             : 
    8116             : /************************************************************************/
    8117             : /*                          GetNextFeature()                            */
    8118             : /************************************************************************/
    8119             : 
    8120             : /**
    8121             :  \brief Fetch the next available feature from this dataset.
    8122             : 
    8123             :  This method is intended for the few drivers where OGRLayer::GetNextFeature()
    8124             :  is not efficient, but in general OGRLayer::GetNextFeature() is a more
    8125             :  natural API.
    8126             : 
    8127             :  See GetFeatures() for a C++ iterator version of this method.
    8128             : 
    8129             :  The returned feature becomes the responsibility of the caller to
    8130             :  delete with OGRFeature::DestroyFeature().
    8131             : 
    8132             :  Depending on the driver, this method may return features from layers in a
    8133             :  non sequential way. This is what may happen when the
    8134             :  ODsCRandomLayerRead capability is declared (for example for the
    8135             :  OSM and GMLAS drivers). When datasets declare this capability, it is strongly
    8136             :  advised to use GDALDataset::GetNextFeature() instead of
    8137             :  OGRLayer::GetNextFeature(), as the later might have a slow, incomplete or stub
    8138             :  implementation.
    8139             : 
    8140             :  The default implementation, used by most drivers, will
    8141             :  however iterate over each layer, and then over each feature within this
    8142             :  layer.
    8143             : 
    8144             :  This method takes into account spatial and attribute filters set on layers that
    8145             :  will be iterated upon.
    8146             : 
    8147             :  The ResetReading() method can be used to start at the beginning again.
    8148             : 
    8149             :  Depending on drivers, this may also have the side effect of calling
    8150             :  OGRLayer::GetNextFeature() on the layers of this dataset.
    8151             : 
    8152             :  This method is the same as the C function GDALDatasetGetNextFeature().
    8153             : 
    8154             :  @param ppoBelongingLayer a pointer to a OGRLayer* variable to receive the
    8155             :                           layer to which the object belongs to, or NULL.
    8156             :                           It is possible that the output of *ppoBelongingLayer
    8157             :                           to be NULL despite the feature not being NULL.
    8158             :  @param pdfProgressPct    a pointer to a double variable to receive the
    8159             :                           percentage progress (in [0,1] range), or NULL.
    8160             :                           On return, the pointed value might be negative if
    8161             :                           determining the progress is not possible.
    8162             :  @param pfnProgress       a progress callback to report progress (for
    8163             :                           GetNextFeature() calls that might have a long
    8164             :                           duration) and offer cancellation possibility, or NULL.
    8165             :  @param pProgressData     user data provided to pfnProgress, or NULL
    8166             :  @return a feature, or NULL if no more features are available.
    8167             :  @see GetFeatures()
    8168             : */
    8169             : 
    8170          60 : OGRFeature *GDALDataset::GetNextFeature(OGRLayer **ppoBelongingLayer,
    8171             :                                         double *pdfProgressPct,
    8172             :                                         GDALProgressFunc pfnProgress,
    8173             :                                         void *pProgressData)
    8174             : {
    8175          60 :     if (!m_poPrivate || m_poPrivate->nCurrentLayerIdx < 0)
    8176             :     {
    8177           2 :         if (ppoBelongingLayer != nullptr)
    8178           2 :             *ppoBelongingLayer = nullptr;
    8179           2 :         if (pdfProgressPct != nullptr)
    8180           1 :             *pdfProgressPct = 1.0;
    8181           2 :         if (pfnProgress != nullptr)
    8182           0 :             pfnProgress(1.0, "", pProgressData);
    8183           2 :         return nullptr;
    8184             :     }
    8185             : 
    8186          58 :     if (m_poPrivate->poCurrentLayer == nullptr &&
    8187           8 :         (pdfProgressPct != nullptr || pfnProgress != nullptr))
    8188             :     {
    8189           1 :         if (m_poPrivate->nLayerCount < 0)
    8190             :         {
    8191           1 :             m_poPrivate->nLayerCount = GetLayerCount();
    8192             :         }
    8193             : 
    8194           1 :         if (m_poPrivate->nTotalFeatures == TOTAL_FEATURES_NOT_INIT)
    8195             :         {
    8196           1 :             m_poPrivate->nTotalFeatures = 0;
    8197           5 :             for (int i = 0; i < m_poPrivate->nLayerCount; i++)
    8198             :             {
    8199           4 :                 OGRLayer *poLayer = GetLayer(i);
    8200           8 :                 if (poLayer == nullptr ||
    8201           4 :                     !poLayer->TestCapability(OLCFastFeatureCount))
    8202             :                 {
    8203           0 :                     m_poPrivate->nTotalFeatures = TOTAL_FEATURES_UNKNOWN;
    8204           0 :                     break;
    8205             :                 }
    8206           4 :                 GIntBig nCount = poLayer->GetFeatureCount(FALSE);
    8207           4 :                 if (nCount < 0)
    8208             :                 {
    8209           0 :                     m_poPrivate->nTotalFeatures = TOTAL_FEATURES_UNKNOWN;
    8210           0 :                     break;
    8211             :                 }
    8212           4 :                 m_poPrivate->nTotalFeatures += nCount;
    8213             :             }
    8214             :         }
    8215             :     }
    8216             : 
    8217             :     while (true)
    8218             :     {
    8219          71 :         if (m_poPrivate->poCurrentLayer == nullptr)
    8220             :         {
    8221          44 :             m_poPrivate->poCurrentLayer =
    8222          22 :                 GetLayer(m_poPrivate->nCurrentLayerIdx);
    8223          22 :             if (m_poPrivate->poCurrentLayer == nullptr)
    8224             :             {
    8225           7 :                 m_poPrivate->nCurrentLayerIdx = -1;
    8226           7 :                 if (ppoBelongingLayer != nullptr)
    8227           7 :                     *ppoBelongingLayer = nullptr;
    8228           7 :                 if (pdfProgressPct != nullptr)
    8229           1 :                     *pdfProgressPct = 1.0;
    8230           7 :                 return nullptr;
    8231             :             }
    8232          15 :             m_poPrivate->poCurrentLayer->ResetReading();
    8233          15 :             m_poPrivate->nFeatureReadInLayer = 0;
    8234          15 :             if (m_poPrivate->nTotalFeatures < 0 && pdfProgressPct != nullptr)
    8235             :             {
    8236           0 :                 if (m_poPrivate->poCurrentLayer->TestCapability(
    8237           0 :                         OLCFastFeatureCount))
    8238           0 :                     m_poPrivate->nTotalFeaturesInLayer =
    8239           0 :                         m_poPrivate->poCurrentLayer->GetFeatureCount(FALSE);
    8240             :                 else
    8241           0 :                     m_poPrivate->nTotalFeaturesInLayer = 0;
    8242             :             }
    8243             :         }
    8244          64 :         OGRFeature *poFeature = m_poPrivate->poCurrentLayer->GetNextFeature();
    8245          64 :         if (poFeature == nullptr)
    8246             :         {
    8247          13 :             m_poPrivate->nCurrentLayerIdx++;
    8248          13 :             m_poPrivate->poCurrentLayer = nullptr;
    8249          13 :             continue;
    8250             :         }
    8251             : 
    8252          51 :         m_poPrivate->nFeatureReadInLayer++;
    8253          51 :         m_poPrivate->nFeatureReadInDataset++;
    8254          51 :         if (pdfProgressPct != nullptr || pfnProgress != nullptr)
    8255             :         {
    8256           4 :             double dfPct = 0.0;
    8257           4 :             if (m_poPrivate->nTotalFeatures > 0)
    8258             :             {
    8259           4 :                 dfPct = 1.0 * m_poPrivate->nFeatureReadInDataset /
    8260           4 :                         m_poPrivate->nTotalFeatures;
    8261             :             }
    8262             :             else
    8263             :             {
    8264           0 :                 dfPct = 1.0 * m_poPrivate->nCurrentLayerIdx /
    8265           0 :                         m_poPrivate->nLayerCount;
    8266           0 :                 if (m_poPrivate->nTotalFeaturesInLayer > 0)
    8267             :                 {
    8268           0 :                     dfPct += 1.0 * m_poPrivate->nFeatureReadInLayer /
    8269           0 :                              m_poPrivate->nTotalFeaturesInLayer /
    8270           0 :                              m_poPrivate->nLayerCount;
    8271             :                 }
    8272             :             }
    8273           4 :             if (pdfProgressPct)
    8274           4 :                 *pdfProgressPct = dfPct;
    8275           4 :             if (pfnProgress)
    8276           0 :                 pfnProgress(dfPct, "", nullptr);
    8277             :         }
    8278             : 
    8279          51 :         if (ppoBelongingLayer != nullptr)
    8280          51 :             *ppoBelongingLayer = m_poPrivate->poCurrentLayer;
    8281          51 :         return poFeature;
    8282          13 :     }
    8283             : }
    8284             : 
    8285             : /************************************************************************/
    8286             : /*                     GDALDatasetGetNextFeature()                      */
    8287             : /************************************************************************/
    8288             : /**
    8289             :  \brief Fetch the next available feature from this dataset.
    8290             : 
    8291             :  This method is intended for the few drivers where OGR_L_GetNextFeature()
    8292             :  is not efficient, but in general OGR_L_GetNextFeature() is a more
    8293             :  natural API.
    8294             : 
    8295             :  The returned feature becomes the responsibility of the caller to
    8296             :  delete with OGRFeature::DestroyFeature().
    8297             : 
    8298             :  Depending on the driver, this method may return features from layers in a
    8299             :  non sequential way. This is what may happen when the
    8300             :  ODsCRandomLayerRead capability is declared (for example for the
    8301             :  OSM and GMLAS drivers). When datasets declare this capability, it is strongly
    8302             :  advised to use GDALDataset::GetNextFeature() instead of
    8303             :  OGRLayer::GetNextFeature(), as the later might have a slow, incomplete or stub
    8304             :  implementation.
    8305             : 
    8306             :  The default implementation, used by most drivers, will
    8307             :  however iterate over each layer, and then over each feature within this
    8308             :  layer.
    8309             : 
    8310             :  This method takes into account spatial and attribute filters set on layers that
    8311             :  will be iterated upon.
    8312             : 
    8313             :  The ResetReading() method can be used to start at the beginning again.
    8314             : 
    8315             :  Depending on drivers, this may also have the side effect of calling
    8316             :  OGRLayer::GetNextFeature() on the layers of this dataset.
    8317             : 
    8318             :  This method is the same as the C++ method GDALDataset::GetNextFeature()
    8319             : 
    8320             :  @param hDS               dataset handle.
    8321             :  @param phBelongingLayer  a pointer to a OGRLayer* variable to receive the
    8322             :                           layer to which the object belongs to, or NULL.
    8323             :                           It is possible that the output of *ppoBelongingLayer
    8324             :                           to be NULL despite the feature not being NULL.
    8325             :  @param pdfProgressPct    a pointer to a double variable to receive the
    8326             :                           percentage progress (in [0,1] range), or NULL.
    8327             :                           On return, the pointed value might be negative if
    8328             :                           determining the progress is not possible.
    8329             :  @param pfnProgress       a progress callback to report progress (for
    8330             :                           GetNextFeature() calls that might have a long
    8331             :                           duration) and offer cancellation possibility, or NULL
    8332             :  @param pProgressData     user data provided to pfnProgress, or NULL
    8333             :  @return a feature, or NULL if no more features are available.
    8334             : */
    8335        1917 : OGRFeatureH CPL_DLL GDALDatasetGetNextFeature(GDALDatasetH hDS,
    8336             :                                               OGRLayerH *phBelongingLayer,
    8337             :                                               double *pdfProgressPct,
    8338             :                                               GDALProgressFunc pfnProgress,
    8339             :                                               void *pProgressData)
    8340             : {
    8341        1917 :     VALIDATE_POINTER1(hDS, "GDALDatasetGetNextFeature", nullptr);
    8342             : 
    8343        3834 :     return OGRFeature::ToHandle(GDALDataset::FromHandle(hDS)->GetNextFeature(
    8344             :         reinterpret_cast<OGRLayer **>(phBelongingLayer), pdfProgressPct,
    8345        3834 :         pfnProgress, pProgressData));
    8346             : }
    8347             : 
    8348             : /************************************************************************/
    8349             : /*                            TestCapability()                          */
    8350             : /************************************************************************/
    8351             : 
    8352             : /**
    8353             :  \fn GDALDataset::TestCapability( const char * pszCap )
    8354             :  \brief Test if capability is available.
    8355             : 
    8356             :  One of the following dataset capability names can be passed into this
    8357             :  method, and a TRUE or FALSE value will be returned indicating whether or not
    8358             :  the capability is available for this object.
    8359             : 
    8360             :  <ul>
    8361             :   <li> <b>ODsCCreateLayer</b>: True if this datasource can create new layers.<p>
    8362             :   <li> <b>ODsCDeleteLayer</b>: True if this datasource can delete existing
    8363             :           layers.<p>
    8364             :   <li> <b>ODsCCreateGeomFieldAfterCreateLayer</b>: True if the layers of this
    8365             :           datasource support CreateGeomField() just after layer creation.<p>
    8366             :   <li> <b>ODsCCurveGeometries</b>: True if this datasource supports curve
    8367             :           geometries.<p>
    8368             :   <li> <b>ODsCTransactions</b>: True if this datasource supports (efficient)
    8369             :           transactions.<p>
    8370             :   <li> <b>ODsCEmulatedTransactions</b>: True if this datasource supports
    8371             :           transactions through emulation.<p>
    8372             :   <li> <b>ODsCRandomLayerRead</b>: True if this datasource has a dedicated
    8373             :           GetNextFeature() implementation, potentially returning features from
    8374             :           layers in a non sequential way.<p>
    8375             :   <li> <b>ODsCRandomLayerWrite</b>: True if this datasource supports calling
    8376             :          CreateFeature() on layers in a non sequential way.<p>
    8377             :   <li> <b>GDsCAddRelationship</b>: True if AddRelationship() is supported</li>
    8378             :   <li> <b>GDsCDeleteRelationship</b>: True if DeleteRelationship() is supported</li>
    8379             :   <li> <b>GDsCUpdateRelationship</b>: True if UpdateRelationship() is supported</li>
    8380             :   <li> <b>GDsCFastGetExtent</b>: True if GetExtent() is fast</li>
    8381             :   <li> <b>GDsCFastGetExtentWGS84LongLat</b>: True if GetExtentWGS84LongLat() is fast</li>
    8382             :  </ul>
    8383             : 
    8384             :  The \#define macro forms of the capability names should be used in preference
    8385             :  to the strings themselves to avoid misspelling.
    8386             : 
    8387             :  This method is the same as the C function GDALDatasetTestCapability() and the
    8388             :  deprecated OGR_DS_TestCapability().
    8389             : 
    8390             :  @param pszCap the capability to test.
    8391             : 
    8392             :  @return TRUE if capability available otherwise FALSE.
    8393             : */
    8394             : 
    8395         729 : int GDALDataset::TestCapability(const char *pszCap) const
    8396             : {
    8397         729 :     if (EQUAL(pszCap, GDsCFastGetExtent) ||
    8398         727 :         EQUAL(pszCap, GDsCFastGetExtentWGS84LongLat))
    8399             :     {
    8400           4 :         for (auto &&poLayer : GetLayers())
    8401             :         {
    8402           2 :             if (!poLayer->TestCapability(OLCFastGetExtent))
    8403           2 :                 return FALSE;
    8404             :         }
    8405           2 :         return TRUE;
    8406             :     }
    8407         725 :     return FALSE;
    8408             : }
    8409             : 
    8410             : /************************************************************************/
    8411             : /*                     GDALDatasetTestCapability()                      */
    8412             : /************************************************************************/
    8413             : 
    8414             : /**
    8415             :  \brief Test if capability is available.
    8416             : 
    8417             :  One of the following dataset capability names can be passed into this
    8418             :  function, and a TRUE or FALSE value will be returned indicating whether or not
    8419             :  the capability is available for this object.
    8420             : 
    8421             :  <ul>
    8422             :   <li> <b>ODsCCreateLayer</b>: True if this datasource can create new layers.<p>
    8423             :   <li> <b>ODsCDeleteLayer</b>: True if this datasource can delete existing
    8424             :           layers.<p>
    8425             :   <li> <b>ODsCCreateGeomFieldAfterCreateLayer</b>: True if the layers of this
    8426             :           datasource support CreateGeomField() just after layer creation.<p>
    8427             :   <li> <b>ODsCCurveGeometries</b>: True if this datasource supports curve
    8428             :           geometries.<p>
    8429             :   <li> <b>ODsCTransactions</b>: True if this datasource supports (efficient)
    8430             :           transactions.<p>
    8431             :   <li> <b>ODsCEmulatedTransactions</b>: True if this datasource supports
    8432             :           transactions through emulation.<p>
    8433             :   <li> <b>ODsCRandomLayerRead</b>: True if this datasource has a dedicated
    8434             :           GetNextFeature() implementation, potentially returning features from
    8435             :           layers in a non sequential way.<p>
    8436             :   <li> <b>ODsCRandomLayerWrite</b>: True if this datasource supports calling
    8437             :           CreateFeature() on layers in a non sequential way.<p>
    8438             :   <li> <b>GDsCAddRelationship</b>: True if AddRelationship() is supported</li>
    8439             :   <li> <b>GDsCDeleteRelationship</b>: True if DeleteRelationship() is supported</li>
    8440             :   <li> <b>GDsCUpdateRelationship</b>: True if UpdateRelationship() is supported</li>
    8441             :   <li> <b>GDsCFastGetExtent</b>: True if GetExtent() is fast</li>
    8442             :   <li> <b>GDsCFastGetExtentWGS84LongLat</b>: True if GetExtentWGS84LongLat() is fast</li>
    8443             :  </ul>
    8444             : 
    8445             :  The \#define macro forms of the capability names should be used in preference
    8446             :  to the strings themselves to avoid misspelling.
    8447             : 
    8448             :  This function is the same as the C++ method GDALDataset::TestCapability()
    8449             : 
    8450             : 
    8451             :  @param hDS the dataset handle.
    8452             :  @param pszCap the capability to test.
    8453             : 
    8454             :  @return TRUE if capability available otherwise FALSE.
    8455             : */
    8456         127 : int GDALDatasetTestCapability(GDALDatasetH hDS, const char *pszCap)
    8457             : 
    8458             : {
    8459         127 :     VALIDATE_POINTER1(hDS, "GDALDatasetTestCapability", 0);
    8460         127 :     VALIDATE_POINTER1(pszCap, "GDALDatasetTestCapability", 0);
    8461             : 
    8462         127 :     return GDALDataset::FromHandle(hDS)->TestCapability(pszCap);
    8463             : }
    8464             : 
    8465             : /************************************************************************/
    8466             : /*                           StartTransaction()                         */
    8467             : /************************************************************************/
    8468             : 
    8469             : /**
    8470             :  \fn GDALDataset::StartTransaction(int)
    8471             :  \brief For datasources which support transactions, StartTransaction creates a
    8472             : `transaction.
    8473             : 
    8474             :  If starting the transaction fails, will return
    8475             :  OGRERR_FAILURE. Datasources which do not support transactions will
    8476             :  always return OGRERR_UNSUPPORTED_OPERATION.
    8477             : 
    8478             :  Nested transactions are not supported.
    8479             : 
    8480             :  All changes done after the start of the transaction are definitely applied in
    8481             :  the datasource if CommitTransaction() is called. They may be canceled by
    8482             :  calling RollbackTransaction() instead.
    8483             : 
    8484             :  At the time of writing, transactions only apply on vector layers.
    8485             : 
    8486             :  Datasets that support transactions will advertise the ODsCTransactions
    8487             :  capability.  Use of transactions at dataset level is generally preferred to
    8488             :  transactions at layer level, whose scope is rarely limited to the layer from
    8489             :  which it was started.
    8490             : 
    8491             :  In case StartTransaction() fails, neither CommitTransaction() or
    8492             :  RollbackTransaction() should be called.
    8493             : 
    8494             :  If an error occurs after a successful StartTransaction(), the whole transaction
    8495             :  may or may not be implicitly canceled, depending on drivers. (e.g.  the PG
    8496             :  driver will cancel it, SQLite/GPKG not). In any case, in the event of an error,
    8497             :  an explicit call to RollbackTransaction() should be done to keep things
    8498             :  balanced.
    8499             : 
    8500             :  By default, when bForce is set to FALSE, only "efficient" transactions will be
    8501             :  attempted. Some drivers may offer an emulation of transactions, but sometimes
    8502             :  with significant overhead, in which case the user must explicitly allow for
    8503             :  such an emulation by setting bForce to TRUE. Drivers that offer emulated
    8504             :  transactions should advertise the ODsCEmulatedTransactions capability (and not
    8505             :  ODsCTransactions).
    8506             : 
    8507             :  This function is the same as the C function GDALDatasetStartTransaction().
    8508             : 
    8509             :  @param bForce can be set to TRUE if an emulation, possibly slow, of a
    8510             :  transaction
    8511             :                mechanism is acceptable.
    8512             : 
    8513             :  @return OGRERR_NONE on success.
    8514             : */
    8515             : 
    8516          37 : OGRErr GDALDataset::StartTransaction(CPL_UNUSED int bForce)
    8517             : {
    8518          37 :     return OGRERR_UNSUPPORTED_OPERATION;
    8519             : }
    8520             : 
    8521             : /************************************************************************/
    8522             : /*                      GDALDatasetStartTransaction()                   */
    8523             : /************************************************************************/
    8524             : 
    8525             : /**
    8526             :  \brief For datasources which support transactions, StartTransaction creates a
    8527             :  transaction.
    8528             : 
    8529             :  If starting the transaction fails, will return
    8530             :  OGRERR_FAILURE. Datasources which do not support transactions will
    8531             :  always return OGRERR_UNSUPPORTED_OPERATION.
    8532             : 
    8533             :  Nested transactions are not supported.
    8534             : 
    8535             :  All changes done after the start of the transaction are definitely applied in
    8536             :  the datasource if CommitTransaction() is called. They may be canceled by
    8537             :  calling RollbackTransaction() instead.
    8538             : 
    8539             :  At the time of writing, transactions only apply on vector layers.
    8540             : 
    8541             :  Datasets that support transactions will advertise the ODsCTransactions
    8542             :  capability.
    8543             :  Use of transactions at dataset level is generally preferred to transactions at
    8544             :  layer level, whose scope is rarely limited to the layer from which it was
    8545             :  started.
    8546             : 
    8547             :  In case StartTransaction() fails, neither CommitTransaction() or
    8548             :  RollbackTransaction() should be called.
    8549             : 
    8550             :  If an error occurs after a successful StartTransaction(), the whole
    8551             :  transaction may or may not be implicitly canceled, depending on drivers. (e.g.
    8552             :  the PG driver will cancel it, SQLite/GPKG not). In any case, in the event of an
    8553             :  error, an explicit call to RollbackTransaction() should be done to keep things
    8554             :  balanced.
    8555             : 
    8556             :  By default, when bForce is set to FALSE, only "efficient" transactions will be
    8557             :  attempted. Some drivers may offer an emulation of transactions, but sometimes
    8558             :  with significant overhead, in which case the user must explicitly allow for
    8559             :  such an emulation by setting bForce to TRUE. Drivers that offer emulated
    8560             :  transactions should advertise the ODsCEmulatedTransactions capability (and not
    8561             :  ODsCTransactions).
    8562             : 
    8563             :  This function is the same as the C++ method GDALDataset::StartTransaction()
    8564             : 
    8565             :  @param hDS the dataset handle.
    8566             :  @param bForce can be set to TRUE if an emulation, possibly slow, of a
    8567             :  transaction
    8568             :                mechanism is acceptable.
    8569             : 
    8570             :  @return OGRERR_NONE on success.
    8571             : */
    8572         105 : OGRErr GDALDatasetStartTransaction(GDALDatasetH hDS, int bForce)
    8573             : {
    8574         105 :     VALIDATE_POINTER1(hDS, "GDALDatasetStartTransaction",
    8575             :                       OGRERR_INVALID_HANDLE);
    8576             : 
    8577             : #ifdef OGRAPISPY_ENABLED
    8578         105 :     if (bOGRAPISpyEnabled)
    8579           2 :         OGRAPISpy_Dataset_StartTransaction(hDS, bForce);
    8580             : #endif
    8581             : 
    8582         105 :     return GDALDataset::FromHandle(hDS)->StartTransaction(bForce);
    8583             : }
    8584             : 
    8585             : /************************************************************************/
    8586             : /*                           CommitTransaction()                        */
    8587             : /************************************************************************/
    8588             : 
    8589             : /**
    8590             :  \brief For datasources which support transactions, CommitTransaction commits a
    8591             :  transaction.
    8592             : 
    8593             :  If no transaction is active, or the commit fails, will return
    8594             :  OGRERR_FAILURE. Datasources which do not support transactions will
    8595             :  always return OGRERR_UNSUPPORTED_OPERATION.
    8596             : 
    8597             :  Depending on drivers, this may or may not abort layer sequential readings that
    8598             :  are active.
    8599             : 
    8600             :  This function is the same as the C function GDALDatasetCommitTransaction().
    8601             : 
    8602             :  @return OGRERR_NONE on success.
    8603             : */
    8604          52 : OGRErr GDALDataset::CommitTransaction()
    8605             : {
    8606          52 :     return OGRERR_UNSUPPORTED_OPERATION;
    8607             : }
    8608             : 
    8609             : /************************************************************************/
    8610             : /*                        GDALDatasetCommitTransaction()                */
    8611             : /************************************************************************/
    8612             : 
    8613             : /**
    8614             :  \brief For datasources which support transactions, CommitTransaction commits a
    8615             :  transaction.
    8616             : 
    8617             :  If no transaction is active, or the commit fails, will return
    8618             :  OGRERR_FAILURE. Datasources which do not support transactions will
    8619             :  always return OGRERR_UNSUPPORTED_OPERATION.
    8620             : 
    8621             :  Depending on drivers, this may or may not abort layer sequential readings that
    8622             :  are active.
    8623             : 
    8624             :  This function is the same as the C++ method GDALDataset::CommitTransaction()
    8625             : 
    8626             :  @return OGRERR_NONE on success.
    8627             : */
    8628          76 : OGRErr GDALDatasetCommitTransaction(GDALDatasetH hDS)
    8629             : {
    8630          76 :     VALIDATE_POINTER1(hDS, "GDALDatasetCommitTransaction",
    8631             :                       OGRERR_INVALID_HANDLE);
    8632             : 
    8633             : #ifdef OGRAPISPY_ENABLED
    8634          76 :     if (bOGRAPISpyEnabled)
    8635           2 :         OGRAPISpy_Dataset_CommitTransaction(hDS);
    8636             : #endif
    8637             : 
    8638          76 :     return GDALDataset::FromHandle(hDS)->CommitTransaction();
    8639             : }
    8640             : 
    8641             : /************************************************************************/
    8642             : /*                           RollbackTransaction()                      */
    8643             : /************************************************************************/
    8644             : 
    8645             : /**
    8646             :  \brief For datasources which support transactions, RollbackTransaction will
    8647             :  roll back a datasource to its state before the start of the current
    8648             :  transaction.
    8649             :  If no transaction is active, or the rollback fails, will return
    8650             :  OGRERR_FAILURE. Datasources which do not support transactions will
    8651             :  always return OGRERR_UNSUPPORTED_OPERATION.
    8652             : 
    8653             :  This function is the same as the C function GDALDatasetRollbackTransaction().
    8654             : 
    8655             :  @return OGRERR_NONE on success.
    8656             : */
    8657           2 : OGRErr GDALDataset::RollbackTransaction()
    8658             : {
    8659           2 :     return OGRERR_UNSUPPORTED_OPERATION;
    8660             : }
    8661             : 
    8662             : /************************************************************************/
    8663             : /*                     GDALDatasetRollbackTransaction()                 */
    8664             : /************************************************************************/
    8665             : 
    8666             : /**
    8667             :  \brief For datasources which support transactions, RollbackTransaction will
    8668             :  roll back a datasource to its state before the start of the current
    8669             :  transaction.
    8670             :  If no transaction is active, or the rollback fails, will return
    8671             :  OGRERR_FAILURE. Datasources which do not support transactions will
    8672             :  always return OGRERR_UNSUPPORTED_OPERATION.
    8673             : 
    8674             :  This function is the same as the C++ method GDALDataset::RollbackTransaction().
    8675             : 
    8676             :  @return OGRERR_NONE on success.
    8677             : */
    8678          44 : OGRErr GDALDatasetRollbackTransaction(GDALDatasetH hDS)
    8679             : {
    8680          44 :     VALIDATE_POINTER1(hDS, "GDALDatasetRollbackTransaction",
    8681             :                       OGRERR_INVALID_HANDLE);
    8682             : 
    8683             : #ifdef OGRAPISPY_ENABLED
    8684          44 :     if (bOGRAPISpyEnabled)
    8685           2 :         OGRAPISpy_Dataset_RollbackTransaction(hDS);
    8686             : #endif
    8687             : 
    8688          44 :     return GDALDataset::FromHandle(hDS)->RollbackTransaction();
    8689             : }
    8690             : 
    8691             : //! @cond Doxygen_Suppress
    8692             : 
    8693             : /************************************************************************/
    8694             : /*                   ShareLockWithParentDataset()                       */
    8695             : /************************************************************************/
    8696             : 
    8697             : /* To be used typically by the GTiff driver to link overview datasets */
    8698             : /* with their main dataset, so that they share the same lock */
    8699             : /* Cf https://github.com/OSGeo/gdal/issues/1488 */
    8700             : /* The parent dataset should remain alive while the this dataset is alive */
    8701             : 
    8702        2333 : void GDALDataset::ShareLockWithParentDataset(GDALDataset *poParentDataset)
    8703             : {
    8704        2333 :     if (m_poPrivate != nullptr)
    8705             :     {
    8706        2333 :         m_poPrivate->poParentDataset = poParentDataset;
    8707             :     }
    8708        2333 : }
    8709             : 
    8710             : /************************************************************************/
    8711             : /*                   SetQueryLoggerFunc()                               */
    8712             : /************************************************************************/
    8713             : 
    8714           0 : bool GDALDataset::SetQueryLoggerFunc(CPL_UNUSED GDALQueryLoggerFunc callback,
    8715             :                                      CPL_UNUSED void *context)
    8716             : {
    8717           0 :     return false;
    8718             : }
    8719             : 
    8720             : /************************************************************************/
    8721             : /*                          EnterReadWrite()                            */
    8722             : /************************************************************************/
    8723             : 
    8724     8018820 : int GDALDataset::EnterReadWrite(GDALRWFlag eRWFlag)
    8725             : {
    8726    16037600 :     if (m_poPrivate == nullptr ||
    8727     8018820 :         IsThreadSafe(GDAL_OF_RASTER | (nOpenFlags & GDAL_OF_UPDATE)))
    8728       11985 :         return FALSE;
    8729             : 
    8730     8006840 :     if (m_poPrivate->poParentDataset)
    8731      242622 :         return m_poPrivate->poParentDataset->EnterReadWrite(eRWFlag);
    8732             : 
    8733     7764220 :     if (eAccess == GA_Update)
    8734             :     {
    8735     2211930 :         if (m_poPrivate->eStateReadWriteMutex ==
    8736             :             GDALAllowReadWriteMutexState::RW_MUTEX_STATE_UNKNOWN)
    8737             :         {
    8738             :             // In case dead-lock would occur, which is not impossible,
    8739             :             // this can be used to prevent it, but at the risk of other
    8740             :             // issues.
    8741       10662 :             if (CPLTestBool(
    8742             :                     CPLGetConfigOption("GDAL_ENABLE_READ_WRITE_MUTEX", "YES")))
    8743             :             {
    8744       10662 :                 m_poPrivate->eStateReadWriteMutex =
    8745             :                     GDALAllowReadWriteMutexState::RW_MUTEX_STATE_ALLOWED;
    8746             :             }
    8747             :             else
    8748             :             {
    8749           0 :                 m_poPrivate->eStateReadWriteMutex =
    8750             :                     GDALAllowReadWriteMutexState::RW_MUTEX_STATE_DISABLED;
    8751             :             }
    8752             :         }
    8753     2211930 :         if (m_poPrivate->eStateReadWriteMutex ==
    8754             :             GDALAllowReadWriteMutexState::RW_MUTEX_STATE_ALLOWED)
    8755             :         {
    8756             :             // There should be no race related to creating this mutex since
    8757             :             // it should be first created through IWriteBlock() / IRasterIO()
    8758             :             // and then GDALRasterBlock might call it from another thread.
    8759             : #ifdef DEBUG_VERBOSE
    8760             :             CPLDebug("GDAL",
    8761             :                      "[Thread " CPL_FRMT_GIB "] Acquiring RW mutex for %s",
    8762             :                      CPLGetPID(), GetDescription());
    8763             : #endif
    8764     1539610 :             CPLCreateOrAcquireMutex(&(m_poPrivate->hMutex), 1000.0);
    8765             : 
    8766             :             const int nCountMutex =
    8767     1539610 :                 m_poPrivate->oMapThreadToMutexTakenCount[CPLGetPID()]++;
    8768     1539610 :             if (nCountMutex == 0 && eRWFlag == GF_Read)
    8769             :             {
    8770      521208 :                 CPLReleaseMutex(m_poPrivate->hMutex);
    8771     1654830 :                 for (int i = 0; i < nBands; i++)
    8772             :                 {
    8773     1133630 :                     auto blockCache = papoBands[i]->poBandBlockCache;
    8774     1133630 :                     if (blockCache)
    8775      817120 :                         blockCache->WaitCompletionPendingTasks();
    8776             :                 }
    8777      521208 :                 CPLCreateOrAcquireMutex(&(m_poPrivate->hMutex), 1000.0);
    8778             :             }
    8779             : 
    8780     1539610 :             return TRUE;
    8781             :         }
    8782             :     }
    8783     6224610 :     return FALSE;
    8784             : }
    8785             : 
    8786             : /************************************************************************/
    8787             : /*                         LeaveReadWrite()                             */
    8788             : /************************************************************************/
    8789             : 
    8790     1768570 : void GDALDataset::LeaveReadWrite()
    8791             : {
    8792     1768570 :     if (m_poPrivate)
    8793             :     {
    8794     1768570 :         if (m_poPrivate->poParentDataset)
    8795             :         {
    8796      228962 :             m_poPrivate->poParentDataset->LeaveReadWrite();
    8797      228962 :             return;
    8798             :         }
    8799             : 
    8800     1539610 :         m_poPrivate->oMapThreadToMutexTakenCount[CPLGetPID()]--;
    8801     1539610 :         CPLReleaseMutex(m_poPrivate->hMutex);
    8802             : #ifdef DEBUG_VERBOSE
    8803             :         CPLDebug("GDAL", "[Thread " CPL_FRMT_GIB "] Releasing RW mutex for %s",
    8804             :                  CPLGetPID(), GetDescription());
    8805             : #endif
    8806             :     }
    8807             : }
    8808             : 
    8809             : /************************************************************************/
    8810             : /*                           InitRWLock()                               */
    8811             : /************************************************************************/
    8812             : 
    8813     3986570 : void GDALDataset::InitRWLock()
    8814             : {
    8815     3986570 :     if (m_poPrivate)
    8816             :     {
    8817     3986570 :         if (m_poPrivate->poParentDataset)
    8818             :         {
    8819        8584 :             m_poPrivate->poParentDataset->InitRWLock();
    8820        8584 :             return;
    8821             :         }
    8822             : 
    8823     3977990 :         if (m_poPrivate->eStateReadWriteMutex ==
    8824             :             GDALAllowReadWriteMutexState::RW_MUTEX_STATE_UNKNOWN)
    8825             :         {
    8826           1 :             if (EnterReadWrite(GF_Write))
    8827           1 :                 LeaveReadWrite();
    8828             :         }
    8829             :     }
    8830             : }
    8831             : 
    8832             : /************************************************************************/
    8833             : /*                       DisableReadWriteMutex()                        */
    8834             : /************************************************************************/
    8835             : 
    8836             : // The mutex logic is broken in multi-threaded situations, for example
    8837             : // with 2 WarpedVRT datasets being read at the same time. In that
    8838             : // particular case, the mutex is not needed, so allow the VRTWarpedDataset code
    8839             : // to disable it.
    8840       21359 : void GDALDataset::DisableReadWriteMutex()
    8841             : {
    8842       21359 :     if (m_poPrivate)
    8843             :     {
    8844       21359 :         if (m_poPrivate->poParentDataset)
    8845             :         {
    8846           0 :             m_poPrivate->poParentDataset->DisableReadWriteMutex();
    8847           0 :             return;
    8848             :         }
    8849             : 
    8850       21359 :         m_poPrivate->eStateReadWriteMutex =
    8851             :             GDALAllowReadWriteMutexState::RW_MUTEX_STATE_DISABLED;
    8852             :     }
    8853             : }
    8854             : 
    8855             : /************************************************************************/
    8856             : /*                      TemporarilyDropReadWriteLock()                  */
    8857             : /************************************************************************/
    8858             : 
    8859     3402900 : void GDALDataset::TemporarilyDropReadWriteLock()
    8860             : {
    8861     3402900 :     if (m_poPrivate == nullptr)
    8862           0 :         return;
    8863             : 
    8864     3402900 :     if (m_poPrivate->poParentDataset)
    8865             :     {
    8866       26346 :         m_poPrivate->poParentDataset->TemporarilyDropReadWriteLock();
    8867       26346 :         return;
    8868             :     }
    8869             : 
    8870             : #ifndef __COVERITY__
    8871     3376560 :     if (m_poPrivate->hMutex)
    8872             :     {
    8873             : #ifdef DEBUG_VERBOSE
    8874             :         CPLDebug("GDAL",
    8875             :                  "[Thread " CPL_FRMT_GIB "] "
    8876             :                  "Temporarily drop RW mutex for %s",
    8877             :                  CPLGetPID(), GetDescription());
    8878             : #endif
    8879      420857 :         CPLAcquireMutex(m_poPrivate->hMutex, 1000.0);
    8880             :         const int nCount =
    8881      420857 :             m_poPrivate->oMapThreadToMutexTakenCount[CPLGetPID()];
    8882             : #ifdef DEBUG_EXTRA
    8883             :         m_poPrivate->oMapThreadToMutexTakenCountSaved[CPLGetPID()] = nCount;
    8884             : #endif
    8885     1269580 :         for (int i = 0; i < nCount + 1; i++)
    8886             :         {
    8887             :             // The mutex is recursive
    8888      848719 :             CPLReleaseMutex(m_poPrivate->hMutex);
    8889             :         }
    8890             :     }
    8891             : #endif
    8892             : }
    8893             : 
    8894             : /************************************************************************/
    8895             : /*                       ReacquireReadWriteLock()                       */
    8896             : /************************************************************************/
    8897             : 
    8898     3402900 : void GDALDataset::ReacquireReadWriteLock()
    8899             : {
    8900     3402900 :     if (m_poPrivate == nullptr)
    8901           0 :         return;
    8902             : 
    8903     3402900 :     if (m_poPrivate->poParentDataset)
    8904             :     {
    8905       26346 :         m_poPrivate->poParentDataset->ReacquireReadWriteLock();
    8906       26346 :         return;
    8907             :     }
    8908             : 
    8909             : #ifndef __COVERITY__
    8910     3376560 :     if (m_poPrivate->hMutex)
    8911             :     {
    8912             : #ifdef DEBUG_VERBOSE
    8913             :         CPLDebug("GDAL",
    8914             :                  "[Thread " CPL_FRMT_GIB "] "
    8915             :                  "Reacquire temporarily dropped RW mutex for %s",
    8916             :                  CPLGetPID(), GetDescription());
    8917             : #endif
    8918      420858 :         CPLAcquireMutex(m_poPrivate->hMutex, 1000.0);
    8919             :         const int nCount =
    8920      420858 :             m_poPrivate->oMapThreadToMutexTakenCount[CPLGetPID()];
    8921             : #ifdef DEBUG_EXTRA
    8922             :         CPLAssert(nCount ==
    8923             :                   m_poPrivate->oMapThreadToMutexTakenCountSaved[CPLGetPID()]);
    8924             : #endif
    8925      420858 :         if (nCount == 0)
    8926       18665 :             CPLReleaseMutex(m_poPrivate->hMutex);
    8927      446527 :         for (int i = 0; i < nCount - 1; i++)
    8928             :         {
    8929             :             // The mutex is recursive
    8930       25669 :             CPLAcquireMutex(m_poPrivate->hMutex, 1000.0);
    8931             :         }
    8932             :     }
    8933             : #endif
    8934             : }
    8935             : 
    8936             : /************************************************************************/
    8937             : /*                           AcquireMutex()                             */
    8938             : /************************************************************************/
    8939             : 
    8940         196 : int GDALDataset::AcquireMutex()
    8941             : {
    8942         196 :     if (m_poPrivate == nullptr)
    8943           0 :         return 0;
    8944         196 :     if (m_poPrivate->poParentDataset)
    8945             :     {
    8946           0 :         return m_poPrivate->poParentDataset->AcquireMutex();
    8947             :     }
    8948             : 
    8949         196 :     return CPLCreateOrAcquireMutex(&(m_poPrivate->hMutex), 1000.0);
    8950             : }
    8951             : 
    8952             : /************************************************************************/
    8953             : /*                          ReleaseMutex()                              */
    8954             : /************************************************************************/
    8955             : 
    8956         196 : void GDALDataset::ReleaseMutex()
    8957             : {
    8958         196 :     if (m_poPrivate)
    8959             :     {
    8960         196 :         if (m_poPrivate->poParentDataset)
    8961             :         {
    8962           0 :             m_poPrivate->poParentDataset->ReleaseMutex();
    8963           0 :             return;
    8964             :         }
    8965             : 
    8966         196 :         CPLReleaseMutex(m_poPrivate->hMutex);
    8967             :     }
    8968             : }
    8969             : 
    8970             : //! @endcond
    8971             : 
    8972             : /************************************************************************/
    8973             : /*              GDALDataset::Features::Iterator::Private                */
    8974             : /************************************************************************/
    8975             : 
    8976             : struct GDALDataset::Features::Iterator::Private
    8977             : {
    8978             :     GDALDataset::FeatureLayerPair m_oPair{};
    8979             :     GDALDataset *m_poDS = nullptr;
    8980             :     bool m_bEOF = true;
    8981             : };
    8982             : 
    8983           4 : GDALDataset::Features::Iterator::Iterator(GDALDataset *poDS, bool bStart)
    8984           4 :     : m_poPrivate(new GDALDataset::Features::Iterator::Private())
    8985             : {
    8986           4 :     m_poPrivate->m_poDS = poDS;
    8987           4 :     if (bStart)
    8988             :     {
    8989           2 :         poDS->ResetReading();
    8990           4 :         m_poPrivate->m_oPair.feature.reset(poDS->GetNextFeature(
    8991           2 :             &m_poPrivate->m_oPair.layer, nullptr, nullptr, nullptr));
    8992           2 :         m_poPrivate->m_bEOF = m_poPrivate->m_oPair.feature == nullptr;
    8993             :     }
    8994           4 : }
    8995             : 
    8996             : GDALDataset::Features::Iterator::~Iterator() = default;
    8997             : 
    8998             : const GDALDataset::FeatureLayerPair &
    8999          20 : GDALDataset::Features::Iterator::operator*() const
    9000             : {
    9001          20 :     return m_poPrivate->m_oPair;
    9002             : }
    9003             : 
    9004          20 : GDALDataset::Features::Iterator &GDALDataset::Features::Iterator::operator++()
    9005             : {
    9006          40 :     m_poPrivate->m_oPair.feature.reset(m_poPrivate->m_poDS->GetNextFeature(
    9007          20 :         &m_poPrivate->m_oPair.layer, nullptr, nullptr, nullptr));
    9008          20 :     m_poPrivate->m_bEOF = m_poPrivate->m_oPair.feature == nullptr;
    9009          20 :     return *this;
    9010             : }
    9011             : 
    9012          22 : bool GDALDataset::Features::Iterator::operator!=(const Iterator &it) const
    9013             : {
    9014          22 :     return m_poPrivate->m_bEOF != it.m_poPrivate->m_bEOF;
    9015             : }
    9016             : 
    9017             : /************************************************************************/
    9018             : /*                            GetFeatures()                             */
    9019             : /************************************************************************/
    9020             : 
    9021             : /** Function that return an iterable object over features in the dataset
    9022             :  * layer.
    9023             :  *
    9024             :  * This is a C++ iterator friendly version of GetNextFeature().
    9025             :  *
    9026             :  * Using this iterator for standard range-based loops is safe, but
    9027             :  * due to implementation limitations, you shouldn't try to access
    9028             :  * (dereference) more than one iterator step at a time, since the
    9029             :  * FeatureLayerPair reference which is returned is reused.
    9030             :  *
    9031             :  * Typical use is:
    9032             :  * \code{.cpp}
    9033             :  * for( auto&& oFeatureLayerPair: poDS->GetFeatures() )
    9034             :  * {
    9035             :  *       std::cout << "Feature of layer " <<
    9036             :  *               oFeatureLayerPair.layer->GetName() << std::endl;
    9037             :  *       oFeatureLayerPair.feature->DumpReadable();
    9038             :  * }
    9039             :  * \endcode
    9040             :  *
    9041             :  * @see GetNextFeature()
    9042             :  *
    9043             :  */
    9044           2 : GDALDataset::Features GDALDataset::GetFeatures()
    9045             : {
    9046           2 :     return Features(this);
    9047             : }
    9048             : 
    9049             : /************************************************************************/
    9050             : /*                                 begin()                              */
    9051             : /************************************************************************/
    9052             : 
    9053             : /**
    9054             :  \brief Return beginning of feature iterator.
    9055             : 
    9056             : */
    9057             : 
    9058           2 : const GDALDataset::Features::Iterator GDALDataset::Features::begin() const
    9059             : {
    9060           2 :     return {m_poSelf, true};
    9061             : }
    9062             : 
    9063             : /************************************************************************/
    9064             : /*                                  end()                               */
    9065             : /************************************************************************/
    9066             : 
    9067             : /**
    9068             :  \brief Return end of feature iterator.
    9069             : 
    9070             : */
    9071             : 
    9072           2 : const GDALDataset::Features::Iterator GDALDataset::Features::end() const
    9073             : {
    9074           2 :     return {m_poSelf, false};
    9075             : }
    9076             : 
    9077             : /************************************************************************/
    9078             : /*               GDALDataset::Layers::Iterator::Private                 */
    9079             : /************************************************************************/
    9080             : 
    9081             : struct GDALDataset::Layers::Iterator::Private
    9082             : {
    9083             :     OGRLayer *m_poLayer = nullptr;
    9084             :     int m_iCurLayer = 0;
    9085             :     int m_nLayerCount = 0;
    9086             :     GDALDataset *m_poDS = nullptr;
    9087             : };
    9088             : 
    9089           2 : GDALDataset::Layers::Iterator::Iterator() : m_poPrivate(new Private())
    9090             : {
    9091           2 : }
    9092             : 
    9093             : // False positive of cppcheck 1.72
    9094             : // cppcheck-suppress uninitMemberVar
    9095           9 : GDALDataset::Layers::Iterator::Iterator(const Iterator &oOther)
    9096           9 :     : m_poPrivate(new Private(*(oOther.m_poPrivate)))
    9097             : {
    9098           9 : }
    9099             : 
    9100           5 : GDALDataset::Layers::Iterator::Iterator(Iterator &&oOther) noexcept
    9101           5 :     : m_poPrivate(std::move(oOther.m_poPrivate))
    9102             : {
    9103           5 : }
    9104             : 
    9105         648 : GDALDataset::Layers::Iterator::Iterator(GDALDataset *poDS, bool bStart)
    9106         648 :     : m_poPrivate(new Private())
    9107             : {
    9108         648 :     m_poPrivate->m_poDS = poDS;
    9109         648 :     m_poPrivate->m_nLayerCount = poDS->GetLayerCount();
    9110         648 :     if (bStart)
    9111             :     {
    9112         326 :         if (m_poPrivate->m_nLayerCount)
    9113         313 :             m_poPrivate->m_poLayer = poDS->GetLayer(0);
    9114             :     }
    9115             :     else
    9116             :     {
    9117         322 :         m_poPrivate->m_iCurLayer = m_poPrivate->m_nLayerCount;
    9118             :     }
    9119         648 : }
    9120             : 
    9121             : GDALDataset::Layers::Iterator::~Iterator() = default;
    9122             : 
    9123             : // False positive of cppcheck 1.72
    9124             : // cppcheck-suppress operatorEqVarError
    9125             : GDALDataset::Layers::Iterator &
    9126           1 : GDALDataset::Layers::Iterator::operator=(const Iterator &oOther)
    9127             : {
    9128           1 :     *m_poPrivate = *oOther.m_poPrivate;
    9129           1 :     return *this;
    9130             : }
    9131             : 
    9132           3 : GDALDataset::Layers::Iterator &GDALDataset::Layers::Iterator::operator=(
    9133             :     GDALDataset::Layers::Iterator &&oOther) noexcept
    9134             : {
    9135           3 :     m_poPrivate = std::move(oOther.m_poPrivate);
    9136           3 :     return *this;
    9137             : }
    9138             : 
    9139         377 : OGRLayer *GDALDataset::Layers::Iterator::operator*() const
    9140             : {
    9141         377 :     return m_poPrivate->m_poLayer;
    9142             : }
    9143             : 
    9144         358 : GDALDataset::Layers::Iterator &GDALDataset::Layers::Iterator::operator++()
    9145             : {
    9146         358 :     m_poPrivate->m_iCurLayer++;
    9147         358 :     if (m_poPrivate->m_iCurLayer < m_poPrivate->m_nLayerCount)
    9148             :     {
    9149          70 :         m_poPrivate->m_poLayer =
    9150          70 :             m_poPrivate->m_poDS->GetLayer(m_poPrivate->m_iCurLayer);
    9151             :     }
    9152             :     else
    9153             :     {
    9154         288 :         m_poPrivate->m_poLayer = nullptr;
    9155             :     }
    9156         358 :     return *this;
    9157             : }
    9158             : 
    9159           2 : GDALDataset::Layers::Iterator GDALDataset::Layers::Iterator::operator++(int)
    9160             : {
    9161           2 :     GDALDataset::Layers::Iterator temp = *this;
    9162           2 :     ++(*this);
    9163           2 :     return temp;
    9164             : }
    9165             : 
    9166         674 : bool GDALDataset::Layers::Iterator::operator!=(const Iterator &it) const
    9167             : {
    9168         674 :     return m_poPrivate->m_iCurLayer != it.m_poPrivate->m_iCurLayer;
    9169             : }
    9170             : 
    9171             : /************************************************************************/
    9172             : /*                             GetLayers()                              */
    9173             : /************************************************************************/
    9174             : 
    9175             : /** Function that returns an iterable object over layers in the dataset.
    9176             :  *
    9177             :  * This is a C++ iterator friendly version of GetLayer().
    9178             :  *
    9179             :  * Typical use is:
    9180             :  * \code{.cpp}
    9181             :  * for( auto&& poLayer: poDS->GetLayers() )
    9182             :  * {
    9183             :  *       std::cout << "Layer  << poLayer->GetName() << std::endl;
    9184             :  * }
    9185             :  * \endcode
    9186             :  *
    9187             :  * @see GetLayer()
    9188             :  *
    9189             :  */
    9190         327 : GDALDataset::Layers GDALDataset::GetLayers()
    9191             : {
    9192         327 :     return Layers(this);
    9193             : }
    9194             : 
    9195             : /************************************************************************/
    9196             : /*                                 begin()                              */
    9197             : /************************************************************************/
    9198             : 
    9199             : /**
    9200             :  \brief Return beginning of layer iterator.
    9201             : 
    9202             : */
    9203             : 
    9204         326 : GDALDataset::Layers::Iterator GDALDataset::Layers::begin() const
    9205             : {
    9206         326 :     return {m_poSelf, true};
    9207             : }
    9208             : 
    9209             : /************************************************************************/
    9210             : /*                                  end()                               */
    9211             : /************************************************************************/
    9212             : 
    9213             : /**
    9214             :  \brief Return end of layer iterator.
    9215             : 
    9216             : */
    9217             : 
    9218         322 : GDALDataset::Layers::Iterator GDALDataset::Layers::end() const
    9219             : {
    9220         322 :     return {m_poSelf, false};
    9221             : }
    9222             : 
    9223             : /************************************************************************/
    9224             : /*                                  size()                             */
    9225             : /************************************************************************/
    9226             : 
    9227             : /**
    9228             :  \brief Get the number of layers in this dataset.
    9229             : 
    9230             :  @return layer count.
    9231             : 
    9232             : */
    9233             : 
    9234           1 : size_t GDALDataset::Layers::size() const
    9235             : {
    9236           1 :     return static_cast<size_t>(m_poSelf->GetLayerCount());
    9237             : }
    9238             : 
    9239             : /************************************************************************/
    9240             : /*                                operator[]()                          */
    9241             : /************************************************************************/
    9242             : /**
    9243             :  \brief Fetch a layer by index.
    9244             : 
    9245             :  The returned layer remains owned by the
    9246             :  GDALDataset and should not be deleted by the application.
    9247             : 
    9248             :  @param iLayer a layer number between 0 and size()-1.
    9249             : 
    9250             :  @return the layer, or nullptr if iLayer is out of range or an error occurs.
    9251             : 
    9252             : */
    9253             : 
    9254           9 : OGRLayer *GDALDataset::Layers::operator[](int iLayer)
    9255             : {
    9256           9 :     return m_poSelf->GetLayer(iLayer);
    9257             : }
    9258             : 
    9259             : /************************************************************************/
    9260             : /*                                operator[]()                          */
    9261             : /************************************************************************/
    9262             : /**
    9263             :  \brief Fetch a layer by index.
    9264             : 
    9265             :  The returned layer remains owned by the
    9266             :  GDALDataset and should not be deleted by the application.
    9267             : 
    9268             :  @param iLayer a layer number between 0 and size()-1.
    9269             : 
    9270             :  @return the layer, or nullptr if iLayer is out of range or an error occurs.
    9271             : 
    9272             : */
    9273             : 
    9274           1 : OGRLayer *GDALDataset::Layers::operator[](size_t iLayer)
    9275             : {
    9276           1 :     return m_poSelf->GetLayer(static_cast<int>(iLayer));
    9277             : }
    9278             : 
    9279             : /************************************************************************/
    9280             : /*                                operator[]()                          */
    9281             : /************************************************************************/
    9282             : /**
    9283             :  \brief Fetch a layer by name.
    9284             : 
    9285             :  The returned layer remains owned by the
    9286             :  GDALDataset and should not be deleted by the application.
    9287             : 
    9288             :  @param pszLayerName layer name
    9289             : 
    9290             :  @return the layer, or nullptr if pszLayerName does not match with a layer
    9291             : 
    9292             : */
    9293             : 
    9294           1 : OGRLayer *GDALDataset::Layers::operator[](const char *pszLayerName)
    9295             : {
    9296           1 :     return m_poSelf->GetLayerByName(pszLayerName);
    9297             : }
    9298             : 
    9299             : /************************************************************************/
    9300             : /*               GDALDataset::ConstLayers::Iterator::Private            */
    9301             : /************************************************************************/
    9302             : 
    9303             : struct GDALDataset::ConstLayers::Iterator::Private
    9304             : {
    9305             :     const OGRLayer *m_poLayer = nullptr;
    9306             :     int m_iCurLayer = 0;
    9307             :     int m_nLayerCount = 0;
    9308             :     const GDALDataset *m_poDS = nullptr;
    9309             : };
    9310             : 
    9311           2 : GDALDataset::ConstLayers::Iterator::Iterator() : m_poPrivate(new Private())
    9312             : {
    9313           2 : }
    9314             : 
    9315             : // False positive of cppcheck 1.72
    9316             : // cppcheck-suppress uninitMemberVar
    9317           9 : GDALDataset::ConstLayers::Iterator::Iterator(const Iterator &oOther)
    9318           9 :     : m_poPrivate(new Private(*(oOther.m_poPrivate)))
    9319             : {
    9320           9 : }
    9321             : 
    9322           5 : GDALDataset::ConstLayers::Iterator::Iterator(Iterator &&oOther) noexcept
    9323           5 :     : m_poPrivate(std::move(oOther.m_poPrivate))
    9324             : {
    9325           5 : }
    9326             : 
    9327       35126 : GDALDataset::ConstLayers::Iterator::Iterator(const GDALDataset *poDS,
    9328       35126 :                                              bool bStart)
    9329       35126 :     : m_poPrivate(new Private())
    9330             : {
    9331       35126 :     m_poPrivate->m_poDS = poDS;
    9332       35126 :     m_poPrivate->m_nLayerCount = poDS->GetLayerCount();
    9333       35126 :     if (bStart)
    9334             :     {
    9335       17565 :         if (m_poPrivate->m_nLayerCount)
    9336         218 :             m_poPrivate->m_poLayer = poDS->GetLayer(0);
    9337             :     }
    9338             :     else
    9339             :     {
    9340       17561 :         m_poPrivate->m_iCurLayer = m_poPrivate->m_nLayerCount;
    9341             :     }
    9342       35126 : }
    9343             : 
    9344             : GDALDataset::ConstLayers::Iterator::~Iterator() = default;
    9345             : 
    9346             : // False positive of cppcheck 1.72
    9347             : // cppcheck-suppress operatorEqVarError
    9348             : GDALDataset::ConstLayers::Iterator &
    9349           1 : GDALDataset::ConstLayers::Iterator::operator=(const Iterator &oOther)
    9350             : {
    9351           1 :     *m_poPrivate = *oOther.m_poPrivate;
    9352           1 :     return *this;
    9353             : }
    9354             : 
    9355             : GDALDataset::ConstLayers::Iterator &
    9356           3 : GDALDataset::ConstLayers::Iterator::operator=(
    9357             :     GDALDataset::ConstLayers::Iterator &&oOther) noexcept
    9358             : {
    9359           3 :     m_poPrivate = std::move(oOther.m_poPrivate);
    9360           3 :     return *this;
    9361             : }
    9362             : 
    9363       16176 : const OGRLayer *GDALDataset::ConstLayers::Iterator::operator*() const
    9364             : {
    9365       16176 :     return m_poPrivate->m_poLayer;
    9366             : }
    9367             : 
    9368             : GDALDataset::ConstLayers::Iterator &
    9369       16171 : GDALDataset::ConstLayers::Iterator::operator++()
    9370             : {
    9371       16171 :     m_poPrivate->m_iCurLayer++;
    9372       16171 :     if (m_poPrivate->m_iCurLayer < m_poPrivate->m_nLayerCount)
    9373             :     {
    9374       15964 :         m_poPrivate->m_poLayer =
    9375       15964 :             m_poPrivate->m_poDS->GetLayer(m_poPrivate->m_iCurLayer);
    9376             :     }
    9377             :     else
    9378             :     {
    9379         207 :         m_poPrivate->m_poLayer = nullptr;
    9380             :     }
    9381       16171 :     return *this;
    9382             : }
    9383             : 
    9384             : GDALDataset::ConstLayers::Iterator
    9385           2 : GDALDataset::ConstLayers::Iterator::operator++(int)
    9386             : {
    9387           2 :     GDALDataset::ConstLayers::Iterator temp = *this;
    9388           2 :     ++(*this);
    9389           2 :     return temp;
    9390             : }
    9391             : 
    9392       33726 : bool GDALDataset::ConstLayers::Iterator::operator!=(const Iterator &it) const
    9393             : {
    9394       33726 :     return m_poPrivate->m_iCurLayer != it.m_poPrivate->m_iCurLayer;
    9395             : }
    9396             : 
    9397             : /************************************************************************/
    9398             : /*                             GetLayers()                              */
    9399             : /************************************************************************/
    9400             : 
    9401             : /** Function that returns an iterable object over layers in the dataset.
    9402             :  *
    9403             :  * This is a C++ iterator friendly version of GetLayer().
    9404             :  *
    9405             :  * Typical use is:
    9406             :  * \code{.cpp}
    9407             :  * for( auto&& poLayer: poDS->GetLayers() )
    9408             :  * {
    9409             :  *       std::cout << "Layer  << poLayer->GetName() << std::endl;
    9410             :  * }
    9411             :  * \endcode
    9412             :  *
    9413             :  * @see GetLayer()
    9414             :  *
    9415             :  * @since GDAL 3.12
    9416             :  */
    9417       17566 : GDALDataset::ConstLayers GDALDataset::GetLayers() const
    9418             : {
    9419       17566 :     return ConstLayers(this);
    9420             : }
    9421             : 
    9422             : /************************************************************************/
    9423             : /*                                 begin()                              */
    9424             : /************************************************************************/
    9425             : 
    9426             : /**
    9427             :  \brief Return beginning of layer iterator.
    9428             : 
    9429             :  @since GDAL 3.12
    9430             : */
    9431             : 
    9432       17565 : GDALDataset::ConstLayers::Iterator GDALDataset::ConstLayers::begin() const
    9433             : {
    9434       17565 :     return {m_poSelf, true};
    9435             : }
    9436             : 
    9437             : /************************************************************************/
    9438             : /*                                  end()                               */
    9439             : /************************************************************************/
    9440             : 
    9441             : /**
    9442             :  \brief Return end of layer iterator.
    9443             : 
    9444             :  @since GDAL 3.12
    9445             : */
    9446             : 
    9447       17561 : GDALDataset::ConstLayers::Iterator GDALDataset::ConstLayers::end() const
    9448             : {
    9449       17561 :     return {m_poSelf, false};
    9450             : }
    9451             : 
    9452             : /************************************************************************/
    9453             : /*                                  size()                             */
    9454             : /************************************************************************/
    9455             : 
    9456             : /**
    9457             :  \brief Get the number of layers in this dataset.
    9458             : 
    9459             :  @return layer count.
    9460             : 
    9461             :  @since GDAL 3.12
    9462             : */
    9463             : 
    9464           1 : size_t GDALDataset::ConstLayers::size() const
    9465             : {
    9466           1 :     return static_cast<size_t>(m_poSelf->GetLayerCount());
    9467             : }
    9468             : 
    9469             : /************************************************************************/
    9470             : /*                                operator[]()                          */
    9471             : /************************************************************************/
    9472             : /**
    9473             :  \brief Fetch a layer by index.
    9474             : 
    9475             :  The returned layer remains owned by the
    9476             :  GDALDataset and should not be deleted by the application.
    9477             : 
    9478             :  @param iLayer a layer number between 0 and size()-1.
    9479             : 
    9480             :  @return the layer, or nullptr if iLayer is out of range or an error occurs.
    9481             : 
    9482             :  @since GDAL 3.12
    9483             : */
    9484             : 
    9485           9 : const OGRLayer *GDALDataset::ConstLayers::operator[](int iLayer)
    9486             : {
    9487           9 :     return m_poSelf->GetLayer(iLayer);
    9488             : }
    9489             : 
    9490             : /************************************************************************/
    9491             : /*                                operator[]()                          */
    9492             : /************************************************************************/
    9493             : /**
    9494             :  \brief Fetch a layer by index.
    9495             : 
    9496             :  The returned layer remains owned by the
    9497             :  GDALDataset and should not be deleted by the application.
    9498             : 
    9499             :  @param iLayer a layer number between 0 and size()-1.
    9500             : 
    9501             :  @return the layer, or nullptr if iLayer is out of range or an error occurs.
    9502             : 
    9503             :  @since GDAL 3.12
    9504             : */
    9505             : 
    9506           1 : const OGRLayer *GDALDataset::ConstLayers::operator[](size_t iLayer)
    9507             : {
    9508           1 :     return m_poSelf->GetLayer(static_cast<int>(iLayer));
    9509             : }
    9510             : 
    9511             : /************************************************************************/
    9512             : /*                                operator[]()                          */
    9513             : /************************************************************************/
    9514             : /**
    9515             :  \brief Fetch a layer by name.
    9516             : 
    9517             :  The returned layer remains owned by the
    9518             :  GDALDataset and should not be deleted by the application.
    9519             : 
    9520             :  @param pszLayerName layer name
    9521             : 
    9522             :  @return the layer, or nullptr if pszLayerName does not match with a layer
    9523             : 
    9524             :  @since GDAL 3.12
    9525             : */
    9526             : 
    9527           1 : const OGRLayer *GDALDataset::ConstLayers::operator[](const char *pszLayerName)
    9528             : {
    9529           1 :     return const_cast<GDALDataset *>(m_poSelf)->GetLayerByName(pszLayerName);
    9530             : }
    9531             : 
    9532             : /************************************************************************/
    9533             : /*               GDALDataset::Bands::Iterator::Private                 */
    9534             : /************************************************************************/
    9535             : 
    9536             : struct GDALDataset::Bands::Iterator::Private
    9537             : {
    9538             :     GDALRasterBand *m_poBand = nullptr;
    9539             :     int m_iCurBand = 0;
    9540             :     int m_nBandCount = 0;
    9541             :     GDALDataset *m_poDS = nullptr;
    9542             : };
    9543             : 
    9544           6 : GDALDataset::Bands::Iterator::Iterator(GDALDataset *poDS, bool bStart)
    9545           6 :     : m_poPrivate(new GDALDataset::Bands::Iterator::Private())
    9546             : {
    9547           6 :     m_poPrivate->m_poDS = poDS;
    9548           6 :     m_poPrivate->m_nBandCount = poDS->GetRasterCount();
    9549           6 :     if (bStart)
    9550             :     {
    9551           3 :         if (m_poPrivate->m_nBandCount)
    9552           3 :             m_poPrivate->m_poBand = poDS->GetRasterBand(1);
    9553             :     }
    9554             :     else
    9555             :     {
    9556           3 :         m_poPrivate->m_iCurBand = m_poPrivate->m_nBandCount;
    9557             :     }
    9558           6 : }
    9559             : 
    9560             : GDALDataset::Bands::Iterator::~Iterator() = default;
    9561             : 
    9562           5 : GDALRasterBand *GDALDataset::Bands::Iterator::operator*()
    9563             : {
    9564           5 :     return m_poPrivate->m_poBand;
    9565             : }
    9566             : 
    9567           3 : GDALDataset::Bands::Iterator &GDALDataset::Bands::Iterator::operator++()
    9568             : {
    9569           3 :     m_poPrivate->m_iCurBand++;
    9570           3 :     if (m_poPrivate->m_iCurBand < m_poPrivate->m_nBandCount)
    9571             :     {
    9572           2 :         m_poPrivate->m_poBand =
    9573           2 :             m_poPrivate->m_poDS->GetRasterBand(1 + m_poPrivate->m_iCurBand);
    9574             :     }
    9575             :     else
    9576             :     {
    9577           1 :         m_poPrivate->m_poBand = nullptr;
    9578             :     }
    9579           3 :     return *this;
    9580             : }
    9581             : 
    9582           6 : bool GDALDataset::Bands::Iterator::operator!=(const Iterator &it) const
    9583             : {
    9584           6 :     return m_poPrivate->m_iCurBand != it.m_poPrivate->m_iCurBand;
    9585             : }
    9586             : 
    9587             : /************************************************************************/
    9588             : /*                              GetBands()                              */
    9589             : /************************************************************************/
    9590             : 
    9591             : /** Function that returns an iterable object over GDALRasterBand in the dataset.
    9592             :  *
    9593             :  * This is a C++ iterator friendly version of GetRasterBand().
    9594             :  *
    9595             :  * Typical use is:
    9596             :  * \code{.cpp}
    9597             :  * for( auto&& poBand: poDS->GetBands() )
    9598             :  * {
    9599             :  *       std::cout << "Band  << poBand->GetDescription() << std::endl;
    9600             :  * }
    9601             :  * \endcode
    9602             :  *
    9603             :  * @see GetRasterBand()
    9604             :  *
    9605             :  */
    9606           7 : GDALDataset::Bands GDALDataset::GetBands()
    9607             : {
    9608           7 :     return Bands(this);
    9609             : }
    9610             : 
    9611             : /************************************************************************/
    9612             : /*                                 begin()                              */
    9613             : /************************************************************************/
    9614             : 
    9615             : /**
    9616             :  \brief Return beginning of band iterator.
    9617             : 
    9618             : */
    9619             : 
    9620           3 : const GDALDataset::Bands::Iterator GDALDataset::Bands::begin() const
    9621             : {
    9622           3 :     return {m_poSelf, true};
    9623             : }
    9624             : 
    9625             : /************************************************************************/
    9626             : /*                                  end()                               */
    9627             : /************************************************************************/
    9628             : 
    9629             : /**
    9630             :  \brief Return end of band iterator.
    9631             : 
    9632             : */
    9633             : 
    9634           3 : const GDALDataset::Bands::Iterator GDALDataset::Bands::end() const
    9635             : {
    9636           3 :     return {m_poSelf, false};
    9637             : }
    9638             : 
    9639             : /************************************************************************/
    9640             : /*                                  size()                             */
    9641             : /************************************************************************/
    9642             : 
    9643             : /**
    9644             :  \brief Get the number of raster bands in this dataset.
    9645             : 
    9646             :  @return raster band count.
    9647             : 
    9648             : */
    9649             : 
    9650           2 : size_t GDALDataset::Bands::size() const
    9651             : {
    9652           2 :     return static_cast<size_t>(m_poSelf->GetRasterCount());
    9653             : }
    9654             : 
    9655             : /************************************************************************/
    9656             : /*                                operator[]()                          */
    9657             : /************************************************************************/
    9658             : /**
    9659             :  \brief Fetch a raster band by index.
    9660             : 
    9661             :  The returned band remains owned by the
    9662             :  GDALDataset and should not be deleted by the application.
    9663             : 
    9664             :  @warning Contrary to GDALDataset::GetRasterBand(), the indexing here is
    9665             :  consistent with the conventions of C/C++, i.e. starting at 0.
    9666             : 
    9667             :  @param iBand a band index between 0 and size()-1.
    9668             : 
    9669             :  @return the band, or nullptr if iBand is out of range or an error occurs.
    9670             : 
    9671             : */
    9672             : 
    9673           1 : GDALRasterBand *GDALDataset::Bands::operator[](int iBand)
    9674             : {
    9675           1 :     return m_poSelf->GetRasterBand(1 + iBand);
    9676             : }
    9677             : 
    9678             : /************************************************************************/
    9679             : /*                                operator[]()                          */
    9680             : /************************************************************************/
    9681             : 
    9682             : /**
    9683             :  \brief Fetch a raster band by index.
    9684             : 
    9685             :  The returned band remains owned by the
    9686             :  GDALDataset and should not be deleted by the application.
    9687             : 
    9688             :  @warning Contrary to GDALDataset::GetRasterBand(), the indexing here is
    9689             :  consistent with the conventions of C/C++, i.e. starting at 0.
    9690             : 
    9691             :  @param iBand a band index between 0 and size()-1.
    9692             : 
    9693             :  @return the band, or nullptr if iBand is out of range or an error occurs.
    9694             : 
    9695             : */
    9696             : 
    9697           1 : GDALRasterBand *GDALDataset::Bands::operator[](size_t iBand)
    9698             : {
    9699           1 :     return m_poSelf->GetRasterBand(1 + static_cast<int>(iBand));
    9700             : }
    9701             : 
    9702             : /************************************************************************/
    9703             : /*               GDALDataset::ConstBands::Iterator::Private             */
    9704             : /************************************************************************/
    9705             : 
    9706             : struct GDALDataset::ConstBands::Iterator::Private
    9707             : {
    9708             :     const GDALRasterBand *m_poBand = nullptr;
    9709             :     int m_iCurBand = 0;
    9710             :     int m_nBandCount = 0;
    9711             :     const GDALDataset *m_poDS = nullptr;
    9712             : };
    9713             : 
    9714           2 : GDALDataset::ConstBands::Iterator::Iterator(const GDALDataset *poDS,
    9715           2 :                                             bool bStart)
    9716           2 :     : m_poPrivate(new GDALDataset::ConstBands::Iterator::Private())
    9717             : {
    9718           2 :     m_poPrivate->m_poDS = poDS;
    9719           2 :     m_poPrivate->m_nBandCount = poDS->GetRasterCount();
    9720           2 :     if (bStart)
    9721             :     {
    9722           1 :         if (m_poPrivate->m_nBandCount)
    9723           1 :             m_poPrivate->m_poBand = poDS->GetRasterBand(1);
    9724             :     }
    9725             :     else
    9726             :     {
    9727           1 :         m_poPrivate->m_iCurBand = m_poPrivate->m_nBandCount;
    9728             :     }
    9729           2 : }
    9730             : 
    9731             : GDALDataset::ConstBands::Iterator::~Iterator() = default;
    9732             : 
    9733           3 : const GDALRasterBand *GDALDataset::ConstBands::Iterator::operator*() const
    9734             : {
    9735           3 :     return m_poPrivate->m_poBand;
    9736             : }
    9737             : 
    9738             : GDALDataset::ConstBands::Iterator &
    9739           3 : GDALDataset::ConstBands::Iterator::operator++()
    9740             : {
    9741           3 :     m_poPrivate->m_iCurBand++;
    9742           3 :     if (m_poPrivate->m_iCurBand < m_poPrivate->m_nBandCount)
    9743             :     {
    9744           2 :         m_poPrivate->m_poBand =
    9745           2 :             m_poPrivate->m_poDS->GetRasterBand(1 + m_poPrivate->m_iCurBand);
    9746             :     }
    9747             :     else
    9748             :     {
    9749           1 :         m_poPrivate->m_poBand = nullptr;
    9750             :     }
    9751           3 :     return *this;
    9752             : }
    9753             : 
    9754           4 : bool GDALDataset::ConstBands::Iterator::operator!=(const Iterator &it) const
    9755             : {
    9756           4 :     return m_poPrivate->m_iCurBand != it.m_poPrivate->m_iCurBand;
    9757             : }
    9758             : 
    9759             : /************************************************************************/
    9760             : /*                             GetBands()                               */
    9761             : /************************************************************************/
    9762             : 
    9763             : /** Function that returns an iterable object over GDALRasterBand in the dataset.
    9764             :  *
    9765             :  * This is a C++ iterator friendly version of GetRasterBand().
    9766             :  *
    9767             :  * Typical use is:
    9768             :  * \code{.cpp}
    9769             :  * for( const auto* poBand: poDS->GetConstBands() )
    9770             :  * {
    9771             :  *       std::cout << "Band  << poBand->GetDescription() << std::endl;
    9772             :  * }
    9773             :  * \endcode
    9774             :  *
    9775             :  * @see GetRasterBand()
    9776             :  *
    9777             :  * @since GDAL 3.12
    9778             :  */
    9779           4 : GDALDataset::ConstBands GDALDataset::GetBands() const
    9780             : {
    9781           4 :     return ConstBands(this);
    9782             : }
    9783             : 
    9784             : /************************************************************************/
    9785             : /*                                 begin()                              */
    9786             : /************************************************************************/
    9787             : 
    9788             : /**
    9789             :  \brief Return beginning of band iterator.
    9790             : 
    9791             :  @since GDAL 3.12
    9792             : */
    9793             : 
    9794           1 : const GDALDataset::ConstBands::Iterator GDALDataset::ConstBands::begin() const
    9795             : {
    9796           1 :     return {m_poSelf, true};
    9797             : }
    9798             : 
    9799             : /************************************************************************/
    9800             : /*                                  end()                               */
    9801             : /************************************************************************/
    9802             : 
    9803             : /**
    9804             :  \brief Return end of band iterator.
    9805             : 
    9806             :  @since GDAL 3.12
    9807             : */
    9808             : 
    9809           1 : const GDALDataset::ConstBands::Iterator GDALDataset::ConstBands::end() const
    9810             : {
    9811           1 :     return {m_poSelf, false};
    9812             : }
    9813             : 
    9814             : /************************************************************************/
    9815             : /*                                  size()                             */
    9816             : /************************************************************************/
    9817             : 
    9818             : /**
    9819             :  \brief Get the number of raster bands in this dataset.
    9820             : 
    9821             :  @return raster band count.
    9822             : 
    9823             :  @since GDAL 3.12
    9824             : */
    9825             : 
    9826           1 : size_t GDALDataset::ConstBands::size() const
    9827             : {
    9828           1 :     return static_cast<size_t>(m_poSelf->GetRasterCount());
    9829             : }
    9830             : 
    9831             : /************************************************************************/
    9832             : /*                                operator[]()                          */
    9833             : /************************************************************************/
    9834             : /**
    9835             :  \brief Fetch a raster band by index.
    9836             : 
    9837             :  The returned band remains owned by the
    9838             :  GDALDataset and should not be deleted by the application.
    9839             : 
    9840             :  @warning Contrary to GDALDataset::GetRasterBand(), the indexing here is
    9841             :  consistent with the conventions of C/C++, i.e. starting at 0.
    9842             : 
    9843             :  @param iBand a band index between 0 and size()-1.
    9844             : 
    9845             :  @return the band, or nullptr if iBand is out of range or an error occurs.
    9846             : 
    9847             :  @since GDAL 3.12
    9848             : */
    9849             : 
    9850           1 : const GDALRasterBand *GDALDataset::ConstBands::operator[](int iBand) const
    9851             : {
    9852           1 :     return m_poSelf->GetRasterBand(1 + iBand);
    9853             : }
    9854             : 
    9855             : /************************************************************************/
    9856             : /*                                operator[]()                          */
    9857             : /************************************************************************/
    9858             : 
    9859             : /**
    9860             :  \brief Fetch a raster band by index.
    9861             : 
    9862             :  The returned band remains owned by the
    9863             :  GDALDataset and should not be deleted by the application.
    9864             : 
    9865             :  @warning Contrary to GDALDataset::GetRasterBand(), the indexing here is
    9866             :  consistent with the conventions of C/C++, i.e. starting at 0.
    9867             : 
    9868             :  @param iBand a band index between 0 and size()-1.
    9869             : 
    9870             :  @return the band, or nullptr if iBand is out of range or an error occurs.
    9871             : 
    9872             :  @since GDAL 3.12
    9873             : */
    9874             : 
    9875           1 : const GDALRasterBand *GDALDataset::ConstBands::operator[](size_t iBand) const
    9876             : {
    9877           1 :     return m_poSelf->GetRasterBand(1 + static_cast<int>(iBand));
    9878             : }
    9879             : 
    9880             : /************************************************************************/
    9881             : /*                           GetRootGroup()                             */
    9882             : /************************************************************************/
    9883             : 
    9884             : /**
    9885             :  \brief Return the root GDALGroup of this dataset.
    9886             : 
    9887             :  Only valid for multidimensional datasets.
    9888             : 
    9889             :  This is the same as the C function GDALDatasetGetRootGroup().
    9890             : 
    9891             :  @since GDAL 3.1
    9892             : */
    9893             : 
    9894        2875 : std::shared_ptr<GDALGroup> GDALDataset::GetRootGroup() const
    9895             : {
    9896        2875 :     return nullptr;
    9897             : }
    9898             : 
    9899             : /************************************************************************/
    9900             : /*                        GetRawBinaryLayout()                          */
    9901             : /************************************************************************/
    9902             : 
    9903             : //! @cond Doxygen_Suppress
    9904             : /**
    9905             :  \brief Return the layout of a dataset that can be considered as a raw binary
    9906             :  format.
    9907             : 
    9908             :  @param sLayout Structure that will be set if the dataset is a raw binary one.
    9909             :  @return true if the dataset is a raw binary one.
    9910             :  @since GDAL 3.1
    9911             : */
    9912             : 
    9913           0 : bool GDALDataset::GetRawBinaryLayout(RawBinaryLayout &sLayout)
    9914             : {
    9915           0 :     CPL_IGNORE_RET_VAL(sLayout);
    9916           0 :     return false;
    9917             : }
    9918             : 
    9919             : //! @endcond
    9920             : 
    9921             : /************************************************************************/
    9922             : /*                          ClearStatistics()                           */
    9923             : /************************************************************************/
    9924             : 
    9925             : /**
    9926             :  \brief Clear statistics
    9927             : 
    9928             :  Only implemented for now in PAM supported datasets
    9929             : 
    9930             :  This is the same as the C function GDALDatasetClearStatistics().
    9931             : 
    9932             :  @since GDAL 3.2
    9933             : */
    9934             : 
    9935          11 : void GDALDataset::ClearStatistics()
    9936             : {
    9937          22 :     auto poRootGroup = GetRootGroup();
    9938          11 :     if (poRootGroup)
    9939           1 :         poRootGroup->ClearStatistics();
    9940          11 : }
    9941             : 
    9942             : /************************************************************************/
    9943             : /*                        GDALDatasetClearStatistics()                  */
    9944             : /************************************************************************/
    9945             : 
    9946             : /**
    9947             :  \brief Clear statistics
    9948             : 
    9949             :  This is the same as the C++ method GDALDataset::ClearStatistics().
    9950             : 
    9951             :  @since GDAL 3.2
    9952             : */
    9953             : 
    9954           2 : void GDALDatasetClearStatistics(GDALDatasetH hDS)
    9955             : {
    9956           2 :     VALIDATE_POINTER0(hDS, __func__);
    9957           2 :     GDALDataset::FromHandle(hDS)->ClearStatistics();
    9958             : }
    9959             : 
    9960             : /************************************************************************/
    9961             : /*                        GetFieldDomainNames()                         */
    9962             : /************************************************************************/
    9963             : 
    9964             : /** Returns a list of the names of all field domains stored in the dataset.
    9965             :  *
    9966             :  * @note The default implementation assumes that drivers fully populate
    9967             :  * m_oMapFieldDomains when opening a dataset. If this assumption is incorrect
    9968             :  * then a specialized implementation of GetFieldDomainNames() must be
    9969             :  * implemented.
    9970             :  *
    9971             :  * @param papszOptions Driver specific options determining how attributes
    9972             :  * should be retrieved. Pass nullptr for default behavior.
    9973             :  *
    9974             :  * @return list of field domain names
    9975             :  * @since GDAL 3.5
    9976             :  */
    9977             : std::vector<std::string>
    9978          46 : GDALDataset::GetFieldDomainNames(CPL_UNUSED CSLConstList papszOptions) const
    9979             : {
    9980             : 
    9981          46 :     std::vector<std::string> names;
    9982          46 :     names.reserve(m_oMapFieldDomains.size());
    9983          58 :     for (const auto &it : m_oMapFieldDomains)
    9984             :     {
    9985          12 :         names.emplace_back(it.first);
    9986             :     }
    9987          46 :     return names;
    9988             : }
    9989             : 
    9990             : /************************************************************************/
    9991             : /*                      GDALDatasetGetFieldDomainNames()                */
    9992             : /************************************************************************/
    9993             : 
    9994             : /** Returns a list of the names of all field domains stored in the dataset.
    9995             :  *
    9996             :  * This is the same as the C++ method GDALDataset::GetFieldDomainNames().
    9997             :  *
    9998             :  * @param hDS Dataset handle.
    9999             :  * @param papszOptions Driver specific options determining how attributes
   10000             :  * should be retrieved. Pass nullptr for default behavior.
   10001             :  *
   10002             :  * @return list of field domain names, to be freed with CSLDestroy()
   10003             :  * @since GDAL 3.5
   10004             :  */
   10005          34 : char **GDALDatasetGetFieldDomainNames(GDALDatasetH hDS,
   10006             :                                       CSLConstList papszOptions)
   10007             : {
   10008          34 :     VALIDATE_POINTER1(hDS, __func__, nullptr);
   10009             :     auto names =
   10010          68 :         GDALDataset::FromHandle(hDS)->GetFieldDomainNames(papszOptions);
   10011          68 :     CPLStringList res;
   10012         154 :     for (const auto &name : names)
   10013             :     {
   10014         120 :         res.AddString(name.c_str());
   10015             :     }
   10016          34 :     return res.StealList();
   10017             : }
   10018             : 
   10019             : /************************************************************************/
   10020             : /*                        GetFieldDomain()                              */
   10021             : /************************************************************************/
   10022             : 
   10023             : /** Get a field domain from its name.
   10024             :  *
   10025             :  * @return the field domain, or nullptr if not found.
   10026             :  * @since GDAL 3.3
   10027             :  */
   10028         323 : const OGRFieldDomain *GDALDataset::GetFieldDomain(const std::string &name) const
   10029             : {
   10030         323 :     const auto iter = m_oMapFieldDomains.find(name);
   10031         323 :     if (iter == m_oMapFieldDomains.end())
   10032         151 :         return nullptr;
   10033         172 :     return iter->second.get();
   10034             : }
   10035             : 
   10036             : /************************************************************************/
   10037             : /*                      GDALDatasetGetFieldDomain()                     */
   10038             : /************************************************************************/
   10039             : 
   10040             : /** Get a field domain from its name.
   10041             :  *
   10042             :  * This is the same as the C++ method GDALDataset::GetFieldDomain().
   10043             :  *
   10044             :  * @param hDS Dataset handle.
   10045             :  * @param pszName Name of field domain.
   10046             :  * @return the field domain (ownership remains to the dataset), or nullptr if
   10047             :  * not found.
   10048             :  * @since GDAL 3.3
   10049             :  */
   10050         130 : OGRFieldDomainH GDALDatasetGetFieldDomain(GDALDatasetH hDS, const char *pszName)
   10051             : {
   10052         130 :     VALIDATE_POINTER1(hDS, __func__, nullptr);
   10053         130 :     VALIDATE_POINTER1(pszName, __func__, nullptr);
   10054         130 :     return OGRFieldDomain::ToHandle(const_cast<OGRFieldDomain *>(
   10055         130 :         GDALDataset::FromHandle(hDS)->GetFieldDomain(pszName)));
   10056             : }
   10057             : 
   10058             : /************************************************************************/
   10059             : /*                         AddFieldDomain()                             */
   10060             : /************************************************************************/
   10061             : 
   10062             : /** Add a field domain to the dataset.
   10063             :  *
   10064             :  * Only a few drivers will support this operation, and some of them might only
   10065             :  * support it only for some types of field domains.
   10066             :  * At the time of writing (GDAL 3.3), only the Memory and GeoPackage drivers
   10067             :  * support this operation. A dataset having at least some support for this
   10068             :  * operation should report the ODsCAddFieldDomain dataset capability.
   10069             :  *
   10070             :  * Anticipated failures will not be emitted through the CPLError()
   10071             :  * infrastructure, but will be reported in the failureReason output parameter.
   10072             :  *
   10073             :  * @note Drivers should make sure to update m_oMapFieldDomains in order for the
   10074             :  * default implementation of GetFieldDomainNames() to work correctly, or
   10075             :  * alternatively a specialized implementation of GetFieldDomainNames() should be
   10076             :  * implemented.
   10077             :  *
   10078             :  * @param domain The domain definition.
   10079             :  * @param failureReason      Output parameter. Will contain an error message if
   10080             :  *                           an error occurs.
   10081             :  * @return true in case of success.
   10082             :  * @since GDAL 3.3
   10083             :  */
   10084           0 : bool GDALDataset::AddFieldDomain(
   10085             :     CPL_UNUSED std::unique_ptr<OGRFieldDomain> &&domain,
   10086             :     std::string &failureReason)
   10087             : {
   10088           0 :     failureReason = "AddFieldDomain not supported by this driver";
   10089           0 :     return false;
   10090             : }
   10091             : 
   10092             : /************************************************************************/
   10093             : /*                     GDALDatasetAddFieldDomain()                      */
   10094             : /************************************************************************/
   10095             : 
   10096             : /** Add a field domain to the dataset.
   10097             :  *
   10098             :  * Only a few drivers will support this operation, and some of them might only
   10099             :  * support it only for some types of field domains.
   10100             :  * At the time of writing (GDAL 3.3), only the Memory and GeoPackage drivers
   10101             :  * support this operation. A dataset having at least some support for this
   10102             :  * operation should report the ODsCAddFieldDomain dataset capability.
   10103             :  *
   10104             :  * Anticipated failures will not be emitted through the CPLError()
   10105             :  * infrastructure, but will be reported in the ppszFailureReason output
   10106             :  * parameter.
   10107             :  *
   10108             :  * @param hDS                Dataset handle.
   10109             :  * @param hFieldDomain       The domain definition. Contrary to the C++ version,
   10110             :  *                           the passed object is copied.
   10111             :  * @param ppszFailureReason  Output parameter. Will contain an error message if
   10112             :  *                           an error occurs (*ppszFailureReason to be freed
   10113             :  *                           with CPLFree). May be NULL.
   10114             :  * @return true in case of success.
   10115             :  * @since GDAL 3.3
   10116             :  */
   10117          37 : bool GDALDatasetAddFieldDomain(GDALDatasetH hDS, OGRFieldDomainH hFieldDomain,
   10118             :                                char **ppszFailureReason)
   10119             : {
   10120          37 :     VALIDATE_POINTER1(hDS, __func__, false);
   10121          37 :     VALIDATE_POINTER1(hFieldDomain, __func__, false);
   10122             :     auto poDomain = std::unique_ptr<OGRFieldDomain>(
   10123          74 :         OGRFieldDomain::FromHandle(hFieldDomain)->Clone());
   10124          37 :     if (poDomain == nullptr)
   10125           0 :         return false;
   10126          37 :     std::string failureReason;
   10127          74 :     const bool bRet = GDALDataset::FromHandle(hDS)->AddFieldDomain(
   10128          37 :         std::move(poDomain), failureReason);
   10129          37 :     if (ppszFailureReason)
   10130             :     {
   10131          37 :         *ppszFailureReason =
   10132          37 :             failureReason.empty() ? nullptr : CPLStrdup(failureReason.c_str());
   10133             :     }
   10134          37 :     return bRet;
   10135             : }
   10136             : 
   10137             : /************************************************************************/
   10138             : /*                        DeleteFieldDomain()                           */
   10139             : /************************************************************************/
   10140             : 
   10141             : /** Removes a field domain from the dataset.
   10142             :  *
   10143             :  * Only a few drivers will support this operation.
   10144             :  *
   10145             :  * At the time of writing (GDAL 3.5), only the Memory and GeoPackage drivers
   10146             :  * support this operation. A dataset having at least some support for this
   10147             :  * operation should report the ODsCDeleteFieldDomain dataset capability.
   10148             :  *
   10149             :  * Anticipated failures will not be emitted through the CPLError()
   10150             :  * infrastructure, but will be reported in the failureReason output parameter.
   10151             :  *
   10152             :  * @note Drivers should make sure to update m_oMapFieldDomains in order for the
   10153             :  * default implementation of GetFieldDomainNames() to work correctly, or
   10154             :  * alternatively a specialized implementation of GetFieldDomainNames() should be
   10155             :  * implemented.
   10156             :  *
   10157             :  * @param name The domain name.
   10158             :  * @param failureReason      Output parameter. Will contain an error message if
   10159             :  *                           an error occurs.
   10160             :  * @return true in case of success.
   10161             :  * @since GDAL 3.5
   10162             :  */
   10163           0 : bool GDALDataset::DeleteFieldDomain(CPL_UNUSED const std::string &name,
   10164             :                                     std::string &failureReason)
   10165             : {
   10166           0 :     failureReason = "DeleteFieldDomain not supported by this driver";
   10167           0 :     return false;
   10168             : }
   10169             : 
   10170             : /************************************************************************/
   10171             : /*                  GDALDatasetDeleteFieldDomain()                      */
   10172             : /************************************************************************/
   10173             : 
   10174             : /** Removes a field domain from the dataset.
   10175             :  *
   10176             :  * Only a few drivers will support this operation.
   10177             :  *
   10178             :  * At the time of writing (GDAL 3.5), only the Memory and GeoPackage drivers
   10179             :  * support this operation. A dataset having at least some support for this
   10180             :  * operation should report the ODsCDeleteFieldDomain dataset capability.
   10181             :  *
   10182             :  * Anticipated failures will not be emitted through the CPLError()
   10183             :  * infrastructure, but will be reported in the ppszFailureReason output
   10184             :  * parameter.
   10185             :  *
   10186             :  * @param hDS                Dataset handle.
   10187             :  * @param pszName            The domain name.
   10188             :  * @param ppszFailureReason  Output parameter. Will contain an error message if
   10189             :  *                           an error occurs (*ppszFailureReason to be freed
   10190             :  *                           with CPLFree). May be NULL.
   10191             :  * @return true in case of success.
   10192             :  * @since GDAL 3.3
   10193             :  */
   10194          25 : bool GDALDatasetDeleteFieldDomain(GDALDatasetH hDS, const char *pszName,
   10195             :                                   char **ppszFailureReason)
   10196             : {
   10197          25 :     VALIDATE_POINTER1(hDS, __func__, false);
   10198          25 :     VALIDATE_POINTER1(pszName, __func__, false);
   10199          25 :     std::string failureReason;
   10200             :     const bool bRet =
   10201          25 :         GDALDataset::FromHandle(hDS)->DeleteFieldDomain(pszName, failureReason);
   10202          25 :     if (ppszFailureReason)
   10203             :     {
   10204           0 :         *ppszFailureReason =
   10205           0 :             failureReason.empty() ? nullptr : CPLStrdup(failureReason.c_str());
   10206             :     }
   10207          25 :     return bRet;
   10208             : }
   10209             : 
   10210             : /************************************************************************/
   10211             : /*                       UpdateFieldDomain()                            */
   10212             : /************************************************************************/
   10213             : 
   10214             : /** Updates an existing field domain by replacing its definition.
   10215             :  *
   10216             :  * The existing field domain with matching name will be replaced.
   10217             :  *
   10218             :  * Only a few drivers will support this operation, and some of them might only
   10219             :  * support it only for some types of field domains.
   10220             :  * At the time of writing (GDAL 3.5), only the Memory driver
   10221             :  * supports this operation. A dataset having at least some support for this
   10222             :  * operation should report the ODsCUpdateFieldDomain dataset capability.
   10223             :  *
   10224             :  * Anticipated failures will not be emitted through the CPLError()
   10225             :  * infrastructure, but will be reported in the failureReason output parameter.
   10226             :  *
   10227             :  * @param domain The domain definition.
   10228             :  * @param failureReason      Output parameter. Will contain an error message if
   10229             :  *                           an error occurs.
   10230             :  * @return true in case of success.
   10231             :  * @since GDAL 3.5
   10232             :  */
   10233           0 : bool GDALDataset::UpdateFieldDomain(
   10234             :     CPL_UNUSED std::unique_ptr<OGRFieldDomain> &&domain,
   10235             :     std::string &failureReason)
   10236             : {
   10237           0 :     failureReason = "UpdateFieldDomain not supported by this driver";
   10238           0 :     return false;
   10239             : }
   10240             : 
   10241             : /************************************************************************/
   10242             : /*                  GDALDatasetUpdateFieldDomain()                      */
   10243             : /************************************************************************/
   10244             : 
   10245             : /** Updates an existing field domain by replacing its definition.
   10246             :  *
   10247             :  * The existing field domain with matching name will be replaced.
   10248             :  *
   10249             :  * Only a few drivers will support this operation, and some of them might only
   10250             :  * support it only for some types of field domains.
   10251             :  * At the time of writing (GDAL 3.5), only the Memory driver
   10252             :  * supports this operation. A dataset having at least some support for this
   10253             :  * operation should report the ODsCUpdateFieldDomain dataset capability.
   10254             :  *
   10255             :  * Anticipated failures will not be emitted through the CPLError()
   10256             :  * infrastructure, but will be reported in the failureReason output parameter.
   10257             :  *
   10258             :  * @param hDS                Dataset handle.
   10259             :  * @param hFieldDomain       The domain definition. Contrary to the C++ version,
   10260             :  *                           the passed object is copied.
   10261             :  * @param ppszFailureReason  Output parameter. Will contain an error message if
   10262             :  *                           an error occurs (*ppszFailureReason to be freed
   10263             :  *                           with CPLFree). May be NULL.
   10264             :  * @return true in case of success.
   10265             :  * @since GDAL 3.5
   10266             :  */
   10267           7 : bool GDALDatasetUpdateFieldDomain(GDALDatasetH hDS,
   10268             :                                   OGRFieldDomainH hFieldDomain,
   10269             :                                   char **ppszFailureReason)
   10270             : {
   10271           7 :     VALIDATE_POINTER1(hDS, __func__, false);
   10272           7 :     VALIDATE_POINTER1(hFieldDomain, __func__, false);
   10273             :     auto poDomain = std::unique_ptr<OGRFieldDomain>(
   10274          14 :         OGRFieldDomain::FromHandle(hFieldDomain)->Clone());
   10275           7 :     if (poDomain == nullptr)
   10276           0 :         return false;
   10277           7 :     std::string failureReason;
   10278          14 :     const bool bRet = GDALDataset::FromHandle(hDS)->UpdateFieldDomain(
   10279           7 :         std::move(poDomain), failureReason);
   10280           7 :     if (ppszFailureReason)
   10281             :     {
   10282           0 :         *ppszFailureReason =
   10283           0 :             failureReason.empty() ? nullptr : CPLStrdup(failureReason.c_str());
   10284             :     }
   10285           7 :     return bRet;
   10286             : }
   10287             : 
   10288             : /************************************************************************/
   10289             : /*                        GetRelationshipNames()                        */
   10290             : /************************************************************************/
   10291             : 
   10292             : /** Returns a list of the names of all relationships stored in the dataset.
   10293             :  *
   10294             :  * @param papszOptions Driver specific options determining how relationships
   10295             :  * should be retrieved. Pass nullptr for default behavior.
   10296             :  *
   10297             :  * @return list of relationship names
   10298             :  * @since GDAL 3.6
   10299             :  */
   10300             : std::vector<std::string>
   10301         185 : GDALDataset::GetRelationshipNames(CPL_UNUSED CSLConstList papszOptions) const
   10302             : {
   10303         185 :     return {};
   10304             : }
   10305             : 
   10306             : /************************************************************************/
   10307             : /*                     GDALDatasetGetRelationshipNames()                */
   10308             : /************************************************************************/
   10309             : 
   10310             : /** Returns a list of the names of all relationships stored in the dataset.
   10311             :  *
   10312             :  * This is the same as the C++ method GDALDataset::GetRelationshipNames().
   10313             :  *
   10314             :  * @param hDS Dataset handle.
   10315             :  * @param papszOptions Driver specific options determining how relationships
   10316             :  * should be retrieved. Pass nullptr for default behavior.
   10317             :  *
   10318             :  * @return list of relationship names, to be freed with CSLDestroy()
   10319             :  * @since GDAL 3.6
   10320             :  */
   10321          46 : char **GDALDatasetGetRelationshipNames(GDALDatasetH hDS,
   10322             :                                        CSLConstList papszOptions)
   10323             : {
   10324          46 :     VALIDATE_POINTER1(hDS, __func__, nullptr);
   10325             :     auto names =
   10326          92 :         GDALDataset::FromHandle(hDS)->GetRelationshipNames(papszOptions);
   10327          92 :     CPLStringList res;
   10328         146 :     for (const auto &name : names)
   10329             :     {
   10330         100 :         res.AddString(name.c_str());
   10331             :     }
   10332          46 :     return res.StealList();
   10333             : }
   10334             : 
   10335             : /************************************************************************/
   10336             : /*                        GetRelationship()                             */
   10337             : /************************************************************************/
   10338             : 
   10339             : /** Get a relationship from its name.
   10340             :  *
   10341             :  * @return the relationship, or nullptr if not found.
   10342             :  * @since GDAL 3.6
   10343             :  */
   10344             : const GDALRelationship *
   10345           0 : GDALDataset::GetRelationship(CPL_UNUSED const std::string &name) const
   10346             : {
   10347           0 :     return nullptr;
   10348             : }
   10349             : 
   10350             : /************************************************************************/
   10351             : /*                      GDALDatasetGetRelationship()                    */
   10352             : /************************************************************************/
   10353             : 
   10354             : /** Get a relationship from its name.
   10355             :  *
   10356             :  * This is the same as the C++ method GDALDataset::GetRelationship().
   10357             :  *
   10358             :  * @param hDS Dataset handle.
   10359             :  * @param pszName Name of relationship.
   10360             :  * @return the relationship (ownership remains to the dataset), or nullptr if
   10361             :  * not found.
   10362             :  * @since GDAL 3.6
   10363             :  */
   10364          52 : GDALRelationshipH GDALDatasetGetRelationship(GDALDatasetH hDS,
   10365             :                                              const char *pszName)
   10366             : {
   10367          52 :     VALIDATE_POINTER1(hDS, __func__, nullptr);
   10368          52 :     VALIDATE_POINTER1(pszName, __func__, nullptr);
   10369          52 :     return GDALRelationship::ToHandle(const_cast<GDALRelationship *>(
   10370          52 :         GDALDataset::FromHandle(hDS)->GetRelationship(pszName)));
   10371             : }
   10372             : 
   10373             : /************************************************************************/
   10374             : /*                         AddRelationship()                            */
   10375             : /************************************************************************/
   10376             : 
   10377             : /** Add a relationship to the dataset.
   10378             :  *
   10379             :  * Only a few drivers will support this operation, and some of them might only
   10380             :  * support it only for some types of relationships.
   10381             :  *
   10382             :  * A dataset having at least some support for this
   10383             :  * operation should report the GDsCAddRelationship dataset capability.
   10384             :  *
   10385             :  * Anticipated failures will not be emitted through the CPLError()
   10386             :  * infrastructure, but will be reported in the failureReason output parameter.
   10387             :  *
   10388             :  * When adding a many-to-many relationship
   10389             :  * (GDALRelationshipCardinality::GRC_MANY_TO_MANY), it is possible to omit the
   10390             :  * mapping table name (see GDALRelationship::GetMappingTableName) to instruct
   10391             :  * the driver to create an appropriately named and structured mapping table.
   10392             :  * Some dataset formats require particular naming conventions and field
   10393             :  * structures for the mapping table, and delegating the construction of the
   10394             :  * mapping table to the driver will avoid these pitfalls.
   10395             :  *
   10396             :  * @param relationship The relationship definition.
   10397             :  * @param failureReason      Output parameter. Will contain an error message if
   10398             :  *                           an error occurs.
   10399             :  * @return true in case of success.
   10400             :  * @since GDAL 3.6
   10401             :  */
   10402           0 : bool GDALDataset::AddRelationship(
   10403             :     CPL_UNUSED std::unique_ptr<GDALRelationship> &&relationship,
   10404             :     std::string &failureReason)
   10405             : {
   10406           0 :     failureReason = "AddRelationship not supported by this driver";
   10407           0 :     return false;
   10408             : }
   10409             : 
   10410             : /************************************************************************/
   10411             : /*                     GDALDatasetAddRelationship()                     */
   10412             : /************************************************************************/
   10413             : 
   10414             : /** Add a relationship to the dataset.
   10415             :  *
   10416             :  * Only a few drivers will support this operation, and some of them might only
   10417             :  * support it only for some types of relationships.
   10418             :  *
   10419             :  * A dataset having at least some support for this
   10420             :  * operation should report the GDsCAddRelationship dataset capability.
   10421             :  *
   10422             :  * Anticipated failures will not be emitted through the CPLError()
   10423             :  * infrastructure, but will be reported in the failureReason output parameter.
   10424             :  *
   10425             :  * When adding a many-to-many relationship
   10426             :  * (GDALRelationshipCardinality::GRC_MANY_TO_MANY), it is possible to omit the
   10427             :  * mapping table name (see GDALRelationshipGetMappingTableName) to instruct the
   10428             :  * driver to create an appropriately named and structured mapping table. Some
   10429             :  * dataset formats require particular naming conventions and field structures
   10430             :  * for the mapping table, and delegating the construction of the mapping table
   10431             :  * to the driver will avoid these pitfalls.
   10432             :  *
   10433             :  * @param hDS                Dataset handle.
   10434             :  * @param hRelationship      The relationship definition. Contrary to the C++
   10435             :  * version, the passed object is copied.
   10436             :  * @param ppszFailureReason  Output parameter. Will contain an error message if
   10437             :  *                           an error occurs (*ppszFailureReason to be freed
   10438             :  *                           with CPLFree). May be NULL.
   10439             :  * @return true in case of success.
   10440             :  * @since GDAL 3.6
   10441             :  */
   10442          42 : bool GDALDatasetAddRelationship(GDALDatasetH hDS,
   10443             :                                 GDALRelationshipH hRelationship,
   10444             :                                 char **ppszFailureReason)
   10445             : {
   10446          42 :     VALIDATE_POINTER1(hDS, __func__, false);
   10447          42 :     VALIDATE_POINTER1(hRelationship, __func__, false);
   10448             :     std::unique_ptr<GDALRelationship> poRelationship(
   10449          84 :         new GDALRelationship(*GDALRelationship::FromHandle(hRelationship)));
   10450          42 :     std::string failureReason;
   10451          84 :     const bool bRet = GDALDataset::FromHandle(hDS)->AddRelationship(
   10452          42 :         std::move(poRelationship), failureReason);
   10453          42 :     if (ppszFailureReason)
   10454             :     {
   10455           0 :         *ppszFailureReason =
   10456           0 :             failureReason.empty() ? nullptr : CPLStrdup(failureReason.c_str());
   10457             :     }
   10458          42 :     return bRet;
   10459             : }
   10460             : 
   10461             : /************************************************************************/
   10462             : /*                        DeleteRelationship()                          */
   10463             : /************************************************************************/
   10464             : 
   10465             : /** Removes a relationship from the dataset.
   10466             :  *
   10467             :  * Only a few drivers will support this operation.
   10468             :  *
   10469             :  * A dataset having at least some support for this
   10470             :  * operation should report the GDsCDeleteRelationship dataset capability.
   10471             :  *
   10472             :  * Anticipated failures will not be emitted through the CPLError()
   10473             :  * infrastructure, but will be reported in the failureReason output parameter.
   10474             :  *
   10475             :  * @param name The relationship name.
   10476             :  * @param failureReason      Output parameter. Will contain an error message if
   10477             :  *                           an error occurs.
   10478             :  * @return true in case of success.
   10479             :  * @since GDAL 3.6
   10480             :  */
   10481           0 : bool GDALDataset::DeleteRelationship(CPL_UNUSED const std::string &name,
   10482             :                                      std::string &failureReason)
   10483             : {
   10484           0 :     failureReason = "DeleteRelationship not supported by this driver";
   10485           0 :     return false;
   10486             : }
   10487             : 
   10488             : /************************************************************************/
   10489             : /*                  GDALDatasetDeleteRelationship()                     */
   10490             : /************************************************************************/
   10491             : 
   10492             : /** Removes a relationship from the dataset.
   10493             :  *
   10494             :  * Only a few drivers will support this operation.
   10495             :  *
   10496             :  * A dataset having at least some support for this
   10497             :  * operation should report the GDsCDeleteRelationship dataset capability.
   10498             :  *
   10499             :  * Anticipated failures will not be emitted through the CPLError()
   10500             :  * infrastructure, but will be reported in the ppszFailureReason output
   10501             :  * parameter.
   10502             :  *
   10503             :  * @param hDS                Dataset handle.
   10504             :  * @param pszName            The relationship name.
   10505             :  * @param ppszFailureReason  Output parameter. Will contain an error message if
   10506             :  *                           an error occurs (*ppszFailureReason to be freed
   10507             :  *                           with CPLFree). May be NULL.
   10508             :  * @return true in case of success.
   10509             :  * @since GDAL 3.6
   10510             :  */
   10511           6 : bool GDALDatasetDeleteRelationship(GDALDatasetH hDS, const char *pszName,
   10512             :                                    char **ppszFailureReason)
   10513             : {
   10514           6 :     VALIDATE_POINTER1(hDS, __func__, false);
   10515           6 :     VALIDATE_POINTER1(pszName, __func__, false);
   10516           6 :     std::string failureReason;
   10517          12 :     const bool bRet = GDALDataset::FromHandle(hDS)->DeleteRelationship(
   10518           6 :         pszName, failureReason);
   10519           6 :     if (ppszFailureReason)
   10520             :     {
   10521           0 :         *ppszFailureReason =
   10522           0 :             failureReason.empty() ? nullptr : CPLStrdup(failureReason.c_str());
   10523             :     }
   10524           6 :     return bRet;
   10525             : }
   10526             : 
   10527             : /************************************************************************/
   10528             : /*                       UpdateRelationship()                           */
   10529             : /************************************************************************/
   10530             : 
   10531             : /** Updates an existing relationship by replacing its definition.
   10532             :  *
   10533             :  * The existing relationship with matching name will be replaced.
   10534             :  *
   10535             :  * Only a few drivers will support this operation, and some of them might only
   10536             :  * support it only for some types of relationships.
   10537             :  * A dataset having at least some support for this
   10538             :  * operation should report the GDsCUpdateRelationship dataset capability.
   10539             :  *
   10540             :  * Anticipated failures will not be emitted through the CPLError()
   10541             :  * infrastructure, but will be reported in the failureReason output parameter.
   10542             :  *
   10543             :  * @param relationship   The relationship definition.
   10544             :  * @param failureReason  Output parameter. Will contain an error message if
   10545             :  *                       an error occurs.
   10546             :  * @return true in case of success.
   10547             :  * @since GDAL 3.6
   10548             :  */
   10549           0 : bool GDALDataset::UpdateRelationship(
   10550             :     CPL_UNUSED std::unique_ptr<GDALRelationship> &&relationship,
   10551             :     std::string &failureReason)
   10552             : {
   10553           0 :     failureReason = "UpdateRelationship not supported by this driver";
   10554           0 :     return false;
   10555             : }
   10556             : 
   10557             : /************************************************************************/
   10558             : /*                  GDALDatasetUpdateRelationship()                     */
   10559             : /************************************************************************/
   10560             : 
   10561             : /** Updates an existing relationship by replacing its definition.
   10562             :  *
   10563             :  * The existing relationship with matching name will be replaced.
   10564             :  *
   10565             :  * Only a few drivers will support this operation, and some of them might only
   10566             :  * support it only for some types of relationships.
   10567             :  * A dataset having at least some support for this
   10568             :  * operation should report the GDsCUpdateRelationship dataset capability.
   10569             :  *
   10570             :  * Anticipated failures will not be emitted through the CPLError()
   10571             :  * infrastructure, but will be reported in the failureReason output parameter.
   10572             :  *
   10573             :  * @param hDS                Dataset handle.
   10574             :  * @param hRelationship      The relationship definition. Contrary to the C++
   10575             :  * version, the passed object is copied.
   10576             :  * @param ppszFailureReason  Output parameter. Will contain an error message if
   10577             :  *                           an error occurs (*ppszFailureReason to be freed
   10578             :  *                           with CPLFree). May be NULL.
   10579             :  * @return true in case of success.
   10580             :  * @since GDAL 3.5
   10581             :  */
   10582           9 : bool GDALDatasetUpdateRelationship(GDALDatasetH hDS,
   10583             :                                    GDALRelationshipH hRelationship,
   10584             :                                    char **ppszFailureReason)
   10585             : {
   10586           9 :     VALIDATE_POINTER1(hDS, __func__, false);
   10587           9 :     VALIDATE_POINTER1(hRelationship, __func__, false);
   10588             :     std::unique_ptr<GDALRelationship> poRelationship(
   10589          18 :         new GDALRelationship(*GDALRelationship::FromHandle(hRelationship)));
   10590           9 :     std::string failureReason;
   10591          18 :     const bool bRet = GDALDataset::FromHandle(hDS)->UpdateRelationship(
   10592           9 :         std::move(poRelationship), failureReason);
   10593           9 :     if (ppszFailureReason)
   10594             :     {
   10595           0 :         *ppszFailureReason =
   10596           0 :             failureReason.empty() ? nullptr : CPLStrdup(failureReason.c_str());
   10597             :     }
   10598           9 :     return bRet;
   10599             : }
   10600             : 
   10601             : /************************************************************************/
   10602             : /*                  GDALDatasetSetQueryLoggerFunc()                     */
   10603             : /************************************************************************/
   10604             : 
   10605             : /**
   10606             :  * Sets the SQL query logger callback.
   10607             :  *
   10608             :  * When supported by the driver, the callback will be called with
   10609             :  * the executed SQL text, the error message, the execution time in milliseconds,
   10610             :  * the number of records fetched/affected and the client status data.
   10611             :  *
   10612             :  * A value of -1 in the execution time or in the number of records indicates
   10613             :  * that the values are unknown.
   10614             :  *
   10615             :  * @param hDS                   Dataset handle.
   10616             :  * @param pfnQueryLoggerFunc    Callback function
   10617             :  * @param poQueryLoggerArg      Opaque client status data
   10618             :  * @return                      true in case of success.
   10619             :  * @since                       GDAL 3.7
   10620             :  */
   10621           1 : bool GDALDatasetSetQueryLoggerFunc(GDALDatasetH hDS,
   10622             :                                    GDALQueryLoggerFunc pfnQueryLoggerFunc,
   10623             :                                    void *poQueryLoggerArg)
   10624             : {
   10625           1 :     VALIDATE_POINTER1(hDS, __func__, false);
   10626           2 :     return GDALDataset::FromHandle(hDS)->SetQueryLoggerFunc(pfnQueryLoggerFunc,
   10627           1 :                                                             poQueryLoggerArg);
   10628             : }
   10629             : 
   10630             : //! @cond Doxygen_Suppress
   10631             : 
   10632             : /************************************************************************/
   10633             : /*                       SetEnableOverviews()                           */
   10634             : /************************************************************************/
   10635             : 
   10636        7531 : void GDALDataset::SetEnableOverviews(bool bEnable)
   10637             : {
   10638        7531 :     if (m_poPrivate)
   10639             :     {
   10640        7531 :         m_poPrivate->m_bOverviewsEnabled = bEnable;
   10641             :     }
   10642        7531 : }
   10643             : 
   10644             : /************************************************************************/
   10645             : /*                      AreOverviewsEnabled()                           */
   10646             : /************************************************************************/
   10647             : 
   10648     2006520 : bool GDALDataset::AreOverviewsEnabled() const
   10649             : {
   10650     2006520 :     return m_poPrivate ? m_poPrivate->m_bOverviewsEnabled : true;
   10651             : }
   10652             : 
   10653             : /************************************************************************/
   10654             : /*                             IsAllBands()                             */
   10655             : /************************************************************************/
   10656             : 
   10657        3695 : bool GDALDataset::IsAllBands(int nBandCount, const int *panBandList) const
   10658             : {
   10659        3695 :     if (nBands != nBandCount)
   10660           1 :         return false;
   10661        3694 :     if (panBandList)
   10662             :     {
   10663       13677 :         for (int i = 0; i < nBandCount; ++i)
   10664             :         {
   10665       10077 :             if (panBandList[i] != i + 1)
   10666          27 :                 return false;
   10667             :         }
   10668             :     }
   10669        3667 :     return true;
   10670             : }
   10671             : 
   10672             : //! @endcond
   10673             : 
   10674             : /************************************************************************/
   10675             : /*                       GetCompressionFormats()                        */
   10676             : /************************************************************************/
   10677             : 
   10678             : /** Return the compression formats that can be natively obtained for the
   10679             :  * window of interest and requested bands.
   10680             :  *
   10681             :  * For example, a tiled dataset may be able to return data in a compressed
   10682             :  * format if the window of interest matches exactly a tile. For some formats,
   10683             :  * drivers may also be able to merge several tiles together (not currently
   10684             :  * implemented though).
   10685             :  *
   10686             :  * Each format string is a pseudo MIME type, whose first part can be passed
   10687             :  * as the pszFormat argument of ReadCompressedData(), with additional
   10688             :  * parameters specified as key=value with a semi-colon separator.
   10689             :  *
   10690             :  * The amount and types of optional parameters passed after the MIME type is
   10691             :  * format dependent, and driver dependent (some drivers might not be able to
   10692             :  * return those extra information without doing a rather costly processing).
   10693             :  *
   10694             :  * For example, a driver might return "JPEG;frame_type=SOF0_baseline;"
   10695             :  * "bit_depth=8;num_components=3;subsampling=4:2:0;colorspace=YCbCr", and
   10696             :  * consequently "JPEG" can be passed as the pszFormat argument of
   10697             :  * ReadCompressedData(). For JPEG, implementations can use the
   10698             :  * GDALGetCompressionFormatForJPEG() helper method to generate a string like
   10699             :  * above from a JPEG codestream.
   10700             :  *
   10701             :  * Several values might be returned. For example,
   10702             :  * the JPEGXL driver will return "JXL", but also potentially "JPEG"
   10703             :  * if the JPEGXL codestream includes a JPEG reconstruction box.
   10704             :  *
   10705             :  * In the general case this method will return an empty list.
   10706             :  *
   10707             :  * This is the same as C function GDALDatasetGetCompressionFormats().
   10708             :  *
   10709             :  * @param nXOff The pixel offset to the top left corner of the region
   10710             :  * of the band to be accessed.  This would be zero to start from the left side.
   10711             :  *
   10712             :  * @param nYOff The line offset to the top left corner of the region
   10713             :  * of the band to be accessed.  This would be zero to start from the top.
   10714             :  *
   10715             :  * @param nXSize The width of the region of the band to be accessed in pixels.
   10716             :  *
   10717             :  * @param nYSize The height of the region of the band to be accessed in lines.
   10718             :  *
   10719             :  * @param nBandCount the number of bands being requested.
   10720             :  *
   10721             :  * @param panBandList the list of nBandCount band numbers.
   10722             :  * Note band numbers are 1 based. This may be NULL to select the first
   10723             :  * nBandCount bands.
   10724             :  *
   10725             :  * @return a list of compatible formats (which may be empty)
   10726             :  *
   10727             :  * For example, to check if native compression format(s) are available on the
   10728             :  * whole image:
   10729             :  * \code{.cpp}
   10730             :  *   const CPLStringList aosFormats =
   10731             :  *      poDataset->GetCompressionFormats(0, 0,
   10732             :  *                                       poDataset->GetRasterXSize(),
   10733             :  *                                       poDataset->GetRasterYSize(),
   10734             :  *                                       poDataset->GetRasterCount(),
   10735             :  *                                       nullptr);
   10736             :  *   for( const char* pszFormat: aosFormats )
   10737             :  *   {
   10738             :  *      // Remove optional parameters and just print out the MIME type.
   10739             :  *      const CPLStringList aosTokens(CSLTokenizeString2(pszFormat, ";", 0));
   10740             :  *      printf("Found format %s\n, aosTokens[0]);
   10741             :  *   }
   10742             :  * \endcode
   10743             :  *
   10744             :  * @since GDAL 3.7
   10745             :  */
   10746             : CPLStringList
   10747           0 : GDALDataset::GetCompressionFormats(CPL_UNUSED int nXOff, CPL_UNUSED int nYOff,
   10748             :                                    CPL_UNUSED int nXSize, CPL_UNUSED int nYSize,
   10749             :                                    CPL_UNUSED int nBandCount,
   10750             :                                    CPL_UNUSED const int *panBandList)
   10751             : {
   10752           0 :     return CPLStringList();
   10753             : }
   10754             : 
   10755             : /************************************************************************/
   10756             : /*                 GDALDatasetGetCompressionFormats()                   */
   10757             : /************************************************************************/
   10758             : 
   10759             : /** Return the compression formats that can be natively obtained for the
   10760             :  * window of interest and requested bands.
   10761             :  *
   10762             :  * For example, a tiled dataset may be able to return data in a compressed
   10763             :  * format if the window of interest matches exactly a tile. For some formats,
   10764             :  * drivers may also be able to merge several tiles together (not currently
   10765             :  * implemented though).
   10766             :  *
   10767             :  * Each format string is a pseudo MIME type, whose first part can be passed
   10768             :  * as the pszFormat argument of ReadCompressedData(), with additional
   10769             :  * parameters specified as key=value with a semi-colon separator.
   10770             :  *
   10771             :  * The amount and types of optional parameters passed after the MIME type is
   10772             :  * format dependent, and driver dependent (some drivers might not be able to
   10773             :  * return those extra information without doing a rather costly processing).
   10774             :  *
   10775             :  * For example, a driver might return "JPEG;frame_type=SOF0_baseline;"
   10776             :  * "bit_depth=8;num_components=3;subsampling=4:2:0;colorspace=YCbCr", and
   10777             :  * consequently "JPEG" can be passed as the pszFormat argument of
   10778             :  * ReadCompressedData(). For JPEG, implementations can use the
   10779             :  * GDALGetCompressionFormatForJPEG() helper method to generate a string like
   10780             :  * above from a JPEG codestream.
   10781             :  *
   10782             :  * Several values might be returned. For example,
   10783             :  * the JPEGXL driver will return "JXL", but also potentially "JPEG"
   10784             :  * if the JPEGXL codestream includes a JPEG reconstruction box.
   10785             :  *
   10786             :  * In the general case this method will return an empty list.
   10787             :  *
   10788             :  * This is the same as C++ method GDALDataset::GetCompressionFormats().
   10789             :  *
   10790             :  * @param hDS Dataset handle.
   10791             :  *
   10792             :  * @param nXOff The pixel offset to the top left corner of the region
   10793             :  * of the band to be accessed.  This would be zero to start from the left side.
   10794             :  *
   10795             :  * @param nYOff The line offset to the top left corner of the region
   10796             :  * of the band to be accessed.  This would be zero to start from the top.
   10797             :  *
   10798             :  * @param nXSize The width of the region of the band to be accessed in pixels.
   10799             :  *
   10800             :  * @param nYSize The height of the region of the band to be accessed in lines.
   10801             :  *
   10802             :  * @param nBandCount the number of bands being requested.
   10803             :  *
   10804             :  * @param panBandList the list of nBandCount band numbers.
   10805             :  * Note band numbers are 1 based. This may be NULL to select the first
   10806             :  * nBandCount bands.
   10807             :  *
   10808             :  * @return a list of compatible formats (which may be empty) that should be
   10809             :  * freed with CSLDestroy(), or nullptr.
   10810             :  *
   10811             :  * @since GDAL 3.7
   10812             :  */
   10813           9 : char **GDALDatasetGetCompressionFormats(GDALDatasetH hDS, int nXOff, int nYOff,
   10814             :                                         int nXSize, int nYSize, int nBandCount,
   10815             :                                         const int *panBandList)
   10816             : {
   10817           9 :     VALIDATE_POINTER1(hDS, __func__, nullptr);
   10818           9 :     return GDALDataset::FromHandle(hDS)
   10819           9 :         ->GetCompressionFormats(nXOff, nYOff, nXSize, nYSize, nBandCount,
   10820           9 :                                 panBandList)
   10821           9 :         .StealList();
   10822             : }
   10823             : 
   10824             : /************************************************************************/
   10825             : /*                         ReadCompressedData()                         */
   10826             : /************************************************************************/
   10827             : 
   10828             : /** Return the compressed content that can be natively obtained for the
   10829             :  * window of interest and requested bands.
   10830             :  *
   10831             :  * For example, a tiled dataset may be able to return data in compressed format
   10832             :  * if the window of interest matches exactly a tile. For some formats, drivers
   10833             :  * may also be example to merge several tiles together (not currently
   10834             :  * implemented though).
   10835             :  *
   10836             :  * The implementation should make sure that the content returned forms a valid
   10837             :  * standalone file. For example, for the GeoTIFF implementation of this method,
   10838             :  * when extracting a JPEG tile, the method will automatically add the content
   10839             :  * of the JPEG Huffman and/or quantization tables that might be stored in the
   10840             :  * TIFF JpegTables tag, and not in tile data itself.
   10841             :  *
   10842             :  * In the general case this method will return CE_Failure.
   10843             :  *
   10844             :  * This is the same as C function GDALDatasetReadCompressedData().
   10845             :  *
   10846             :  * @param pszFormat Requested compression format (e.g. "JPEG",
   10847             :  * "WEBP", "JXL"). This is the MIME type of one of the values
   10848             :  * returned by GetCompressionFormats(). The format string is designed to
   10849             :  * potentially include at a later point key=value optional parameters separated
   10850             :  * by a semi-colon character. At time of writing, none are implemented.
   10851             :  * ReadCompressedData() implementations should verify optional parameters and
   10852             :  * return CE_Failure if they cannot support one of them.
   10853             :  *
   10854             :  * @param nXOff The pixel offset to the top left corner of the region
   10855             :  * of the band to be accessed.  This would be zero to start from the left side.
   10856             :  *
   10857             :  * @param nYOff The line offset to the top left corner of the region
   10858             :  * of the band to be accessed.  This would be zero to start from the top.
   10859             :  *
   10860             :  * @param nXSize The width of the region of the band to be accessed in pixels.
   10861             :  *
   10862             :  * @param nYSize The height of the region of the band to be accessed in lines.
   10863             :  *
   10864             :  * @param nBandCount the number of bands being requested.
   10865             :  *
   10866             :  * @param panBandList the list of nBandCount band numbers.
   10867             :  * Note band numbers are 1 based. This may be NULL to select the first
   10868             :  * nBandCount bands.
   10869             :  *
   10870             :  * @param ppBuffer Pointer to a buffer to store the compressed data or nullptr.
   10871             :  * If ppBuffer is not nullptr, then pnBufferSize should also not be nullptr.
   10872             :  * If ppBuffer is not nullptr, and *ppBuffer is not nullptr, then the provided
   10873             :  * buffer will be filled with the compressed data, provided that pnBufferSize
   10874             :  * and *pnBufferSize are not nullptr, and *pnBufferSize, indicating the size
   10875             :  * of *ppBuffer, is sufficiently large to hold the data.
   10876             :  * If ppBuffer is not nullptr, but *ppBuffer is nullptr, then the method will
   10877             :  * allocate *ppBuffer using VSIMalloc(), and thus the caller is responsible to
   10878             :  * free it with VSIFree().
   10879             :  * If ppBuffer is nullptr, then the compressed data itself will not be returned,
   10880             :  * but *pnBufferSize will be updated with an upper bound of the size that would
   10881             :  * be necessary to hold it (if pnBufferSize != nullptr).
   10882             :  *
   10883             :  * @param pnBufferSize Output buffer size, or nullptr.
   10884             :  * If ppBuffer != nullptr && *ppBuffer != nullptr, then pnBufferSize should
   10885             :  * be != nullptr and *pnBufferSize contain the size of *ppBuffer. If the
   10886             :  * method is successful, *pnBufferSize will be updated with the actual size
   10887             :  * used.
   10888             :  *
   10889             :  * @param ppszDetailedFormat Pointer to an output string, or nullptr.
   10890             :  * If ppszDetailedFormat is not nullptr, then, on success, the method will
   10891             :  * allocate a new string in *ppszDetailedFormat (to be freed with VSIFree())
   10892             :  * *ppszDetailedFormat might contain strings like
   10893             :  * "JPEG;frame_type=SOF0_baseline;bit_depth=8;num_components=3;"
   10894             :  * "subsampling=4:2:0;colorspace=YCbCr" or simply the MIME type.
   10895             :  * The string will contain at least as much information as what
   10896             :  * GetCompressionFormats() returns, and potentially more when
   10897             :  * ppBuffer != nullptr.
   10898             :  *
   10899             :  * @return CE_None in case of success, CE_Failure otherwise.
   10900             :  *
   10901             :  * For example, to request JPEG content on the whole image and let GDAL deal
   10902             :  * with the buffer allocation.
   10903             :  * \code{.cpp}
   10904             :  *   void* pBuffer = nullptr;
   10905             :  *   size_t nBufferSize = 0;
   10906             :  *   CPLErr eErr =
   10907             :  *      poDataset->ReadCompressedData("JPEG",
   10908             :  *                                    0, 0,
   10909             :  *                                    poDataset->GetRasterXSize(),
   10910             :  *                                    poDataset->GetRasterYSize(),
   10911             :  *                                    poDataset->GetRasterCount(),
   10912             :  *                                    nullptr, // panBandList
   10913             :  *                                    &pBuffer,
   10914             :  *                                    &nBufferSize,
   10915             :  *                                    nullptr // ppszDetailedFormat
   10916             :  *                                   );
   10917             :  *   if (eErr == CE_None)
   10918             :  *   {
   10919             :  *       CPLAssert(pBuffer != nullptr);
   10920             :  *       CPLAssert(nBufferSize > 0);
   10921             :  *       VSILFILE* fp = VSIFOpenL("my.jpeg", "wb");
   10922             :  *       if (fp)
   10923             :  *       {
   10924             :  *           VSIFWriteL(pBuffer, nBufferSize, 1, fp);
   10925             :  *           VSIFCloseL(fp);
   10926             :  *       }
   10927             :  *       VSIFree(pBuffer);
   10928             :  *   }
   10929             :  * \endcode
   10930             :  *
   10931             :  * Or to manage the buffer allocation on your side:
   10932             :  * \code{.cpp}
   10933             :  *   size_t nUpperBoundBufferSize = 0;
   10934             :  *   CPLErr eErr =
   10935             :  *      poDataset->ReadCompressedData("JPEG",
   10936             :  *                                    0, 0,
   10937             :  *                                    poDataset->GetRasterXSize(),
   10938             :  *                                    poDataset->GetRasterYSize(),
   10939             :  *                                    poDataset->GetRasterCount(),
   10940             :  *                                    nullptr, // panBandList
   10941             :  *                                    nullptr, // ppBuffer,
   10942             :  *                                    &nUpperBoundBufferSize,
   10943             :  *                                    nullptr // ppszDetailedFormat
   10944             :  *                                   );
   10945             :  *   if (eErr == CE_None)
   10946             :  *   {
   10947             :  *       std::vector<uint8_t> myBuffer;
   10948             :  *       myBuffer.resize(nUpperBoundBufferSize);
   10949             :  *       void* pBuffer = myBuffer.data();
   10950             :  *       size_t nActualSize = nUpperBoundBufferSize;
   10951             :  *       char* pszDetailedFormat = nullptr;
   10952             :  *       // We also request detailed format, but we could have passed it to
   10953             :  *       // nullptr as well.
   10954             :  *       eErr =
   10955             :  *         poDataset->ReadCompressedData("JPEG",
   10956             :  *                                       0, 0,
   10957             :  *                                       poDataset->GetRasterXSize(),
   10958             :  *                                       poDataset->GetRasterYSize(),
   10959             :  *                                       poDataset->GetRasterCount(),
   10960             :  *                                       nullptr, // panBandList
   10961             :  *                                       &pBuffer,
   10962             :  *                                       &nActualSize,
   10963             :  *                                       &pszDetailedFormat);
   10964             :  *       if (eErr == CE_None)
   10965             :  *       {
   10966             :  *          CPLAssert(pBuffer == myBuffer.data()); // pointed value not modified
   10967             :  *          CPLAssert(nActualSize <= nUpperBoundBufferSize);
   10968             :  *          myBuffer.resize(nActualSize);
   10969             :  *          // do something useful
   10970             :  *          VSIFree(pszDetailedFormat);
   10971             :  *       }
   10972             :  *   }
   10973             :  * \endcode
   10974             :  *
   10975             :  * @since GDAL 3.7
   10976             :  */
   10977         441 : CPLErr GDALDataset::ReadCompressedData(
   10978             :     CPL_UNUSED const char *pszFormat, CPL_UNUSED int nXOff,
   10979             :     CPL_UNUSED int nYOff, CPL_UNUSED int nXSize, CPL_UNUSED int nYSize,
   10980             :     CPL_UNUSED int nBandCount, CPL_UNUSED const int *panBandList,
   10981             :     CPL_UNUSED void **ppBuffer, CPL_UNUSED size_t *pnBufferSize,
   10982             :     CPL_UNUSED char **ppszDetailedFormat)
   10983             : {
   10984         441 :     return CE_Failure;
   10985             : }
   10986             : 
   10987             : /************************************************************************/
   10988             : /*                  GDALDatasetReadCompressedData()                     */
   10989             : /************************************************************************/
   10990             : 
   10991             : /** Return the compressed content that can be natively obtained for the
   10992             :  * window of interest and requested bands.
   10993             :  *
   10994             :  * For example, a tiled dataset may be able to return data in compressed format
   10995             :  * if the window of interest matches exactly a tile. For some formats, drivers
   10996             :  * may also be example to merge several tiles together (not currently
   10997             :  * implemented though).
   10998             :  *
   10999             :  * The implementation should make sure that the content returned forms a valid
   11000             :  * standalone file. For example, for the GeoTIFF implementation of this method,
   11001             :  * when extracting a JPEG tile, the method will automatically adds the content
   11002             :  * of the JPEG Huffman and/or quantization tables that might be stored in the
   11003             :  * TIFF JpegTables tag, and not in tile data itself.
   11004             :  *
   11005             :  * In the general case this method will return CE_Failure.
   11006             :  *
   11007             :  * This is the same as C++ method GDALDataset:ReadCompressedData().
   11008             :  *
   11009             :  * @param hDS Dataset handle.
   11010             :  *
   11011             :  * @param pszFormat Requested compression format (e.g. "JPEG",
   11012             :  * "WEBP", "JXL"). This is the MIME type of one of the values
   11013             :  * returned by GetCompressionFormats(). The format string is designed to
   11014             :  * potentially include at a later point key=value optional parameters separated
   11015             :  * by a semi-colon character. At time of writing, none are implemented.
   11016             :  * ReadCompressedData() implementations should verify optional parameters and
   11017             :  * return CE_Failure if they cannot support one of them.
   11018             :  *
   11019             :  * @param nXOff The pixel offset to the top left corner of the region
   11020             :  * of the band to be accessed.  This would be zero to start from the left side.
   11021             :  *
   11022             :  * @param nYOff The line offset to the top left corner of the region
   11023             :  * of the band to be accessed.  This would be zero to start from the top.
   11024             :  *
   11025             :  * @param nXSize The width of the region of the band to be accessed in pixels.
   11026             :  *
   11027             :  * @param nYSize The height of the region of the band to be accessed in lines.
   11028             :  *
   11029             :  * @param nBandCount the number of bands being requested.
   11030             :  *
   11031             :  * @param panBandList the list of nBandCount band numbers.
   11032             :  * Note band numbers are 1 based. This may be NULL to select the first
   11033             :  * nBandCount bands.
   11034             :  *
   11035             :  * @param ppBuffer Pointer to a buffer to store the compressed data or nullptr.
   11036             :  * If ppBuffer is not nullptr, then pnBufferSize should also not be nullptr.
   11037             :  * If ppBuffer is not nullptr, and *ppBuffer is not nullptr, then the provided
   11038             :  * buffer will be filled with the compressed data, provided that pnBufferSize
   11039             :  * and *pnBufferSize are not nullptr, and *pnBufferSize, indicating the size
   11040             :  * of *ppBuffer, is sufficiently large to hold the data.
   11041             :  * If ppBuffer is not nullptr, but *ppBuffer is nullptr, then the method will
   11042             :  * allocate *ppBuffer using VSIMalloc(), and thus the caller is responsible to
   11043             :  * free it with VSIFree().
   11044             :  * If ppBuffer is nullptr, then the compressed data itself will not be returned,
   11045             :  * but *pnBufferSize will be updated with an upper bound of the size that would
   11046             :  * be necessary to hold it (if pnBufferSize != nullptr).
   11047             :  *
   11048             :  * @param pnBufferSize Output buffer size, or nullptr.
   11049             :  * If ppBuffer != nullptr && *ppBuffer != nullptr, then pnBufferSize should
   11050             :  * be != nullptr and *pnBufferSize contain the size of *ppBuffer. If the
   11051             :  * method is successful, *pnBufferSize will be updated with the actual size
   11052             :  * used.
   11053             :  *
   11054             :  * @param ppszDetailedFormat Pointer to an output string, or nullptr.
   11055             :  * If ppszDetailedFormat is not nullptr, then, on success, the method will
   11056             :  * allocate a new string in *ppszDetailedFormat (to be freed with VSIFree())
   11057             :  * *ppszDetailedFormat might contain strings like
   11058             :  * "JPEG;frame_type=SOF0_baseline;bit_depth=8;num_components=3;"
   11059             :  * "subsampling=4:2:0;colorspace=YCbCr" or simply the MIME type.
   11060             :  * The string will contain at least as much information as what
   11061             :  * GetCompressionFormats() returns, and potentially more when
   11062             :  * ppBuffer != nullptr.
   11063             :  *
   11064             :  * @return CE_None in case of success, CE_Failure otherwise.
   11065             :  *
   11066             :  * @since GDAL 3.7
   11067             :  */
   11068          28 : CPLErr GDALDatasetReadCompressedData(GDALDatasetH hDS, const char *pszFormat,
   11069             :                                      int nXOff, int nYOff, int nXSize,
   11070             :                                      int nYSize, int nBandCount,
   11071             :                                      const int *panBandList, void **ppBuffer,
   11072             :                                      size_t *pnBufferSize,
   11073             :                                      char **ppszDetailedFormat)
   11074             : {
   11075          28 :     VALIDATE_POINTER1(hDS, __func__, CE_Failure);
   11076          56 :     return GDALDataset::FromHandle(hDS)->ReadCompressedData(
   11077             :         pszFormat, nXOff, nYOff, nXSize, nYSize, nBandCount, panBandList,
   11078          28 :         ppBuffer, pnBufferSize, ppszDetailedFormat);
   11079             : }
   11080             : 
   11081             : /************************************************************************/
   11082             : /*                           CanBeCloned()                              */
   11083             : /************************************************************************/
   11084             : 
   11085             : //! @cond Doxygen_Suppress
   11086             : 
   11087             : /** This method is called by GDALThreadSafeDataset::Create() to determine if
   11088             :  * it is possible to create a thread-safe wrapper for a dataset, which involves
   11089             :  * the ability to Clone() it.
   11090             :  *
   11091             :  * Implementations of this method must be thread-safe.
   11092             :  *
   11093             :  * @param nScopeFlags Combination of GDAL_OF_RASTER, GDAL_OF_VECTOR, etc. flags,
   11094             :  *                    expressing the intended use for thread-safety.
   11095             :  *                    Currently, the only valid scope is in the base
   11096             :  *                    implementation is GDAL_OF_RASTER.
   11097             :  * @param bCanShareState Determines if cloned datasets are allowed to share
   11098             :  *                       state with the dataset they have been cloned from.
   11099             :  *                       If set to true, the dataset from which they have been
   11100             :  *                       cloned from must remain opened during the lifetime of
   11101             :  *                       its clones.
   11102             :  * @return true if the Clone() method is expected to succeed with the same values
   11103             :  *         of nScopeFlags and bCanShareState.
   11104             :  */
   11105         149 : bool GDALDataset::CanBeCloned(int nScopeFlags,
   11106             :                               [[maybe_unused]] bool bCanShareState) const
   11107             : {
   11108         149 :     return m_bCanBeReopened && nScopeFlags == GDAL_OF_RASTER;
   11109             : }
   11110             : 
   11111             : //! @endcond
   11112             : 
   11113             : /************************************************************************/
   11114             : /*                               Clone()                                */
   11115             : /************************************************************************/
   11116             : 
   11117             : //! @cond Doxygen_Suppress
   11118             : 
   11119             : /** This method "clones" the current dataset, that is it returns a new instance
   11120             :  * that is opened on the same underlying "file".
   11121             :  *
   11122             :  * The base implementation uses GDALDataset::Open() to re-open the dataset.
   11123             :  * The MEM driver has a specialized implementation that returns a new instance,
   11124             :  * but which shares the same memory buffer as this.
   11125             :  *
   11126             :  * Implementations of this method must be thread-safe.
   11127             :  *
   11128             :  * @param nScopeFlags Combination of GDAL_OF_RASTER, GDAL_OF_VECTOR, etc. flags,
   11129             :  *                    expressing the intended use for thread-safety.
   11130             :  *                    Currently, the only valid scope is in the base
   11131             :  *                    implementation is GDAL_OF_RASTER.
   11132             :  * @param bCanShareState Determines if cloned datasets are allowed to share
   11133             :  *                       state with the dataset they have been cloned from.
   11134             :  *                       If set to true, the dataset from which they have been
   11135             :  *                       cloned from must remain opened during the lifetime of
   11136             :  *                       its clones.
   11137             :  * @return a new instance, or nullptr in case of error.
   11138             :  */
   11139             : std::unique_ptr<GDALDataset>
   11140        2051 : GDALDataset::Clone(int nScopeFlags, [[maybe_unused]] bool bCanShareState) const
   11141             : {
   11142        4102 :     CPLStringList aosAllowedDrivers;
   11143        2051 :     if (poDriver)
   11144        2051 :         aosAllowedDrivers.AddString(poDriver->GetDescription());
   11145             :     return std::unique_ptr<GDALDataset>(GDALDataset::Open(
   11146        2051 :         GetDescription(),
   11147        2051 :         nScopeFlags | GDAL_OF_INTERNAL | GDAL_OF_VERBOSE_ERROR,
   11148        4102 :         aosAllowedDrivers.List(), papszOpenOptions));
   11149             : }
   11150             : 
   11151             : //! @endcond
   11152             : 
   11153             : /************************************************************************/
   11154             : /*                    GeolocationToPixelLine()                          */
   11155             : /************************************************************************/
   11156             : 
   11157             : /** Transform georeferenced coordinates to pixel/line coordinates.
   11158             :  *
   11159             :  * When poSRS is null, those georeferenced coordinates (dfGeolocX, dfGeolocY)
   11160             :  * must be in the "natural" SRS of the dataset, that is the one returned by
   11161             :  * GetSpatialRef() if there is a geotransform, GetGCPSpatialRef() if there are
   11162             :  * GCPs, WGS 84 if there are RPC coefficients, or the SRS of the geolocation
   11163             :  * array (generally WGS 84) if there is a geolocation array.
   11164             :  * If that natural SRS is a geographic one, dfGeolocX must be a longitude, and
   11165             :  * dfGeolocY a latitude. If that natural SRS is a projected one, dfGeolocX must
   11166             :  * be a easting, and dfGeolocY a northing.
   11167             :  *
   11168             :  * When poSRS is set to a non-null value, (dfGeolocX, dfGeolocY) must be
   11169             :  * expressed in that CRS, and that tuple must be conformant with the
   11170             :  * data-axis-to-crs-axis setting of poSRS, that is the one returned by
   11171             :  * the OGRSpatialReference::GetDataAxisToSRSAxisMapping(). If you want to be sure
   11172             :  * of the axis order, then make sure to call poSRS->SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER)
   11173             :  * before calling this method, and in that case, dfGeolocX must be a longitude
   11174             :  * or an easting value, and dfGeolocX a latitude or a northing value.
   11175             :  *
   11176             :  * This method uses GDALCreateGenImgProjTransformer2() underneath.
   11177             :  *
   11178             :  * @param dfGeolocX X coordinate of the position (longitude or easting if poSRS
   11179             :  * is null, otherwise consistent with poSRS data-axis-to-crs-axis mapping),
   11180             :  * where interpolation should be done.
   11181             :  * @param dfGeolocY Y coordinate of the position (latitude or northing if poSRS
   11182             :  * is null, otherwise consistent with poSRS data-axis-to-crs-axis mapping),
   11183             :  * where interpolation should be done.
   11184             :  * @param poSRS If set, override the natural CRS in which dfGeolocX, dfGeolocY are expressed
   11185             :  * @param[out] pdfPixel Pointer to the variable where to the store the pixel/column coordinate.
   11186             :  * @param[out] pdfLine Pointer to the variable where to the store the line coordinate.
   11187             :  * @param papszTransformerOptions Options accepted by GDALCreateGenImgProjTransformer2(), or nullptr.
   11188             :  *
   11189             :  * @return CE_None on success, or an error code on failure.
   11190             :  * @since GDAL 3.11
   11191             :  */
   11192             : 
   11193             : CPLErr
   11194          15 : GDALDataset::GeolocationToPixelLine(double dfGeolocX, double dfGeolocY,
   11195             :                                     const OGRSpatialReference *poSRS,
   11196             :                                     double *pdfPixel, double *pdfLine,
   11197             :                                     CSLConstList papszTransformerOptions) const
   11198             : {
   11199          30 :     CPLStringList aosTO(papszTransformerOptions);
   11200             : 
   11201          15 :     if (poSRS)
   11202             :     {
   11203           4 :         const char *const apszOptions[] = {"FORMAT=WKT2", nullptr};
   11204           8 :         const std::string osWKT = poSRS->exportToWkt(apszOptions);
   11205           4 :         aosTO.SetNameValue("DST_SRS", osWKT.c_str());
   11206           4 :         const auto eAxisMappingStrategy = poSRS->GetAxisMappingStrategy();
   11207           4 :         if (eAxisMappingStrategy == OAMS_TRADITIONAL_GIS_ORDER)
   11208             :             aosTO.SetNameValue("DST_SRS_AXIS_MAPPING_STRATEGY",
   11209           1 :                                "TRADITIONAL_GIS_ORDER");
   11210           3 :         else if (eAxisMappingStrategy == OAMS_AUTHORITY_COMPLIANT)
   11211             :             aosTO.SetNameValue("DST_SRS_AXIS_MAPPING_STRATEGY",
   11212           1 :                                "AUTHORITY_COMPLIANT");
   11213             :         else
   11214             :         {
   11215           2 :             const auto &anValues = poSRS->GetDataAxisToSRSAxisMapping();
   11216           4 :             std::string osVal;
   11217           6 :             for (int v : anValues)
   11218             :             {
   11219           4 :                 if (!osVal.empty())
   11220           2 :                     osVal += ',';
   11221           4 :                 osVal += std::to_string(v);
   11222             :             }
   11223             :             aosTO.SetNameValue("DST_SRS_DATA_AXIS_TO_SRS_AXIS_MAPPING",
   11224           2 :                                osVal.c_str());
   11225             :         }
   11226             :     }
   11227             : 
   11228          15 :     auto hTransformer = GDALCreateGenImgProjTransformer2(
   11229             :         GDALDataset::ToHandle(const_cast<GDALDataset *>(this)), nullptr,
   11230          15 :         aosTO.List());
   11231          15 :     if (hTransformer == nullptr)
   11232             :     {
   11233           1 :         return CE_Failure;
   11234             :     }
   11235             : 
   11236          14 :     double z = 0;
   11237          14 :     int bSuccess = 0;
   11238          14 :     GDALGenImgProjTransform(hTransformer, TRUE, 1, &dfGeolocX, &dfGeolocY, &z,
   11239             :                             &bSuccess);
   11240          14 :     GDALDestroyTransformer(hTransformer);
   11241          14 :     if (bSuccess)
   11242             :     {
   11243          14 :         if (pdfPixel)
   11244          14 :             *pdfPixel = dfGeolocX;
   11245          14 :         if (pdfLine)
   11246          14 :             *pdfLine = dfGeolocY;
   11247          14 :         return CE_None;
   11248             :     }
   11249             :     else
   11250             :     {
   11251           0 :         return CE_Failure;
   11252             :     }
   11253             : }
   11254             : 
   11255             : /************************************************************************/
   11256             : /*                  GDALDatasetGeolocationToPixelLine()                 */
   11257             : /************************************************************************/
   11258             : 
   11259             : /** Transform georeferenced coordinates to pixel/line coordinates.
   11260             :  *
   11261             :  * @see GDALDataset::GeolocationToPixelLine()
   11262             :  * @since GDAL 3.11
   11263             :  */
   11264             : 
   11265           0 : CPLErr GDALDatasetGeolocationToPixelLine(GDALDatasetH hDS, double dfGeolocX,
   11266             :                                          double dfGeolocY,
   11267             :                                          OGRSpatialReferenceH hSRS,
   11268             :                                          double *pdfPixel, double *pdfLine,
   11269             :                                          CSLConstList papszTransformerOptions)
   11270             : {
   11271           0 :     VALIDATE_POINTER1(hDS, "GDALDatasetGeolocationToPixelLine", CE_Failure);
   11272             : 
   11273           0 :     GDALDataset *poDS = GDALDataset::FromHandle(hDS);
   11274           0 :     return poDS->GeolocationToPixelLine(
   11275           0 :         dfGeolocX, dfGeolocY, OGRSpatialReference::FromHandle(hSRS), pdfPixel,
   11276           0 :         pdfLine, papszTransformerOptions);
   11277             : }
   11278             : 
   11279             : /************************************************************************/
   11280             : /*                               GetExtent()                            */
   11281             : /************************************************************************/
   11282             : 
   11283             : /** Return extent of dataset in specified CRS.
   11284             :  *
   11285             :  * OGREnvelope.MinX/MaxX represents longitudes, and MinY/MaxY latitudes.
   11286             :  *
   11287             :  * For rasters, the base implementation of this method only succeeds if
   11288             :  * GetGeoTransform() and GetSpatialRef() succeed.
   11289             :  * For vectors, the base implementation of this method iterates over layers
   11290             :  * and call their OGRLayer::GetExtent() method.
   11291             :  *
   11292             :  * TestCapability(GDsCFastGetExtent) can be used to test if the execution
   11293             :  * time of this method is fast.
   11294             :  *
   11295             :  * This is the same as C function GDALGetExtent()
   11296             :  *
   11297             :  * @param[out] psExtent Pointer to output extent. Must NOT be null.
   11298             :  * @param poCRS CRS in which to express the extent. If not specified, this will
   11299             :  * be the raster CRS or the CRS of the first layer for a vector dataset.
   11300             :  * @return CE_None in case of success, CE_Failure otherwise
   11301             :  * @since GDAL 3.12
   11302             :  */
   11303             : 
   11304         229 : CPLErr GDALDataset::GetExtent(OGREnvelope *psExtent,
   11305             :                               const OGRSpatialReference *poCRS) const
   11306             : {
   11307         229 :     const OGRSpatialReference *poThisCRS = GetSpatialRefRasterOnly();
   11308         229 :     int nLayerCount = 0;
   11309         229 :     if (!poThisCRS)
   11310             :     {
   11311          93 :         nLayerCount = GetLayerCount();
   11312          93 :         if (nLayerCount >= 1)
   11313             :         {
   11314           3 :             if (auto poLayer = GetLayer(0))
   11315           3 :                 poThisCRS = poLayer->GetSpatialRef();
   11316             :         }
   11317             :     }
   11318         229 :     if (!poCRS)
   11319         131 :         poCRS = poThisCRS;
   11320          98 :     else if (!poThisCRS)
   11321           3 :         return CE_Failure;
   11322             : 
   11323         226 :     *psExtent = OGREnvelope();
   11324             : 
   11325         226 :     GDALGeoTransform gt;
   11326         226 :     auto poThisDS = const_cast<GDALDataset *>(this);
   11327         226 :     const bool bHasGT = poThisDS->GetGeoTransform(gt) == CE_None;
   11328         226 :     if (bHasGT)
   11329             :     {
   11330           0 :         std::unique_ptr<OGRCoordinateTransformation> poCT;
   11331         221 :         if (poCRS)
   11332             :         {
   11333         136 :             poCT.reset(OGRCreateCoordinateTransformation(poThisCRS, poCRS));
   11334             :         }
   11335             : 
   11336         221 :         constexpr int DENSIFY_POINT_COUNT = 21;
   11337         221 :         double dfULX = gt[0];
   11338         221 :         double dfULY = gt[3];
   11339         221 :         double dfURX = 0, dfURY = 0;
   11340         221 :         gt.Apply(nRasterXSize, 0, &dfURX, &dfURY);
   11341         221 :         double dfLLX = 0, dfLLY = 0;
   11342         221 :         gt.Apply(0, nRasterYSize, &dfLLX, &dfLLY);
   11343         221 :         double dfLRX = 0, dfLRY = 0;
   11344         221 :         gt.Apply(nRasterXSize, nRasterYSize, &dfLRX, &dfLRY);
   11345         221 :         const double xmin = std::min({dfULX, dfURX, dfLLX, dfLRX});
   11346         221 :         const double ymin = std::min({dfULY, dfURY, dfLLY, dfLRY});
   11347         221 :         const double xmax = std::max({dfULX, dfURX, dfLLX, dfLRX});
   11348         221 :         const double ymax = std::max({dfULY, dfURY, dfLLY, dfLRY});
   11349         221 :         if (poCT)
   11350             :         {
   11351         136 :             OGREnvelope sEnvTmp;
   11352         272 :             if (!poCT->TransformBounds(xmin, ymin, xmax, ymax, &(sEnvTmp.MinX),
   11353             :                                        &(sEnvTmp.MinY), &(sEnvTmp.MaxX),
   11354         136 :                                        &(sEnvTmp.MaxY), DENSIFY_POINT_COUNT))
   11355             :             {
   11356           0 :                 return CE_Failure;
   11357             :             }
   11358         136 :             *psExtent = sEnvTmp;
   11359             :         }
   11360             :         else
   11361             :         {
   11362          85 :             psExtent->MinX = xmin;
   11363          85 :             psExtent->MinY = ymin;
   11364          85 :             psExtent->MaxX = xmax;
   11365          85 :             psExtent->MaxY = ymax;
   11366             :         }
   11367             :     }
   11368             : 
   11369         226 :     if (nLayerCount > 0)
   11370             :     {
   11371           6 :         for (auto &&poLayer : poThisDS->GetLayers())
   11372             :         {
   11373           3 :             auto poLayerCRS = poLayer->GetSpatialRef();
   11374           3 :             if (poLayerCRS)
   11375             :             {
   11376           3 :                 OGREnvelope sLayerExtent;
   11377           3 :                 if (poLayer->GetExtent(&sLayerExtent) == OGRERR_NONE)
   11378             :                 {
   11379             :                     auto poCT = std::unique_ptr<OGRCoordinateTransformation>(
   11380           6 :                         OGRCreateCoordinateTransformation(poLayerCRS, poCRS));
   11381           3 :                     if (poCT)
   11382             :                     {
   11383           3 :                         constexpr int DENSIFY_POINT_COUNT = 21;
   11384           3 :                         OGREnvelope sEnvTmp;
   11385           3 :                         if (poCT->TransformBounds(
   11386             :                                 sLayerExtent.MinX, sLayerExtent.MinY,
   11387             :                                 sLayerExtent.MaxX, sLayerExtent.MaxY,
   11388             :                                 &(sEnvTmp.MinX), &(sEnvTmp.MinY),
   11389             :                                 &(sEnvTmp.MaxX), &(sEnvTmp.MaxY),
   11390           3 :                                 DENSIFY_POINT_COUNT))
   11391             :                         {
   11392           3 :                             psExtent->Merge(sEnvTmp);
   11393             :                         }
   11394             :                     }
   11395             :                 }
   11396             :             }
   11397             :         }
   11398             :     }
   11399             : 
   11400         226 :     return psExtent->IsInit() ? CE_None : CE_Failure;
   11401             : }
   11402             : 
   11403             : /************************************************************************/
   11404             : /*                           GDALGetExtent()                            */
   11405             : /************************************************************************/
   11406             : 
   11407             : /** Return extent of dataset in specified CRS.
   11408             :  *
   11409             :  * OGREnvelope.MinX/MaxX represents longitudes, and MinY/MaxY latitudes.
   11410             :  *
   11411             :  * For rasters, the base implementation of this method only succeeds if
   11412             :  * GetGeoTransform() and GetSpatialRef() succeed.
   11413             :  * For vectors, the base implementation of this method iterates over layers
   11414             :  * and call their OGRLayer::GetExtent() method.
   11415             :  *
   11416             :  * TestCapability(GDsCFastGetExtent) can be used to test if the execution
   11417             :  * time of this method is fast.
   11418             :  *
   11419             :  * This is the same as C++ method GDALDataset::GetExtent()
   11420             :  *
   11421             :  * @param hDS Dataset handle. Must NOT be null.
   11422             :  * @param[out] psExtent Pointer to output extent. Must NOT be null.
   11423             :  * @param hCRS CRS in which to express the extent. If not specified, this will
   11424             :  * be the raster CRS or the CRS of the first layer for a vector dataset.
   11425             :  * @return extent in poCRS (valid only if IsInit() method returns true)
   11426             :  * @since GDAL 3.12
   11427             :  */
   11428             : 
   11429          28 : CPLErr GDALGetExtent(GDALDatasetH hDS, OGREnvelope *psExtent,
   11430             :                      OGRSpatialReferenceH hCRS)
   11431             : {
   11432          28 :     VALIDATE_POINTER1(hDS, __func__, CE_Failure);
   11433          28 :     VALIDATE_POINTER1(psExtent, __func__, CE_Failure);
   11434          56 :     return GDALDataset::FromHandle(hDS)->GetExtent(
   11435          28 :         psExtent, OGRSpatialReference::FromHandle(hCRS));
   11436             : }
   11437             : 
   11438             : /************************************************************************/
   11439             : /*                         GetExtentWGS84LongLat()                      */
   11440             : /************************************************************************/
   11441             : 
   11442             : /** Return extent of dataset in WGS84 longitude/latitude
   11443             :  *
   11444             :  * OGREnvelope.MinX/MaxX represents longitudes, and MinY/MaxY latitudes.
   11445             :  *
   11446             :  * TestCapability(GDsCFastGetExtentWGS84LongLat) can be used to test if the execution
   11447             :  * time of this method is fast.
   11448             :  *
   11449             :  * This is the same as C function GDALGetExtentWGS84LongLat()
   11450             :  *
   11451             :  * @return extent (valid only if IsInit() method returns true)
   11452             :  * @since GDAL 3.12
   11453             :  */
   11454             : 
   11455          96 : CPLErr GDALDataset::GetExtentWGS84LongLat(OGREnvelope *psExtent) const
   11456             : {
   11457         192 :     OGRSpatialReference oSRS_WGS84;
   11458          96 :     oSRS_WGS84.SetFromUserInput("WGS84");
   11459          96 :     oSRS_WGS84.SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
   11460         192 :     return GetExtent(psExtent, &oSRS_WGS84);
   11461             : }
   11462             : 
   11463             : /************************************************************************/
   11464             : /*                    GDALGetExtentWGS84LongLat()                       */
   11465             : /************************************************************************/
   11466             : 
   11467             : /** Return extent of dataset in WGS84 longitude/latitude
   11468             :  *
   11469             :  * OGREnvelope.MinX/MaxX represents longitudes, and MinY/MaxY latitudes.
   11470             :  *
   11471             :  * TestCapability(GDsCFastGetExtentWGS84LongLat) can be used to test if the execution
   11472             :  * time of this method is fast.
   11473             :  *
   11474             :  * This is the same as C++ method GDALDataset::GetExtentWGS84LongLat()
   11475             :  *
   11476             :  * @param hDS Dataset handle. Must NOT be null.
   11477             :  * @param[out] psExtent Pointer to output extent. Must NOT be null.
   11478             :  * @return extent (valid only if IsInit() method returns true)
   11479             :  * @since GDAL 3.12
   11480             :  */
   11481             : 
   11482           4 : CPLErr GDALGetExtentWGS84LongLat(GDALDatasetH hDS, OGREnvelope *psExtent)
   11483             : {
   11484           4 :     VALIDATE_POINTER1(hDS, __func__, CE_Failure);
   11485           4 :     VALIDATE_POINTER1(psExtent, __func__, CE_Failure);
   11486           4 :     return GDALDataset::FromHandle(hDS)->GetExtentWGS84LongLat(psExtent);
   11487             : }
   11488             : 
   11489             : /************************************************************************/
   11490             : /*                  ReportUpdateNotSupportedByDriver()                  */
   11491             : /************************************************************************/
   11492             : 
   11493             : //! @cond Doxygen_Suppress
   11494             : 
   11495             : /* static */
   11496           1 : void GDALDataset::ReportUpdateNotSupportedByDriver(const char *pszDriverName)
   11497             : {
   11498           1 :     CPLError(CE_Failure, CPLE_NotSupported,
   11499             :              "The %s driver does not support update access to existing "
   11500             :              "datasets.",
   11501             :              pszDriverName);
   11502           1 : }
   11503             : 
   11504             : //! @endcond
   11505             : 
   11506             : /************************************************************************/
   11507             : /*                         BuildFilename()                              */
   11508             : /************************************************************************/
   11509             : 
   11510             : /** Generates a filename, potentially relative to another one.
   11511             :  *
   11512             :  * Given the path to a reference directory, and a path to a file
   11513             :  * referenced from it, build a path to the file that the current application
   11514             :  * can use. If the file path is already absolute, rather than relative, or if
   11515             :  * bRelativeToReferencePath is false, then the filename of interest will be
   11516             :  * returned unaltered.
   11517             :  *
   11518             :  * This is enhanced version of CPLProjectRelativeFilenameSafe() that takes
   11519             :  * into account the subdataset syntax.
   11520             :  *
   11521             :  * Examples:
   11522             :  * \code{.cpp}
   11523             :  * BuildFilename("tmp/abc.gif", "abc/def", true) == "abc/def/tmp/abc.gif"
   11524             :  * BuildFilename("../abc.gif", "/abc/def") == "/abc/abc.gif"
   11525             :  * BuildFilename("abc.gif", "C:\WIN", true) == "C:\WIN\abc.gif"
   11526             :  * BuildFilename("abc.gif", "C:\WIN", false) == "abc.gif"
   11527             :  * BuildFilename("/home/even/foo.tif", "/home/even/workdir", true) == "/home/even/foo.tif"
   11528             :  * \endcode
   11529             :  *
   11530             :  * @param pszFilename Filename of interest.
   11531             :  * @param pszReferencePath Path to a reference directory.
   11532             :  * @param bRelativeToReferencePath Whether pszFilename, if a relative path, is
   11533             :  *                                 relative to pszReferencePath
   11534             :  * @since 3.11
   11535             :  */
   11536             : 
   11537             : /* static */
   11538      104264 : std::string GDALDataset::BuildFilename(const char *pszFilename,
   11539             :                                        const char *pszReferencePath,
   11540             :                                        bool bRelativeToReferencePath)
   11541             : {
   11542      104264 :     std::string osSrcDSName;
   11543      104264 :     if (pszReferencePath != nullptr && bRelativeToReferencePath)
   11544             :     {
   11545             :         // Try subdatasetinfo API first
   11546             :         // Note: this will become the only branch when subdatasetinfo will become
   11547             :         //       available for NITF_IM, RASTERLITE and TILEDB
   11548        2594 :         const auto oSubDSInfo{GDALGetSubdatasetInfo(pszFilename)};
   11549        2594 :         if (oSubDSInfo && !oSubDSInfo->GetPathComponent().empty())
   11550             :         {
   11551           8 :             auto path{oSubDSInfo->GetPathComponent()};
   11552          12 :             osSrcDSName = oSubDSInfo->ModifyPathComponent(
   11553           8 :                 CPLProjectRelativeFilenameSafe(pszReferencePath, path.c_str())
   11554           4 :                     .c_str());
   11555           4 :             GDALDestroySubdatasetInfo(oSubDSInfo);
   11556             :         }
   11557             :         else
   11558             :         {
   11559        2590 :             bool bDone = false;
   11560       15525 :             for (const char *pszSyntax : apszSpecialSubDatasetSyntax)
   11561             :             {
   11562       12938 :                 CPLString osPrefix(pszSyntax);
   11563       12938 :                 osPrefix.resize(strchr(pszSyntax, ':') - pszSyntax + 1);
   11564       12938 :                 if (pszSyntax[osPrefix.size()] == '"')
   11565        2587 :                     osPrefix += '"';
   11566       12938 :                 if (EQUALN(pszFilename, osPrefix, osPrefix.size()))
   11567             :                 {
   11568           3 :                     if (STARTS_WITH_CI(pszSyntax + osPrefix.size(), "{ANY}"))
   11569             :                     {
   11570           3 :                         const char *pszLastPart = strrchr(pszFilename, ':') + 1;
   11571             :                         // CSV:z:/foo.xyz
   11572           3 :                         if ((pszLastPart[0] == '/' || pszLastPart[0] == '\\') &&
   11573           0 :                             pszLastPart - pszFilename >= 3 &&
   11574           0 :                             pszLastPart[-3] == ':')
   11575             :                         {
   11576           0 :                             pszLastPart -= 2;
   11577             :                         }
   11578           3 :                         CPLString osPrefixFilename = pszFilename;
   11579           3 :                         osPrefixFilename.resize(pszLastPart - pszFilename);
   11580           6 :                         osSrcDSName = osPrefixFilename +
   11581           6 :                                       CPLProjectRelativeFilenameSafe(
   11582           3 :                                           pszReferencePath, pszLastPart);
   11583           3 :                         bDone = true;
   11584             :                     }
   11585           0 :                     else if (STARTS_WITH_CI(pszSyntax + osPrefix.size(),
   11586             :                                             "{FILENAME}"))
   11587             :                     {
   11588           0 :                         CPLString osFilename(pszFilename + osPrefix.size());
   11589           0 :                         size_t nPos = 0;
   11590           0 :                         if (osFilename.size() >= 3 && osFilename[1] == ':' &&
   11591           0 :                             (osFilename[2] == '\\' || osFilename[2] == '/'))
   11592           0 :                             nPos = 2;
   11593           0 :                         nPos = osFilename.find(
   11594           0 :                             pszSyntax[osPrefix.size() + strlen("{FILENAME}")],
   11595             :                             nPos);
   11596           0 :                         if (nPos != std::string::npos)
   11597             :                         {
   11598           0 :                             const CPLString osSuffix = osFilename.substr(nPos);
   11599           0 :                             osFilename.resize(nPos);
   11600           0 :                             osSrcDSName = osPrefix +
   11601           0 :                                           CPLProjectRelativeFilenameSafe(
   11602           0 :                                               pszReferencePath, osFilename) +
   11603           0 :                                           osSuffix;
   11604           0 :                             bDone = true;
   11605             :                         }
   11606             :                     }
   11607           3 :                     break;
   11608             :                 }
   11609             :             }
   11610        2590 :             if (!bDone)
   11611             :             {
   11612        2587 :                 std::string osReferencePath = pszReferencePath;
   11613        2587 :                 if (!CPLIsFilenameRelative(pszReferencePath))
   11614             :                 {
   11615             :                     // Simplify path by replacing "foo/a/../b" with "foo/b"
   11616        2294 :                     while (STARTS_WITH(pszFilename, "../"))
   11617             :                     {
   11618             :                         osReferencePath =
   11619           5 :                             CPLGetPathSafe(osReferencePath.c_str());
   11620           5 :                         pszFilename += strlen("../");
   11621             :                     }
   11622             :                 }
   11623             : 
   11624        5174 :                 osSrcDSName = CPLProjectRelativeFilenameSafe(
   11625        2587 :                     osReferencePath.c_str(), pszFilename);
   11626             :             }
   11627        2594 :         }
   11628             :     }
   11629             :     else
   11630             :     {
   11631      101670 :         osSrcDSName = pszFilename;
   11632             :     }
   11633      104264 :     return osSrcDSName;
   11634             : }
   11635             : 
   11636             : /************************************************************************/
   11637             : /*                       GDALMDArrayFromDataset                         */
   11638             : /************************************************************************/
   11639             : 
   11640             : class GDALMDArrayFromDataset final : public GDALMDArray
   11641             : {
   11642             :     CPL_DISALLOW_COPY_ASSIGN(GDALMDArrayFromDataset)
   11643             : 
   11644             :     GDALDataset *const m_poDS;
   11645             :     const GDALExtendedDataType m_dt;
   11646             :     std::vector<std::shared_ptr<GDALDimension>> m_dims{};
   11647             :     std::string m_osUnit{};
   11648             :     std::vector<GByte> m_abyNoData{};
   11649             :     std::shared_ptr<GDALMDArray> m_varX{};
   11650             :     std::shared_ptr<GDALMDArray> m_varY{};
   11651             :     std::shared_ptr<GDALMDArray> m_varBand{};
   11652             :     const std::string m_osFilename;
   11653             :     int m_iBandDim = 0;
   11654             :     int m_iYDim = 1;
   11655             :     int m_iXDim = 2;
   11656             : 
   11657             :     bool ReadWrite(GDALRWFlag eRWFlag, const GUInt64 *arrayStartIdx,
   11658             :                    const size_t *count, const GInt64 *arrayStep,
   11659             :                    const GPtrDiff_t *bufferStride,
   11660             :                    const GDALExtendedDataType &bufferDataType,
   11661             :                    void *pBuffer) const;
   11662             : 
   11663             :   protected:
   11664          15 :     GDALMDArrayFromDataset(GDALDataset *poDS, CSLConstList papszOptions)
   11665          30 :         : GDALAbstractMDArray(std::string(),
   11666          30 :                               std::string(poDS->GetDescription())),
   11667          30 :           GDALMDArray(std::string(), std::string(poDS->GetDescription())),
   11668             :           m_poDS(poDS), m_dt(GDALExtendedDataType::Create(
   11669             :                             poDS->GetRasterBand(1)->GetRasterDataType())),
   11670          75 :           m_osFilename(poDS->GetDescription())
   11671             :     {
   11672          15 :         m_poDS->Reference();
   11673             : 
   11674          15 :         const int nBandCount = poDS->GetRasterCount();
   11675          43 :         for (int i = 1; i <= nBandCount; ++i)
   11676             :         {
   11677          28 :             const auto poBand = poDS->GetRasterBand(i);
   11678          28 :             if (i == 1)
   11679          15 :                 m_osUnit = poBand->GetUnitType();
   11680          13 :             else if (m_osUnit != poBand->GetUnitType())
   11681           7 :                 m_osUnit.clear();
   11682             : 
   11683          56 :             std::vector<GByte> abyNoData;
   11684          28 :             int bHasNoData = false;
   11685          28 :             switch (poBand->GetRasterDataType())
   11686             :             {
   11687           0 :                 case GDT_Int64:
   11688             :                 {
   11689             :                     const auto nNoData =
   11690           0 :                         poBand->GetNoDataValueAsInt64(&bHasNoData);
   11691           0 :                     if (bHasNoData)
   11692             :                     {
   11693           0 :                         abyNoData.resize(m_dt.GetSize());
   11694           0 :                         GDALCopyWords64(&nNoData, GDT_Int64, 0, &abyNoData[0],
   11695             :                                         m_dt.GetNumericDataType(), 0, 1);
   11696             :                     }
   11697           0 :                     break;
   11698             :                 }
   11699             : 
   11700           0 :                 case GDT_UInt64:
   11701             :                 {
   11702             :                     const auto nNoData =
   11703           0 :                         poBand->GetNoDataValueAsUInt64(&bHasNoData);
   11704           0 :                     if (bHasNoData)
   11705             :                     {
   11706           0 :                         abyNoData.resize(m_dt.GetSize());
   11707           0 :                         GDALCopyWords64(&nNoData, GDT_UInt64, 0, &abyNoData[0],
   11708             :                                         m_dt.GetNumericDataType(), 0, 1);
   11709             :                     }
   11710           0 :                     break;
   11711             :                 }
   11712             : 
   11713          28 :                 default:
   11714             :                 {
   11715          28 :                     const auto dfNoData = poBand->GetNoDataValue(&bHasNoData);
   11716          28 :                     if (bHasNoData)
   11717             :                     {
   11718          11 :                         abyNoData.resize(m_dt.GetSize());
   11719          22 :                         GDALCopyWords64(&dfNoData, GDT_Float64, 0,
   11720          11 :                                         &abyNoData[0],
   11721             :                                         m_dt.GetNumericDataType(), 0, 1);
   11722             :                     }
   11723          28 :                     break;
   11724             :                 }
   11725             :             }
   11726             : 
   11727          28 :             if (i == 1)
   11728          15 :                 m_abyNoData = std::move(abyNoData);
   11729          13 :             else if (m_abyNoData != abyNoData)
   11730           7 :                 m_abyNoData.clear();
   11731             :         }
   11732             : 
   11733          15 :         const int nXSize = poDS->GetRasterXSize();
   11734          15 :         const int nYSize = poDS->GetRasterYSize();
   11735             : 
   11736          15 :         auto poSRS = poDS->GetSpatialRef();
   11737          30 :         std::string osTypeY;
   11738          30 :         std::string osTypeX;
   11739          30 :         std::string osDirectionY;
   11740          30 :         std::string osDirectionX;
   11741          15 :         if (poSRS && poSRS->GetAxesCount() == 2)
   11742             :         {
   11743           8 :             const auto &mapping = poSRS->GetDataAxisToSRSAxisMapping();
   11744           8 :             OGRAxisOrientation eOrientation1 = OAO_Other;
   11745           8 :             poSRS->GetAxis(nullptr, 0, &eOrientation1);
   11746           8 :             OGRAxisOrientation eOrientation2 = OAO_Other;
   11747           8 :             poSRS->GetAxis(nullptr, 1, &eOrientation2);
   11748           8 :             if (eOrientation1 == OAO_East && eOrientation2 == OAO_North)
   11749             :             {
   11750           6 :                 if (mapping == std::vector<int>{1, 2})
   11751             :                 {
   11752           6 :                     osTypeY = GDAL_DIM_TYPE_HORIZONTAL_Y;
   11753           6 :                     osDirectionY = "NORTH";
   11754           6 :                     osTypeX = GDAL_DIM_TYPE_HORIZONTAL_X;
   11755           6 :                     osDirectionX = "EAST";
   11756             :                 }
   11757             :             }
   11758           2 :             else if (eOrientation1 == OAO_North && eOrientation2 == OAO_East)
   11759             :             {
   11760           2 :                 if (mapping == std::vector<int>{2, 1})
   11761             :                 {
   11762           2 :                     osTypeY = GDAL_DIM_TYPE_HORIZONTAL_Y;
   11763           2 :                     osDirectionY = "NORTH";
   11764           2 :                     osTypeX = GDAL_DIM_TYPE_HORIZONTAL_X;
   11765           2 :                     osDirectionX = "EAST";
   11766             :                 }
   11767             :             }
   11768             :         }
   11769             : 
   11770          41 :         const bool bBandYX = [papszOptions, poDS, nBandCount]()
   11771             :         {
   11772             :             const char *pszDimOrder =
   11773          15 :                 CSLFetchNameValueDef(papszOptions, "DIM_ORDER", "AUTO");
   11774          15 :             if (EQUAL(pszDimOrder, "AUTO"))
   11775             :             {
   11776             :                 const char *pszInterleave =
   11777          13 :                     poDS->GetMetadataItem("INTERLEAVE", "IMAGE_STRUCTURE");
   11778          22 :                 return nBandCount == 1 || !pszInterleave ||
   11779          22 :                        !EQUAL(pszInterleave, "PIXEL");
   11780             :             }
   11781             :             else
   11782             :             {
   11783           2 :                 return EQUAL(pszDimOrder, "BAND,Y,X");
   11784             :             }
   11785          15 :         }();
   11786             :         const char *const pszBandDimName =
   11787          15 :             CSLFetchNameValueDef(papszOptions, "BAND_DIM_NAME", "Band");
   11788             :         auto poBandDim = std::make_shared<GDALDimensionWeakIndexingVar>(
   11789          45 :             "/", pszBandDimName, std::string(), std::string(), nBandCount);
   11790             :         const char *const pszYDimName =
   11791          15 :             CSLFetchNameValueDef(papszOptions, "Y_DIM_NAME", "Y");
   11792             :         auto poYDim = std::make_shared<GDALDimensionWeakIndexingVar>(
   11793          30 :             "/", pszYDimName, osTypeY, osDirectionY, nYSize);
   11794             :         const char *const pszXDimName =
   11795          15 :             CSLFetchNameValueDef(papszOptions, "X_DIM_NAME", "X");
   11796             :         auto poXDim = std::make_shared<GDALDimensionWeakIndexingVar>(
   11797          30 :             "/", pszXDimName, osTypeX, osDirectionX, nXSize);
   11798             : 
   11799          15 :         const char *const pszBandIndexingVarItem = CSLFetchNameValueDef(
   11800             :             papszOptions, "BAND_INDEXING_VAR_ITEM", "{Description}");
   11801          15 :         if (EQUAL(pszBandIndexingVarItem, "{Description}"))
   11802             :         {
   11803             :             const auto oIndexingVarType =
   11804          18 :                 GDALExtendedDataType::CreateString(strlen("Band 65535"));
   11805           9 :             auto poBandVar = MEMMDArray::Create("/", poBandDim->GetName(),
   11806          36 :                                                 {poBandDim}, oIndexingVarType);
   11807           9 :             CPL_IGNORE_RET_VAL(poBandVar->Init());
   11808          25 :             for (int i = 0; i < nBandCount; ++i)
   11809             :             {
   11810             :                 const char *pszDesc =
   11811          16 :                     poDS->GetRasterBand(i + 1)->GetDescription();
   11812             :                 const std::string osBandName =
   11813          32 :                     pszDesc[0] ? pszDesc : CPLSPrintf("Band %d", i + 1);
   11814          16 :                 const char *pszBandName = osBandName.c_str();
   11815          16 :                 const char *const apszBandVal[] = {pszBandName};
   11816          16 :                 const GUInt64 anStartIdx[] = {static_cast<GUInt64>(i)};
   11817          16 :                 const size_t anCount[] = {1};
   11818          16 :                 const GInt64 arrayStep[] = {1};
   11819          16 :                 const GPtrDiff_t anBufferStride[] = {1};
   11820          16 :                 poBandVar->Write(anStartIdx, anCount, arrayStep, anBufferStride,
   11821             :                                  oIndexingVarType, apszBandVal);
   11822             :             }
   11823           9 :             m_varBand = std::move(poBandVar);
   11824           9 :             poBandDim->SetIndexingVariable(m_varBand);
   11825             :         }
   11826           6 :         else if (EQUAL(pszBandIndexingVarItem, "{Index}"))
   11827             :         {
   11828             :             const auto oIndexingVarType =
   11829           2 :                 GDALExtendedDataType::Create(GDT_Int32);
   11830           1 :             auto poBandVar = MEMMDArray::Create("/", poBandDim->GetName(),
   11831           4 :                                                 {poBandDim}, oIndexingVarType);
   11832           1 :             CPL_IGNORE_RET_VAL(poBandVar->Init());
   11833           3 :             for (int i = 0; i < nBandCount; ++i)
   11834             :             {
   11835           2 :                 const int anBandIdx[] = {i + 1};
   11836           2 :                 const GUInt64 anStartIdx[] = {static_cast<GUInt64>(i)};
   11837           2 :                 const size_t anCount[] = {1};
   11838           2 :                 const GInt64 arrayStep[] = {1};
   11839           2 :                 const GPtrDiff_t anBufferStride[] = {1};
   11840           2 :                 poBandVar->Write(anStartIdx, anCount, arrayStep, anBufferStride,
   11841             :                                  oIndexingVarType, anBandIdx);
   11842             :             }
   11843           1 :             m_varBand = std::move(poBandVar);
   11844           1 :             poBandDim->SetIndexingVariable(m_varBand);
   11845             :         }
   11846           5 :         else if (EQUAL(pszBandIndexingVarItem, "{ColorInterpretation}"))
   11847             :         {
   11848           1 :             size_t nMaxLen = 0;
   11849           3 :             for (int i = 0; i < nBandCount; ++i)
   11850             :             {
   11851           2 :                 const char *pszDesc = GDALGetColorInterpretationName(
   11852           2 :                     poDS->GetRasterBand(i + 1)->GetColorInterpretation());
   11853           2 :                 nMaxLen = std::max(nMaxLen, strlen(pszDesc));
   11854             :             }
   11855             :             const auto oIndexingVarType =
   11856           2 :                 GDALExtendedDataType::CreateString(nMaxLen);
   11857           1 :             auto poBandVar = MEMMDArray::Create("/", poBandDim->GetName(),
   11858           4 :                                                 {poBandDim}, oIndexingVarType);
   11859           1 :             CPL_IGNORE_RET_VAL(poBandVar->Init());
   11860           3 :             for (int i = 0; i < nBandCount; ++i)
   11861             :             {
   11862           2 :                 const char *pszDesc = GDALGetColorInterpretationName(
   11863           2 :                     poDS->GetRasterBand(i + 1)->GetColorInterpretation());
   11864           2 :                 const char *const apszBandVal[] = {pszDesc};
   11865           2 :                 const GUInt64 anStartIdx[] = {static_cast<GUInt64>(i)};
   11866           2 :                 const size_t anCount[] = {1};
   11867           2 :                 const GInt64 arrayStep[] = {1};
   11868           2 :                 const GPtrDiff_t anBufferStride[] = {1};
   11869           2 :                 poBandVar->Write(anStartIdx, anCount, arrayStep, anBufferStride,
   11870             :                                  oIndexingVarType, apszBandVal);
   11871             :             }
   11872           1 :             m_varBand = std::move(poBandVar);
   11873           1 :             poBandDim->SetIndexingVariable(m_varBand);
   11874             :         }
   11875           4 :         else if (!EQUAL(pszBandIndexingVarItem, "{None}"))
   11876             :         {
   11877           3 :             const char *const pszBandIndexingVarType = CSLFetchNameValueDef(
   11878             :                 papszOptions, "BAND_INDEXING_VAR_TYPE", "String");
   11879           3 :             size_t nMaxLen = 0;
   11880           3 :             if (EQUAL(pszBandIndexingVarType, "String"))
   11881             :             {
   11882           3 :                 for (int i = 0; i < nBandCount; ++i)
   11883             :                 {
   11884             :                     const char *pszVal =
   11885           2 :                         poDS->GetRasterBand(i + 1)->GetMetadataItem(
   11886           2 :                             pszBandIndexingVarItem);
   11887           2 :                     if (pszVal)
   11888           1 :                         nMaxLen = std::max(nMaxLen, strlen(pszVal));
   11889             :                 }
   11890             :             }
   11891             :             const auto oIndexingVarType =
   11892           3 :                 EQUAL(pszBandIndexingVarType, "String")
   11893             :                     ? GDALExtendedDataType::CreateString(nMaxLen)
   11894           2 :                 : EQUAL(pszBandIndexingVarType, "Integer")
   11895             :                     ? GDALExtendedDataType::Create(GDT_Int32)
   11896           6 :                     : GDALExtendedDataType::Create(GDT_Float64);
   11897           3 :             auto poBandVar = MEMMDArray::Create("/", poBandDim->GetName(),
   11898          12 :                                                 {poBandDim}, oIndexingVarType);
   11899           3 :             CPL_IGNORE_RET_VAL(poBandVar->Init());
   11900           9 :             for (int i = 0; i < nBandCount; ++i)
   11901             :             {
   11902           6 :                 const GUInt64 anStartIdx[] = {static_cast<GUInt64>(i)};
   11903           6 :                 const size_t anCount[] = {1};
   11904           6 :                 const GInt64 arrayStep[] = {1};
   11905           6 :                 const GPtrDiff_t anBufferStride[] = {1};
   11906             :                 const char *pszVal =
   11907           6 :                     poDS->GetRasterBand(i + 1)->GetMetadataItem(
   11908           6 :                         pszBandIndexingVarItem);
   11909           6 :                 if (oIndexingVarType.GetClass() == GEDTC_STRING)
   11910             :                 {
   11911           2 :                     const char *const apszBandVal[] = {pszVal ? pszVal : ""};
   11912           2 :                     poBandVar->Write(anStartIdx, anCount, arrayStep,
   11913             :                                      anBufferStride, oIndexingVarType,
   11914             :                                      apszBandVal);
   11915             :                 }
   11916           4 :                 else if (oIndexingVarType.GetNumericDataType() == GDT_Int32)
   11917             :                 {
   11918           2 :                     const int anVal[] = {pszVal ? atoi(pszVal) : 0};
   11919           2 :                     poBandVar->Write(anStartIdx, anCount, arrayStep,
   11920             :                                      anBufferStride, oIndexingVarType, anVal);
   11921             :                 }
   11922             :                 else
   11923             :                 {
   11924           2 :                     const double adfVal[] = {pszVal ? CPLAtof(pszVal) : 0.0};
   11925           2 :                     poBandVar->Write(anStartIdx, anCount, arrayStep,
   11926             :                                      anBufferStride, oIndexingVarType, adfVal);
   11927             :                 }
   11928             :             }
   11929           3 :             m_varBand = std::move(poBandVar);
   11930           3 :             poBandDim->SetIndexingVariable(m_varBand);
   11931             :         }
   11932             : 
   11933          15 :         GDALGeoTransform gt;
   11934          15 :         if (m_poDS->GetGeoTransform(gt) == CE_None && gt[2] == 0 && gt[4] == 0)
   11935             :         {
   11936          24 :             m_varX = GDALMDArrayRegularlySpaced::Create(
   11937          24 :                 "/", poBandDim->GetName(), poXDim, gt[0], gt[1], 0.5);
   11938           8 :             poXDim->SetIndexingVariable(m_varX);
   11939             : 
   11940          24 :             m_varY = GDALMDArrayRegularlySpaced::Create(
   11941          24 :                 "/", poYDim->GetName(), poYDim, gt[3], gt[5], 0.5);
   11942           8 :             poYDim->SetIndexingVariable(m_varY);
   11943             :         }
   11944          15 :         if (bBandYX)
   11945             :         {
   11946          84 :             m_dims = {std::move(poBandDim), std::move(poYDim),
   11947          70 :                       std::move(poXDim)};
   11948             :         }
   11949             :         else
   11950             :         {
   11951           1 :             m_iYDim = 0;
   11952           1 :             m_iXDim = 1;
   11953           1 :             m_iBandDim = 2;
   11954           6 :             m_dims = {std::move(poYDim), std::move(poXDim),
   11955           5 :                       std::move(poBandDim)};
   11956             :         }
   11957          15 :     }
   11958             : 
   11959             :     bool IRead(const GUInt64 *arrayStartIdx, const size_t *count,
   11960             :                const GInt64 *arrayStep, const GPtrDiff_t *bufferStride,
   11961             :                const GDALExtendedDataType &bufferDataType,
   11962             :                void *pDstBuffer) const override;
   11963             : 
   11964           1 :     bool IWrite(const GUInt64 *arrayStartIdx, const size_t *count,
   11965             :                 const GInt64 *arrayStep, const GPtrDiff_t *bufferStride,
   11966             :                 const GDALExtendedDataType &bufferDataType,
   11967             :                 const void *pSrcBuffer) override
   11968             :     {
   11969           1 :         return ReadWrite(GF_Write, arrayStartIdx, count, arrayStep,
   11970             :                          bufferStride, bufferDataType,
   11971           1 :                          const_cast<void *>(pSrcBuffer));
   11972             :     }
   11973             : 
   11974             :   public:
   11975          30 :     ~GDALMDArrayFromDataset() override
   11976          15 :     {
   11977          15 :         m_poDS->ReleaseRef();
   11978          30 :     }
   11979             : 
   11980          15 :     static std::shared_ptr<GDALMDArray> Create(GDALDataset *poDS,
   11981             :                                                CSLConstList papszOptions)
   11982             :     {
   11983             :         auto array(std::shared_ptr<GDALMDArrayFromDataset>(
   11984          30 :             new GDALMDArrayFromDataset(poDS, papszOptions)));
   11985          15 :         array->SetSelf(array);
   11986          30 :         return array;
   11987             :     }
   11988             : 
   11989           2 :     bool IsWritable() const override
   11990             :     {
   11991           2 :         return m_poDS->GetAccess() == GA_Update;
   11992             :     }
   11993             : 
   11994          16 :     const std::string &GetFilename() const override
   11995             :     {
   11996          16 :         return m_osFilename;
   11997             :     }
   11998             : 
   11999             :     const std::vector<std::shared_ptr<GDALDimension>> &
   12000          99 :     GetDimensions() const override
   12001             :     {
   12002          99 :         return m_dims;
   12003             :     }
   12004             : 
   12005          38 :     const GDALExtendedDataType &GetDataType() const override
   12006             :     {
   12007          38 :         return m_dt;
   12008             :     }
   12009             : 
   12010           5 :     const std::string &GetUnit() const override
   12011             :     {
   12012           5 :         return m_osUnit;
   12013             :     }
   12014             : 
   12015           5 :     const void *GetRawNoDataValue() const override
   12016             :     {
   12017           5 :         return m_abyNoData.empty() ? nullptr : m_abyNoData.data();
   12018             :     }
   12019             : 
   12020           5 :     double GetOffset(bool *pbHasOffset,
   12021             :                      GDALDataType *peStorageType) const override
   12022             :     {
   12023           5 :         double dfRes = 0;
   12024           5 :         int bHasOffset = false;
   12025           5 :         auto poFirstBand = m_poDS->GetRasterBand(1);
   12026           5 :         if (poFirstBand)  // to avoid -Wnull-dereference
   12027             :         {
   12028           5 :             dfRes = poFirstBand->GetOffset(&bHasOffset);
   12029           7 :             for (int i = 2; bHasOffset && i <= m_poDS->GetRasterCount(); ++i)
   12030             :             {
   12031             :                 const double dfOtherRes =
   12032           2 :                     m_poDS->GetRasterBand(i)->GetOffset(&bHasOffset);
   12033           2 :                 bHasOffset = bHasOffset && (dfOtherRes == dfRes);
   12034             :             }
   12035             :         }
   12036           5 :         if (pbHasOffset)
   12037           5 :             *pbHasOffset = CPL_TO_BOOL(bHasOffset);
   12038           5 :         if (peStorageType)
   12039           3 :             *peStorageType = GDT_Unknown;
   12040           5 :         return dfRes;
   12041             :     }
   12042             : 
   12043           5 :     double GetScale(bool *pbHasScale,
   12044             :                     GDALDataType *peStorageType) const override
   12045             :     {
   12046           5 :         double dfRes = 0;
   12047           5 :         int bHasScale = false;
   12048           5 :         auto poFirstBand = m_poDS->GetRasterBand(1);
   12049           5 :         if (poFirstBand)  // to avoid -Wnull-dereference
   12050             :         {
   12051           5 :             dfRes = poFirstBand->GetScale(&bHasScale);
   12052           7 :             for (int i = 2; bHasScale && i <= m_poDS->GetRasterCount(); ++i)
   12053             :             {
   12054             :                 const double dfOtherRes =
   12055           2 :                     m_poDS->GetRasterBand(i)->GetScale(&bHasScale);
   12056           2 :                 bHasScale = bHasScale && (dfOtherRes == dfRes);
   12057             :             }
   12058             :         }
   12059           5 :         if (pbHasScale)
   12060           5 :             *pbHasScale = CPL_TO_BOOL(bHasScale);
   12061           5 :         if (peStorageType)
   12062           3 :             *peStorageType = GDT_Unknown;
   12063           5 :         return dfRes;
   12064             :     }
   12065             : 
   12066           9 :     std::shared_ptr<OGRSpatialReference> GetSpatialRef() const override
   12067             :     {
   12068           9 :         auto poSrcSRS = m_poDS->GetSpatialRef();
   12069           9 :         if (!poSrcSRS)
   12070           1 :             return nullptr;
   12071          16 :         auto poSRS = std::shared_ptr<OGRSpatialReference>(poSrcSRS->Clone());
   12072             : 
   12073          16 :         auto axisMapping = poSRS->GetDataAxisToSRSAxisMapping();
   12074          24 :         for (auto &m : axisMapping)
   12075             :         {
   12076          16 :             if (m == 1)
   12077           8 :                 m = m_iXDim + 1;
   12078           8 :             else if (m == 2)
   12079           8 :                 m = m_iYDim + 1;
   12080             :             else
   12081           0 :                 m = 0;
   12082             :         }
   12083           8 :         poSRS->SetDataAxisToSRSAxisMapping(axisMapping);
   12084           8 :         return poSRS;
   12085             :     }
   12086             : 
   12087           7 :     std::vector<GUInt64> GetBlockSize() const override
   12088             :     {
   12089           7 :         int nBlockXSize = 0;
   12090           7 :         int nBlockYSize = 0;
   12091           7 :         m_poDS->GetRasterBand(1)->GetBlockSize(&nBlockXSize, &nBlockYSize);
   12092           7 :         if (m_iBandDim == 0)
   12093             :         {
   12094           6 :             return std::vector<GUInt64>{1, static_cast<GUInt64>(nBlockYSize),
   12095           6 :                                         static_cast<GUInt64>(nBlockXSize)};
   12096             :         }
   12097             :         else
   12098             :         {
   12099           1 :             return std::vector<GUInt64>{static_cast<GUInt64>(nBlockYSize),
   12100           1 :                                         static_cast<GUInt64>(nBlockXSize), 1};
   12101             :         }
   12102             :     }
   12103             : 
   12104             :     std::vector<std::shared_ptr<GDALAttribute>>
   12105           7 :     GetAttributes(CSLConstList) const override
   12106             :     {
   12107           7 :         std::vector<std::shared_ptr<GDALAttribute>> res;
   12108           7 :         auto papszMD = m_poDS->GetMetadata();
   12109          14 :         for (auto iter = papszMD; iter && iter[0]; ++iter)
   12110             :         {
   12111           7 :             char *pszKey = nullptr;
   12112           7 :             const char *pszValue = CPLParseNameValue(*iter, &pszKey);
   12113           7 :             if (pszKey && pszValue)
   12114             :             {
   12115             :                 res.emplace_back(
   12116           7 :                     std::make_shared<GDALMDIAsAttribute>(pszKey, pszValue));
   12117             :             }
   12118           7 :             CPLFree(pszKey);
   12119             :         }
   12120           7 :         return res;
   12121             :     }
   12122             : };
   12123             : 
   12124          10 : bool GDALMDArrayFromDataset::IRead(const GUInt64 *arrayStartIdx,
   12125             :                                    const size_t *count, const GInt64 *arrayStep,
   12126             :                                    const GPtrDiff_t *bufferStride,
   12127             :                                    const GDALExtendedDataType &bufferDataType,
   12128             :                                    void *pDstBuffer) const
   12129             : {
   12130          10 :     return ReadWrite(GF_Read, arrayStartIdx, count, arrayStep, bufferStride,
   12131          10 :                      bufferDataType, pDstBuffer);
   12132             : }
   12133             : 
   12134             : /************************************************************************/
   12135             : /*                            ReadWrite()                               */
   12136             : /************************************************************************/
   12137             : 
   12138          11 : bool GDALMDArrayFromDataset::ReadWrite(
   12139             :     GDALRWFlag eRWFlag, const GUInt64 *arrayStartIdx, const size_t *count,
   12140             :     const GInt64 *arrayStep, const GPtrDiff_t *bufferStride,
   12141             :     const GDALExtendedDataType &bufferDataType, void *pBuffer) const
   12142             : {
   12143          11 :     const auto eDT(bufferDataType.GetNumericDataType());
   12144          11 :     const auto nDTSize(GDALGetDataTypeSizeBytes(eDT));
   12145          11 :     const int nX =
   12146          11 :         arrayStep[m_iXDim] > 0
   12147          11 :             ? static_cast<int>(arrayStartIdx[m_iXDim])
   12148           0 :             : static_cast<int>(arrayStartIdx[m_iXDim] -
   12149           0 :                                (count[m_iXDim] - 1) * -arrayStep[m_iXDim]);
   12150          11 :     const int nY =
   12151          11 :         arrayStep[m_iYDim] > 0
   12152          11 :             ? static_cast<int>(arrayStartIdx[m_iYDim])
   12153           1 :             : static_cast<int>(arrayStartIdx[m_iYDim] -
   12154           1 :                                (count[m_iYDim] - 1) * -arrayStep[m_iYDim]);
   12155          11 :     const int nSizeX =
   12156          11 :         static_cast<int>(count[m_iXDim] * ABS(arrayStep[m_iXDim]));
   12157          11 :     const int nSizeY =
   12158          11 :         static_cast<int>(count[m_iYDim] * ABS(arrayStep[m_iYDim]));
   12159          11 :     GByte *pabyBuffer = static_cast<GByte *>(pBuffer);
   12160          11 :     int nStrideXSign = 1;
   12161          11 :     if (arrayStep[m_iXDim] < 0)
   12162             :     {
   12163           0 :         pabyBuffer += (count[m_iXDim] - 1) * bufferStride[m_iXDim] * nDTSize;
   12164           0 :         nStrideXSign = -1;
   12165             :     }
   12166          11 :     int nStrideYSign = 1;
   12167          11 :     if (arrayStep[m_iYDim] < 0)
   12168             :     {
   12169           1 :         pabyBuffer += (count[m_iYDim] - 1) * bufferStride[m_iYDim] * nDTSize;
   12170           1 :         nStrideYSign = -1;
   12171             :     }
   12172          11 :     const GSpacing nPixelSpace =
   12173          11 :         static_cast<GSpacing>(nStrideXSign * bufferStride[m_iXDim] * nDTSize);
   12174          11 :     const GSpacing nLineSpace =
   12175          11 :         static_cast<GSpacing>(nStrideYSign * bufferStride[m_iYDim] * nDTSize);
   12176          11 :     const GSpacing nBandSpace =
   12177          11 :         static_cast<GSpacing>(bufferStride[m_iBandDim] * nDTSize);
   12178          11 :     std::vector<int> anBandList;
   12179          28 :     for (int i = 0; i < static_cast<int>(count[m_iBandDim]); ++i)
   12180          17 :         anBandList.push_back(1 + static_cast<int>(arrayStartIdx[m_iBandDim]) +
   12181          17 :                              i * static_cast<int>(arrayStep[m_iBandDim]));
   12182             : 
   12183          33 :     return m_poDS->RasterIO(eRWFlag, nX, nY, nSizeX, nSizeY, pabyBuffer,
   12184          11 :                             static_cast<int>(count[m_iXDim]),
   12185          11 :                             static_cast<int>(count[m_iYDim]), eDT,
   12186          11 :                             static_cast<int>(count[m_iBandDim]),
   12187          11 :                             anBandList.data(), nPixelSpace, nLineSpace,
   12188          22 :                             nBandSpace, nullptr) == CE_None;
   12189             : }
   12190             : 
   12191             : /************************************************************************/
   12192             : /*                            AsMDArray()                               */
   12193             : /************************************************************************/
   12194             : 
   12195             : /** Return a view of this dataset as a 3D multidimensional GDALMDArray.
   12196             :  *
   12197             :  * If this dataset is not already marked as shared, it will be, so that the
   12198             :  * returned array holds a reference to it.
   12199             :  *
   12200             :  * If the dataset has a geotransform attached, the X and Y dimensions of the
   12201             :  * returned array will have an associated indexing variable.
   12202             :  *
   12203             :  * The currently supported list of options is:
   12204             :  * <ul>
   12205             :  * <li>DIM_ORDER=&lt;order&gt; where order can be "AUTO", "Band,Y,X" or "Y,X,Band".
   12206             :  * "Band,Y,X" means that the first (slowest changing) dimension is Band
   12207             :  * and the last (fastest changing direction) is X
   12208             :  * "Y,X,Band" means that the first (slowest changing) dimension is Y
   12209             :  * and the last (fastest changing direction) is Band.
   12210             :  * "AUTO" (the default) selects "Band,Y,X" for single band datasets, or takes
   12211             :  * into account the INTERLEAVE metadata item in the IMAGE_STRUCTURE domain.
   12212             :  * If it equals BAND, then "Band,Y,X" is used. Otherwise (if it equals PIXEL),
   12213             :  * "Y,X,Band" is use.
   12214             :  * </li>
   12215             :  * <li>BAND_INDEXING_VAR_ITEM={Description}|{None}|{Index}|{ColorInterpretation}|&lt;BandMetadataItem&gt;:
   12216             :  * item from which to build the band indexing variable.
   12217             :  * <ul>
   12218             :  * <li>"{Description}", the default, means to use the band description (or "Band index" if empty).</li>
   12219             :  * <li>"{None}" means that no band indexing variable must be created.</li>
   12220             :  * <li>"{Index}" means that the band index (starting at one) is used.</li>
   12221             :  * <li>"{ColorInterpretation}" means that the band color interpretation is used (i.e. "Red", "Green", "Blue").</li>
   12222             :  * <li>&lt;BandMetadataItem&gt; is the name of a band metadata item to use.</li>
   12223             :  * </ul>
   12224             :  * </li>
   12225             :  * <li>BAND_INDEXING_VAR_TYPE=String|Real|Integer: the data type of the band
   12226             :  * indexing variable, when BAND_INDEXING_VAR_ITEM corresponds to a band metadata item.
   12227             :  * Defaults to String.
   12228             :  * </li>
   12229             :  * <li>BAND_DIM_NAME=&lt;string&gt;: Name of the band dimension.
   12230             :  * Defaults to "Band".
   12231             :  * </li>
   12232             :  * <li>X_DIM_NAME=&lt;string&gt;: Name of the X dimension. Defaults to "X".
   12233             :  * </li>
   12234             :  * <li>Y_DIM_NAME=&lt;string&gt;: Name of the Y dimension. Defaults to "Y".
   12235             :  * </li>
   12236             :  * </ul>
   12237             :  *
   12238             :  * This is the same as the C function GDALDatasetAsMDArray().
   12239             :  *
   12240             :  * The "reverse" method is GDALMDArray::AsClassicDataset().
   12241             :  *
   12242             :  * @param papszOptions Null-terminated list of strings, or nullptr.
   12243             :  * @return a new array, or nullptr.
   12244             :  *
   12245             :  * @since GDAL 3.12
   12246             :  */
   12247          18 : std::shared_ptr<GDALMDArray> GDALDataset::AsMDArray(CSLConstList papszOptions)
   12248             : {
   12249          18 :     if (!GetShared())
   12250             :     {
   12251          17 :         MarkAsShared();
   12252             :     }
   12253          18 :     if (nBands == 0 || nRasterXSize == 0 || nRasterYSize == 0)
   12254             :     {
   12255           1 :         ReportError(
   12256             :             CE_Failure, CPLE_AppDefined,
   12257             :             "Degenerated array (band, Y and/or X dimension of size zero)");
   12258           1 :         return nullptr;
   12259             :     }
   12260          17 :     const GDALDataType eDT = papoBands[0]->GetRasterDataType();
   12261          30 :     for (int i = 1; i < nBands; ++i)
   12262             :     {
   12263          14 :         if (eDT != papoBands[i]->GetRasterDataType())
   12264             :         {
   12265           1 :             ReportError(CE_Failure, CPLE_AppDefined,
   12266             :                         "Non-uniform data type amongst bands");
   12267           1 :             return nullptr;
   12268             :         }
   12269             :     }
   12270             :     const char *pszDimOrder =
   12271          16 :         CSLFetchNameValueDef(papszOptions, "DIM_ORDER", "AUTO");
   12272          16 :     if (!EQUAL(pszDimOrder, "AUTO") && !EQUAL(pszDimOrder, "Band,Y,X") &&
   12273           2 :         !EQUAL(pszDimOrder, "Y,X,Band"))
   12274             :     {
   12275           1 :         ReportError(CE_Failure, CPLE_IllegalArg,
   12276             :                     "Illegal value for DIM_ORDER option");
   12277           1 :         return nullptr;
   12278             :     }
   12279          15 :     return GDALMDArrayFromDataset::Create(this, papszOptions);
   12280             : }
   12281             : 
   12282             : /************************************************************************/
   12283             : /*              GDALDataset::GetInterBandCovarianceMatrix()             */
   12284             : /************************************************************************/
   12285             : 
   12286             : /**
   12287             :  \brief Fetch or compute the covariance matrix between bands of this dataset.
   12288             : 
   12289             :  The covariance indicates the level to which two bands vary together.
   12290             : 
   12291             :  If we call \f$ v_i[y,x] \f$ the value of pixel at row=y and column=x for band i,
   12292             :  and \f$ mean_i \f$ the mean value of all pixels of band i, then
   12293             : 
   12294             :  \f[
   12295             :     \mathrm{cov}[i,j] =
   12296             :     \frac{
   12297             :         \sum_{y,x} \left( v_i[y,x] - \mathrm{mean}_i \right)
   12298             :         \left( v_j[y,x] - \mathrm{mean}_j \right)
   12299             :     }{
   12300             :         \mathrm{pixel\_count} - \mathrm{nDeltaDegreeOfFreedom}
   12301             :     }
   12302             :  \f]
   12303             : 
   12304             :  When there are no nodata values, \f$ pixel\_count = GetRasterXSize() * GetRasterYSize() \f$.
   12305             :  We can see that \f$ cov[i,j] = cov[j,i] \f$, and consequently the returned matrix
   12306             :  is symmetric.
   12307             : 
   12308             :  A value of nDeltaDegreeOfFreedom=1 (the default) will return a unbiased estimate
   12309             :  if the pixels in bands are considered to be a sample of the whole population.
   12310             :  This is consistent with the default of
   12311             :  https://numpy.org/doc/stable/reference/generated/numpy.cov.html and the returned
   12312             :  matrix is consistent with what can be obtained with
   12313             : 
   12314             :  \verbatim embed:rst
   12315             :  .. code-block:: python
   12316             : 
   12317             :      numpy.cov(
   12318             :         [ds.GetRasterBand(n + 1).ReadAsArray().ravel() for n in range(ds.RasterCount)]
   12319             :      )
   12320             :  \endverbatim
   12321             : 
   12322             :  Otherwise a value of nDeltaDegreeOfFreedom=0 can be used if they are considered
   12323             :  to be the whole population.
   12324             : 
   12325             :  If STATISTICS_COVARIANCES metadata items are available in band metadata,
   12326             :  this method uses them.
   12327             :  Otherwise, if bForce is true, ComputeInterBandCovarianceMatrix() is called.
   12328             :  Otherwise, if bForce is false, an empty vector is returned
   12329             : 
   12330             :  @param nBandCount Zero for all bands, or number of values in panBandList.
   12331             :                    Defaults to 0.
   12332             :  @param panBandList nullptr for all bands if nBandCount == 0, or array of
   12333             :                     nBandCount values such as panBandList[i] is the index
   12334             :                     between 1 and GetRasterCount() of a band that must be used
   12335             :                     in the covariance computation. Defaults to nullptr.
   12336             :  @param bApproxOK Whether it is acceptable to use a subsample of values in
   12337             :                   ComputeInterBandCovarianceMatrix().
   12338             :                   Defaults to false.
   12339             :  @param bForce Whether ComputeInterBandCovarianceMatrix() should be called
   12340             :                when the STATISTICS_COVARIANCES metadata items are missing.
   12341             :                Defaults to false.
   12342             :  @param bWriteIntoMetadata Whether ComputeInterBandCovarianceMatrix() must
   12343             :                            write STATISTICS_COVARIANCES band metadata items.
   12344             :                            Defaults to true.
   12345             :  @param nDeltaDegreeOfFreedom Correction term to subtract in the final
   12346             :                               averaging phase of the covariance computation.
   12347             :                               Defaults to 1.
   12348             :  @param pfnProgress a function to call to report progress, or NULL.
   12349             :  @param pProgressData application data to pass to the progress function.
   12350             : 
   12351             :  @return a vector of nBandCount * nBandCount values if successful,
   12352             :          in row-major order, or an empty vector in case of failure
   12353             : 
   12354             :  @since 3.13
   12355             : 
   12356             :  @see ComputeInterBandCovarianceMatrix()
   12357             :  */
   12358             : 
   12359           0 : std::vector<double> GDALDataset::GetInterBandCovarianceMatrix(
   12360             :     int nBandCount, const int *panBandList, bool bApproxOK, bool bForce,
   12361             :     bool bWriteIntoMetadata, int nDeltaDegreeOfFreedom,
   12362             :     GDALProgressFunc pfnProgress, void *pProgressData)
   12363             : {
   12364           0 :     std::vector<double> res;
   12365           0 :     const int nBandCountToUse = nBandCount == 0 ? nBands : nBandCount;
   12366           0 :     if (nBandCountToUse == 0)
   12367           0 :         return res;
   12368             :     if constexpr (sizeof(size_t) < sizeof(uint64_t))
   12369             :     {
   12370             :         // Check that nBandCountToUse * nBandCountToUse will not overflow size_t
   12371             :         if (static_cast<uint32_t>(nBandCountToUse) >
   12372             :             std::numeric_limits<uint16_t>::max())
   12373             :         {
   12374             :             CPLError(CE_Failure, CPLE_OutOfMemory,
   12375             :                      "Not enough memory to store result");
   12376             :             return res;
   12377             :         }
   12378             :     }
   12379             :     try
   12380             :     {
   12381           0 :         res.resize(static_cast<size_t>(nBandCountToUse) * nBandCountToUse);
   12382             :     }
   12383           0 :     catch (const std::exception &)
   12384             :     {
   12385           0 :         CPLError(CE_Failure, CPLE_OutOfMemory,
   12386             :                  "Not enough memory to store result");
   12387           0 :         return res;
   12388             :     }
   12389             : 
   12390           0 :     if (GetInterBandCovarianceMatrix(res.data(), res.size(), nBandCount,
   12391             :                                      panBandList, bApproxOK, bForce,
   12392             :                                      bWriteIntoMetadata, nDeltaDegreeOfFreedom,
   12393           0 :                                      pfnProgress, pProgressData) != CE_None)
   12394             :     {
   12395           0 :         res.clear();
   12396             :     }
   12397           0 :     return res;
   12398             : }
   12399             : 
   12400             : /************************************************************************/
   12401             : /*              GDALDataset::GetInterBandCovarianceMatrix()             */
   12402             : /************************************************************************/
   12403             : 
   12404             : /**
   12405             :  \brief Fetch or compute the covariance matrix between bands of this dataset.
   12406             : 
   12407             :  The covariance indicates the level to which two bands vary together.
   12408             : 
   12409             :  If we call \f$ v_i[y,x] \f$ the value of pixel at row=y and column=x for band i,
   12410             :  and \f$ mean_i \f$ the mean value of all pixels of band i, then
   12411             : 
   12412             :  \f[
   12413             :     \mathrm{cov}[i,j] =
   12414             :     \frac{
   12415             :         \sum_{y,x} \left( v_i[y,x] - \mathrm{mean}_i \right)
   12416             :         \left( v_j[y,x] - \mathrm{mean}_j \right)
   12417             :     }{
   12418             :         \mathrm{pixel\_count} - \mathrm{nDeltaDegreeOfFreedom}
   12419             :     }
   12420             :  \f]
   12421             : 
   12422             :  When there are no nodata values, \f$ pixel\_count = GetRasterXSize() * GetRasterYSize() \f$.
   12423             :  We can see that \f$ cov[i,j] = cov[j,i] \f$, and consequently the returned matrix
   12424             :  is symmetric.
   12425             : 
   12426             :  A value of nDeltaDegreeOfFreedom=1 (the default) will return a unbiased estimate
   12427             :  if the pixels in bands are considered to be a sample of the whole population.
   12428             :  This is consistent with the default of
   12429             :  https://numpy.org/doc/stable/reference/generated/numpy.cov.html and the returned
   12430             :  matrix is consistent with what can be obtained with
   12431             : 
   12432             :  \verbatim embed:rst
   12433             :  .. code-block:: python
   12434             : 
   12435             :      numpy.cov(
   12436             :         [ds.GetRasterBand(n + 1).ReadAsArray().ravel() for n in range(ds.RasterCount)]
   12437             :      )
   12438             :  \endverbatim
   12439             : 
   12440             :  Otherwise a value of nDeltaDegreeOfFreedom=0 can be used if they are considered
   12441             :  to be the whole population.
   12442             : 
   12443             :  The caller must provide an already allocated array in padfCovMatrix of size
   12444             :  at least nBandCount * nBandCount.
   12445             : 
   12446             :  If STATISTICS_COVARIANCES metadata items are available in band metadata,
   12447             :  this method uses them.
   12448             :  Otherwise, if bForce is true, ComputeInterBandCovarianceMatrix() is called.
   12449             :  Otherwise, if bForce is false, an empty vector is returned
   12450             : 
   12451             :  This is the same as the C function GDALDatasetGetInterBandCovarianceMatrix()
   12452             : 
   12453             :  @param[out] padfCovMatrix Pointer to an already allocated output array, of size at least
   12454             :                       nBandCount * nBandCount.
   12455             :  @param nSize Number of elements in output array.
   12456             :  @param nBandCount Zero for all bands, or number of values in panBandList.
   12457             :                    Defaults to 0.
   12458             :  @param panBandList nullptr for all bands if nBandCount == 0, or array of
   12459             :                     nBandCount values such as panBandList[i] is the index
   12460             :                     between 1 and GetRasterCount() of a band that must be used
   12461             :                     in the covariance computation. Defaults to nullptr.
   12462             :  @param bApproxOK Whether it is acceptable to use a subsample of values in
   12463             :                   ComputeInterBandCovarianceMatrix().
   12464             :                   Defaults to false.
   12465             :  @param bForce Whether ComputeInterBandCovarianceMatrix() should be called
   12466             :                when the STATISTICS_COVARIANCES metadata items are missing.
   12467             :                Defaults to false.
   12468             :  @param bWriteIntoMetadata Whether ComputeInterBandCovarianceMatrix() must
   12469             :                            write STATISTICS_COVARIANCES band metadata items.
   12470             :                            Defaults to true.
   12471             :  @param nDeltaDegreeOfFreedom Correction term to subtract in the final
   12472             :                               averaging phase of the covariance computation.
   12473             :                               Defaults to 1.
   12474             :  @param pfnProgress a function to call to report progress, or NULL.
   12475             :  @param pProgressData application data to pass to the progress function.
   12476             : 
   12477             :  @return CE_None if successful, CE_Warning if values are not available in
   12478             :          metadata and bForce is false, or CE_Failure in case of failure
   12479             : 
   12480             :  @since 3.13
   12481             : 
   12482             :  @see ComputeInterBandCovarianceMatrix()
   12483             :  */
   12484             : 
   12485          11 : CPLErr GDALDataset::GetInterBandCovarianceMatrix(
   12486             :     double *padfCovMatrix, size_t nSize, int nBandCount, const int *panBandList,
   12487             :     bool bApproxOK, bool bForce, bool bWriteIntoMetadata,
   12488             :     int nDeltaDegreeOfFreedom, GDALProgressFunc pfnProgress,
   12489             :     void *pProgressData)
   12490             : {
   12491          22 :     std::vector<int> anBandListTmp;  // keep in this scope
   12492          11 :     if (nBandCount == 0)
   12493             :     {
   12494           0 :         if (nBands == 0)
   12495           0 :             return CE_None;
   12496           0 :         for (int i = 0; i < nBands; ++i)
   12497           0 :             anBandListTmp.push_back(i + 1);
   12498           0 :         nBandCount = nBands;
   12499           0 :         panBandList = anBandListTmp.data();
   12500             :     }
   12501             :     else
   12502             :     {
   12503          11 :         if (nBandCount > nBands)
   12504             :         {
   12505           1 :             CPLError(CE_Failure, CPLE_AppDefined,
   12506             :                      "GetInterBandCovarianceMatrix(): nBandCount > nBands");
   12507           1 :             return CE_Failure;
   12508             :         }
   12509          29 :         for (int i = 0; i < nBandCount; ++i)
   12510             :         {
   12511          21 :             if (panBandList[i] <= 0 || panBandList[i] > nBands)
   12512             :             {
   12513           2 :                 CPLError(CE_Failure, CPLE_AppDefined,
   12514             :                          "GetInterBandCovarianceMatrix(): invalid value "
   12515             :                          "panBandList[%d] = %d",
   12516           2 :                          i, panBandList[i]);
   12517           2 :                 return CE_Failure;
   12518             :             }
   12519             :         }
   12520             :     }
   12521             : 
   12522           8 :     if (nSize < static_cast<uint64_t>(nBandCount) * nBandCount)
   12523             :     {
   12524           0 :         CPLError(
   12525             :             CE_Failure, CPLE_AppDefined,
   12526             :             "GetInterBandCovarianceMatrix(): too small result matrix provided");
   12527           0 :         return CE_Failure;
   12528             :     }
   12529           8 :     bool bGotFromMD = true;
   12530           8 :     size_t resIdx = 0;
   12531          20 :     for (int i = 0; bGotFromMD && i < nBandCount; ++i)
   12532             :     {
   12533          24 :         const char *pszCov = papoBands[panBandList[i] - 1]->GetMetadataItem(
   12534          12 :             "STATISTICS_COVARIANCES");
   12535          12 :         bGotFromMD = pszCov != nullptr;
   12536          12 :         if (bGotFromMD)
   12537             :         {
   12538          12 :             const CPLStringList aosTokens(CSLTokenizeString2(pszCov, ",", 0));
   12539           6 :             bGotFromMD = aosTokens.size() == nBands;
   12540           6 :             if (bGotFromMD)
   12541             :             {
   12542          24 :                 for (int j = 0; j < nBandCount; ++j)
   12543          18 :                     padfCovMatrix[resIdx++] =
   12544          18 :                         CPLAtof(aosTokens[panBandList[j] - 1]);
   12545             :             }
   12546             :         }
   12547             :     }
   12548           8 :     if (bGotFromMD)
   12549           2 :         return CE_None;
   12550             : 
   12551           6 :     if (!bForce)
   12552           1 :         return CE_Warning;
   12553           5 :     return ComputeInterBandCovarianceMatrix(
   12554             :         padfCovMatrix, nSize, nBandCount, panBandList, bApproxOK,
   12555           5 :         bWriteIntoMetadata, nDeltaDegreeOfFreedom, pfnProgress, pProgressData);
   12556             : }
   12557             : 
   12558             : /************************************************************************/
   12559             : /*                  GDALDatasetGetInterBandCovarianceMatrix()           */
   12560             : /************************************************************************/
   12561             : 
   12562             : /**
   12563             :  \brief Fetch or compute the covariance matrix between bands of this dataset.
   12564             : 
   12565             :  The covariance indicates the level to which two bands vary together.
   12566             : 
   12567             :  If we call \f$ v_i[y,x] \f$ the value of pixel at row=y and column=x for band i,
   12568             :  and \f$ mean_i \f$ the mean value of all pixels of band i, then
   12569             : 
   12570             :  \f[
   12571             :     \mathrm{cov}[i,j] =
   12572             :     \frac{
   12573             :         \sum_{y,x} \left( v_i[y,x] - \mathrm{mean}_i \right)
   12574             :         \left( v_j[y,x] - \mathrm{mean}_j \right)
   12575             :     }{
   12576             :         \mathrm{pixel\_count} - \mathrm{nDeltaDegreeOfFreedom}
   12577             :     }
   12578             :  \f]
   12579             : 
   12580             :  When there are no nodata values, \f$ pixel\_count = GetRasterXSize() * GetRasterYSize() \f$.
   12581             :  We can see that \f$ cov[i,j] = cov[j,i] \f$, and consequently the returned matrix
   12582             :  is symmetric.
   12583             : 
   12584             :  A value of nDeltaDegreeOfFreedom=1 (the default) will return a unbiased estimate
   12585             :  if the pixels in bands are considered to be a sample of the whole population.
   12586             :  This is consistent with the default of
   12587             :  https://numpy.org/doc/stable/reference/generated/numpy.cov.html and the returned
   12588             :  matrix is consistent with what can be obtained with
   12589             : 
   12590             :  \verbatim embed:rst
   12591             :  .. code-block:: python
   12592             : 
   12593             :      numpy.cov(
   12594             :         [ds.GetRasterBand(n + 1).ReadAsArray().ravel() for n in range(ds.RasterCount)]
   12595             :      )
   12596             :  \endverbatim
   12597             : 
   12598             :  Otherwise a value of nDeltaDegreeOfFreedom=0 can be used if they are considered
   12599             :  to be the whole population.
   12600             : 
   12601             :  The caller must provide an already allocated array in padfCovMatrix of size
   12602             :  at least nBandCount * nBandCount.
   12603             : 
   12604             :  If STATISTICS_COVARIANCES metadata items are available in band metadata,
   12605             :  this method uses them.
   12606             :  Otherwise, if bForce is true, GDALDatasetComputeInterBandCovarianceMatrix() is called.
   12607             :  Otherwise, if bForce is false, an empty vector is returned
   12608             : 
   12609             :  This is the same as the C++ method GDALDataset::GetInterBandCovarianceMatrix()
   12610             : 
   12611             :  @param hDS Dataset handle.
   12612             :  @param[out] padfCovMatrix Pointer to an already allocated output array, of size at least
   12613             :                       nBandCount * nBandCount.
   12614             :  @param nSize Number of elements in output array.
   12615             :  @param nBandCount Zero for all bands, or number of values in panBandList.
   12616             :                    Defaults to 0.
   12617             :  @param panBandList nullptr for all bands if nBandCount == 0, or array of
   12618             :                     nBandCount values such as panBandList[i] is the index
   12619             :                     between 1 and GetRasterCount() of a band that must be used
   12620             :                     in the covariance computation. Defaults to nullptr.
   12621             :  @param bApproxOK Whether it is acceptable to use a subsample of values in
   12622             :                   GDALDatasetComputeInterBandCovarianceMatrix().
   12623             :                   Defaults to false.
   12624             :  @param bForce Whether GDALDatasetComputeInterBandCovarianceMatrix() should be called
   12625             :                when the STATISTICS_COVARIANCES metadata items are missing.
   12626             :                Defaults to false.
   12627             :  @param bWriteIntoMetadata Whether GDALDatasetComputeInterBandCovarianceMatrix() must
   12628             :                            write STATISTICS_COVARIANCES band metadata items.
   12629             :                            Defaults to true.
   12630             :  @param nDeltaDegreeOfFreedom Correction term to subtract in the final
   12631             :                               averaging phase of the covariance computation.
   12632             :                               Defaults to 1.
   12633             :  @param pfnProgress a function to call to report progress, or NULL.
   12634             :  @param pProgressData application data to pass to the progress function.
   12635             : 
   12636             :  @return CE_None if successful, CE_Warning if values are not available in
   12637             :          metadata and bForce is false, or CE_Failure in case of failure
   12638             : 
   12639             :  @since 3.13
   12640             : 
   12641             :  @see GDALDatasetComputeInterBandCovarianceMatrix()
   12642             :  */
   12643          11 : CPLErr GDALDatasetGetInterBandCovarianceMatrix(
   12644             :     GDALDatasetH hDS, double *padfCovMatrix, size_t nSize, int nBandCount,
   12645             :     const int *panBandList, bool bApproxOK, bool bForce,
   12646             :     bool bWriteIntoMetadata, int nDeltaDegreeOfFreedom,
   12647             :     GDALProgressFunc pfnProgress, void *pProgressData)
   12648             : {
   12649          11 :     VALIDATE_POINTER1(hDS, __func__, CE_Failure);
   12650          11 :     VALIDATE_POINTER1(padfCovMatrix, __func__, CE_Failure);
   12651          11 :     return GDALDataset::FromHandle(hDS)->GetInterBandCovarianceMatrix(
   12652             :         padfCovMatrix, nSize, nBandCount, panBandList, bApproxOK, bForce,
   12653          11 :         bWriteIntoMetadata, nDeltaDegreeOfFreedom, pfnProgress, pProgressData);
   12654             : }
   12655             : 
   12656             : /************************************************************************/
   12657             : /*              GDALDataset::ComputeInterBandCovarianceMatrix()         */
   12658             : /************************************************************************/
   12659             : 
   12660             : /**
   12661             :  \brief Compute the covariance matrix between bands of this dataset.
   12662             : 
   12663             :  The covariance indicates the level to which two bands vary together.
   12664             : 
   12665             :  If we call \f$ v_i[y,x] \f$ the value of pixel at row=y and column=x for band i,
   12666             :  and \f$ mean_i \f$ the mean value of all pixels of band i, then
   12667             : 
   12668             :  \f[
   12669             :     \mathrm{cov}[i,j] =
   12670             :     \frac{
   12671             :         \sum_{y,x} \left( v_i[y,x] - \mathrm{mean}_i \right)
   12672             :         \left( v_j[y,x] - \mathrm{mean}_j \right)
   12673             :     }{
   12674             :         \mathrm{pixel\_count} - \mathrm{nDeltaDegreeOfFreedom}
   12675             :     }
   12676             :  \f]
   12677             : 
   12678             :  When there are no nodata values, \f$ pixel\_count = GetRasterXSize() * GetRasterYSize() \f$.
   12679             :  We can see that \f$ cov[i,j] = cov[j,i] \f$, and consequently the returned matrix
   12680             :  is symmetric.
   12681             : 
   12682             :  A value of nDeltaDegreeOfFreedom=1 (the default) will return a unbiased estimate
   12683             :  if the pixels in bands are considered to be a sample of the whole population.
   12684             :  This is consistent with the default of
   12685             :  https://numpy.org/doc/stable/reference/generated/numpy.cov.html and the returned
   12686             :  matrix is consistent with what can be obtained with
   12687             : 
   12688             :  \verbatim embed:rst
   12689             :  .. code-block:: python
   12690             : 
   12691             :      numpy.cov(
   12692             :         [ds.GetRasterBand(n + 1).ReadAsArray().ravel() for n in range(ds.RasterCount)]
   12693             :      )
   12694             :  \endverbatim
   12695             : 
   12696             :  Otherwise a value of nDeltaDegreeOfFreedom=0 can be used if they are considered
   12697             :  to be the whole population.
   12698             : 
   12699             :  This method recomputes the covariance matrix, even if STATISTICS_COVARIANCES
   12700             :  metadata items are available in bands. See GetInterBandCovarianceMatrix()
   12701             :  to use them.
   12702             : 
   12703             :  @param nBandCount Zero for all bands, or number of values in panBandList.
   12704             :                    Defaults to 0.
   12705             :  @param panBandList nullptr for all bands if nBandCount == 0, or array of
   12706             :                     nBandCount values such as panBandList[i] is the index
   12707             :                     between 1 and GetRasterCount() of a band that must be used
   12708             :                     in the covariance computation. Defaults to nullptr.
   12709             :  @param bApproxOK Whether it is acceptable to use a subsample of values.
   12710             :                   Defaults to false.
   12711             :  @param bWriteIntoMetadata Whether this method must write
   12712             :                            STATISTICS_COVARIANCES band metadata items.
   12713             :                            Defaults to true.
   12714             :  @param nDeltaDegreeOfFreedom Correction term to subtract in the final
   12715             :                               averaging phase of the covariance computation.
   12716             :                               Defaults to 1.
   12717             :  @param pfnProgress a function to call to report progress, or NULL.
   12718             :  @param pProgressData application data to pass to the progress function.
   12719             : 
   12720             :  @return a vector of nBandCount * nBandCount values if successful,
   12721             :          in row-major order, or an empty vector in case of failure
   12722             : 
   12723             :  @since 3.13
   12724             : 
   12725             :  @see GetInterBandCovarianceMatrix()
   12726             :  */
   12727           0 : std::vector<double> GDALDataset::ComputeInterBandCovarianceMatrix(
   12728             :     int nBandCount, const int *panBandList, bool bApproxOK,
   12729             :     bool bWriteIntoMetadata, int nDeltaDegreeOfFreedom,
   12730             :     GDALProgressFunc pfnProgress, void *pProgressData)
   12731             : {
   12732           0 :     std::vector<double> res;
   12733           0 :     const int nBandCountToUse = nBandCount == 0 ? nBands : nBandCount;
   12734           0 :     if (nBandCountToUse == 0)
   12735           0 :         return res;
   12736             :     if constexpr (sizeof(size_t) < sizeof(uint64_t))
   12737             :     {
   12738             :         // Check that nBandCountToUse * nBandCountToUse will not overflow size_t
   12739             :         if (static_cast<uint32_t>(nBandCountToUse) >
   12740             :             std::numeric_limits<uint16_t>::max())
   12741             :         {
   12742             :             CPLError(CE_Failure, CPLE_OutOfMemory,
   12743             :                      "Not enough memory to store result");
   12744             :             return res;
   12745             :         }
   12746             :     }
   12747             :     try
   12748             :     {
   12749           0 :         res.resize(static_cast<size_t>(nBandCountToUse) * nBandCountToUse);
   12750             :     }
   12751           0 :     catch (const std::exception &)
   12752             :     {
   12753           0 :         CPLError(CE_Failure, CPLE_OutOfMemory,
   12754             :                  "Not enough memory to store result");
   12755           0 :         return res;
   12756             :     }
   12757             : 
   12758           0 :     if (ComputeInterBandCovarianceMatrix(
   12759             :             res.data(), res.size(), nBandCount, panBandList, bApproxOK,
   12760             :             bWriteIntoMetadata, nDeltaDegreeOfFreedom, pfnProgress,
   12761           0 :             pProgressData) != CE_None)
   12762           0 :         res.clear();
   12763           0 :     return res;
   12764             : }
   12765             : 
   12766             : /************************************************************************/
   12767             : /*                 ComputeInterBandCovarianceMatrixInternal()           */
   12768             : /************************************************************************/
   12769             : 
   12770             : template <class T>
   12771             : // CPL_NOSANITIZE_UNSIGNED_INT_OVERFLOW because it seems the uses of openmp-simd
   12772             : // causes that to happen
   12773             : CPL_NOSANITIZE_UNSIGNED_INT_OVERFLOW static CPLErr
   12774          15 : ComputeInterBandCovarianceMatrixInternal(GDALDataset *poDS,
   12775             :                                          double *padfCovMatrix, int nBandCount,
   12776             :                                          const int *panBandList,
   12777             :                                          GDALRasterBand *const *papoBands,
   12778             :                                          int nDeltaDegreeOfFreedom,
   12779             :                                          GDALProgressFunc pfnProgress,
   12780             :                                          void *pProgressData)
   12781             : {
   12782             :     // We use the padfCovMatrix to accumulate co-moments
   12783             :     // Dimension = nBandCount * nBandCount
   12784          15 :     double *const padfComomentMatrix = padfCovMatrix;
   12785             : 
   12786             :     // Matrix of  nBandCount * nBandCount storing co-moments, in optimized
   12787             :     // case when the block has no nodata value
   12788             :     // Only used if T != double
   12789          30 :     [[maybe_unused]] std::vector<T> aCurBlockComomentMatrix;
   12790             : 
   12791             :     // Count number of valid values in padfComomentMatrix for each (i,j) tuple
   12792             :     // Updated while iterating over blocks
   12793             :     // Dimension = nBandCount * nBandCount
   12794          30 :     std::vector<uint64_t> anCount;
   12795             : 
   12796             :     // Mean of bands, for each (i,j) tuple.
   12797             :     // Updated while iterating over blocks.
   12798             :     // This is a matrix rather than a vector due to the fact when need to update
   12799             :     // it in sync with padfComomentMatrix
   12800             :     // Dimension = nBandCount * nBandCount
   12801          30 :     std::vector<T> adfMean;
   12802             : 
   12803             :     // Number of valid values when computing adfMean, for each (i,j) tuple.
   12804             :     // Updated while iterating over blocks.
   12805             :     // This is a matrix rather than a vector due to the fact when need to update
   12806             :     // it in sync with padfComomentMatrix
   12807             :     // Dimension = nBandCount * nBandCount
   12808          30 :     std::vector<uint64_t> anCountMean;
   12809             : 
   12810             :     // Mean of values for each band i. Refreshed for each block.
   12811             :     // Dimension = nBandCount
   12812          30 :     std::vector<T> adfCurBlockMean;
   12813             : 
   12814             :     // Number of values participating to the mean for each band i.
   12815             :     // Refreshed for each block. Dimension = nBandCount
   12816          30 :     std::vector<size_t> anCurBlockCount;
   12817             : 
   12818             :     // Pixel values for all selected values for the current block
   12819             :     // Dimension = nBlockXSize * nBlockYSize * nBandCount
   12820          30 :     std::vector<T> adfCurBlockPixelsAllBands;
   12821             : 
   12822             :     // Vector of nodata values for all bands. Dimension = nBandCount
   12823          30 :     std::vector<T> adfNoData;
   12824             : 
   12825             :     // Vector of mask bands for all bands. Dimension = nBandCount
   12826          30 :     std::vector<GDALRasterBand *> apoMaskBands;
   12827             : 
   12828             :     // Vector of vector of mask values. Dimension = nBandCount
   12829          30 :     std::vector<std::vector<GByte>> aabyCurBlockMask;
   12830             : 
   12831             :     // Vector of pointer to vector of mask values. Dimension = nBandCount
   12832          30 :     std::vector<std::vector<GByte> *> pabyCurBlockMask;
   12833             : 
   12834          15 :     int nBlockXSize = 0;
   12835          15 :     int nBlockYSize = 0;
   12836          15 :     papoBands[panBandList[0] - 1]->GetBlockSize(&nBlockXSize, &nBlockYSize);
   12837             : 
   12838          30 :     if (static_cast<uint64_t>(nBlockXSize) * nBlockYSize >
   12839          15 :         std::numeric_limits<size_t>::max() / nBandCount)
   12840             :     {
   12841           0 :         poDS->ReportError(CE_Failure, CPLE_OutOfMemory,
   12842             :                           "Not enough memory for intermediate computations");
   12843           0 :         return CE_Failure;
   12844             :     }
   12845          15 :     const size_t nPixelsInBlock =
   12846          15 :         static_cast<size_t>(nBlockXSize) * nBlockYSize;
   12847             : 
   12848             :     // Allocate temporary matrices and vectors
   12849          15 :     const auto nMatrixSize = static_cast<size_t>(nBandCount) * nBandCount;
   12850             : 
   12851             :     using MySignedSize_t = std::make_signed_t<size_t>;
   12852          15 :     const auto kMax =
   12853          15 :         static_cast<MySignedSize_t>(nBandCount) * (nBandCount + 1) / 2;
   12854          30 :     std::vector<std::pair<int, int>> anMapLinearIdxToIJ;
   12855             :     try
   12856             :     {
   12857          15 :         anCount.resize(nMatrixSize);
   12858          15 :         adfMean.resize(nMatrixSize);
   12859          15 :         anCountMean.resize(nMatrixSize);
   12860             : 
   12861             :         if constexpr (!std::is_same_v<T, double>)
   12862             :         {
   12863             :             aCurBlockComomentMatrix.resize(nMatrixSize);
   12864             :         }
   12865             : 
   12866          15 :         anMapLinearIdxToIJ.resize(kMax);
   12867             : 
   12868          15 :         adfCurBlockPixelsAllBands.resize(nPixelsInBlock * nBandCount);
   12869             : 
   12870          15 :         adfCurBlockMean.resize(nBandCount);
   12871          15 :         anCurBlockCount.resize(nBandCount);
   12872          15 :         adfNoData.resize(nBandCount);
   12873          15 :         apoMaskBands.resize(nBandCount);
   12874          15 :         aabyCurBlockMask.resize(nBandCount);
   12875          15 :         pabyCurBlockMask.resize(nBandCount);
   12876             :     }
   12877           0 :     catch (const std::exception &)
   12878             :     {
   12879           0 :         poDS->ReportError(CE_Failure, CPLE_OutOfMemory,
   12880             :                           "Not enough memory for intermediate computations");
   12881           0 :         return CE_Failure;
   12882             :     }
   12883             : 
   12884          15 :     constexpr T ZERO{0};
   12885          15 :     std::fill(padfComomentMatrix,
   12886          15 :               padfComomentMatrix + static_cast<size_t>(nBandCount) * nBandCount,
   12887          15 :               0);
   12888             : 
   12889             :     {
   12890          15 :         MySignedSize_t nLinearIdx = 0;
   12891        1045 :         for (int i = 0; i < nBandCount; ++i)
   12892             :         {
   12893      501581 :             for (int j = i; j < nBandCount; ++j)
   12894             :             {
   12895      500551 :                 anMapLinearIdxToIJ[nLinearIdx] = {i, j};
   12896      500551 :                 ++nLinearIdx;
   12897             :             }
   12898             :         }
   12899             :     }
   12900             : 
   12901             :     // Fetch nodata values and mask bands
   12902          15 :     bool bAllBandsSameMask = false;
   12903          15 :     bool bIsAllInteger = false;
   12904          15 :     bool bNoneHasMaskOrNodata = false;
   12905        1045 :     for (int i = 0; i < nBandCount; ++i)
   12906             :     {
   12907        1030 :         const auto poBand = papoBands[panBandList[i] - 1];
   12908        2057 :         bIsAllInteger = (i == 0 || bIsAllInteger) &&
   12909        1027 :                         GDALDataTypeIsInteger(poBand->GetRasterDataType());
   12910        1030 :         int bHasNoData = FALSE;
   12911        1030 :         double dfNoData = poBand->GetNoDataValue(&bHasNoData);
   12912        1030 :         if (!bHasNoData)
   12913             :         {
   12914        1028 :             dfNoData = std::numeric_limits<double>::quiet_NaN();
   12915             : 
   12916        1032 :             if (poBand->GetMaskFlags() != GMF_ALL_VALID &&
   12917           4 :                 poBand->GetColorInterpretation() != GCI_AlphaBand)
   12918             :             {
   12919           4 :                 apoMaskBands[i] = poBand->GetMaskBand();
   12920             :                 try
   12921             :                 {
   12922           4 :                     aabyCurBlockMask[i].resize(nPixelsInBlock);
   12923             :                 }
   12924           0 :                 catch (const std::exception &)
   12925             :                 {
   12926           0 :                     poDS->ReportError(
   12927             :                         CE_Failure, CPLE_OutOfMemory,
   12928             :                         "Not enough memory for intermediate computations");
   12929           0 :                     return CE_Failure;
   12930             :                 }
   12931             :                 // coverity[escape]
   12932           4 :                 pabyCurBlockMask[i] = &aabyCurBlockMask[i];
   12933             :             }
   12934             :         }
   12935        1030 :         adfNoData[i] = static_cast<T>(dfNoData);
   12936        1030 :         if (i == 0)
   12937          15 :             bAllBandsSameMask = (apoMaskBands[0] != nullptr);
   12938        1015 :         else if (bAllBandsSameMask)
   12939           2 :             bAllBandsSameMask = (apoMaskBands[i] == apoMaskBands[0]);
   12940             : 
   12941        3072 :         bNoneHasMaskOrNodata = (i == 0 || bNoneHasMaskOrNodata) &&
   12942        3072 :                                std::isnan(dfNoData) &&
   12943        1026 :                                apoMaskBands[i] == nullptr;
   12944             :     }
   12945          15 :     if (bAllBandsSameMask)
   12946             :     {
   12947           2 :         for (int i = 1; i < nBandCount; ++i)
   12948             :         {
   12949           1 :             apoMaskBands[i] = nullptr;
   12950           1 :             aabyCurBlockMask[i].clear();
   12951           1 :             pabyCurBlockMask[i] = pabyCurBlockMask[0];
   12952             :         }
   12953             :     }
   12954             : 
   12955          15 :     const auto nIterCount =
   12956             :         static_cast<uint64_t>(
   12957          15 :             cpl::div_round_up(poDS->GetRasterXSize(), nBlockXSize)) *
   12958          15 :         cpl::div_round_up(poDS->GetRasterYSize(), nBlockYSize);
   12959          15 :     uint64_t nCurIter = 0;
   12960             : 
   12961          15 :     int nNumThreads = 1;
   12962             : #ifdef HAVE_OPENMP
   12963          15 :     if (nBandCount >= 100)
   12964             :     {
   12965           1 :         const int nNumCPUs = CPLGetNumCPUs();
   12966           1 :         nNumThreads = std::max(1, nNumCPUs / 2);
   12967             :         const char *pszThreads =
   12968           1 :             CPLGetConfigOption("GDAL_NUM_THREADS", nullptr);
   12969           1 :         if (pszThreads && !EQUAL(pszThreads, "ALL_CPUS"))
   12970             :         {
   12971           0 :             nNumThreads = std::clamp(atoi(pszThreads), 1, nNumCPUs);
   12972             :         }
   12973             :     }
   12974             : #endif
   12975             : 
   12976             : #ifdef CAN_DETECT_AVX2_FMA_AT_RUNTIME
   12977          30 :     const bool bHasAVX2_FMA = CPLHaveRuntimeAVX() &&
   12978          30 :                               __builtin_cpu_supports("avx2") &&
   12979             :                               __builtin_cpu_supports("fma");
   12980             : #endif
   12981             : 
   12982             :     // Iterate over all blocks
   12983          77 :     for (const auto &window : papoBands[panBandList[0] - 1]->IterateWindows())
   12984             :     {
   12985          32 :         const auto nThisBlockPixelCount =
   12986          32 :             static_cast<size_t>(window.nXSize) * window.nYSize;
   12987             : 
   12988             :         // Extract pixel values and masks
   12989          96 :         CPLErr eErr = poDS->RasterIO(
   12990          32 :             GF_Read, window.nXOff, window.nYOff, window.nXSize, window.nYSize,
   12991          32 :             adfCurBlockPixelsAllBands.data(), window.nXSize, window.nYSize,
   12992             :             gdal::CXXTypeTraits<T>::gdal_type, nBandCount, panBandList, 0, 0, 0,
   12993             :             nullptr);
   12994          32 :         if (eErr == CE_None && bAllBandsSameMask)
   12995             :         {
   12996           2 :             eErr = apoMaskBands[0]->RasterIO(
   12997           1 :                 GF_Read, window.nXOff, window.nYOff, window.nXSize,
   12998           1 :                 window.nYSize, aabyCurBlockMask[0].data(), window.nXSize,
   12999           1 :                 window.nYSize, GDT_Byte, 0, 0, nullptr);
   13000             :         }
   13001             :         else
   13002             :         {
   13003        1108 :             for (int i = 0; eErr == CE_None && i < nBandCount; ++i)
   13004             :             {
   13005        1077 :                 if (apoMaskBands[i])
   13006             :                 {
   13007           4 :                     eErr = apoMaskBands[i]->RasterIO(
   13008           2 :                         GF_Read, window.nXOff, window.nYOff, window.nXSize,
   13009           2 :                         window.nYSize, aabyCurBlockMask[i].data(),
   13010           2 :                         window.nXSize, window.nYSize, GDT_Byte, 0, 0, nullptr);
   13011             :                 }
   13012             :             }
   13013             :         }
   13014          32 :         if (eErr != CE_None)
   13015           1 :             return eErr;
   13016             : 
   13017             :         // Compute the mean of all bands for this block
   13018          32 :         bool bAllBandsAreAllNodata = false;
   13019          32 :         bool bNoBandHasNodata = false;
   13020        1111 :         for (int i = 0; i < nBandCount; ++i)
   13021             :         {
   13022        1079 :             T dfSum = 0;
   13023        1079 :             size_t nCount = 0;
   13024        1079 :             const T dfNoDataI = adfNoData[i];
   13025        1079 :             const T *padfI =
   13026        1079 :                 adfCurBlockPixelsAllBands.data() + i * nThisBlockPixelCount;
   13027             : #ifdef HAVE_OPENMP_SIMD
   13028        1079 : #pragma omp simd reduction(+ : dfSum)
   13029             : #endif
   13030             :             for (size_t iPixel = 0; iPixel < nThisBlockPixelCount; ++iPixel)
   13031             :             {
   13032      822482 :                 const T dfI = padfI[iPixel];
   13033      822482 :                 const bool bIsValid =
   13034     1644950 :                     !std::isnan(dfI) && dfI != dfNoDataI &&
   13035      822466 :                     (!pabyCurBlockMask[i] || (*pabyCurBlockMask[i])[iPixel]);
   13036      822482 :                 nCount += bIsValid;
   13037      822482 :                 dfSum += bIsValid ? dfI : ZERO;
   13038             :             }
   13039        1079 :             adfCurBlockMean[i] = nCount > 0 ? dfSum / nCount : ZERO;
   13040        1079 :             anCurBlockCount[i] = nCount;
   13041        1079 :             bAllBandsAreAllNodata =
   13042        1079 :                 (i == 0 || bAllBandsAreAllNodata) && (nCount == 0);
   13043        1079 :             bNoBandHasNodata = (i == 0 || bNoBandHasNodata) &&
   13044             :                                (nCount == nThisBlockPixelCount);
   13045             :         }
   13046             : 
   13047             :         // Modify the pixel values to shift them by minus the mean
   13048          32 :         if (!bAllBandsAreAllNodata)
   13049             :         {
   13050        1103 :             for (int i = 0; i < nBandCount; ++i)
   13051             :             {
   13052        1074 :                 T *padfI =
   13053        1074 :                     adfCurBlockPixelsAllBands.data() + i * nThisBlockPixelCount;
   13054        1074 :                 const T dfMeanI = adfCurBlockMean[i];
   13055      823546 :                 for (size_t iPixel = 0; iPixel < nThisBlockPixelCount; ++iPixel)
   13056             :                 {
   13057      822472 :                     padfI[iPixel] -= dfMeanI;
   13058             :                 }
   13059             :             }
   13060             :         }
   13061             : 
   13062             :         // Update padfComomentMatrix, anCount, adfMean, anCountMean
   13063             :         // from dfComoment, nCount, adfCurBlockMean, anCurBlockCount
   13064          32 :         const auto UpdateGlobalValues =
   13065    13507600 :             [&anCount, &adfMean, &anCountMean, &adfCurBlockMean,
   13066             :              &anCurBlockCount, padfComomentMatrix,
   13067             :              nBandCount](int i, int j, size_t nCount, T dfComoment)
   13068             :         {
   13069      500647 :             const auto idxInMatrixI = static_cast<size_t>(i) * nBandCount + j;
   13070      500647 :             const auto idxInMatrixJ = static_cast<size_t>(j) * nBandCount + i;
   13071             : 
   13072             :             // Update the total comoment using last formula of paragraph
   13073             :             // https://en.wikipedia.org/wiki/Algorithms_for_calculating_variance#Online :
   13074             :             // CoMoment(A+B) = CoMoment(A) + CoMoment(B) +
   13075             :             //                 (mean_I(A) - mean_I(B)) *
   13076             :             //                 (mean_J(A) - mean_J(B)) *
   13077             :             //                 (count(A) * count(B)) / (count(A) + count(B))
   13078             :             //
   13079             :             // There might be a small gotcha in the fact that the set of
   13080             :             // pixels on which the means are computed is not always the
   13081             :             // same as the the one on which the comoment is computed, if
   13082             :             // pixels are not valid/invalid at the same indices among bands
   13083             :             // It is not obvious (to me) what should be the correct behavior.
   13084             :             // The current approach has the benefit to avoid recomputing
   13085             :             // the mean for each (i,j) tuple, but only for all i.
   13086      500647 :             if (nCount > 0)
   13087             :             {
   13088      500639 :                 padfComomentMatrix[idxInMatrixI] +=
   13089             :                     static_cast<double>(dfComoment);
   13090      500639 :                 padfComomentMatrix[idxInMatrixI] +=
   13091      500639 :                     static_cast<double>(adfMean[idxInMatrixI] -
   13092      500639 :                                         adfCurBlockMean[i]) *
   13093      500639 :                     static_cast<double>(adfMean[idxInMatrixJ] -
   13094      500639 :                                         adfCurBlockMean[j]) *
   13095      500639 :                     (static_cast<double>(anCount[idxInMatrixI]) *
   13096      500639 :                      static_cast<double>(nCount) /
   13097      500639 :                      static_cast<double>(anCount[idxInMatrixI] + nCount));
   13098             : 
   13099      500639 :                 anCount[idxInMatrixI] += nCount;
   13100             :             }
   13101             : 
   13102             :             // Update means
   13103      500647 :             if (anCurBlockCount[i] > 0)
   13104             :             {
   13105     1001280 :                 adfMean[idxInMatrixI] +=
   13106      500640 :                     (adfCurBlockMean[i] - adfMean[idxInMatrixI]) *
   13107             :                     static_cast<T>(
   13108      500640 :                         static_cast<double>(anCurBlockCount[i]) /
   13109      500640 :                         static_cast<double>(anCountMean[idxInMatrixI] +
   13110             :                                             anCurBlockCount[i]));
   13111             : 
   13112      500640 :                 anCountMean[idxInMatrixI] += anCurBlockCount[i];
   13113             :             }
   13114             : 
   13115      500647 :             if (idxInMatrixI != idxInMatrixJ && anCurBlockCount[j] > 0)
   13116             :             {
   13117      999132 :                 adfMean[idxInMatrixJ] +=
   13118      499566 :                     (adfCurBlockMean[j] - adfMean[idxInMatrixJ]) *
   13119             :                     static_cast<T>(
   13120      499566 :                         static_cast<double>(anCurBlockCount[j]) /
   13121      499566 :                         static_cast<double>(anCountMean[idxInMatrixJ] +
   13122             :                                             anCurBlockCount[j]));
   13123             : 
   13124      499566 :                 anCountMean[idxInMatrixJ] += anCurBlockCount[j];
   13125             :             }
   13126             :         };
   13127             : 
   13128          32 :         if (bAllBandsAreAllNodata)
   13129             :         {
   13130             :             // Optimized code path where all values in the current block
   13131             :             // are invalid
   13132             : 
   13133           8 :             for (int i = 0; i < nBandCount; ++i)
   13134             :             {
   13135          12 :                 for (int j = i; j < nBandCount; ++j)
   13136             :                 {
   13137           7 :                     UpdateGlobalValues(i, j, 0, ZERO);
   13138             :                 }
   13139             :             }
   13140             :         }
   13141          29 :         else if (bNoBandHasNodata)
   13142             :         {
   13143             :             // Optimized code path where there are no invalid value in the
   13144             :             // current block
   13145             : 
   13146             :             if constexpr (!std::is_same_v<T, double>)
   13147             :             {
   13148             :                 std::fill(aCurBlockComomentMatrix.begin(),
   13149             :                           aCurBlockComomentMatrix.end(), ZERO);
   13150             : 
   13151             :                 GDALMatrixMultiplyAByTransposeAUpperTriangle(
   13152             :                     nNumThreads, adfCurBlockPixelsAllBands.data(),
   13153             :                     aCurBlockComomentMatrix.data(), nBandCount,
   13154             :                     nThisBlockPixelCount);
   13155             :             }
   13156             : #ifdef CAN_DETECT_AVX2_FMA_AT_RUNTIME
   13157          24 :             else if (bHasAVX2_FMA)
   13158             :             {
   13159          24 :                 GDALMatrixMultiplyAByTransposeAUpperTriangle_AVX2_FMA(
   13160             :                     nNumThreads, adfCurBlockPixelsAllBands.data(),
   13161             :                     padfComomentMatrix, nBandCount, nThisBlockPixelCount);
   13162             :             }
   13163             : #endif
   13164             :             else
   13165             :             {
   13166           0 :                 GDALMatrixMultiplyAByTransposeAUpperTriangle(
   13167             :                     nNumThreads, adfCurBlockPixelsAllBands.data(),
   13168             :                     padfComomentMatrix, nBandCount, nThisBlockPixelCount);
   13169             :             }
   13170             : 
   13171        1088 :             for (int i = 0; i < nBandCount; ++i)
   13172             :             {
   13173      501689 :                 for (int j = i; j < nBandCount; ++j)
   13174             :                 {
   13175             :                     if constexpr (!std::is_same_v<T, double>)
   13176             :                     {
   13177             :                         const auto idxInMatrixI =
   13178             :                             static_cast<size_t>(i) * nBandCount + j;
   13179             :                         UpdateGlobalValues(
   13180             :                             i, j, nThisBlockPixelCount,
   13181             :                             aCurBlockComomentMatrix[idxInMatrixI]);
   13182             :                     }
   13183             :                     else
   13184             :                     {
   13185      500625 :                         UpdateGlobalValues(i, j, nThisBlockPixelCount, ZERO);
   13186             :                     }
   13187             :                 }
   13188             :             }
   13189             :         }
   13190             :         else
   13191             :         {
   13192             : #ifdef HAVE_OPENMP
   13193           5 : #pragma omp parallel for schedule(static) num_threads(nNumThreads)
   13194             : #endif
   13195             :             for (MySignedSize_t k = 0; k < kMax; ++k)
   13196             :             {
   13197             :                 int i, j;
   13198             :                 std::tie(i, j) = anMapLinearIdxToIJ[k];
   13199             : 
   13200             :                 // Now compute the moment of (i, j), but just for this block
   13201             :                 size_t nCount = 0;
   13202             :                 T dfComoment = 0;
   13203             :                 const T *padfI =
   13204             :                     adfCurBlockPixelsAllBands.data() + i * nThisBlockPixelCount;
   13205             :                 const T *padfJ =
   13206             :                     adfCurBlockPixelsAllBands.data() + j * nThisBlockPixelCount;
   13207             : 
   13208             :                 // Use https://en.wikipedia.org/wiki/Algorithms_for_calculating_variance#Two-pass
   13209             :                 // for the current block
   13210             :                 if ((anCurBlockCount[i] == nThisBlockPixelCount &&
   13211             :                      anCurBlockCount[j] == nThisBlockPixelCount) ||
   13212             :                     (bNoneHasMaskOrNodata && bIsAllInteger))
   13213             :                 {
   13214             :                     // Most optimized code path: integer, no nodata, no mask
   13215             : #ifdef HAVE_OPENMP_SIMD
   13216             : #pragma omp simd reduction(+ : dfComoment)
   13217             : #endif
   13218             :                     for (size_t iPixel = 0; iPixel < nThisBlockPixelCount;
   13219             :                          ++iPixel)
   13220             :                     {
   13221             :                         dfComoment += padfI[iPixel] * padfJ[iPixel];
   13222             :                     }
   13223             :                     nCount = nThisBlockPixelCount;
   13224             :                 }
   13225             :                 else if (bNoneHasMaskOrNodata)
   13226             :                 {
   13227             :                     // Floating-point code path with no nodata and no mask
   13228             : #ifdef HAVE_OPENMP_SIMD
   13229             : #pragma omp simd reduction(+ : dfComoment)
   13230             : #endif
   13231             :                     for (size_t iPixel = 0; iPixel < nThisBlockPixelCount;
   13232             :                          ++iPixel)
   13233             :                     {
   13234             :                         const T dfAcc = padfI[iPixel] * padfJ[iPixel];
   13235             :                         const bool bIsValid = !std::isnan(dfAcc);
   13236             :                         nCount += bIsValid;
   13237             :                         dfComoment += bIsValid ? dfAcc : ZERO;
   13238             :                     }
   13239             :                 }
   13240             :                 else if (!std::isnan(adfNoData[i]) && !std::isnan(adfNoData[j]))
   13241             :                 {
   13242             :                     // Code path when there are both nodata values
   13243             :                     const T shiftedNoDataI = adfNoData[i] - adfCurBlockMean[i];
   13244             :                     const T shiftedNoDataJ = adfNoData[j] - adfCurBlockMean[j];
   13245             : 
   13246             : #ifdef HAVE_OPENMP_SIMD
   13247             : #pragma omp simd reduction(+ : dfComoment)
   13248             : #endif
   13249             :                     for (size_t iPixel = 0; iPixel < nThisBlockPixelCount;
   13250             :                          ++iPixel)
   13251             :                     {
   13252             :                         const T dfI = padfI[iPixel];
   13253             :                         const T dfJ = padfJ[iPixel];
   13254             :                         const T dfAcc = dfI * dfJ;
   13255             :                         const bool bIsValid = !std::isnan(dfAcc) &&
   13256             :                                               dfI != shiftedNoDataI &&
   13257             :                                               dfJ != shiftedNoDataJ;
   13258             :                         nCount += bIsValid;
   13259             :                         dfComoment += bIsValid ? dfAcc : ZERO;
   13260             :                     }
   13261             :                 }
   13262             :                 else
   13263             :                 {
   13264             :                     // Generic code path
   13265             :                     const T shiftedNoDataI = adfNoData[i] - adfCurBlockMean[i];
   13266             :                     const T shiftedNoDataJ = adfNoData[j] - adfCurBlockMean[j];
   13267             : 
   13268             : #ifdef HAVE_OPENMP_SIMD
   13269             : #pragma omp simd reduction(+ : dfComoment)
   13270             : #endif
   13271             :                     for (size_t iPixel = 0; iPixel < nThisBlockPixelCount;
   13272             :                          ++iPixel)
   13273             :                     {
   13274             :                         const T dfI = padfI[iPixel];
   13275             :                         const T dfJ = padfJ[iPixel];
   13276             :                         const T dfAcc = dfI * dfJ;
   13277             :                         const bool bIsValid =
   13278             :                             !std::isnan(dfAcc) && dfI != shiftedNoDataI &&
   13279             :                             dfJ != shiftedNoDataJ &&
   13280             :                             (!pabyCurBlockMask[i] ||
   13281             :                              (*pabyCurBlockMask[i])[iPixel]) &&
   13282             :                             (!pabyCurBlockMask[j] ||
   13283             :                              (*pabyCurBlockMask[j])[iPixel]);
   13284             :                         nCount += bIsValid;
   13285             :                         dfComoment += bIsValid ? dfAcc : ZERO;
   13286             :                     }
   13287             :                 }
   13288             : 
   13289             :                 UpdateGlobalValues(i, j, nCount, dfComoment);
   13290             :             }
   13291             :         }
   13292             : 
   13293          32 :         ++nCurIter;
   13294          35 :         if (pfnProgress &&
   13295           3 :             !pfnProgress(static_cast<double>(nCurIter) / nIterCount, "",
   13296             :                          pProgressData))
   13297             :         {
   13298           1 :             poDS->ReportError(CE_Failure, CPLE_UserInterrupt,
   13299             :                               "User terminated");
   13300           1 :             return CE_Failure;
   13301             :         }
   13302             :     }
   13303             : 
   13304             :     // Finalize by dividing co-moments by the number of contributing values
   13305             :     // (minus nDeltaDegreeOfFreedom) to compute final covariances.
   13306          44 :     for (int i = 0; i < nBandCount; ++i)
   13307             :     {
   13308             :         // The covariance matrix is symmetric. So start at i
   13309          81 :         for (int j = i; j < nBandCount; ++j)
   13310             :         {
   13311          51 :             const auto idxInMatrixI = static_cast<size_t>(i) * nBandCount + j;
   13312          51 :             const double dfCovariance =
   13313          51 :                 (nDeltaDegreeOfFreedom < 0 ||
   13314          51 :                  anCount[idxInMatrixI] <=
   13315          51 :                      static_cast<uint64_t>(nDeltaDegreeOfFreedom))
   13316           4 :                     ? std::numeric_limits<double>::quiet_NaN()
   13317          94 :                     : padfComomentMatrix[idxInMatrixI] /
   13318          47 :                           static_cast<double>(anCount[idxInMatrixI] -
   13319          47 :                                               nDeltaDegreeOfFreedom);
   13320             : 
   13321          51 :             padfCovMatrix[idxInMatrixI] = dfCovariance;
   13322             :             // Fill lower triangle
   13323          51 :             padfCovMatrix[static_cast<size_t>(j) * nBandCount + i] =
   13324             :                 dfCovariance;
   13325             :         }
   13326             :     }
   13327             : 
   13328          14 :     return CE_None;
   13329             : }
   13330             : 
   13331             : /************************************************************************/
   13332             : /*              GDALDataset::ComputeInterBandCovarianceMatrix()         */
   13333             : /************************************************************************/
   13334             : 
   13335             : /**
   13336             :  \brief Compute the covariance matrix between bands of this dataset.
   13337             : 
   13338             :  The covariance indicates the level to which two bands vary together.
   13339             : 
   13340             :  If we call \f$ v_i[y,x] \f$ the value of pixel at row=y and column=x for band i,
   13341             :  and \f$ mean_i \f$ the mean value of all pixels of band i, then
   13342             : 
   13343             :  \f[
   13344             :     \mathrm{cov}[i,j] =
   13345             :     \frac{
   13346             :         \sum_{y,x} \left( v_i[y,x] - \mathrm{mean}_i \right)
   13347             :         \left( v_j[y,x] - \mathrm{mean}_j \right)
   13348             :     }{
   13349             :         \mathrm{pixel\_count} - \mathrm{nDeltaDegreeOfFreedom}
   13350             :     }
   13351             :  \f]
   13352             : 
   13353             :  When there are no nodata values, \f$ pixel\_count = GetRasterXSize() * GetRasterYSize() \f$.
   13354             :  We can see that \f$ cov[i,j] = cov[j,i] \f$, and consequently the returned matrix
   13355             :  is symmetric.
   13356             : 
   13357             :  A value of nDeltaDegreeOfFreedom=1 (the default) will return a unbiased estimate
   13358             :  if the pixels in bands are considered to be a sample of the whole population.
   13359             :  This is consistent with the default of
   13360             :  https://numpy.org/doc/stable/reference/generated/numpy.cov.html and the returned
   13361             :  matrix is consistent with what can be obtained with
   13362             : 
   13363             :  \verbatim embed:rst
   13364             :  .. code-block:: python
   13365             : 
   13366             :      numpy.cov(
   13367             :         [ds.GetRasterBand(n + 1).ReadAsArray().ravel() for n in range(ds.RasterCount)]
   13368             :      )
   13369             :  \endverbatim
   13370             : 
   13371             :  Otherwise a value of nDeltaDegreeOfFreedom=0 can be used if they are considered
   13372             :  to be the whole population.
   13373             : 
   13374             :  The caller must provide an already allocated array in padfCovMatrix of size
   13375             :  at least nBandCount * nBandCount.
   13376             : 
   13377             :  This method recomputes the covariance matrix, even if STATISTICS_COVARIANCES
   13378             :  metadata items are available in bands. See GetInterBandCovarianceMatrix()
   13379             :  to use them.
   13380             : 
   13381             :  The implementation is optimized to minimize the amount of pixel reading.
   13382             : 
   13383             :  This method is the same as the C function GDALDatasetComputeInterBandCovarianceMatrix()
   13384             : 
   13385             :  @param[out] padfCovMatrix Pointer to an already allocated output array, of size at least
   13386             :                       nBandCount * nBandCount.
   13387             :  @param nSize Number of elements in output array.
   13388             :  @param nBandCount Zero for all bands, or number of values in panBandList.
   13389             :                    Defaults to 0.
   13390             :  @param panBandList nullptr for all bands if nBandCount == 0, or array of
   13391             :                     nBandCount values such as panBandList[i] is the index
   13392             :                     between 1 and GetRasterCount() of a band that must be used
   13393             :                     in the covariance computation. Defaults to nullptr.
   13394             :  @param bApproxOK Whether it is acceptable to use a subsample of values.
   13395             :                   Defaults to false.
   13396             :  @param bWriteIntoMetadata Whether this method must write
   13397             :                            STATISTICS_COVARIANCES band metadata items.
   13398             :                            Defaults to true.
   13399             :  @param nDeltaDegreeOfFreedom Correction term to subtract in the final
   13400             :                               averaging phase of the covariance computation.
   13401             :                               Defaults to 1.
   13402             :  @param pfnProgress a function to call to report progress, or NULL.
   13403             :  @param pProgressData application data to pass to the progress function.
   13404             : 
   13405             :  @return CE_None if successful, or CE_Failure in case of failure
   13406             : 
   13407             :  @since 3.13
   13408             : 
   13409             :  @see GetInterBandCovarianceMatrix()
   13410             :  */
   13411          22 : CPLErr GDALDataset::ComputeInterBandCovarianceMatrix(
   13412             :     double *padfCovMatrix, size_t nSize, int nBandCount, const int *panBandList,
   13413             :     bool bApproxOK, bool bWriteIntoMetadata, int nDeltaDegreeOfFreedom,
   13414             :     GDALProgressFunc pfnProgress, void *pProgressData)
   13415             : {
   13416          44 :     std::vector<int> anBandListTmp;  // keep in this scope
   13417          22 :     if (nBandCount == 0)
   13418             :     {
   13419           0 :         if (nBands == 0)
   13420           0 :             return CE_None;
   13421           0 :         for (int i = 0; i < nBands; ++i)
   13422           0 :             anBandListTmp.push_back(i + 1);
   13423           0 :         nBandCount = nBands;
   13424           0 :         panBandList = anBandListTmp.data();
   13425             :     }
   13426             :     else
   13427             :     {
   13428          22 :         if (nBandCount > nBands)
   13429             :         {
   13430           1 :             CPLError(CE_Failure, CPLE_AppDefined,
   13431             :                      "ComputeInterBandCovarianceMatrix(): nBandCount > nBands");
   13432           1 :             return CE_Failure;
   13433             :         }
   13434        1057 :         for (int i = 0; i < nBandCount; ++i)
   13435             :         {
   13436        1038 :             if (panBandList[i] <= 0 || panBandList[i] > nBands)
   13437             :             {
   13438           2 :                 CPLError(CE_Failure, CPLE_AppDefined,
   13439             :                          "ComputeInterBandCovarianceMatrix(): invalid value "
   13440             :                          "panBandList[%d] = %d",
   13441           2 :                          i, panBandList[i]);
   13442           2 :                 return CE_Failure;
   13443             :             }
   13444             :         }
   13445             : 
   13446          19 :         if (bWriteIntoMetadata)
   13447             :         {
   13448          14 :             bool bOK = nBandCount == nBands;
   13449          38 :             for (int i = 0; bOK && i < nBandCount; ++i)
   13450             :             {
   13451          24 :                 bOK = (panBandList[i] == i + 1);
   13452             :             }
   13453          14 :             if (!bOK)
   13454             :             {
   13455           4 :                 CPLError(CE_Failure, CPLE_AppDefined,
   13456             :                          "ComputeInterBandCovarianceMatrix(): cannot write "
   13457             :                          "STATISTICS_COVARIANCES metadata since the input band "
   13458             :                          "list is not [1, 2, ... GetRasterCount()]");
   13459           4 :                 return CE_Failure;
   13460             :             }
   13461             :         }
   13462             :     }
   13463             : 
   13464          15 :     const auto nMatrixSize = static_cast<size_t>(nBandCount) * nBandCount;
   13465          15 :     if (nSize < nMatrixSize)
   13466             :     {
   13467           0 :         CPLError(CE_Failure, CPLE_AppDefined,
   13468             :                  "ComputeInterBandCovarianceMatrix(): too small result matrix "
   13469             :                  "provided");
   13470           0 :         return CE_Failure;
   13471             :     }
   13472             : 
   13473             :     // Find appropriate overview dataset
   13474          15 :     GDALDataset *poActiveDS = this;
   13475          15 :     if (bApproxOK && papoBands[panBandList[0] - 1]->GetOverviewCount() > 0)
   13476             :     {
   13477           1 :         GDALDataset *poOvrDS = nullptr;
   13478           4 :         for (int i = 0; i < nBandCount; ++i)
   13479             :         {
   13480           3 :             const int nIdxBand = panBandList[i] - 1;
   13481           6 :             auto poOvrBand = papoBands[nIdxBand]->GetRasterSampleOverview(
   13482           3 :                 GDALSTAT_APPROX_NUMSAMPLES);
   13483             : 
   13484           6 :             if (poOvrBand == papoBands[i] ||
   13485           3 :                 poOvrBand->GetBand() != panBandList[i])
   13486             :             {
   13487           0 :                 poOvrDS = nullptr;
   13488           0 :                 break;
   13489             :             }
   13490           3 :             else if (i == 0)
   13491             :             {
   13492           1 :                 if (poOvrBand->GetDataset() == this)
   13493             :                 {
   13494           0 :                     break;
   13495             :                 }
   13496           1 :                 poOvrDS = poOvrBand->GetDataset();
   13497             :             }
   13498           2 :             else if (poOvrBand->GetDataset() != poOvrDS)
   13499             :             {
   13500           0 :                 poOvrDS = nullptr;
   13501           0 :                 break;
   13502             :             }
   13503             :         }
   13504           1 :         if (poOvrDS)
   13505             :         {
   13506           1 :             poActiveDS = poOvrDS;
   13507             :         }
   13508             :     }
   13509             : 
   13510             : #ifdef GDAL_COVARIANCE_CAN_USE_FLOAT32
   13511             :     const auto UseFloat32 = [](GDALDataType eDT)
   13512             :     {
   13513             :         return eDT == GDT_UInt8 || eDT == GDT_Int8 || eDT == GDT_UInt16 ||
   13514             :                eDT == GDT_Int16 || eDT == GDT_Float32;
   13515             :     };
   13516             : 
   13517             :     bool bUseFloat32 = UseFloat32(
   13518             :         poActiveDS->GetRasterBand(panBandList[0])->GetRasterDataType());
   13519             :     for (int i = 1; bUseFloat32 && i < nBandCount; ++i)
   13520             :     {
   13521             :         bUseFloat32 = UseFloat32(
   13522             :             poActiveDS->GetRasterBand(panBandList[i])->GetRasterDataType());
   13523             :     }
   13524             : #endif
   13525             : 
   13526             :     CPLErr eErr =
   13527             : #ifdef GDAL_COVARIANCE_CAN_USE_FLOAT32
   13528             :         bUseFloat32 ? ComputeInterBandCovarianceMatrixInternal<float>(
   13529             :                           poActiveDS, padfCovMatrix, nBandCount, panBandList,
   13530             :                           poActiveDS->papoBands, nDeltaDegreeOfFreedom,
   13531             :                           pfnProgress, pProgressData)
   13532             :                     :
   13533             : #endif
   13534          30 :                     ComputeInterBandCovarianceMatrixInternal<double>(
   13535             :                         poActiveDS, padfCovMatrix, nBandCount, panBandList,
   13536          15 :                         poActiveDS->papoBands, nDeltaDegreeOfFreedom,
   13537             :                         pfnProgress, pProgressData);
   13538             : 
   13539          15 :     if (bWriteIntoMetadata && eErr == CE_None)
   13540             :     {
   13541          10 :         CPLAssert(nBands == nBandCount);
   13542          20 :         std::string osStr;
   13543          10 :         size_t idx = 0;
   13544          32 :         for (int i = 0; i < nBands; ++i)
   13545             :         {
   13546          22 :             osStr.clear();
   13547          74 :             for (int j = 0; j < nBands; ++j, ++idx)
   13548             :             {
   13549          52 :                 if (j > 0)
   13550          30 :                     osStr += ',';
   13551          52 :                 osStr += CPLSPrintf("%.17g", padfCovMatrix[idx]);
   13552             :             }
   13553          22 :             papoBands[i]->SetMetadataItem("STATISTICS_COVARIANCES",
   13554          22 :                                           osStr.c_str());
   13555             :         }
   13556             :     }
   13557             : 
   13558          15 :     return eErr;
   13559             : }
   13560             : 
   13561             : /************************************************************************/
   13562             : /*               GDALDatasetComputeInterBandCovarianceMatrix()          */
   13563             : /************************************************************************/
   13564             : 
   13565             : /**
   13566             :  \brief Compute the covariance matrix between bands of this dataset.
   13567             : 
   13568             :  The covariance indicates the level to which two bands vary together.
   13569             : 
   13570             :  If we call \f$ v_i[y,x] \f$ the value of pixel at row=y and column=x for band i,
   13571             :  and \f$ mean_i \f$ the mean value of all pixels of band i, then
   13572             : 
   13573             :  \f[
   13574             :     \mathrm{cov}[i,j] =
   13575             :     \frac{
   13576             :         \sum_{y,x} \left( v_i[y,x] - \mathrm{mean}_i \right)
   13577             :         \left( v_j[y,x] - \mathrm{mean}_j \right)
   13578             :     }{
   13579             :         \mathrm{pixel\_count} - \mathrm{nDeltaDegreeOfFreedom}
   13580             :     }
   13581             :  \f]
   13582             : 
   13583             :  When there are no nodata values, \f$ pixel\_count = GetRasterXSize() * GetRasterYSize() \f$.
   13584             :  We can see that \f$ cov[i,j] = cov[j,i] \f$, and consequently the returned matrix
   13585             :  is symmetric.
   13586             : 
   13587             :  A value of nDeltaDegreeOfFreedom=1 (the default) will return a unbiased estimate
   13588             :  if the pixels in bands are considered to be a sample of the whole population.
   13589             :  This is consistent with the default of
   13590             :  https://numpy.org/doc/stable/reference/generated/numpy.cov.html and the returned
   13591             :  matrix is consistent with what can be obtained with
   13592             : 
   13593             :  \verbatim embed:rst
   13594             :  .. code-block:: python
   13595             : 
   13596             :      numpy.cov(
   13597             :         [ds.GetRasterBand(n + 1).ReadAsArray().ravel() for n in range(ds.RasterCount)]
   13598             :      )
   13599             :  \endverbatim
   13600             : 
   13601             :  Otherwise a value of nDeltaDegreeOfFreedom=0 can be used if they are considered
   13602             :  to be the whole population.
   13603             : 
   13604             :  The caller must provide an already allocated array in padfCovMatrix of size
   13605             :  at least GDALGetRasterCount() * GDALGetRasterCount().
   13606             : 
   13607             :  This method recomputes the covariance matrix, even if STATISTICS_COVARIANCES
   13608             :  metadata items are available in bands. See GDALDatasetGetInterBandCovarianceMatrix()
   13609             :  to use them.
   13610             : 
   13611             :  This function is the same as the C++ method GDALDataset::ComputeInterBandCovarianceMatrix()
   13612             : 
   13613             :  @param hDS Dataset handle.
   13614             :  @param[out] padfCovMatrix Pointer to an already allocated output array, of size at least
   13615             :                       nBandCount * nBandCount.
   13616             :  @param nSize Number of elements in output array.
   13617             :  @param nBandCount Zero for all bands, or number of values in panBandList.
   13618             :                    Defaults to 0.
   13619             :  @param panBandList nullptr for all bands if nBandCount == 0, or array of
   13620             :                     nBandCount values such as panBandList[i] is the index
   13621             :                     between 1 and GetRasterCount() of a band that must be used
   13622             :                     in the covariance computation. Defaults to nullptr.
   13623             :  @param bApproxOK Whether it is acceptable to use a subsample of values.
   13624             :                   Defaults to false.
   13625             :  @param bWriteIntoMetadata Whether this method must write
   13626             :                            STATISTICS_COVARIANCES band metadata items.
   13627             :                            Defaults to true.
   13628             :  @param nDeltaDegreeOfFreedom Correction term to subtract in the final
   13629             :                               averaging phase of the covariance computation.
   13630             :                               Defaults to 1.
   13631             :  @param pfnProgress a function to call to report progress, or NULL.
   13632             :  @param pProgressData application data to pass to the progress function.
   13633             : 
   13634             :  @return CE_None if successful, or CE_Failure in case of failure
   13635             : 
   13636             :  @since 3.13
   13637             : 
   13638             :  @see GDALDatasetGetInterBandCovarianceMatrix()
   13639             :  */
   13640          17 : CPLErr GDALDatasetComputeInterBandCovarianceMatrix(
   13641             :     GDALDatasetH hDS, double *padfCovMatrix, size_t nSize, int nBandCount,
   13642             :     const int *panBandList, bool bApproxOK, bool bWriteIntoMetadata,
   13643             :     int nDeltaDegreeOfFreedom, GDALProgressFunc pfnProgress,
   13644             :     void *pProgressData)
   13645             : {
   13646          17 :     VALIDATE_POINTER1(hDS, __func__, CE_Failure);
   13647          17 :     VALIDATE_POINTER1(padfCovMatrix, __func__, CE_Failure);
   13648          17 :     return GDALDataset::FromHandle(hDS)->ComputeInterBandCovarianceMatrix(
   13649             :         padfCovMatrix, nSize, nBandCount, panBandList, bApproxOK,
   13650          17 :         bWriteIntoMetadata, nDeltaDegreeOfFreedom, pfnProgress, pProgressData);
   13651             : }

Generated by: LCOV version 1.14